@@ -8,8 +8,9 @@ use arrayvec::ArrayVec;
88use base_db:: { CrateId , Edition } ;
99use chalk_ir:: { cast:: Cast , Mutability , UniverseIndex } ;
1010use hir_def:: {
11- item_scope:: ItemScope , nameres:: DefMap , AssocItemId , BlockId , ConstId , FunctionId ,
12- GenericDefId , HasModule , ImplId , ItemContainerId , Lookup , ModuleDefId , ModuleId , TraitId ,
11+ data:: ImplData , item_scope:: ItemScope , nameres:: DefMap , AssocItemId , BlockId , ConstId ,
12+ FunctionId , GenericDefId , HasModule , ImplId , ItemContainerId , Lookup , ModuleDefId , ModuleId ,
13+ TraitId ,
1314} ;
1415use hir_expand:: name:: Name ;
1516use rustc_hash:: { FxHashMap , FxHashSet } ;
@@ -247,7 +248,7 @@ impl TraitImpls {
247248 self . map
248249 . get ( & trait_)
249250 . into_iter ( )
250- . flat_map ( move |map| map. get ( & None ) . into_iter ( ) . chain ( map. get ( & Some ( self_ty ) ) ) )
251+ . flat_map ( move |map| map. get ( & Some ( self_ty ) ) . into_iter ( ) . chain ( map. get ( & None ) ) )
251252 . flat_map ( |v| v. iter ( ) . copied ( ) )
252253 }
253254
@@ -575,6 +576,32 @@ pub(crate) fn iterate_method_candidates<T>(
575576 slot
576577}
577578
579+ pub fn lookup_trait_m_for_self_ty (
580+ self_ty : & Ty ,
581+ db : & dyn HirDatabase ,
582+ env : Arc < TraitEnvironment > ,
583+ implied_trait : TraitId ,
584+ name : & Name ,
585+ ) -> Option < FunctionId > {
586+ let self_ty_tp = TyFingerprint :: for_trait_impl ( self_ty) ?;
587+ let trait_impls = TraitImpls :: trait_impls_in_deps_query ( db, env. krate ) ;
588+ let impls = trait_impls. for_trait_and_self_ty ( implied_trait, self_ty_tp) ;
589+ let mut table = InferenceTable :: new ( db, env. clone ( ) ) ;
590+ if let Some ( data) = Valid :: valid_impl ( impls, & mut table, & self_ty) {
591+ for & impl_item in data. items . iter ( ) {
592+ if Valid :: is_valid_item ( & mut table, Some ( name) , None , impl_item, self_ty, None ) {
593+ match impl_item {
594+ AssocItemId :: FunctionId ( f) => {
595+ return Some ( f) ;
596+ }
597+ _ => ( ) ,
598+ }
599+ }
600+ }
601+ }
602+ None
603+ }
604+
578605pub fn iterate_path_candidates (
579606 ty : & Canonical < Ty > ,
580607 db : & dyn HirDatabase ,
@@ -850,7 +877,7 @@ fn iterate_trait_method_candidates(
850877 for & ( _, item) in data. items . iter ( ) {
851878 // Don't pass a `visible_from_module` down to `is_valid_candidate`,
852879 // since only inherent methods should be included into visibility checking.
853- if !is_valid_candidate ( table, name, receiver_ty, item, self_ty, None ) {
880+ if !Valid :: is_valid_item ( table, name, receiver_ty, item, self_ty, None ) {
854881 continue ;
855882 }
856883 if !known_implemented {
@@ -932,8 +959,14 @@ fn iterate_inherent_methods(
932959 let impls_for_self_ty = impls. for_self_ty ( self_ty) ;
933960 for & impl_def in impls_for_self_ty {
934961 for & item in & db. impl_data ( impl_def) . items {
935- if !is_valid_candidate ( table, name, receiver_ty, item, self_ty, visible_from_module)
936- {
962+ if !Valid :: is_valid_item (
963+ table,
964+ name,
965+ receiver_ty,
966+ item,
967+ self_ty,
968+ visible_from_module,
969+ ) {
937970 continue ;
938971 }
939972 callback ( receiver_adjustments. clone ( ) . unwrap_or_default ( ) , item) ?;
@@ -961,97 +994,125 @@ pub fn resolve_indexing_op(
961994 }
962995 None
963996}
997+ struct Valid ;
998+ impl Valid {
999+ fn valid_impl (
1000+ impls : impl Iterator < Item = ImplId > ,
1001+ table : & mut InferenceTable ,
1002+ self_ty : & Ty ,
1003+ ) -> Option < Arc < ImplData > > {
1004+ let db = table. db ;
1005+ for impl_ in impls {
1006+ let impl_data = db. impl_data ( impl_) ;
1007+ let substs =
1008+ TyBuilder :: subst_for_def ( db, impl_) . fill_with_inference_vars ( table) . build ( ) ;
1009+ let impl_ty =
1010+ substs. apply ( db. impl_self_ty ( impl_) . into_value_and_skipped_binders ( ) . 0 , Interner ) ;
1011+
1012+ if !table. unify ( self_ty, & impl_ty) {
1013+ continue ;
1014+ }
9641015
965- fn is_valid_candidate (
966- table : & mut InferenceTable ,
967- name : Option < & Name > ,
968- receiver_ty : Option < & Ty > ,
969- item : AssocItemId ,
970- self_ty : & Ty ,
971- visible_from_module : Option < ModuleId > ,
972- ) -> bool {
973- let db = table. db ;
974- match item {
975- AssocItemId :: FunctionId ( m) => {
976- let data = db. function_data ( m) ;
977- if let Some ( name) = name {
978- if & data. name != name {
979- return false ;
980- }
1016+ let wh_goals = crate :: chalk_db:: convert_where_clauses ( db, impl_. into ( ) , & substs)
1017+ . into_iter ( )
1018+ . map ( |b| b. into_well_formed_goal ( Interner ) . cast ( Interner ) ) ;
1019+
1020+ let goal = crate :: Goal :: all ( Interner , wh_goals) ;
1021+
1022+ if table. try_obligation ( goal) . is_some ( ) {
1023+ return Some ( impl_data) ;
9811024 }
982- table . run_in_snapshot ( |table| {
983- let subst = TyBuilder :: subst_for_def ( db , m ) . fill_with_inference_vars ( table ) . build ( ) ;
984- let expected_self_ty = match m . lookup ( db . upcast ( ) ) . container {
985- ItemContainerId :: TraitId ( _ ) => {
986- subst . at ( Interner , 0 ) . assert_ty_ref ( Interner ) . clone ( )
987- }
988- ItemContainerId :: ImplId ( impl_id ) => {
989- subst . apply ( db . impl_self_ty ( impl_id ) . skip_binders ( ) . clone ( ) , Interner )
990- }
991- // We should only get called for associated items (impl/trait)
992- ItemContainerId :: ModuleId ( _ ) | ItemContainerId :: ExternBlockId ( _ ) => {
993- unreachable ! ( )
994- }
995- } ;
996- if !table . unify ( & expected_self_ty , & self_ty ) {
1025+ }
1026+ None
1027+ }
1028+
1029+ fn is_valid_item (
1030+ table : & mut InferenceTable ,
1031+ name : Option < & Name > ,
1032+ receiver_ty : Option < & Ty > ,
1033+ item : AssocItemId ,
1034+ self_ty : & Ty ,
1035+ visible_from_module : Option < ModuleId > ,
1036+ ) -> bool {
1037+ macro_rules! assert {
1038+ ( $cond : expr ) => {
1039+ if !$cond {
9971040 return false ;
9981041 }
999- if let Some ( receiver_ty) = receiver_ty {
1000- if !data. has_self_param ( ) {
1001- return false ;
1002- }
1042+ } ;
1043+ }
10031044
1004- let sig = db. callable_item_signature ( m. into ( ) ) ;
1005- let expected_receiver =
1006- sig. map ( |s| s. params ( ) [ 0 ] . clone ( ) ) . substitute ( Interner , & subst) ;
1007- let receiver_matches = table. unify ( & receiver_ty, & expected_receiver) ;
1045+ let db = table. db ;
1046+ match item {
1047+ AssocItemId :: FunctionId ( m) => {
1048+ let data = db. function_data ( m) ;
1049+
1050+ assert ! ( name. map_or( true , |n| n == & data. name) ) ;
1051+ assert ! ( visible_from_module. map_or( true , |from_module| {
1052+ let v = db. function_visibility( m) . is_visible_from( db. upcast( ) , from_module) ;
1053+ if !v {
1054+ cov_mark:: hit!( autoderef_candidate_not_visible) ;
1055+ }
1056+ v
1057+ } ) ) ;
10081058
1009- if !receiver_matches {
1010- return false ;
1059+ table. run_in_snapshot ( |table| {
1060+ let subst =
1061+ TyBuilder :: subst_for_def ( db, m) . fill_with_inference_vars ( table) . build ( ) ;
1062+ let expect_self_ty = match m. lookup ( db. upcast ( ) ) . container {
1063+ ItemContainerId :: TraitId ( _) => {
1064+ subst. at ( Interner , 0 ) . assert_ty_ref ( Interner ) . clone ( )
1065+ }
1066+ ItemContainerId :: ImplId ( impl_id) => {
1067+ subst. apply ( db. impl_self_ty ( impl_id) . skip_binders ( ) . clone ( ) , Interner )
1068+ }
1069+ // We should only get called for associated items (impl/trait)
1070+ ItemContainerId :: ModuleId ( _) | ItemContainerId :: ExternBlockId ( _) => {
1071+ unreachable ! ( )
1072+ }
1073+ } ;
1074+ assert ! ( table. unify( & expect_self_ty, self_ty) ) ;
1075+ if let Some ( receiver_ty) = receiver_ty {
1076+ assert ! ( data. has_self_param( ) ) ;
1077+
1078+ let sig = db. callable_item_signature ( m. into ( ) ) ;
1079+ let expected_receiver =
1080+ sig. map ( |s| s. params ( ) [ 0 ] . clone ( ) ) . substitute ( Interner , & subst) ;
1081+
1082+ assert ! ( table. unify( & receiver_ty, & expected_receiver) ) ;
10111083 }
1012- }
1013- if let Some ( from_module) = visible_from_module {
1014- if !db. function_visibility ( m) . is_visible_from ( db. upcast ( ) , from_module) {
1015- cov_mark:: hit!( autoderef_candidate_not_visible) ;
1084+ true
1085+ } )
1086+ }
1087+ AssocItemId :: ConstId ( c) => {
1088+ let data = db. const_data ( c) ;
1089+ assert ! ( receiver_ty. is_none( ) ) ;
1090+
1091+ assert ! ( name. map_or( true , |n| data. name. as_ref( ) == Some ( n) ) ) ;
1092+ assert ! ( visible_from_module. map_or( true , |from_module| {
1093+ let v = db. const_visibility( c) . is_visible_from( db. upcast( ) , from_module) ;
1094+ if !v {
1095+ cov_mark:: hit!( const_candidate_not_visible) ;
1096+ }
1097+ v
1098+ } ) ) ;
1099+ if let ItemContainerId :: ImplId ( impl_id) = c. lookup ( db. upcast ( ) ) . container {
1100+ let self_ty_matches = table. run_in_snapshot ( |table| {
1101+ let subst =
1102+ TyBuilder :: subst_for_def ( db, c) . fill_with_inference_vars ( table) . build ( ) ;
1103+ let expected_self_ty =
1104+ subst. apply ( db. impl_self_ty ( impl_id) . skip_binders ( ) . clone ( ) , Interner ) ;
1105+ table. unify ( & expected_self_ty, & self_ty)
1106+ } ) ;
1107+ if !self_ty_matches {
1108+ cov_mark:: hit!( const_candidate_self_type_mismatch) ;
10161109 return false ;
10171110 }
10181111 }
1019-
10201112 true
1021- } )
1022- }
1023- AssocItemId :: ConstId ( c) => {
1024- let data = db. const_data ( c) ;
1025- if receiver_ty. is_some ( ) {
1026- return false ;
1027- }
1028- if let Some ( name) = name {
1029- if data. name . as_ref ( ) != Some ( name) {
1030- return false ;
1031- }
1032- }
1033- if let Some ( from_module) = visible_from_module {
1034- if !db. const_visibility ( c) . is_visible_from ( db. upcast ( ) , from_module) {
1035- cov_mark:: hit!( const_candidate_not_visible) ;
1036- return false ;
1037- }
1038- }
1039- if let ItemContainerId :: ImplId ( impl_id) = c. lookup ( db. upcast ( ) ) . container {
1040- let self_ty_matches = table. run_in_snapshot ( |table| {
1041- let subst =
1042- TyBuilder :: subst_for_def ( db, c) . fill_with_inference_vars ( table) . build ( ) ;
1043- let expected_self_ty =
1044- subst. apply ( db. impl_self_ty ( impl_id) . skip_binders ( ) . clone ( ) , Interner ) ;
1045- table. unify ( & expected_self_ty, & self_ty)
1046- } ) ;
1047- if !self_ty_matches {
1048- cov_mark:: hit!( const_candidate_self_type_mismatch) ;
1049- return false ;
1050- }
10511113 }
1052- true
1114+ _ => false ,
10531115 }
1054- _ => false ,
10551116 }
10561117}
10571118
0 commit comments