@@ -8,8 +8,9 @@ use arrayvec::ArrayVec;
8
8
use base_db:: { CrateId , Edition } ;
9
9
use chalk_ir:: { cast:: Cast , Mutability , UniverseIndex } ;
10
10
use 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 ,
13
14
} ;
14
15
use hir_expand:: name:: Name ;
15
16
use rustc_hash:: { FxHashMap , FxHashSet } ;
@@ -247,7 +248,7 @@ impl TraitImpls {
247
248
self . map
248
249
. get ( & trait_)
249
250
. 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 ) ) )
251
252
. flat_map ( |v| v. iter ( ) . copied ( ) )
252
253
}
253
254
@@ -575,6 +576,32 @@ pub(crate) fn iterate_method_candidates<T>(
575
576
slot
576
577
}
577
578
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
+
578
605
pub fn iterate_path_candidates (
579
606
ty : & Canonical < Ty > ,
580
607
db : & dyn HirDatabase ,
@@ -850,7 +877,7 @@ fn iterate_trait_method_candidates(
850
877
for & ( _, item) in data. items . iter ( ) {
851
878
// Don't pass a `visible_from_module` down to `is_valid_candidate`,
852
879
// 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 ) {
854
881
continue ;
855
882
}
856
883
if !known_implemented {
@@ -932,8 +959,14 @@ fn iterate_inherent_methods(
932
959
let impls_for_self_ty = impls. for_self_ty ( self_ty) ;
933
960
for & impl_def in impls_for_self_ty {
934
961
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
+ ) {
937
970
continue ;
938
971
}
939
972
callback ( receiver_adjustments. clone ( ) . unwrap_or_default ( ) , item) ?;
@@ -961,97 +994,125 @@ pub fn resolve_indexing_op(
961
994
}
962
995
None
963
996
}
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
+ }
964
1015
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) ;
981
1024
}
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 {
997
1040
return false ;
998
1041
}
999
- if let Some ( receiver_ty) = receiver_ty {
1000
- if !data. has_self_param ( ) {
1001
- return false ;
1002
- }
1042
+ } ;
1043
+ }
1003
1044
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
+ } ) ) ;
1008
1058
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) ) ;
1011
1083
}
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) ;
1016
1109
return false ;
1017
1110
}
1018
1111
}
1019
-
1020
1112
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
- }
1051
1113
}
1052
- true
1114
+ _ => false ,
1053
1115
}
1054
- _ => false ,
1055
1116
}
1056
1117
}
1057
1118
0 commit comments