Lower generic arguments for GATs in associated type bindings

This commit is contained in:
Ryo Yoshida 2022-10-27 17:11:16 +09:00
parent 63cba43b48
commit 5fc18ad6fa
No known key found for this signature in database
GPG Key ID: E25698A930586171
2 changed files with 66 additions and 2 deletions

View File

@ -808,7 +808,15 @@ impl<'a> TyLoweringContext<'a> {
// 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 {
// Generic parameters for associated types are not supposed to have defaults, so we just
// ignore them.
let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
let container = id.lookup(self.db.upcast()).container;
matches!(container, ItemContainerId::TraitId(_))
} else {
false
};
if !is_assoc_ty && (!infer_args || had_explicit_args) {
let defaults = self.db.generic_defaults(def);
assert_eq!(total_len, defaults.len());
let parent_from = item_len - substs.len();
@ -997,9 +1005,28 @@ impl<'a> TyLoweringContext<'a> {
None => return SmallVec::new(),
Some(t) => t,
};
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
// generic params. It's inefficient to splice the `Substitution`s, so we may want
// that method to optionally take parent `Substitution` as we already know them at
// this point (`super_trait_ref.substitution`).
let substitution = self.substs_from_path_segment(
// FIXME: This is hack. We shouldn't really build `PathSegment` directly.
PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
Some(associated_ty.into()),
false, // this is not relevant
Some(super_trait_ref.self_type_parameter(Interner)),
);
let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
let substitution = Substitution::from_iter(
Interner,
substitution
.iter(Interner)
.take(self_params)
.chain(super_trait_ref.substitution.iter(Interner)),
);
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
substitution: super_trait_ref.substitution,
substitution,
};
let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),

View File

@ -4083,3 +4083,40 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
"#]],
);
}
#[test]
fn gats_in_associated_type_binding() {
check_infer_with_mismatches(
r#"
trait Trait {
type Assoc<T>;
fn get<U>(&self) -> Self::Assoc<U>;
}
fn f<T>(t: T)
where
T: Trait<Assoc<i32> = u32>,
T: Trait<Assoc<isize> = usize>,
{
let a = t.get::<i32>();
let a = t.get::<isize>();
let a = t.get::<()>();
}
"#,
expect![[r#"
48..52 'self': &Self
84..85 't': T
164..252 '{ ...>(); }': ()
174..175 'a': u32
178..179 't': T
178..192 't.get::<i32>()': u32
202..203 'a': usize
206..207 't': T
206..222 't.get:...ize>()': usize
232..233 'a': Trait::Assoc<(), T>
236..237 't': T
236..249 't.get::<()>()': Trait::Assoc<(), T>
"#]],
)
}