Skip to content

Commit ed7481a

Browse files
committed
Test all generic args for trait when finding matching impl
1 parent 6afd0f5 commit ed7481a

File tree

4 files changed

+131
-37
lines changed

4 files changed

+131
-37
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ impl<'a> InferenceTable<'a> {
340340
self.resolve_with_fallback(t, &|_, _, d, _| d)
341341
}
342342

343-
/// Unify two types and register new trait goals that arise from that.
344-
pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
343+
/// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
344+
pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
345345
let result = match self.try_unify(ty1, ty2) {
346346
Ok(r) => r,
347347
Err(_) => return false,
@@ -352,7 +352,11 @@ impl<'a> InferenceTable<'a> {
352352

353353
/// Unify two types and return new trait goals arising from it, so the
354354
/// caller needs to deal with them.
355-
pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
355+
pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
356+
&mut self,
357+
t1: &T,
358+
t2: &T,
359+
) -> InferResult<()> {
356360
match self.var_unification_table.relate(
357361
Interner,
358362
&self.db,

crates/hir-ty/src/method_resolution.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{
2525
static_lifetime,
2626
utils::all_super_traits,
2727
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
28-
Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
28+
Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
2929
};
3030

3131
/// This is used as a key for indexing impls.
@@ -625,17 +625,22 @@ pub(crate) fn iterate_method_candidates<T>(
625625
}
626626

627627
pub fn lookup_impl_method(
628-
self_ty: &Ty,
629628
db: &dyn HirDatabase,
630629
env: Arc<TraitEnvironment>,
631630
trait_: TraitId,
632631
name: &Name,
632+
fn_subst: Substitution,
633633
) -> Option<FunctionId> {
634+
let trait_params = db.generic_params(trait_.into()).type_or_consts.len();
635+
let fn_params = fn_subst.len(Interner) - trait_params;
636+
let trait_subst = Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params));
637+
638+
let self_ty = trait_subst.at(Interner, 0).ty(Interner)?;
634639
let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
635640
let trait_impls = db.trait_impls_in_deps(env.krate);
636641
let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
637-
let mut table = InferenceTable::new(db, env.clone());
638-
find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
642+
let mut table = InferenceTable::new(db, env);
643+
find_matching_impl(impls, &mut table, trait_subst).and_then(|data| {
639644
data.items.iter().find_map(|it| match it {
640645
AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
641646
_ => None,
@@ -646,30 +651,31 @@ pub fn lookup_impl_method(
646651
fn find_matching_impl(
647652
mut impls: impl Iterator<Item = ImplId>,
648653
table: &mut InferenceTable<'_>,
649-
self_ty: &Ty,
654+
expected_subst: Substitution,
650655
) -> Option<Arc<ImplData>> {
651656
let db = table.db;
652657
loop {
653658
let impl_ = impls.next()?;
654659
let r = table.run_in_snapshot(|table| {
655660
let impl_data = db.impl_data(impl_);
656-
let substs =
661+
let impl_substs =
657662
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
658-
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
663+
let trait_ref = db
664+
.impl_trait(impl_)
665+
.expect("non-trait method in find_matching_impl")
666+
.substitute(Interner, &impl_substs);
659667

660-
table
661-
.unify(self_ty, &impl_ty)
662-
.then(|| {
663-
let wh_goals =
664-
crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
665-
.into_iter()
666-
.map(|b| b.cast(Interner));
667-
668-
let goal = crate::Goal::all(Interner, wh_goals);
668+
if !table
669+
.unify(trait_ref.substitution.as_slice(Interner), expected_subst.as_slice(Interner))
670+
{
671+
return None;
672+
}
669673

670-
table.try_obligation(goal).map(|_| impl_data)
671-
})
672-
.flatten()
674+
let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs)
675+
.into_iter()
676+
.map(|b| b.cast(Interner));
677+
let goal = crate::Goal::all(Interner, wcs);
678+
table.try_obligation(goal).map(|_| impl_data)
673679
});
674680
if r.is_some() {
675681
break r;
@@ -1214,7 +1220,7 @@ fn is_valid_fn_candidate(
12141220
let expected_receiver =
12151221
sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
12161222

1217-
check_that!(table.unify(&receiver_ty, &expected_receiver));
1223+
check_that!(table.unify(receiver_ty, &expected_receiver));
12181224
}
12191225

12201226
if let ItemContainerId::ImplId(impl_id) = container {

crates/hir/src/source_analyzer.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ impl SourceAnalyzer {
270270
let expr_id = self.expr_id(db, &call.clone().into())?;
271271
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
272272

273-
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
273+
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
274274
}
275275

276276
pub(crate) fn resolve_await_to_poll(
@@ -311,7 +311,7 @@ impl SourceAnalyzer {
311311
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
312312
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
313313
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
314-
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
314+
Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
315315
}
316316

317317
pub(crate) fn resolve_prefix_expr(
@@ -331,7 +331,7 @@ impl SourceAnalyzer {
331331
// don't have any generic parameters, so we skip building another subst for the methods.
332332
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
333333

334-
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
334+
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
335335
}
336336

337337
pub(crate) fn resolve_index_expr(
@@ -351,7 +351,7 @@ impl SourceAnalyzer {
351351
.push(base_ty.clone())
352352
.push(index_ty.clone())
353353
.build();
354-
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
354+
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
355355
}
356356

357357
pub(crate) fn resolve_bin_expr(
@@ -372,7 +372,7 @@ impl SourceAnalyzer {
372372
.push(rhs.clone())
373373
.build();
374374

375-
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
375+
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
376376
}
377377

378378
pub(crate) fn resolve_try_expr(
@@ -392,7 +392,7 @@ impl SourceAnalyzer {
392392
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
393393
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
394394

395-
Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
395+
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
396396
}
397397

398398
pub(crate) fn resolve_field(
@@ -497,7 +497,7 @@ impl SourceAnalyzer {
497497
None => assoc,
498498
Some(func_ty) => {
499499
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
500-
self.resolve_impl_method(db, f_in_trait, subs)
500+
self.resolve_impl_method(db, f_in_trait, subs.clone())
501501
.map(AssocItemId::FunctionId)
502502
.unwrap_or(assoc)
503503
} else {
@@ -783,31 +783,33 @@ impl SourceAnalyzer {
783783
&self,
784784
db: &dyn HirDatabase,
785785
func: FunctionId,
786-
substs: &Substitution,
786+
fn_substs: Substitution,
787787
) -> Option<FunctionId> {
788788
let impled_trait = match func.lookup(db.upcast()).container {
789789
ItemContainerId::TraitId(trait_id) => trait_id,
790790
_ => return None,
791791
};
792-
if substs.is_empty(Interner) {
793-
return None;
794-
}
795-
let self_ty = substs.at(Interner, 0).ty(Interner)?;
796792
let krate = self.resolver.krate();
797793
let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
798794
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
799795
|d| db.trait_environment(d),
800796
);
801797

802798
let fun_data = db.function_data(func);
803-
method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
799+
method_resolution::lookup_impl_method(
800+
db,
801+
trait_env,
802+
impled_trait,
803+
&fun_data.name,
804+
fn_substs,
805+
)
804806
}
805807

806808
fn resolve_impl_method_or_trait_def(
807809
&self,
808810
db: &dyn HirDatabase,
809811
func: FunctionId,
810-
substs: &Substitution,
812+
substs: Substitution,
811813
) -> FunctionId {
812814
self.resolve_impl_method(db, func, substs).unwrap_or(func)
813815
}

crates/ide/src/goto_definition.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,4 +1834,86 @@ fn f() {
18341834
"#,
18351835
);
18361836
}
1837+
1838+
#[test]
1839+
fn goto_bin_op_multiple_impl() {
1840+
check(
1841+
r#"
1842+
//- minicore: add
1843+
struct S;
1844+
impl core::ops::Add for S {
1845+
fn add(
1846+
//^^^
1847+
) {}
1848+
}
1849+
impl core::ops::Add<usize> for S {
1850+
fn add(
1851+
) {}
1852+
}
1853+
1854+
fn f() {
1855+
S +$0 S
1856+
}
1857+
"#,
1858+
);
1859+
1860+
check(
1861+
r#"
1862+
//- minicore: add
1863+
struct S;
1864+
impl core::ops::Add for S {
1865+
fn add(
1866+
) {}
1867+
}
1868+
impl core::ops::Add<usize> for S {
1869+
fn add(
1870+
//^^^
1871+
) {}
1872+
}
1873+
1874+
fn f() {
1875+
S +$0 0usize
1876+
}
1877+
"#,
1878+
);
1879+
}
1880+
1881+
#[test]
1882+
fn path_call_multiple_trait_impl() {
1883+
check(
1884+
r#"
1885+
trait Trait<T> {
1886+
fn f(_: T);
1887+
}
1888+
impl Trait<i32> for usize {
1889+
fn f(_: i32) {}
1890+
//^
1891+
}
1892+
impl Trait<i64> for usize {
1893+
fn f(_: i64) {}
1894+
}
1895+
fn main() {
1896+
usize::f$0(0i32);
1897+
}
1898+
"#,
1899+
);
1900+
1901+
check(
1902+
r#"
1903+
trait Trait<T> {
1904+
fn f(_: T);
1905+
}
1906+
impl Trait<i32> for usize {
1907+
fn f(_: i32) {}
1908+
}
1909+
impl Trait<i64> for usize {
1910+
fn f(_: i64) {}
1911+
//^
1912+
}
1913+
fn main() {
1914+
usize::f$0(0i64);
1915+
}
1916+
"#,
1917+
)
1918+
}
18371919
}

0 commit comments

Comments
 (0)