Skip to content

Commit 5fc18ad

Browse files
committed
Lower generic arguments for GATs in associated type bindings
1 parent 63cba43 commit 5fc18ad

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

crates/hir-ty/src/lower.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,15 @@ impl<'a> TyLoweringContext<'a> {
808808
// handle defaults. In expression or pattern path segments without
809809
// explicitly specified type arguments, missing type arguments are inferred
810810
// (i.e. defaults aren't used).
811-
if !infer_args || had_explicit_args {
811+
// Generic parameters for associated types are not supposed to have defaults, so we just
812+
// ignore them.
813+
let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
814+
let container = id.lookup(self.db.upcast()).container;
815+
matches!(container, ItemContainerId::TraitId(_))
816+
} else {
817+
false
818+
};
819+
if !is_assoc_ty && (!infer_args || had_explicit_args) {
812820
let defaults = self.db.generic_defaults(def);
813821
assert_eq!(total_len, defaults.len());
814822
let parent_from = item_len - substs.len();
@@ -997,9 +1005,28 @@ impl<'a> TyLoweringContext<'a> {
9971005
None => return SmallVec::new(),
9981006
Some(t) => t,
9991007
};
1008+
// FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
1009+
// generic params. It's inefficient to splice the `Substitution`s, so we may want
1010+
// that method to optionally take parent `Substitution` as we already know them at
1011+
// this point (`super_trait_ref.substitution`).
1012+
let substitution = self.substs_from_path_segment(
1013+
// FIXME: This is hack. We shouldn't really build `PathSegment` directly.
1014+
PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
1015+
Some(associated_ty.into()),
1016+
false, // this is not relevant
1017+
Some(super_trait_ref.self_type_parameter(Interner)),
1018+
);
1019+
let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
1020+
let substitution = Substitution::from_iter(
1021+
Interner,
1022+
substitution
1023+
.iter(Interner)
1024+
.take(self_params)
1025+
.chain(super_trait_ref.substitution.iter(Interner)),
1026+
);
10001027
let projection_ty = ProjectionTy {
10011028
associated_ty_id: to_assoc_type_id(associated_ty),
1002-
substitution: super_trait_ref.substitution,
1029+
substitution,
10031030
};
10041031
let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
10051032
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),

crates/hir-ty/src/tests/traits.rs

+37
Original file line numberDiff line numberDiff line change
@@ -4083,3 +4083,40 @@ fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
40834083
"#]],
40844084
);
40854085
}
4086+
4087+
#[test]
4088+
fn gats_in_associated_type_binding() {
4089+
check_infer_with_mismatches(
4090+
r#"
4091+
trait Trait {
4092+
type Assoc<T>;
4093+
fn get<U>(&self) -> Self::Assoc<U>;
4094+
}
4095+
4096+
fn f<T>(t: T)
4097+
where
4098+
T: Trait<Assoc<i32> = u32>,
4099+
T: Trait<Assoc<isize> = usize>,
4100+
{
4101+
let a = t.get::<i32>();
4102+
let a = t.get::<isize>();
4103+
let a = t.get::<()>();
4104+
}
4105+
4106+
"#,
4107+
expect![[r#"
4108+
48..52 'self': &Self
4109+
84..85 't': T
4110+
164..252 '{ ...>(); }': ()
4111+
174..175 'a': u32
4112+
178..179 't': T
4113+
178..192 't.get::<i32>()': u32
4114+
202..203 'a': usize
4115+
206..207 't': T
4116+
206..222 't.get:...ize>()': usize
4117+
232..233 'a': Trait::Assoc<(), T>
4118+
236..237 't': T
4119+
236..249 't.get::<()>()': Trait::Assoc<(), T>
4120+
"#]],
4121+
)
4122+
}

0 commit comments

Comments
 (0)