@@ -22,10 +22,10 @@ use crate::{
2222 from_foreign_def_id,
2323 infer:: { unify:: InferenceTable , Adjust , Adjustment , AutoBorrow , OverloadedDeref , PointerCast } ,
2424 primitive:: { FloatTy , IntTy , UintTy } ,
25- static_lifetime,
25+ static_lifetime, to_chalk_trait_id ,
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 , TraitRef , TraitRefExt , Ty , TyBuilder , TyExt , TyKind ,
2929} ;
3030
3131/// This is used as a key for indexing impls.
@@ -624,52 +624,76 @@ pub(crate) fn iterate_method_candidates<T>(
624624 slot
625625}
626626
627+ /// Looks up the impl method that actually runs for the trait method `func`.
628+ ///
629+ /// Returns `func` if it's not a method defined in a trait or the lookup failed.
627630pub fn lookup_impl_method (
628- self_ty : & Ty ,
629631 db : & dyn HirDatabase ,
630632 env : Arc < TraitEnvironment > ,
631- trait_ : TraitId ,
633+ func : FunctionId ,
634+ fn_subst : Substitution ,
635+ ) -> FunctionId {
636+ let trait_id = match func. lookup ( db. upcast ( ) ) . container {
637+ ItemContainerId :: TraitId ( id) => id,
638+ _ => return func,
639+ } ;
640+ let trait_params = db. generic_params ( trait_id. into ( ) ) . type_or_consts . len ( ) ;
641+ let fn_params = fn_subst. len ( Interner ) - trait_params;
642+ let trait_ref = TraitRef {
643+ trait_id : to_chalk_trait_id ( trait_id) ,
644+ substitution : Substitution :: from_iter ( Interner , fn_subst. iter ( Interner ) . skip ( fn_params) ) ,
645+ } ;
646+
647+ let name = & db. function_data ( func) . name ;
648+ lookup_impl_method_for_trait_ref ( trait_ref, db, env, name) . unwrap_or ( func)
649+ }
650+
651+ fn lookup_impl_method_for_trait_ref (
652+ trait_ref : TraitRef ,
653+ db : & dyn HirDatabase ,
654+ env : Arc < TraitEnvironment > ,
632655 name : & Name ,
633656) -> Option < FunctionId > {
634- let self_ty_fp = TyFingerprint :: for_trait_impl ( self_ty) ?;
635- let trait_impls = db. trait_impls_in_deps ( env. krate ) ;
636- 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| {
639- data. items . iter ( ) . find_map ( |it| match it {
640- AssocItemId :: FunctionId ( f) => ( db. function_data ( * f) . name == * name) . then ( || * f) ,
641- _ => None ,
642- } )
657+ let self_ty = trait_ref. self_type_parameter ( Interner ) ;
658+ let self_ty_fp = TyFingerprint :: for_trait_impl ( & self_ty) ?;
659+ let impls = db. trait_impls_in_deps ( env. krate ) ;
660+ let impls = impls. for_trait_and_self_ty ( trait_ref. hir_trait_id ( ) , self_ty_fp) ;
661+
662+ let table = InferenceTable :: new ( db, env) ;
663+
664+ let impl_data = find_matching_impl ( impls, table, trait_ref) ?;
665+ impl_data. items . iter ( ) . find_map ( |it| match it {
666+ AssocItemId :: FunctionId ( f) => ( db. function_data ( * f) . name == * name) . then ( || * f) ,
667+ _ => None ,
643668 } )
644669}
645670
646671fn find_matching_impl (
647672 mut impls : impl Iterator < Item = ImplId > ,
648- table : & mut InferenceTable < ' _ > ,
649- self_ty : & Ty ,
673+ mut table : InferenceTable < ' _ > ,
674+ actual_trait_ref : TraitRef ,
650675) -> Option < Arc < ImplData > > {
651676 let db = table. db ;
652677 loop {
653678 let impl_ = impls. next ( ) ?;
654679 let r = table. run_in_snapshot ( |table| {
655680 let impl_data = db. impl_data ( impl_) ;
656- let substs =
681+ let impl_substs =
657682 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) ;
659-
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 ) ) ;
683+ let trait_ref = db
684+ . impl_trait ( impl_)
685+ . expect ( "non-trait method in find_matching_impl" )
686+ . substitute ( Interner , & impl_substs) ;
667687
668- let goal = crate :: Goal :: all ( Interner , wh_goals) ;
688+ if !table. unify ( & trait_ref, & actual_trait_ref) {
689+ return None ;
690+ }
669691
670- table. try_obligation ( goal) . map ( |_| impl_data)
671- } )
672- . flatten ( )
692+ let wcs = crate :: chalk_db:: convert_where_clauses ( db, impl_. into ( ) , & impl_substs)
693+ . into_iter ( )
694+ . map ( |b| b. cast ( Interner ) ) ;
695+ let goal = crate :: Goal :: all ( Interner , wcs) ;
696+ table. try_obligation ( goal) . map ( |_| impl_data)
673697 } ) ;
674698 if r. is_some ( ) {
675699 break r;
0 commit comments