Skip to content

Commit e95ec55

Browse files
committed
fix: better resolve assoc item with type bound
1 parent 58de0b1 commit e95ec55

File tree

4 files changed

+156
-23
lines changed

4 files changed

+156
-23
lines changed

crates/hir-ty/src/infer/unify.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,35 @@ impl<'a> InferenceTable<'a> {
495495
solution
496496
}
497497

498+
pub(crate) fn try_resolve_alias(&mut self, goal: Goal) -> bool {
499+
let in_env = InEnvironment::new(&self.trait_env.env, goal);
500+
let canonicalized = self.canonicalize(in_env);
501+
let solution = self.db.trait_solve(
502+
self.trait_env.krate,
503+
self.trait_env.block,
504+
canonicalized.value.clone(),
505+
);
506+
507+
match solution {
508+
Some(Solution::Unique(canonical_subst)) => {
509+
canonicalized.apply_solution(
510+
self,
511+
Canonical {
512+
binders: canonical_subst.binders,
513+
value: canonical_subst.value.subst,
514+
},
515+
);
516+
true
517+
}
518+
Some(Solution::Ambig(Guidance::Definite(substs))) => {
519+
canonicalized.apply_solution(self, substs);
520+
true
521+
}
522+
Some(_) => true,
523+
None => false,
524+
}
525+
}
526+
498527
pub(crate) fn register_obligation(&mut self, goal: Goal) {
499528
let in_env = InEnvironment::new(&self.trait_env.env, goal);
500529
self.register_obligation_in_env(in_env)

crates/hir-ty/src/lower.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,10 +1097,25 @@ impl<'a> TyLoweringContext<'a> {
10971097
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
10981098
);
10991099
if let Some(type_ref) = &binding.type_ref {
1100-
let ty = self.lower_ty(type_ref);
1101-
let alias_eq =
1102-
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
1103-
predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
1100+
if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) =
1101+
(type_ref, &self.impl_trait_mode)
1102+
{
1103+
for bound in bounds {
1104+
predicates.extend(
1105+
self.lower_type_bound(
1106+
bound,
1107+
TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
1108+
.intern(Interner),
1109+
false,
1110+
),
1111+
);
1112+
}
1113+
} else {
1114+
let ty = self.lower_ty(type_ref);
1115+
let alias_eq =
1116+
AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
1117+
predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
1118+
}
11041119
}
11051120
for bound in binding.bounds.iter() {
11061121
predicates.extend(self.lower_type_bound(

crates/hir-ty/src/method_resolution.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,26 +1478,38 @@ fn is_valid_fn_candidate(
14781478
// We need to consider the bounds on the impl to distinguish functions of the same name
14791479
// for a type.
14801480
let predicates = db.generic_predicates(impl_id.into());
1481-
let valid = predicates
1482-
.iter()
1483-
.map(|predicate| {
1484-
let (p, b) = predicate
1485-
.clone()
1486-
.substitute(Interner, &impl_subst)
1487-
// Skipping the inner binders is ok, as we don't handle quantified where
1488-
// clauses yet.
1489-
.into_value_and_skipped_binders();
1490-
stdx::always!(b.len(Interner) == 0);
1491-
p
1492-
})
1493-
// It's ok to get ambiguity here, as we may not have enough information to prove
1494-
// obligations. We'll check if the user is calling the selected method properly
1495-
// later anyway.
1496-
.all(|p| table.try_obligation(p.cast(Interner)).is_some());
1497-
match valid {
1498-
true => IsValidCandidate::Yes,
1499-
false => IsValidCandidate::No,
1481+
let mut alias = Vec::new();
1482+
let mut other_predicate = Vec::new();
1483+
1484+
for predicate in predicates.iter() {
1485+
let (p, b) = predicate
1486+
.clone()
1487+
.substitute(Interner, &impl_subst)
1488+
// Skipping the inner binders is ok, as we don't handle quantified where
1489+
// clauses yet.
1490+
.into_value_and_skipped_binders();
1491+
stdx::always!(b.len(Interner) == 0);
1492+
1493+
if let WhereClause::AliasEq(_) = p {
1494+
alias.push(p);
1495+
} else {
1496+
other_predicate.push(p);
1497+
}
1498+
}
1499+
1500+
for p in alias {
1501+
if !table.try_resolve_alias(p.cast(Interner)) {
1502+
return IsValidCandidate::No;
1503+
}
15001504
}
1505+
1506+
for p in other_predicate {
1507+
if table.try_obligation(p.cast(Interner)).is_none() {
1508+
return IsValidCandidate::No;
1509+
}
1510+
}
1511+
1512+
IsValidCandidate::Yes
15011513
} else {
15021514
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
15031515
// `iterate_trait_method_candidates()`.

crates/ide-completion/src/completions/dot.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,4 +1095,81 @@ fn test(s: S<Unknown>) {
10951095
"#]],
10961096
);
10971097
}
1098+
1099+
#[test]
1100+
fn assoc_impl_1() {
1101+
check(
1102+
r#"
1103+
//- minicore: deref
1104+
fn main() {
1105+
let foo: Foo<&u8> = Foo::new(&42_u8);
1106+
foo.$0
1107+
}
1108+
1109+
trait Bar {
1110+
fn bar(&self);
1111+
}
1112+
1113+
impl Bar for u8 {
1114+
fn bar(&self) {}
1115+
}
1116+
1117+
struct Foo<F> {
1118+
foo: F,
1119+
}
1120+
1121+
impl<F> Foo<F> {
1122+
fn new(foo: F) -> Foo<F> {
1123+
Foo { foo }
1124+
}
1125+
}
1126+
1127+
impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
1128+
fn foobar(&self) {
1129+
self.foo.deref().bar()
1130+
}
1131+
}
1132+
"#,
1133+
expect![[r#"
1134+
fd foo &u8
1135+
me foobar() fn(&self)
1136+
"#]],
1137+
);
1138+
}
1139+
1140+
#[test]
1141+
fn assoc_impl_2() {
1142+
check(
1143+
r#"
1144+
//- minicore: deref
1145+
fn main() {
1146+
let foo: Foo<&u8> = Foo::new(&42_u8);
1147+
foo.$0
1148+
}
1149+
1150+
trait Bar {
1151+
fn bar(&self);
1152+
}
1153+
1154+
struct Foo<F> {
1155+
foo: F,
1156+
}
1157+
1158+
impl<F> Foo<F> {
1159+
fn new(foo: F) -> Foo<F> {
1160+
Foo { foo }
1161+
}
1162+
}
1163+
1164+
impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> {
1165+
fn foobar(&self) {
1166+
self.foo.deref().bar()
1167+
}
1168+
}
1169+
"#,
1170+
expect![[r#"
1171+
fd foo &u8
1172+
"#]],
1173+
);
1174+
}
10981175
}

0 commit comments

Comments
 (0)