summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty/src/lower.rs')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs145
1 files changed, 92 insertions, 53 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 592410008..299646737 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -23,24 +23,24 @@ use hir_def::{
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
- intern::Interned,
- lang_item::lang_attr,
+ lang_item::{lang_attr, LangItem},
path::{GenericArg, ModPath, Path, PathKind, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{
ConstScalarOrPath, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
},
AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
- HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
- TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
+ HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, StaticId, StructId,
+ TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
+use intern::Interned;
use itertools::Either;
-use la_arena::ArenaMap;
+use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use stdx::{impl_from, never};
-use syntax::{ast, SmolStr};
+use syntax::ast;
use crate::{
all_super_traits,
@@ -58,6 +58,51 @@ use crate::{
};
#[derive(Debug)]
+enum ImplTraitLoweringState {
+ /// When turning `impl Trait` into opaque types, we have to collect the
+ /// bounds at the same time to get the IDs correct (without becoming too
+ /// complicated). I don't like using interior mutability (as for the
+ /// counter), but I've tried and failed to make the lifetimes work for
+ /// passing around a `&mut TyLoweringContext`. The core problem is that
+ /// we're grouping the mutable data (the counter and this field) together
+ /// with the immutable context (the references to the DB and resolver).
+ /// Splitting this up would be a possible fix.
+ Opaque(RefCell<Arena<ReturnTypeImplTrait>>),
+ Param(Cell<u16>),
+ Variable(Cell<u16>),
+ Disallowed,
+}
+impl ImplTraitLoweringState {
+ fn new(impl_trait_mode: ImplTraitLoweringMode) -> ImplTraitLoweringState {
+ match impl_trait_mode {
+ ImplTraitLoweringMode::Opaque => Self::Opaque(RefCell::new(Arena::new())),
+ ImplTraitLoweringMode::Param => Self::Param(Cell::new(0)),
+ ImplTraitLoweringMode::Variable => Self::Variable(Cell::new(0)),
+ ImplTraitLoweringMode::Disallowed => Self::Disallowed,
+ }
+ }
+
+ fn take(&self) -> Self {
+ match self {
+ Self::Opaque(x) => Self::Opaque(RefCell::new(x.take())),
+ Self::Param(x) => Self::Param(Cell::new(x.get())),
+ Self::Variable(x) => Self::Variable(Cell::new(x.get())),
+ Self::Disallowed => Self::Disallowed,
+ }
+ }
+
+ fn swap(&self, impl_trait_mode: &Self) {
+ match (self, impl_trait_mode) {
+ (Self::Opaque(x), Self::Opaque(y)) => x.swap(y),
+ (Self::Param(x), Self::Param(y)) => x.swap(y),
+ (Self::Variable(x), Self::Variable(y)) => x.swap(y),
+ (Self::Disallowed, Self::Disallowed) => (),
+ _ => panic!("mismatched lowering mode"),
+ }
+ }
+}
+
+#[derive(Debug)]
pub struct TyLoweringContext<'a> {
pub db: &'a dyn HirDatabase,
pub resolver: &'a Resolver,
@@ -67,17 +112,7 @@ pub struct TyLoweringContext<'a> {
/// should be converted to variables. I think in practice, this isn't
/// possible currently, so this should be fine for now.
pub type_param_mode: ParamLoweringMode,
- pub impl_trait_mode: ImplTraitLoweringMode,
- impl_trait_counter: Cell<u16>,
- /// When turning `impl Trait` into opaque types, we have to collect the
- /// bounds at the same time to get the IDs correct (without becoming too
- /// complicated). I don't like using interior mutability (as for the
- /// counter), but I've tried and failed to make the lifetimes work for
- /// passing around a `&mut TyLoweringContext`. The core problem is that
- /// we're grouping the mutable data (the counter and this field) together
- /// with the immutable context (the references to the DB and resolver).
- /// Splitting this up would be a possible fix.
- opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
+ impl_trait_mode: ImplTraitLoweringState,
expander: RefCell<Option<Expander>>,
/// Tracks types with explicit `?Sized` bounds.
pub(crate) unsized_types: RefCell<FxHashSet<Ty>>,
@@ -85,19 +120,15 @@ pub struct TyLoweringContext<'a> {
impl<'a> TyLoweringContext<'a> {
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
- let impl_trait_counter = Cell::new(0);
- let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
+ let impl_trait_mode = ImplTraitLoweringState::Disallowed;
let type_param_mode = ParamLoweringMode::Placeholder;
let in_binders = DebruijnIndex::INNERMOST;
- let opaque_type_data = RefCell::new(Vec::new());
Self {
db,
resolver,
in_binders,
impl_trait_mode,
- impl_trait_counter,
type_param_mode,
- opaque_type_data,
expander: RefCell::new(None),
unsized_types: RefCell::default(),
}
@@ -108,20 +139,18 @@ impl<'a> TyLoweringContext<'a> {
debruijn: DebruijnIndex,
f: impl FnOnce(&TyLoweringContext<'_>) -> T,
) -> T {
- let opaque_ty_data_vec = self.opaque_type_data.take();
+ let impl_trait_mode = self.impl_trait_mode.take();
let expander = self.expander.take();
let unsized_types = self.unsized_types.take();
let new_ctx = Self {
in_binders: debruijn,
- impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
- opaque_type_data: RefCell::new(opaque_ty_data_vec),
+ impl_trait_mode,
expander: RefCell::new(expander),
unsized_types: RefCell::new(unsized_types),
..*self
};
let result = f(&new_ctx);
- self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
- self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
+ self.impl_trait_mode.swap(&new_ctx.impl_trait_mode);
self.expander.replace(new_ctx.expander.into_inner());
self.unsized_types.replace(new_ctx.unsized_types.into_inner());
result
@@ -136,7 +165,7 @@ impl<'a> TyLoweringContext<'a> {
}
pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
- Self { impl_trait_mode, ..self }
+ Self { impl_trait_mode: ImplTraitLoweringState::new(impl_trait_mode), ..self }
}
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
@@ -244,20 +273,17 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::DynTrait(bounds) => self.lower_dyn_trait(bounds),
TypeRef::ImplTrait(bounds) => {
- match self.impl_trait_mode {
- ImplTraitLoweringMode::Opaque => {
- let idx = self.impl_trait_counter.get();
- self.impl_trait_counter.set(idx + 1);
+ match &self.impl_trait_mode {
+ ImplTraitLoweringState::Opaque(opaque_type_data) => {
let func = match self.resolver.generic_def() {
Some(GenericDefId::FunctionId(f)) => f,
_ => panic!("opaque impl trait lowering in non-function"),
};
- assert!(idx as usize == self.opaque_type_data.borrow().len());
// this dance is to make sure the data is in the right
// place even if we encounter more opaque types while
// lowering the bounds
- self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
+ let idx = opaque_type_data.borrow_mut().alloc(ReturnTypeImplTrait {
bounds: crate::make_single_type_binders(Vec::new()),
});
// We don't want to lower the bounds inside the binders
@@ -273,7 +299,7 @@ impl<'a> TyLoweringContext<'a> {
.with_debruijn(DebruijnIndex::INNERMOST, |ctx| {
ctx.lower_impl_trait(bounds, func)
});
- self.opaque_type_data.borrow_mut()[idx as usize] = actual_opaque_type_data;
+ opaque_type_data.borrow_mut()[idx] = actual_opaque_type_data;
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
@@ -281,10 +307,10 @@ impl<'a> TyLoweringContext<'a> {
let parameters = generics.bound_vars_subst(self.db, self.in_binders);
TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
}
- ImplTraitLoweringMode::Param => {
- let idx = self.impl_trait_counter.get();
+ ImplTraitLoweringState::Param(counter) => {
+ let idx = counter.get();
// FIXME we're probably doing something wrong here
- self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
+ counter.set(idx + count_impl_traits(type_ref) as u16);
if let Some(def) = self.resolver.generic_def() {
let generics = generics(self.db.upcast(), def);
let param = generics
@@ -305,10 +331,10 @@ impl<'a> TyLoweringContext<'a> {
TyKind::Error.intern(Interner)
}
}
- ImplTraitLoweringMode::Variable => {
- let idx = self.impl_trait_counter.get();
+ ImplTraitLoweringState::Variable(counter) => {
+ let idx = counter.get();
// FIXME we're probably doing something wrong here
- self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
+ counter.set(idx + count_impl_traits(type_ref) as u16);
let (
_parent_params,
self_params,
@@ -327,7 +353,7 @@ impl<'a> TyLoweringContext<'a> {
))
.intern(Interner)
}
- ImplTraitLoweringMode::Disallowed => {
+ ImplTraitLoweringState::Disallowed => {
// FIXME: report error
TyKind::Error.intern(Interner)
}
@@ -954,7 +980,7 @@ impl<'a> TyLoweringContext<'a> {
TypeBound::Path(path, TraitBoundModifier::Maybe) => {
let sized_trait = self
.db
- .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
+ .lang_item(self.resolver.krate(), LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait());
// Don't lower associated type bindings as the only possible relaxed trait bound
// `?Sized` has no of them.
@@ -999,7 +1025,7 @@ impl<'a> TyLoweringContext<'a> {
last_segment
.into_iter()
.filter_map(|segment| segment.args_and_bindings)
- .flat_map(|args_and_bindings| &args_and_bindings.bindings)
+ .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
.flat_map(move |binding| {
let found = associated_type_by_name_including_super_traits(
self.db,
@@ -1042,7 +1068,7 @@ impl<'a> TyLoweringContext<'a> {
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
}
- for bound in &binding.bounds {
+ for bound in binding.bounds.iter() {
preds.extend(self.lower_type_bound(
bound,
TyKind::Alias(AliasTy::Projection(projection_ty.clone())).intern(Interner),
@@ -1150,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> {
let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
let sized_trait = ctx
.db
- .lang_item(krate, SmolStr::new_inline("sized"))
+ .lang_item(krate, LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
let sized_clause = sized_trait.map(|trait_id| {
let clause = WhereClause::Implemented(TraitRef {
@@ -1209,7 +1235,7 @@ fn named_associated_type_shorthand_candidates<R>(
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
) -> Option<R> {
let mut search = |t| {
- for t in all_super_trait_refs(db, t) {
+ all_super_trait_refs(db, t, |t| {
let data = db.trait_data(t.hir_trait_id());
for (name, assoc_id) in &data.items {
@@ -1219,8 +1245,8 @@ fn named_associated_type_shorthand_candidates<R>(
}
}
}
- }
- None
+ None
+ })
};
match res {
@@ -1489,7 +1515,7 @@ fn implicitly_sized_clauses<'a>(
let is_trait_def = matches!(def, GenericDefId::TraitId(..));
let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
let sized_trait = db
- .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+ .lang_item(resolver.krate(), LangItem::Sized)
.and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
sized_trait.into_iter().flat_map(move |sized_trait| {
@@ -1704,6 +1730,15 @@ pub enum CallableDefId {
EnumVariantId(EnumVariantId),
}
impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
+impl From<CallableDefId> for ModuleDefId {
+ fn from(def: CallableDefId) -> ModuleDefId {
+ match def {
+ CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f),
+ CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)),
+ CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e),
+ }
+ }
+}
impl CallableDefId {
pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
@@ -1854,8 +1889,12 @@ pub(crate) fn return_type_impl_traits(
.with_type_param_mode(ParamLoweringMode::Variable);
let _ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into());
- let return_type_impl_traits =
- ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
+ let return_type_impl_traits = ReturnTypeImplTraits {
+ impl_traits: match ctx_ret.impl_trait_mode {
+ ImplTraitLoweringState::Opaque(x) => x.into_inner(),
+ _ => unreachable!(),
+ },
+ };
if return_type_impl_traits.impl_traits.is_empty() {
None
} else {
@@ -1931,7 +1970,7 @@ pub(crate) fn const_or_path_to_chalk(
debruijn: DebruijnIndex,
) -> Const {
match value {
- ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty),
+ ConstScalarOrPath::Scalar(s) => intern_const_scalar(*s, expected_ty),
ConstScalarOrPath::Path(n) => {
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
path_to_const(db, resolver, &path, mode, args, debruijn)