From 5fc18ad6fa635adac058160bc7ba13e53abd5ece Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 27 Oct 2022 17:11:16 +0900 Subject: [PATCH] Lower generic arguments for GATs in associated type bindings --- crates/hir-ty/src/lower.rs | 31 ++++++++++++++++++++++++-- crates/hir-ty/src/tests/traits.rs | 37 +++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 44479274518..22a85cf1545 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -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(), diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 2b8468e85a1..7995f6446d0 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4083,3 +4083,40 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { "#]], ); } + +#[test] +fn gats_in_associated_type_binding() { + check_infer_with_mismatches( + r#" +trait Trait { + type Assoc; + fn get(&self) -> Self::Assoc; +} + +fn f(t: T) +where + T: Trait = u32>, + T: Trait = usize>, +{ + let a = t.get::(); + let a = t.get::(); + 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::()': 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> + "#]], + ) +}