Skip to content

Commit cfa50df

Browse files
committed
Refactor a bit
1 parent 456d52f commit cfa50df

File tree

3 files changed

+74
-77
lines changed

3 files changed

+74
-77
lines changed

crates/ra_hir_ty/src/infer/path.rs

+3-35
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
206206
AssocItemId::TypeAliasId(_) => unreachable!(),
207207
};
208208
let substs = match container {
209-
ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()),
209+
ContainerId::ImplId(impl_id) => {
210+
method_resolution::inherent_impl_substs(self.db, impl_id, &ty)
211+
}
210212
ContainerId::TraitId(trait_) => {
211213
// we're picking this method
212214
let trait_substs = Substs::build_for_def(self.db, trait_)
@@ -231,38 +233,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
231233
},
232234
)
233235
}
234-
235-
fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
236-
if let ValueNs::FunctionId(func) = *def {
237-
// We only do the infer if parent has generic params
238-
let gen = self.db.generic_params(func.into());
239-
if gen.count_parent_params() == 0 {
240-
return None;
241-
}
242-
243-
let impl_id = match func.lookup(self.db).container {
244-
ContainerId::ImplId(it) => it,
245-
_ => return None,
246-
};
247-
let self_ty = self.db.impl_self_ty(impl_id).clone();
248-
let self_ty_substs = self_ty.substs()?;
249-
let actual_substs = actual_def_ty.substs()?;
250-
251-
let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
252-
253-
// The following code *link up* the function actual parma type
254-
// and impl_block type param index
255-
self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
256-
if let Ty::Param { idx, .. } = param {
257-
if let Some(s) = new_substs.get_mut(*idx as usize) {
258-
*s = pty.clone();
259-
}
260-
}
261-
});
262-
263-
Some(Substs(new_substs.into()))
264-
} else {
265-
None
266-
}
267-
}
268236
}

crates/ra_hir_ty/src/method_resolution.rs

