Skip to content

Commit 8d3522e

Browse files
committed
Auto merge of rust-lang#15825 - Austaras:master, r=flodiebold
fix: better resolve assoc item with type bound Closes rust-lang#15772
2 parents 2e7e8cc + 808f668 commit 8d3522e

File tree

5 files changed

+173
-26
lines changed

5 files changed

+173
-26
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ where
4343
}
4444

4545
impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
46-
pub(super) fn apply_solution(
46+
pub(crate) fn apply_solution(
4747
&self,
4848
ctx: &mut InferenceTable<'_>,
4949
solution: Canonical<Substitution>,

crates/hir-ty/src/lower.rs

+19-4
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

+48-21
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ use crate::{
2727
primitive::{FloatTy, IntTy, UintTy},
2828
static_lifetime, to_chalk_trait_id,
2929
utils::all_super_traits,
30-
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
31-
Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
30+
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance,
31+
InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef,
32+
TraitRefExt, Ty, TyBuilder, TyExt,
3233
};
3334

3435
/// This is used as a key for indexing impls.
@@ -1478,26 +1479,52 @@ fn is_valid_fn_candidate(
14781479
// We need to consider the bounds on the impl to distinguish functions of the same name
14791480
// for a type.
14801481
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,
1482+
let goals = predicates.iter().map(|p| {
1483+
let (p, b) = p
1484+
.clone()
1485+
.substitute(Interner, &impl_subst)
1486+
// Skipping the inner binders is ok, as we don't handle quantified where
1487+
// clauses yet.
1488+
.into_value_and_skipped_binders();
1489+
stdx::always!(b.len(Interner) == 0);
1490+
1491+
p.cast::<Goal>(Interner)
1492+
});
1493+
1494+
for goal in goals.clone() {
1495+
let in_env = InEnvironment::new(&table.trait_env.env, goal);
1496+
let canonicalized = table.canonicalize(in_env);
1497+
let solution = table.db.trait_solve(
1498+
table.trait_env.krate,
1499+
table.trait_env.block,
1500+
canonicalized.value.clone(),
1501+
);
1502+
1503+
match solution {
1504+
Some(Solution::Unique(canonical_subst)) => {
1505+
canonicalized.apply_solution(
1506+
table,
1507+
Canonical {
1508+
binders: canonical_subst.binders,
1509+
value: canonical_subst.value.subst,
1510+
},
1511+
);
1512+
}
1513+
Some(Solution::Ambig(Guidance::Definite(substs))) => {
1514+
canonicalized.apply_solution(table, substs);
1515+
}
1516+
Some(_) => (),
1517+
None => return IsValidCandidate::No,
1518+
}
15001519
}
1520+
1521+
for goal in goals {
1522+
if table.try_obligation(goal).is_none() {
1523+
return IsValidCandidate::No;
1524+
}
1525+
}
1526+
1527+
IsValidCandidate::Yes
15011528
} else {
15021529
// For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
15031530
// `iterate_trait_method_candidates()`.

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

+28
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,34 @@ fn test<T: Trait>() {
25972597
);
25982598
}
25992599

2600+
#[test]
2601+
fn associated_type_in_type_bound() {
2602+
check_types(
2603+
r#"
2604+
//- minicore: deref
2605+
fn fb(f: Foo<&u8>) {
2606+
f.foobar();
2607+
//^^^^^^^^^^ u8
2608+
}
2609+
trait Bar {
2610+
fn bar(&self) -> u8;
2611+
}
2612+
impl Bar for u8 {
2613+
fn bar(&self) -> u8 { *self }
2614+
}
2615+
2616+
struct Foo<F> {
2617+
foo: F,
2618+
}
2619+
impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
2620+
fn foobar(&self) -> u8 {
2621+
self.foo.deref().bar()
2622+
}
2623+
}
2624+
"#,
2625+
)
2626+
}
2627+
26002628
#[test]
26012629
fn dyn_trait_through_chalk() {
26022630
check_types(

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

+77
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)