From 4ab169e6c152c9b07f0804ec1f8c1bce9a4d16a5 Mon Sep 17 00:00:00 2001 From: Sean Billig Date: Wed, 27 Aug 2025 19:14:56 -0700 Subject: [PATCH] fix associate type candidate collection deduping by TyId would result in erroneous diagnostics --- .../src/name_resolution/path_resolver.rs | 16 +-- .../ty_check/default_generic_trait.fe | 21 +++- .../ty_check/default_generic_trait.snap | 107 ++++++++++++++---- 3 files changed, 107 insertions(+), 37 deletions(-) diff --git a/crates/hir-analysis/src/name_resolution/path_resolver.rs b/crates/hir-analysis/src/name_resolution/path_resolver.rs index 0d6c17028..fecddab77 100644 --- a/crates/hir-analysis/src/name_resolution/path_resolver.rs +++ b/crates/hir-analysis/src/name_resolution/path_resolver.rs @@ -746,10 +746,6 @@ pub fn find_associated_type<'db>( }; } - // Collect unique candidates keyed by their normalized associated type. - // This avoids scanning and dedups different trait bounds that resolve to - // the same concrete type. - let mut candidates: IndexMap, TraitInstId<'db>> = IndexMap::new(); let ingot = scope.ingot(db); // Use a single unification table and snapshots to preserve outer // substitutions while isolating per-candidate attempts. @@ -784,6 +780,7 @@ pub fn find_associated_type<'db>( } } + let mut candidates = SmallVec::new(); // Check explicit bounds in assumptions that match `ty` only when `ty` is a type // parameter (to avoid spurious ambiguities for concrete types that already have impls). if let TyData::TyParam(_) = ty.value.data(db) { @@ -796,7 +793,7 @@ pub fn find_associated_type<'db>( if table.unify(lhs_ty, pred_self_ty).is_ok() { if let Some(assoc_ty) = trait_inst.assoc_ty(db, name) { let folded = assoc_ty.fold_with(&mut table); - candidates.entry(folded).or_insert(trait_inst); + candidates.push((trait_inst, folded)); } } table.rollback_to(snapshot); @@ -811,7 +808,7 @@ pub fn find_associated_type<'db>( if table.unify(lhs_ty, impl_.self_ty(db)).is_ok() { if let Some(ty) = impl_.assoc_ty(db, name) { let folded = ty.fold_with(&mut table); - candidates.entry(folded).or_insert(impl_.trait_(db)); + candidates.push((impl_.trait_(db), folded)); } } table.rollback_to(snapshot); @@ -832,7 +829,7 @@ pub fn find_associated_type<'db>( if table.unify(ty_with_subst, trait_inst.self_ty(db)).is_ok() { if let Some(assoc_ty) = trait_inst.assoc_ty(db, name) { let folded = assoc_ty.fold_with(&mut table); - candidates.entry(folded).or_insert(trait_inst); + candidates.push((trait_inst, folded)); } } table.rollback_to(snapshot); @@ -852,7 +849,7 @@ pub fn find_associated_type<'db>( if let Ok(inst) = lower_trait_ref(db, self_ty, *trait_ref, scope, assumptions) { if let Some(assoc_ty) = inst.assoc_ty(db, name) { let folded = assoc_ty.fold_with(&mut table); - candidates.entry(folded).or_insert(inst); + candidates.push((inst, folded)); } } } @@ -860,9 +857,6 @@ pub fn find_associated_type<'db>( } candidates - .into_iter() - .map(|(ty, inst)| (inst, ty)) - .collect() } pub fn resolve_name_res<'db>( diff --git a/crates/hir-analysis/test_files/ty_check/default_generic_trait.fe b/crates/hir-analysis/test_files/ty_check/default_generic_trait.fe index 0c656b78d..d457202c3 100644 --- a/crates/hir-analysis/test_files/ty_check/default_generic_trait.fe +++ b/crates/hir-analysis/test_files/ty_check/default_generic_trait.fe @@ -3,12 +3,27 @@ trait Add { fn add(self: Self, _ rhs: T) -> Self::Output } +trait Sub { + type Output = Self + + fn sub(self: Self, _ rhs: T) -> Self::Output +} + +struct Foo {} +struct Bar {} -impl Add for i32 { +impl Add for Foo { + fn add(self: Self, _ rhs: Self) -> Self { self } +} +impl Sub for Foo { + fn sub(self: Self, _ rhs: Self) -> Self { self } +} +impl Add for Bar { fn add(self: Self, _ rhs: Self) -> Self { self } } -fn f(x: i32) -> i32 { +fn f(x: Foo, y: Bar) -> Foo { + y.add(y) + x.sub(x) x.add(x) } - diff --git a/crates/hir-analysis/test_files/ty_check/default_generic_trait.snap b/crates/hir-analysis/test_files/ty_check/default_generic_trait.snap index a5cbd1cb6..43bfc0f99 100644 --- a/crates/hir-analysis/test_files/ty_check/default_generic_trait.snap +++ b/crates/hir-analysis/test_files/ty_check/default_generic_trait.snap @@ -4,41 +4,102 @@ expression: res input_file: test_files/ty_check/default_generic_trait.fe --- note: - ┌─ default_generic_trait.fe:8:45 - │ -8 │ fn add(self: Self, _ rhs: Self) -> Self { self } - │ ^^^^^^^^ i32 + ┌─ default_generic_trait.fe:16:45 + │ +16 │ fn add(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^^^^^ Foo + +note: + ┌─ default_generic_trait.fe:16:47 + │ +16 │ fn add(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^ Foo + +note: + ┌─ default_generic_trait.fe:19:45 + │ +19 │ fn sub(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^^^^^ Foo + +note: + ┌─ default_generic_trait.fe:19:47 + │ +19 │ fn sub(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^ Foo + +note: + ┌─ default_generic_trait.fe:22:45 + │ +22 │ fn add(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^^^^^ Bar note: - ┌─ default_generic_trait.fe:8:47 - │ -8 │ fn add(self: Self, _ rhs: Self) -> Self { self } - │ ^^^^ i32 + ┌─ default_generic_trait.fe:22:47 + │ +22 │ fn add(self: Self, _ rhs: Self) -> Self { self } + │ ^^^^ Bar note: - ┌─ default_generic_trait.fe:11:21 + ┌─ default_generic_trait.fe:25:29 │ -11 │ fn f(x: i32) -> i32 { - │ ╭─────────────────────^ -12 │ │ x.add(x) -13 │ │ } - │ ╰─^ i32 +25 │ fn f(x: Foo, y: Bar) -> Foo { + │ ╭─────────────────────────────^ +26 │ │ y.add(y) +27 │ │ x.sub(x) +28 │ │ x.add(x) +29 │ │ } + │ ╰─^ Foo note: - ┌─ default_generic_trait.fe:12:5 + ┌─ default_generic_trait.fe:26:5 │ -12 │ x.add(x) - │ ^ i32 +26 │ y.add(y) + │ ^ Bar note: - ┌─ default_generic_trait.fe:12:5 + ┌─ default_generic_trait.fe:26:5 │ -12 │ x.add(x) - │ ^^^^^^^^ i32 +26 │ y.add(y) + │ ^^^^^^^^ Bar note: - ┌─ default_generic_trait.fe:12:11 + ┌─ default_generic_trait.fe:26:11 │ -12 │ x.add(x) - │ ^ i32 +26 │ y.add(y) + │ ^ Bar +note: + ┌─ default_generic_trait.fe:27:5 + │ +27 │ x.sub(x) + │ ^ Foo + +note: + ┌─ default_generic_trait.fe:27:5 + │ +27 │ x.sub(x) + │ ^^^^^^^^ Foo + +note: + ┌─ default_generic_trait.fe:27:11 + │ +27 │ x.sub(x) + │ ^ Foo + +note: + ┌─ default_generic_trait.fe:28:5 + │ +28 │ x.add(x) + │ ^ Foo + +note: + ┌─ default_generic_trait.fe:28:5 + │ +28 │ x.add(x) + │ ^^^^^^^^ Foo + +note: + ┌─ default_generic_trait.fe:28:11 + │ +28 │ x.add(x) + │ ^ Foo