Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/lower.rs')
-rw-r--r--crates/hir-ty/src/lower.rs193
1 files changed, 114 insertions, 79 deletions
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 82128ae658..0a4b1dfda1 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/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());
@@ -636,13 +653,9 @@ impl<'a> TyLoweringContext<'a> {
infer_args: bool,
) -> Substitution {
let last = path.segments().last().expect("path should have at least one segment");
- let (segment, generic_def) = match resolved {
- ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
- ValueTyDefId::StructId(it) => (last, Some(it.into())),
- ValueTyDefId::UnionId(it) => (last, Some(it.into())),
- ValueTyDefId::ConstId(it) => (last, Some(it.into())),
- ValueTyDefId::StaticId(_) => (last, None),
- ValueTyDefId::EnumVariantId(var) => {
+ let generic_def = resolved.to_generic_def_id();
+ let segment = match resolved {
+ ValueTyDefId::EnumVariantId(_) => {
// the generic args for an enum variant may be either specified
// on the segment referring to the enum, or on the segment
// referring to the variant. So `Option::<T>::None` and
@@ -650,12 +663,12 @@ impl<'a> TyLoweringContext<'a> {
// preferred). See also `def_ids_for_path_segments` in rustc.
let len = path.segments().len();
let penultimate = len.checked_sub(2).and_then(|idx| path.segments().get(idx));
- let segment = match penultimate {
+ match penultimate {
Some(segment) if segment.args_and_bindings.is_some() => segment,
_ => last,
- };
- (segment, Some(var.parent.into()))
+ }
}
+ _ => last,
};
self.substs_from_path_segment(segment, generic_def, infer_args, None)
}
@@ -663,36 +676,27 @@ 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 = 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()
@@ -757,37 +761,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)
}
@@ -1168,10 +1175,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);
}
@@ -1413,6 +1428,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()
@@ -1425,19 +1441,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();
@@ -1454,15 +1468,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();
@@ -1837,26 +1850,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())
}
},
)