Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions crates/hir-analysis/src/name_resolution/path_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TyId<'db>, 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.
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -852,17 +849,14 @@ 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));
}
}
}
}
}

candidates
.into_iter()
.map(|(ty, inst)| (inst, ty))
.collect()
}

pub fn resolve_name_res<'db>(
Expand Down
21 changes: 18 additions & 3 deletions crates/hir-analysis/test_files/ty_check/default_generic_trait.fe
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,27 @@ trait Add<T = Self> {

fn add(self: Self, _ rhs: T) -> Self::Output
}
trait Sub<T = Self> {
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)
}

107 changes: 84 additions & 23 deletions crates/hir-analysis/test_files/ty_check/default_generic_trait.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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
12x.add(x)
│ ^ i32
26y.add(y)
│ ^ Bar

note:
┌─ default_generic_trait.fe:12:5
┌─ default_generic_trait.fe:26:5
12x.add(x)
│ ^^^^^^^^ i32
26y.add(y)
│ ^^^^^^^^ Bar

note:
┌─ default_generic_trait.fe:12:11
┌─ default_generic_trait.fe:26:11
12x.add(x)
│ ^ i32
26y.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
Loading