Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/method_resolution.rs')
| -rw-r--r-- | crates/hir-ty/src/method_resolution.rs | 121 |
1 files changed, 59 insertions, 62 deletions
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 8c7714b9a6..92a17fc3a9 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -579,8 +579,8 @@ impl ReceiverAdjustments { ty = new_ty.clone(); adjust.push(Adjustment { kind: Adjust::Deref(match kind { - // FIXME should we know the mutability here? - AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)), + // FIXME should we know the mutability here, when autoref is `None`? + AutoderefKind::Overloaded => Some(OverloadedDeref(self.autoref)), AutoderefKind::Builtin => None, }), target: new_ty, @@ -660,10 +660,10 @@ pub fn lookup_impl_const( env: Arc<TraitEnvironment>, const_id: ConstId, subs: Substitution, -) -> ConstId { +) -> (ConstId, Substitution) { let trait_id = match const_id.lookup(db.upcast()).container { ItemContainerId::TraitId(id) => id, - _ => return const_id, + _ => return (const_id, subs), }; let substitution = Substitution::from_iter(Interner, subs.iter(Interner)); let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }; @@ -671,12 +671,14 @@ pub fn lookup_impl_const( let const_data = db.const_data(const_id); let name = match const_data.name.as_ref() { Some(name) => name, - None => return const_id, + None => return (const_id, subs), }; lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) - .and_then(|assoc| if let AssocItemId::ConstId(id) = assoc { Some(id) } else { None }) - .unwrap_or(const_id) + .and_then( + |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None }, + ) + .unwrap_or((const_id, subs)) } /// Looks up the impl method that actually runs for the trait method `func`. @@ -687,10 +689,10 @@ pub fn lookup_impl_method( env: Arc<TraitEnvironment>, func: FunctionId, fn_subst: Substitution, -) -> FunctionId { +) -> (FunctionId, Substitution) { let trait_id = match func.lookup(db.upcast()).container { ItemContainerId::TraitId(id) => id, - _ => return func, + _ => return (func, fn_subst), }; let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); let fn_params = fn_subst.len(Interner) - trait_params; @@ -701,8 +703,14 @@ pub fn lookup_impl_method( let name = &db.function_data(func).name; lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) - .and_then(|assoc| if let AssocItemId::FunctionId(id) = assoc { Some(id) } else { None }) - .unwrap_or(func) + .and_then(|assoc| { + if let (AssocItemId::FunctionId(id), subst) = assoc { + Some((id, subst)) + } else { + None + } + }) + .unwrap_or((func, fn_subst)) } fn lookup_impl_assoc_item_for_trait_ref( @@ -710,7 +718,7 @@ fn lookup_impl_assoc_item_for_trait_ref( db: &dyn HirDatabase, env: Arc<TraitEnvironment>, name: &Name, -) -> Option<AssocItemId> { +) -> Option<(AssocItemId, Substitution)> { let self_ty = trait_ref.self_type_parameter(Interner); let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?; let impls = db.trait_impls_in_deps(env.krate); @@ -718,8 +726,8 @@ fn lookup_impl_assoc_item_for_trait_ref( let table = InferenceTable::new(db, env); - let impl_data = find_matching_impl(impls, table, trait_ref)?; - impl_data.items.iter().find_map(|&it| match it { + let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?; + let item = impl_data.items.iter().find_map(|&it| match it { AssocItemId::FunctionId(f) => { (db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f)) } @@ -730,14 +738,15 @@ fn lookup_impl_assoc_item_for_trait_ref( .map(|n| n == name) .and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }), AssocItemId::TypeAliasId(_) => None, - }) + })?; + Some((item, impl_subst)) } fn find_matching_impl( mut impls: impl Iterator<Item = ImplId>, mut table: InferenceTable<'_>, actual_trait_ref: TraitRef, -) -> Option<Arc<ImplData>> { +) -> Option<(Arc<ImplData>, Substitution)> { let db = table.db; loop { let impl_ = impls.next()?; @@ -758,7 +767,7 @@ fn find_matching_impl( .into_iter() .map(|b| b.cast(Interner)); let goal = crate::Goal::all(Interner, wcs); - table.try_obligation(goal).map(|_| impl_data) + table.try_obligation(goal).map(|_| (impl_data, table.resolve_completely(impl_substs))) }); if r.is_some() { break r; @@ -821,9 +830,9 @@ pub fn iterate_method_candidates_dyn( let mut table = InferenceTable::new(db, env.clone()); let ty = table.instantiate_canonical(ty.clone()); - let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); + let deref_chain = autoderef_method_receiver(&mut table, ty); - let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| { + let result = deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| { iterate_method_candidates_with_autoref( &receiver_ty, adj, @@ -867,16 +876,20 @@ fn iterate_method_candidates_with_autoref( return ControlFlow::Continue(()); } - iterate_method_candidates_by_receiver( - receiver_ty, - first_adjustment.clone(), - db, - env.clone(), - traits_in_scope, - visible_from_module, - name, - &mut callback, - )?; + let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| { + iterate_method_candidates_by_receiver( + receiver_ty, + first_adjustment, + db, + env.clone(), + traits_in_scope, + visible_from_module, + name, + &mut callback, + ) + }; + + iterate_method_candidates_by_receiver(receiver_ty, first_adjustment.clone())?; let refed = Canonical { value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone()) @@ -884,16 +897,7 @@ fn iterate_method_candidates_with_autoref( binders: receiver_ty.binders.clone(), }; - iterate_method_candidates_by_receiver( - &refed, - first_adjustment.with_autoref(Mutability::Not), - db, - env.clone(), - traits_in_scope, - visible_from_module, - name, - &mut callback, - )?; + iterate_method_candidates_by_receiver(&refed, first_adjustment.with_autoref(Mutability::Not))?; let ref_muted = Canonical { value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone()) @@ -904,12 +908,6 @@ fn iterate_method_candidates_with_autoref( iterate_method_candidates_by_receiver( &ref_muted, first_adjustment.with_autoref(Mutability::Mut), - db, - env, - traits_in_scope, - visible_from_module, - name, - &mut callback, ) } @@ -1210,8 +1208,8 @@ pub fn resolve_indexing_op( ) -> Option<ReceiverAdjustments> { let mut table = InferenceTable::new(db, env.clone()); let ty = table.instantiate_canonical(ty); - let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty); - for (ty, adj) in deref_chain.into_iter().zip(adj) { + let deref_chain = autoderef_method_receiver(&mut table, ty); + for (ty, adj) in deref_chain { let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); if db.trait_solve(env.krate, goal.cast(Interner)).is_some() { return Some(adj); @@ -1421,25 +1419,24 @@ fn generic_implements_goal( fn autoderef_method_receiver( table: &mut InferenceTable<'_>, ty: Ty, -) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) { - let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new()); +) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> { + let mut deref_chain: Vec<_> = Vec::new(); let mut autoderef = autoderef::Autoderef::new(table, ty); while let Some((ty, derefs)) = autoderef.next() { - deref_chain.push(autoderef.table.canonicalize(ty).value); - adjustments.push(ReceiverAdjustments { - autoref: None, - autoderefs: derefs, - unsize_array: false, - }); + deref_chain.push(( + autoderef.table.canonicalize(ty).value, + ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false }, + )); } // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) - if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = ( - deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())), - adjustments.last().cloned(), - ) { + if let Some((TyKind::Array(parameters, _), binders, adj)) = + deref_chain.last().map(|(ty, adj)| (ty.value.kind(Interner), ty.binders.clone(), adj)) + { let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner); - deref_chain.push(Canonical { value: unsized_ty, binders }); - adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj }); + deref_chain.push(( + Canonical { value: unsized_ty, binders }, + ReceiverAdjustments { unsize_array: true, ..adj.clone() }, + )); } - (deref_chain, adjustments) + deref_chain } |