+56-42
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,13 @@ pub fn iterate_method_candidates<T>(
191191
let ty = InEnvironment { value: ty.clone(), environment };
192192
let krate = resolver.krate()?;
193193

194-
// We have to be careful about the order of operations here.
195-
// Consider the case where we're resolving `x.clone()` where `x:
196-
// &Vec<_>`. This resolves to the clone method with self type
197-
// `Vec<_>`, *not* `&_`. I.e. we need to consider methods where the
198-
// receiver type exactly matches before cases where we have to do
199-
// autoref. But in the autoderef steps, the `&_` self type comes up
200-
// *before* the `Vec<_>` self type.
194+
// We have to be careful about the order we're looking at candidates
195+
// in here. Consider the case where we're resolving `x.clone()`
196+
// where `x: &Vec<_>`. This resolves to the clone method with self
197+
// type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
198+
// the receiver type exactly matches before cases where we have to
199+
// do autoref. But in the autoderef steps, the `&_` self type comes
200+
// up *before* the `Vec<_>` self type.
201201
//
202202
// On the other hand, we don't want to just pick any by-value method
203203
// before any by-autoref method; it's just that we need to consider
@@ -206,7 +206,7 @@ pub fn iterate_method_candidates<T>(
206206

207207
let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208208
for i in 0..deref_chain.len() {
209-
if let Some(result) = iterate_method_candidates_autoref(
209+
if let Some(result) = iterate_method_candidates_with_autoref(
210210
&deref_chain[i..],
211211
db,
212212
resolver,
@@ -220,12 +220,12 @@ pub fn iterate_method_candidates<T>(
220220
}
221221
LookupMode::Path => {
222222
// No autoderef for path lookups
223-
iterate_method_candidates_inner(&ty, db, resolver, name, None, &mut callback)
223+
iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
224224
}
225225
}
226226
}
227227

228-
fn iterate_method_candidates_autoref<T>(
228+
fn iterate_method_candidates_with_autoref<T>(
229229
deref_chain: &[Canonical<Ty>],
230230
db: &impl HirDatabase,
231231
resolver: &Resolver,
@@ -275,18 +275,25 @@ fn iterate_method_candidates_autoref<T>(
275275

276276
fn iterate_method_candidates_by_receiver<T>(
277277
receiver_ty: &Canonical<Ty>,
278-
deref_chain: &[Canonical<Ty>],
278+
rest_of_deref_chain: &[Canonical<Ty>],
279279
db: &impl HirDatabase,
280280
resolver: &Resolver,
281281
name: Option<&Name>,
282282
mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283283
) -> Option<T> {
284-
// TODO: do we need to do the whole loop for inherents before traits?
285284
// We're looking for methods with *receiver* type receiver_ty. These could
286285
// be found in any of the derefs of receiver_ty, so we have to go through
287286
// that.
288-
for self_ty in std::iter::once(receiver_ty).chain(deref_chain) {
289-
if let Some(result) = iterate_method_candidates_inner(
287+
let krate = resolver.krate()?;
288+
for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289+
if let Some(result) =
290+
iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291+
{
292+
return Some(result);
293+
}
294+
}
295+
for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296+
if let Some(result) = iterate_trait_method_candidates(
290297
self_ty,
291298
db,
292299
resolver,
@@ -300,22 +307,19 @@ fn iterate_method_candidates_by_receiver<T>(
300307
None
301308
}
302309

303-
fn iterate_method_candidates_inner<T>(
310+
fn iterate_method_candidates_for_self_ty<T>(
304311
self_ty: &Canonical<Ty>,
305312
db: &impl HirDatabase,
306313
resolver: &Resolver,
307314
name: Option<&Name>,
308-
receiver_ty: Option<&Canonical<Ty>>,
309315
mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
310316
) -> Option<T> {
311317
let krate = resolver.krate()?;
312-
if let Some(result) =
313-
iterate_inherent_methods(self_ty, db, name, receiver_ty, krate, &mut callback)
314-
{
318+
if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
315319
return Some(result);
316320
}
317321
if let Some(result) =
318-
iterate_trait_method_candidates(self_ty, db, resolver, name, receiver_ty, &mut callback)
322+
iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
319323
{
320324
return Some(result);
321325
}
@@ -412,29 +416,11 @@ fn is_valid_candidate(
412416
if !data.has_self_param {
413417
return false;
414418
}
415-
let substs = match m.lookup(db).container {
416-
hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, item)
417-
.push(self_ty.value.clone())
418-
.fill_with_unknown()
419-
.build(),
420-
hir_def::ContainerId::ImplId(impl_id) => {
421-
let vars =
422-
Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
423-
let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
424-
let self_ty_with_vars =
425-
Canonical { num_vars: vars.len(), value: &self_ty_with_vars };
426-
if let Some(substs) = super::infer::unify(self_ty_with_vars, &self_ty.value)
427-
{
428-
substs
429-
} else {
430-
return false;
431-
}
432-
}
433-
hir_def::ContainerId::ModuleId(_) => unreachable!(),
419+
let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
420+
Some(ty) => ty,
421+
None => return false,
434422
};
435-
let sig = db.callable_item_signature(m.into());
436-
let receiver = sig.params()[0].clone().subst(&substs);
437-
if receiver != receiver_ty.value {
423+
if transformed_receiver_ty != receiver_ty.value {
438424
return false;
439425
}
440426
}
@@ -448,6 +434,34 @@ fn is_valid_candidate(
448434
}
449435
}
450436

437+
pub(crate) fn inherent_impl_substs(
438+
db: &impl HirDatabase,
439+
impl_id: ImplId,
440+
self_ty: &Ty,
441+
) -> Option<Substs> {
442+
let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443+
let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444+
let self_ty_with_vars = Canonical { num_vars: vars.len(), value: &self_ty_with_vars };
445+
super::infer::unify(self_ty_with_vars, self_ty)
446+
}
447+
448+
fn transform_receiver_ty(
449+
db: &impl HirDatabase,
450+
function_id: FunctionId,
451+
self_ty: &Canonical<Ty>,
452+
) -> Option<Ty> {
453+
let substs = match function_id.lookup(db).container {
454+
hir_def::ContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455+
.push(self_ty.value.clone())
456+
.fill_with_unknown()
457+
.build(),
458+
hir_def::ContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty.value)?,
459+
hir_def::ContainerId::ModuleId(_) => unreachable!(),
460+
};
461+
let sig = db.callable_item_signature(function_id.into());
462+
Some(sig.params()[0].clone().subst(&substs))
463+
}
464+
451465
pub fn implements_trait(
452466
ty: &Canonical<Ty>,
453467
db: &impl HirDatabase,

crates/ra_hir_ty/src/tests.rs

+15
Original file line numberDiff line numberDiff line change
@@ -3493,6 +3493,21 @@ fn test() { S.foo()<|>; }
34933493
assert_eq!(t, "i8");
34943494
}
34953495

3496+
#[test]
3497+
fn method_resolution_impl_ref_before_trait() {
3498+
let t = type_at(
3499+
r#"
3500+
//- /main.rs
3501+
trait Trait { fn foo(self) -> u128; }
3502+
struct S;
3503+
impl S { fn foo(&self) -> i8 { 0 } }
3504+
impl Trait for &S { fn foo(self) -> u128 { 0 } }
3505+
fn test() { S.foo()<|>; }
3506+
"#,
3507+
);
3508+
assert_eq!(t, "i8");
3509+
}
3510+
34963511
#[test]
34973512
fn method_resolution_trait_autoderef() {
34983513
let t = type_at(

0 commit comments

Comments
 (0)