@@ -25,7 +25,6 @@ use hir_def::{
25
25
generics:: { GenericParams , TypeOrConstParamData } ,
26
26
} ,
27
27
lang_item:: LangItem ,
28
- nameres:: assoc:: ImplItems ,
29
28
signatures:: { ImplFlags , StructFlags , TraitFlags } ,
30
29
} ;
31
30
@@ -943,7 +942,14 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
943
942
trait_data. associated_type_by_name ( name) . is_some ( )
944
943
} )
945
944
. map ( to_assoc_type_value_id)
946
- . chain ( impl_rpitit_values ( db, impl_id, & trait_ref_binders, & impl_items, & trait_datum) )
945
+ . chain ( trait_datum. associated_ty_ids . iter ( ) . filter_map ( |& trait_assoc| {
946
+ match from_assoc_type_id ( db, trait_assoc) {
947
+ AnyTraitAssocType :: Rpitit ( trait_assoc) => Some ( to_assoc_type_value_id_rpitit (
948
+ RpititImplAssocTyId :: new ( db, RpititImplAssocTy { impl_id, trait_assoc } ) ,
949
+ ) ) ,
950
+ AnyTraitAssocType :: Normal ( _) => None ,
951
+ }
952
+ } ) )
947
953
. collect ( ) ;
948
954
debug ! ( "impl_datum: {:?}" , impl_datum_bound) ;
949
955
let impl_datum = ImplDatum {
@@ -955,157 +961,119 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
955
961
Arc :: new ( impl_datum)
956
962
}
957
963
958
- fn impl_rpitit_values (
964
+ // We return a list and not a hasmap because the number of RPITITs in a function should be small.
965
+ #[ salsa_macros:: tracked( return_ref) ]
966
+ fn impl_method_rpitit_values (
959
967
db : & dyn HirDatabase ,
960
968
impl_id : hir_def:: ImplId ,
961
- impl_trait : & Binders < TraitRef > ,
962
- impl_items : & ImplItems ,
963
- trait_datum : & TraitDatum ,
964
- ) -> impl Iterator < Item = AssociatedTyValueId > {
965
- let mut trait_rpitit_to_impl_rpitit = FxHashMap :: default ( ) ;
966
-
967
- return trait_datum
968
- . associated_ty_ids
969
- . iter ( )
970
- . filter_map ( |& trait_assoc| match from_assoc_type_id ( db, trait_assoc) {
971
- AnyTraitAssocType :: Rpitit ( it) => Some ( it) ,
972
- AnyTraitAssocType :: Normal ( _) => None ,
973
- } )
974
- . map ( move |trait_assoc_id| {
975
- if let Some ( & impl_assoc_id) = trait_rpitit_to_impl_rpitit. get ( & trait_assoc_id) {
976
- return impl_assoc_id;
969
+ trait_method_id : FunctionId ,
970
+ ) -> Box < [ Arc < AssociatedTyValue > ] > {
971
+ let impl_items = db. impl_items ( impl_id) ;
972
+ let trait_method_generics = generics ( db, trait_method_id. into ( ) ) ;
973
+ let impl_datum =
974
+ db. impl_datum ( impl_id. loc ( db) . container . krate ( ) , hir_def:: ImplId :: to_chalk ( impl_id, db) ) ;
975
+ let trait_method = db. function_signature ( trait_method_id) ;
976
+ let Some ( impl_method) = impl_items. items . iter ( ) . find_map ( |( name, id) | {
977
+ if * name == trait_method. name {
978
+ match * id {
979
+ AssocItemId :: FunctionId ( it) => Some ( it) ,
980
+ _ => None ,
977
981
}
982
+ } else {
983
+ None
984
+ }
985
+ } ) else {
986
+ // FIXME: Handle defaulted methods.
987
+ return Box :: default ( ) ;
988
+ } ;
978
989
979
- let trait_assoc = trait_assoc_id. loc ( db) ;
980
- let trait_method_id = trait_assoc. synthesized_from_method ;
981
- let trait_method_generics = generics ( db, trait_method_id. into ( ) ) ;
982
-
983
- let impl_assoc_id = ( || {
984
- let trait_method = db. function_signature ( trait_method_id) ;
985
- let impl_method = impl_items. items . iter ( ) . find_map ( |( name, id) | {
986
- if * name == trait_method. name {
987
- match * id {
988
- AssocItemId :: FunctionId ( it) => Some ( it) ,
989
- _ => None ,
990
- }
991
- } else {
992
- None
993
- }
994
- } ) ?;
995
-
996
- let impl_method_generics = generics ( db, impl_method. into ( ) ) ;
997
-
998
- // First, just so we won't ICE, check that the impl method generics match the trait method generics.
999
- if !check_method_generics_are_structurally_compatible (
1000
- trait_method_generics. self_params ( ) ,
1001
- impl_method_generics. self_params ( ) ,
1002
- ) {
1003
- return None ;
1004
- }
990
+ let impl_method_generics = generics ( db, impl_method. into ( ) ) ;
1005
991
1006
- // The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
1007
- // then we equate the return type of the trait method with the return type of the impl method. The values
1008
- // of the inference vars now represent the value of the RPITIT assoc types.
1009
- let mut table = InferenceTable :: new ( db, db. trait_environment ( impl_method. into ( ) ) ) ;
1010
- let impl_method_placeholder_subst = impl_method_generics. placeholder_subst ( db) ;
1011
-
1012
- let impl_method_ret = db
1013
- . callable_item_signature ( impl_method. into ( ) )
1014
- . substitute ( Interner , & impl_method_placeholder_subst)
1015
- . ret ( )
1016
- . clone ( ) ;
1017
- let impl_method_ret = table. normalize_associated_types_in ( impl_method_ret) ;
1018
-
1019
- // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
1020
- let trait_ref_placeholder_subst = & impl_method_placeholder_subst. as_slice ( Interner )
1021
- [ impl_method_generics. len_self ( ) ..] ;
1022
- // We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
1023
- let impl_trait_ref =
1024
- impl_trait. clone ( ) . substitute ( Interner , trait_ref_placeholder_subst) ;
1025
- let trait_to_impl_args = Substitution :: from_iter (
1026
- Interner ,
1027
- impl_method_placeholder_subst. as_slice ( Interner )
1028
- [ ..impl_method_generics. len_self ( ) ]
1029
- . iter ( )
1030
- . chain ( impl_trait_ref. substitution . as_slice ( Interner ) ) ,
1031
- ) ;
1032
- let trait_method_ret = db
1033
- . callable_item_signature ( trait_method_id. into ( ) )
1034
- . substitute ( Interner , & trait_to_impl_args)
1035
- . ret ( )
1036
- . clone ( ) ;
1037
- let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
1038
- db,
1039
- table : & mut table,
1040
- trait_method_id,
1041
- trait_rpitit_to_infer_var : FxHashMap :: default ( ) ,
1042
- } ;
1043
- let trait_method_ret = trait_method_ret
1044
- . fold_with ( & mut rpitit_to_infer_var_folder, DebruijnIndex :: INNERMOST ) ;
1045
- let trait_rpitit_to_infer_var =
1046
- rpitit_to_infer_var_folder. trait_rpitit_to_infer_var ;
1047
- let trait_method_ret = table. normalize_associated_types_in ( trait_method_ret) ;
1048
-
1049
- table. resolve_obligations_as_possible ( ) ;
1050
- // Even if unification fails, we want to continue. We will fill the RPITITs with error types.
1051
- table. unify ( & trait_method_ret, & impl_method_ret) ;
1052
- table. resolve_obligations_as_possible ( ) ;
1053
- for ( trait_rpitit, infer_var) in trait_rpitit_to_infer_var {
1054
- let impl_rpitit = table. resolve_completely ( infer_var) ;
1055
- let impl_rpitit = impl_rpitit. fold_with (
1056
- & mut PlaceholderToBoundVarFolder {
1057
- db,
1058
- method : impl_method. into ( ) ,
1059
- method_generics : impl_method_generics. self_params ( ) ,
1060
- } ,
1061
- DebruijnIndex :: INNERMOST ,
1062
- ) ;
1063
- let impl_rpitit_binders = VariableKinds :: from_iter (
1064
- Interner ,
1065
- & trait_assoc. bounds . binders . as_slice ( Interner )
1066
- [ ..trait_method_generics. len ( ) ] ,
1067
- ) ;
1068
- let impl_rpitit = Binders :: new (
1069
- impl_rpitit_binders,
1070
- rust_ir:: AssociatedTyValueBound { ty : impl_rpitit } ,
1071
- ) ;
1072
- let impl_rpitit = RpititImplAssocTyId :: new (
1073
- db,
1074
- RpititImplAssocTy {
1075
- impl_id,
1076
- trait_assoc : trait_rpitit,
1077
- value : impl_rpitit,
1078
- } ,
1079
- ) ;
1080
- trait_rpitit_to_impl_rpitit. insert ( trait_rpitit, impl_rpitit) ;
1081
- }
1082
-
1083
- trait_rpitit_to_impl_rpitit. get ( & trait_assoc_id) . copied ( )
1084
- } ) ( ) ;
992
+ // First, just so we won't ICE, check that the impl method generics match the trait method generics.
993
+ if !check_method_generics_are_structurally_compatible (
994
+ trait_method_generics. self_params ( ) ,
995
+ impl_method_generics. self_params ( ) ,
996
+ ) {
997
+ return Box :: default ( ) ;
998
+ }
1085
999
1086
- impl_assoc_id. unwrap_or_else ( || {
1087
- RpititImplAssocTyId :: new (
1000
+ // The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
1001
+ // then we equate the return type of the trait method with the return type of the impl method. The values
1002
+ // of the inference vars now represent the value of the RPITIT assoc types.
1003
+ let mut table = InferenceTable :: new ( db, db. trait_environment ( impl_method. into ( ) ) ) ;
1004
+ let impl_method_placeholder_subst = impl_method_generics. placeholder_subst ( db) ;
1005
+
1006
+ let impl_method_ret = db
1007
+ . callable_item_signature ( impl_method. into ( ) )
1008
+ . substitute ( Interner , & impl_method_placeholder_subst)
1009
+ . ret ( )
1010
+ . clone ( ) ;
1011
+ let impl_method_ret = table. normalize_associated_types_in ( impl_method_ret) ;
1012
+
1013
+ // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
1014
+ let trait_ref_placeholder_subst =
1015
+ & impl_method_placeholder_subst. as_slice ( Interner ) [ impl_method_generics. len_self ( ) ..] ;
1016
+ // We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
1017
+ let impl_trait_ref = impl_datum
1018
+ . binders
1019
+ . as_ref ( )
1020
+ . map ( |it| it. trait_ref . clone ( ) )
1021
+ . substitute ( Interner , trait_ref_placeholder_subst) ;
1022
+ let trait_to_impl_args = Substitution :: from_iter (
1023
+ Interner ,
1024
+ impl_method_placeholder_subst. as_slice ( Interner ) [ ..impl_method_generics. len_self ( ) ]
1025
+ . iter ( )
1026
+ . chain ( impl_trait_ref. substitution . as_slice ( Interner ) ) ,
1027
+ ) ;
1028
+ let trait_method_ret = db
1029
+ . callable_item_signature ( trait_method_id. into ( ) )
1030
+ . substitute ( Interner , & trait_to_impl_args)
1031
+ . ret ( )
1032
+ . clone ( ) ;
1033
+ let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
1034
+ db,
1035
+ table : & mut table,
1036
+ trait_method_id,
1037
+ trait_rpitit_to_infer_var : FxHashMap :: default ( ) ,
1038
+ } ;
1039
+ let trait_method_ret =
1040
+ trait_method_ret. fold_with ( & mut rpitit_to_infer_var_folder, DebruijnIndex :: INNERMOST ) ;
1041
+ let trait_rpitit_to_infer_var = rpitit_to_infer_var_folder. trait_rpitit_to_infer_var ;
1042
+ let trait_method_ret = table. normalize_associated_types_in ( trait_method_ret) ;
1043
+
1044
+ table. resolve_obligations_as_possible ( ) ;
1045
+ // Even if unification fails, we want to continue. We will fill the RPITITs with error types.
1046
+ table. unify ( & trait_method_ret, & impl_method_ret) ;
1047
+ table. resolve_obligations_as_possible ( ) ;
1048
+
1049
+ return trait_rpitit_to_infer_var
1050
+ . into_iter ( )
1051
+ . map ( |( trait_assoc_id, infer_var) | {
1052
+ let impl_rpitit = table. resolve_completely ( infer_var) ;
1053
+ let impl_rpitit = impl_rpitit. fold_with (
1054
+ & mut PlaceholderToBoundVarFolder {
1088
1055
db,
1089
- RpititImplAssocTy {
1090
- impl_id,
1091
- trait_assoc : trait_assoc_id,
1092
- // In this situation, we don't know even that the trait and impl generics match, therefore
1093
- // the only binders we can give to comply with the trait's binders are the trait's binders.
1094
- // However, for impl associated types chalk wants only their own generics, excluding
1095
- // those of the impl (unlike in traits), therefore we filter them here.
1096
- value : Binders :: new (
1097
- VariableKinds :: from_iter (
1098
- Interner ,
1099
- & trait_assoc. bounds . binders . as_slice ( Interner )
1100
- [ ..trait_method_generics. len_self ( ) ] ,
1101
- ) ,
1102
- rust_ir:: AssociatedTyValueBound { ty : TyKind :: Error . intern ( Interner ) } ,
1103
- ) ,
1104
- } ,
1105
- )
1056
+ method : impl_method. into ( ) ,
1057
+ method_generics : impl_method_generics. self_params ( ) ,
1058
+ } ,
1059
+ DebruijnIndex :: INNERMOST ,
1060
+ ) ;
1061
+ let trait_assoc = trait_assoc_id. loc ( db) ;
1062
+ let impl_rpitit_binders = VariableKinds :: from_iter (
1063
+ Interner ,
1064
+ & trait_assoc. bounds . binders . as_slice ( Interner ) [ ..trait_method_generics. len ( ) ] ,
1065
+ ) ;
1066
+ let impl_rpitit = Binders :: new (
1067
+ impl_rpitit_binders,
1068
+ rust_ir:: AssociatedTyValueBound { ty : impl_rpitit } ,
1069
+ ) ;
1070
+ Arc :: new ( AssociatedTyValue {
1071
+ associated_ty_id : to_assoc_type_id_rpitit ( trait_assoc_id) ,
1072
+ impl_id : hir_def:: ImplId :: to_chalk ( impl_id, db) ,
1073
+ value : impl_rpitit,
1106
1074
} )
1107
1075
} )
1108
- . map ( to_assoc_type_value_id_rpitit ) ;
1076
+ . collect ( ) ;
1109
1077
1110
1078
#[ derive( chalk_derive:: FallibleTypeFolder ) ]
1111
1079
#[ has_interner( Interner ) ]
@@ -1322,11 +1290,38 @@ pub(crate) fn associated_ty_value_query(
1322
1290
}
1323
1291
AnyImplAssocType :: Rpitit ( assoc_type_id) => {
1324
1292
let assoc_type = assoc_type_id. loc ( db) ;
1325
- Arc :: new ( AssociatedTyValue {
1326
- impl_id : assoc_type. impl_id . to_chalk ( db) ,
1327
- associated_ty_id : to_assoc_type_id_rpitit ( assoc_type. trait_assoc ) ,
1328
- value : assoc_type. value . clone ( ) ,
1329
- } )
1293
+ let trait_assoc = assoc_type. trait_assoc . loc ( db) ;
1294
+ let all_method_assocs = impl_method_rpitit_values (
1295
+ db,
1296
+ assoc_type. impl_id ,
1297
+ trait_assoc. synthesized_from_method ,
1298
+ ) ;
1299
+ let trait_assoc_id = to_assoc_type_id_rpitit ( assoc_type. trait_assoc ) ;
1300
+ all_method_assocs
1301
+ . iter ( )
1302
+ . find ( |method_assoc| method_assoc. associated_ty_id == trait_assoc_id)
1303
+ . cloned ( )
1304
+ . unwrap_or_else ( || {
1305
+ let impl_id = hir_def:: ImplId :: to_chalk ( assoc_type. impl_id , db) ;
1306
+ let trait_method_generics =
1307
+ generics ( db, trait_assoc. synthesized_from_method . into ( ) ) ;
1308
+ Arc :: new ( AssociatedTyValue {
1309
+ associated_ty_id : trait_assoc_id,
1310
+ impl_id,
1311
+ // In this situation, we don't know even that the trait and impl generics match, therefore
1312
+ // the only binders we can give to comply with the trait's binders are the trait's binders.
1313
+ // However, for impl associated types chalk wants only their own generics, excluding
1314
+ // those of the impl (unlike in traits), therefore we filter them here.
1315
+ value : Binders :: new (
1316
+ VariableKinds :: from_iter (
1317
+ Interner ,
1318
+ & trait_assoc. bounds . binders . as_slice ( Interner )
1319
+ [ ..trait_method_generics. len_self ( ) ] ,
1320
+ ) ,
1321
+ rust_ir:: AssociatedTyValueBound { ty : TyKind :: Error . intern ( Interner ) } ,
1322
+ ) ,
1323
+ } )
1324
+ } )
1330
1325
}
1331
1326
}
1332
1327
}
0 commit comments