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.rs235
1 files changed, 156 insertions, 79 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 532544fee..223d705b1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
// FIXME we're probably doing something wrong here
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
let (
- parent_params,
+ _parent_params,
self_params,
list_params,
const_params,
@@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
};
TyKind::BoundVar(BoundVar::new(
self.in_binders,
- idx as usize + parent_params + self_params + list_params + const_params,
+ idx as usize + self_params + list_params + const_params,
))
.intern(Interner)
}
@@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner)
}
TypeNs::SelfType(impl_id) => {
- let generics = generics(self.db.upcast(), impl_id.into());
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
+ let def =
+ self.resolver.generic_def().expect("impl should have generic param scope");
+ let generics = generics(self.db.upcast(), def);
+
+ match self.type_param_mode {
+ ParamLoweringMode::Placeholder => {
+ // `def` can be either impl itself or item within, and we need impl itself
+ // now.
+ let generics = generics.parent_generics().unwrap_or(&generics);
+ let subst = generics.placeholder_subst(self.db);
+ self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+ }
ParamLoweringMode::Variable => {
- generics.bound_vars_subst(self.db, self.in_binders)
+ let starting_from = match def {
+ GenericDefId::ImplId(_) => 0,
+ // `def` is an item within impl. We need to substitute `BoundVar`s but
+ // remember that they are for parent (i.e. impl) generic params so they
+ // come after our own params.
+ _ => generics.len_self(),
+ };
+ TyBuilder::impl_self_ty(self.db, impl_id)
+ .fill_with_bound_vars(self.in_binders, starting_from)
+ .build()
}
- };
- self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
+ }
}
TypeNs::AdtSelfType(adt) => {
let generics = generics(self.db.upcast(), adt.into());
@@ -663,40 +680,31 @@ impl<'a> TyLoweringContext<'a> {
fn substs_from_path_segment(
&self,
segment: PathSegment<'_>,
- def_generic: Option<GenericDefId>,
+ def: Option<GenericDefId>,
infer_args: bool,
explicit_self_ty: Option<Ty>,
) -> Substitution {
+ // Remember that the item's own generic args come before its parent's.
let mut substs = Vec::new();
- let def_generics = if let Some(def) = def_generic {
- generics(self.db.upcast(), def)
+ let def = if let Some(d) = def {
+ d
} else {
return Substitution::empty(Interner);
};
+ let def_generics = generics(self.db.upcast(), def);
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
def_generics.provenance_split();
- let total_len =
- parent_params + self_params + type_params + const_params + impl_trait_params;
+ let item_len = self_params + type_params + const_params + impl_trait_params;
+ let total_len = parent_params + item_len;
- let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
+ let ty_error = TyKind::Error.intern(Interner).cast(Interner);
let mut def_generic_iter = def_generics.iter_id();
- for _ in 0..parent_params {
- if let Some(eid) = def_generic_iter.next() {
- match eid {
- Either::Left(_) => substs.push(ty_error.clone()),
- Either::Right(x) => {
- substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
- }
- }
- }
- }
-
let fill_self_params = || {
for x in explicit_self_ty
.into_iter()
- .map(|x| GenericArgData::Ty(x).intern(Interner))
+ .map(|x| x.cast(Interner))
.chain(iter::repeat(ty_error.clone()))
.take(self_params)
{
@@ -757,37 +765,40 @@ impl<'a> TyLoweringContext<'a> {
fill_self_params();
}
+ // These params include those of parent.
+ let remaining_params: SmallVec<[_; 2]> = def_generic_iter
+ .map(|eid| match eid {
+ Either::Left(_) => ty_error.clone(),
+ Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
+ })
+ .collect();
+ assert_eq!(remaining_params.len() + substs.len(), total_len);
+
// handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used).
if !infer_args || had_explicit_args {
- if let Some(def_generic) = def_generic {
- let defaults = self.db.generic_defaults(def_generic);
- assert_eq!(total_len, defaults.len());
-
- for default_ty in defaults.iter().skip(substs.len()) {
- // each default can depend on the previous parameters
- let substs_so_far = Substitution::from_iter(Interner, substs.clone());
- if let Some(_id) = def_generic_iter.next() {
- substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
- }
- }
+ let defaults = self.db.generic_defaults(def);
+ assert_eq!(total_len, defaults.len());
+ let parent_from = item_len - substs.len();
+
+ for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
+ // each default can depend on the previous parameters
+ let substs_so_far = Substitution::from_iter(
+ Interner,
+ substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
+ );
+ substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
}
- }
- // add placeholders for args that were not provided
- // FIXME: emit diagnostics in contexts where this is not allowed
- for eid in def_generic_iter {
- match eid {
- Either::Left(_) => substs.push(ty_error.clone()),
- Either::Right(x) => {
- substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
- }
- }
+ // Keep parent's params as unknown.
+ let mut remaining_params = remaining_params;
+ substs.extend(remaining_params.drain(parent_from..));
+ } else {
+ substs.extend(remaining_params);
}
- // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
- assert_eq!(substs.len(), total_len);
+ assert_eq!(substs.len(), total_len);
Substitution::from_iter(Interner, substs)
}
@@ -981,10 +992,11 @@ impl<'a> TyLoweringContext<'a> {
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
- // INVARIANT: The principal trait bound must come first. Others may be in any order but
- // should be in the same order for the same set but possibly different order of bounds in
- // the input.
- // This invariant is used by `TyExt::dyn_trait()` and chalk.
+ // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
+ // order but should be in the same order for the same set but possibly different order of
+ // bounds in the input.
+ // INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
+ // These invariants are utilized by `TyExt::dyn_trait()` and chalk.
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
let mut bounds: Vec<_> = bounds
.iter()
@@ -1035,6 +1047,12 @@ impl<'a> TyLoweringContext<'a> {
return None;
}
+ if bounds.first().and_then(|b| b.trait_id()).is_none() {
+ // When there's no trait bound, that's an error. This happens when the trait refs
+ // are unresolved.
+ return None;
+ }
+
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
// bounds. We shouldn't have repeated elements besides auto traits at this point.
bounds.dedup();
@@ -1046,7 +1064,8 @@ impl<'a> TyLoweringContext<'a> {
let bounds = crate::make_single_type_binders(bounds);
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
} else {
- // FIXME: report error (additional non-auto traits or associated type rebound)
+ // FIXME: report error
+ // (additional non-auto traits, associated type rebound, or no resolved trait)
TyKind::Error.intern(Interner)
}
}
@@ -1139,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
};
match res {
- TypeNs::SelfType(impl_id) => search(
+ TypeNs::SelfType(impl_id) => {
// we're _in_ the impl -- the binders get added back later. Correct,
// but it would be nice to make this more explicit
- db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
- ),
+ let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+
+ let impl_id_as_generic_def: GenericDefId = impl_id.into();
+ if impl_id_as_generic_def != def {
+ // `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
+ // `BoundVar`s from `def`'s point of view.
+ // FIXME: A `HirDatabase` query may be handy if this process is needed in more
+ // places. It'd be almost identical as `impl_trait_query` where `resolver` would be
+ // of `def` instead of `impl_id`.
+ let starting_idx = generics(db.upcast(), def).len_self();
+ let subst = TyBuilder::subst_for_def(db, impl_id, None)
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
+ .build();
+ let trait_ref = subst.apply(trait_ref, Interner);
+ search(trait_ref)
+ } else {
+ search(trait_ref)
+ }
+ }
TypeNs::GenericParam(param_id) => {
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
@@ -1160,10 +1196,18 @@ fn named_associated_type_shorthand_candidates<R>(
}
// Handle `Self::Type` referring to own associated type in trait definitions
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
- let generics = generics(db.upcast(), trait_id.into());
- if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+ let trait_generics = generics(db.upcast(), trait_id.into());
+ if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+ let def_generics = generics(db.upcast(), def);
+ let starting_idx = match def {
+ GenericDefId::TraitId(_) => 0,
+ // `def` is an item within trait. We need to substitute `BoundVar`s but
+ // remember that they are for parent (i.e. trait) generic params so they
+ // come after our own params.
+ _ => def_generics.len_self(),
+ };
let trait_ref = TyBuilder::trait_ref(db, trait_id)
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
.build();
return search(trait_ref);
}
@@ -1405,6 +1449,7 @@ pub(crate) fn generic_defaults_query(
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let generic_params = generics(db.upcast(), def);
+ let parent_start_idx = generic_params.len_self();
let defaults = generic_params
.iter()
@@ -1417,19 +1462,17 @@ pub(crate) fn generic_defaults_query(
let val = unknown_const_as_generic(
db.const_param_ty(ConstParamId::from_unchecked(id)),
);
- return crate::make_binders_with_count(db, idx, &generic_params, val);
+ return make_binders(db, &generic_params, val);
}
};
let mut ty =
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters.
- // type variable default referring to parameter coming
- // after it. This is forbidden (FIXME: report
- // diagnostic)
- ty = fallback_bound_vars(ty, idx);
- let val = GenericArgData::Ty(ty).intern(Interner);
- crate::make_binders_with_count(db, idx, &generic_params, val)
+ // Type variable default referring to parameter coming
+ // after it is forbidden (FIXME: report diagnostic)
+ ty = fallback_bound_vars(ty, idx, parent_start_idx);
+ crate::make_binders(db, &generic_params, ty.cast(Interner))
})
.collect();
@@ -1446,15 +1489,14 @@ pub(crate) fn generic_defaults_recover(
// we still need one default per parameter
let defaults = generic_params
.iter_id()
- .enumerate()
- .map(|(count, id)| {
+ .map(|id| {
let val = match id {
itertools::Either::Left(_) => {
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
}
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
};
- crate::make_binders_with_count(db, count, &generic_params, val)
+ crate::make_binders(db, &generic_params, val)
})
.collect();
@@ -1633,6 +1675,19 @@ pub enum ValueTyDefId {
}
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
+impl ValueTyDefId {
+ pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
+ match self {
+ Self::FunctionId(id) => Some(id.into()),
+ Self::StructId(id) => Some(id.into()),
+ Self::UnionId(id) => Some(id.into()),
+ Self::EnumVariantId(var) => Some(var.into()),
+ Self::ConstId(id) => Some(id.into()),
+ Self::StaticId(_) => None,
+ }
+ }
+}
+
/// Build the declared type of an item. This depends on the namespace; e.g. for
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
/// the constructor function `(usize) -> Foo` which lives in the values
@@ -1816,26 +1871,48 @@ pub(crate) fn const_or_path_to_chalk(
}
}
-/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
-/// num_vars_to_keep) by `TyKind::Unknown`.
+/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
+/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
+/// appears after the generic parameter of `param_index`.
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
s: T,
- num_vars_to_keep: usize,
+ param_index: usize,
+ parent_start: usize,
) -> T {
+ // Keep in mind that parent generic parameters, if any, come *after* those of the item in
+ // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
+ // its parent respectively.
+ let is_allowed = |index| {
+ if param_index < parent_start {
+ // The parameter of `param_index` is one from the item in question. Any parent generic
+ // parameters or the item's generic parameters that come before `param_index` is
+ // allowed.
+ // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
+ // ^^^^^^ ^^^^^^^^^^ these are allowed
+ !(param_index..parent_start).contains(&index)
+ } else {
+ // The parameter of `param_index` is one from the parent generics. Only parent generic
+ // parameters that come before `param_index` are allowed.
+ // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
+ // ^^^^^^ these are allowed
+ (parent_start..param_index).contains(&index)
+ }
+ };
+
crate::fold_free_vars(
s,
|bound, binders| {
- if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
- TyKind::Error.intern(Interner)
- } else {
+ if bound.index_if_innermost().map_or(true, is_allowed) {
bound.shifted_in_from(binders).to_ty(Interner)
+ } else {
+ TyKind::Error.intern(Interner)
}
},
|ty, bound, binders| {
- if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
- unknown_const(ty.clone())
- } else {
+ if bound.index_if_innermost().map_or(true, is_allowed) {
bound.shifted_in_from(binders).to_const(Interner, ty)
+ } else {
+ unknown_const(ty.clone())
}
},
)