@@ -24,7 +24,6 @@ use hir_def::{
24
24
generics:: { GenericParams , TypeOrConstParamData } ,
25
25
hir:: Movability ,
26
26
lang_item:: { LangItem , LangItemTarget } ,
27
- nameres:: assoc:: ImplItems ,
28
27
} ;
29
28
30
29
use crate :: {
@@ -915,7 +914,14 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
915
914
trait_data. associated_type_by_name ( name) . is_some ( )
916
915
} )
917
916
. map ( to_assoc_type_value_id)
918
- . chain ( impl_rpitit_values ( db, impl_id, & trait_ref_binders, & impl_items, & trait_datum) )
917
+ . chain ( trait_datum. associated_ty_ids . iter ( ) . filter_map ( |& trait_assoc| {
918
+ match from_assoc_type_id ( db, trait_assoc) {
919
+ AnyTraitAssocType :: Rpitit ( trait_assoc) => Some ( to_assoc_type_value_id_rpitit (
920
+ RpititImplAssocTyId :: new ( db, RpititImplAssocTy { impl_id, trait_assoc } ) ,
921
+ ) ) ,
922
+ AnyTraitAssocType :: Normal ( _) => None ,
923
+ }
924
+ } ) )
919
925
. collect ( ) ;
920
926
debug ! ( "impl_datum: {:?}" , impl_datum_bound) ;
921
927
let impl_datum = ImplDatum {
@@ -927,157 +933,119 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
927
933
Arc :: new ( impl_datum)
928
934
}
929
935
930
- fn impl_rpitit_values (
936
+ // We return a list and not a hasmap because the number of RPITITs in a function should be small.
937
+ #[ salsa:: tracked( return_ref) ]
938
+ fn impl_method_rpitit_values (
931
939
db : & dyn HirDatabase ,
932
940
impl_id : hir_def:: ImplId ,
933
- impl_trait : & Binders < TraitRef > ,
934
- impl_items : & ImplItems ,
935
- trait_datum : & TraitDatum ,
936
- ) -> impl Iterator < Item = AssociatedTyValueId > {
937
- let mut trait_rpitit_to_impl_rpitit = FxHashMap :: default ( ) ;
938
-
939
- return trait_datum
940
- . associated_ty_ids
941
- . iter ( )
942
- . filter_map ( |& trait_assoc| match from_assoc_type_id ( db, trait_assoc) {
943
- AnyTraitAssocType :: Rpitit ( it) => Some ( it) ,
944
- AnyTraitAssocType :: Normal ( _) => None ,
945
- } )
946
- . map ( move |trait_assoc_id| {
947
- if let Some ( & impl_assoc_id) = trait_rpitit_to_impl_rpitit. get ( & trait_assoc_id) {
948
- return impl_assoc_id;
941
+ trait_method_id : FunctionId ,
942
+ ) -> Box < [ Arc < AssociatedTyValue > ] > {
943
+ let impl_items = db. impl_items ( impl_id) ;
944
+ let trait_method_generics = generics ( db. upcast ( ) , trait_method_id. into ( ) ) ;
945
+ let impl_datum =
946
+ db. impl_datum ( impl_id. loc ( db) . container . krate ( ) , hir_def:: ImplId :: to_chalk ( impl_id, db) ) ;
947
+ let trait_method = db. function_data ( trait_method_id) ;
948
+ let Some ( impl_method) = impl_items. items . iter ( ) . find_map ( |( name, id) | {
949
+ if * name == trait_method. name {
950
+ match * id {
951
+ AssocItemId :: FunctionId ( it) => Some ( it) ,
952
+ _ => None ,
949
953
}
954
+ } else {
955
+ None
956
+ }
957
+ } ) else {
958
+ // FIXME: Handle defaulted methods.
959
+ return Box :: default ( ) ;
960
+ } ;
950
961
951
- let trait_assoc = trait_assoc_id. loc ( db) ;
952
- let trait_method_id = trait_assoc. synthesized_from_method ;
953
- let trait_method_generics = generics ( db. upcast ( ) , trait_method_id. into ( ) ) ;
954
-
955
- let impl_assoc_id = ( || {
956
- let trait_method = db. function_data ( trait_method_id) ;
957
- let impl_method = impl_items. items . iter ( ) . find_map ( |( name, id) | {
958
- if * name == trait_method. name {
959
- match * id {
960
- AssocItemId :: FunctionId ( it) => Some ( it) ,
961
- _ => None ,
962
- }
963
- } else {
964
- None
965
- }
966
- } ) ?;
967
-
968
- let impl_method_generics = generics ( db. upcast ( ) , impl_method. into ( ) ) ;
969
-
970
- // First, just so we won't ICE, check that the impl method generics match the trait method generics.
971
- if !check_method_generics_are_structurally_compatible (
972
- trait_method_generics. self_params ( ) ,
973
- impl_method_generics. self_params ( ) ,
974
- ) {
975
- return None ;
976
- }
977
-
978
- // The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
979
- // then we equate the return type of the trait method with the return type of the impl method. The values
980
- // of the inference vars now represent the value of the RPITIT assoc types.
981
- let mut table = InferenceTable :: new ( db, db. trait_environment ( impl_method. into ( ) ) ) ;
982
- let impl_method_placeholder_subst = impl_method_generics. placeholder_subst ( db) ;
983
-
984
- let impl_method_ret = db
985
- . callable_item_signature ( impl_method. into ( ) )
986
- . substitute ( Interner , & impl_method_placeholder_subst)
987
- . ret ( )
988
- . clone ( ) ;
989
- let impl_method_ret = table. normalize_associated_types_in ( impl_method_ret) ;
990
-
991
- // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
992
- let trait_ref_placeholder_subst = & impl_method_placeholder_subst. as_slice ( Interner )
993
- [ impl_method_generics. len_self ( ) ..] ;
994
- // We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
995
- let impl_trait_ref =
996
- impl_trait. clone ( ) . substitute ( Interner , trait_ref_placeholder_subst) ;
997
- let trait_to_impl_args = Substitution :: from_iter (
998
- Interner ,
999
- impl_method_placeholder_subst. as_slice ( Interner )
1000
- [ ..impl_method_generics. len_self ( ) ]
1001
- . iter ( )
1002
- . chain ( impl_trait_ref. substitution . as_slice ( Interner ) ) ,
1003
- ) ;
1004
- let trait_method_ret = db
1005
- . callable_item_signature ( trait_method_id. into ( ) )
1006
- . substitute ( Interner , & trait_to_impl_args)
1007
- . ret ( )
1008
- . clone ( ) ;
1009
- let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
1010
- db,
1011
- table : & mut table,
1012
- trait_method_id,
1013
- trait_rpitit_to_infer_var : FxHashMap :: default ( ) ,
1014
- } ;
1015
- let trait_method_ret = trait_method_ret
1016
- . fold_with ( & mut rpitit_to_infer_var_folder, DebruijnIndex :: INNERMOST ) ;
1017
- let trait_rpitit_to_infer_var =
1018
- rpitit_to_infer_var_folder. trait_rpitit_to_infer_var ;
1019
- let trait_method_ret = table. normalize_associated_types_in ( trait_method_ret) ;
1020
-
1021
- table. resolve_obligations_as_possible ( ) ;
1022
- // Even if unification fails, we want to continue. We will fill the RPITITs with error types.
1023
- table. unify ( & trait_method_ret, & impl_method_ret) ;
1024
- table. resolve_obligations_as_possible ( ) ;
1025
- for ( trait_rpitit, infer_var) in trait_rpitit_to_infer_var {
1026
- let impl_rpitit = table. resolve_completely ( infer_var) ;
1027
- let impl_rpitit = impl_rpitit. fold_with (
1028
- & mut PlaceholderToBoundVarFolder {
1029
- db,
1030
- method : impl_method. into ( ) ,
1031
- method_generics : impl_method_generics. self_params ( ) ,
1032
- } ,
1033
- DebruijnIndex :: INNERMOST ,
1034
- ) ;
1035
- let impl_rpitit_binders = VariableKinds :: from_iter (
1036
- Interner ,
1037
- & trait_assoc. bounds . binders . as_slice ( Interner )
1038
- [ ..trait_method_generics. len ( ) ] ,
1039
- ) ;
1040
- let impl_rpitit = Binders :: new (
1041
- impl_rpitit_binders,
1042
- rust_ir:: AssociatedTyValueBound { ty : impl_rpitit } ,
1043
- ) ;
1044
- let impl_rpitit = RpititImplAssocTyId :: new (
1045
- db,
1046
- RpititImplAssocTy {
1047
- impl_id,
1048
- trait_assoc : trait_rpitit,
1049
- value : impl_rpitit,
1050
- } ,
1051
- ) ;
1052
- trait_rpitit_to_impl_rpitit. insert ( trait_rpitit, impl_rpitit) ;
1053
- }
962
+ let impl_method_generics = generics ( db. upcast ( ) , impl_method. into ( ) ) ;
1054
963
1055
- trait_rpitit_to_impl_rpitit. get ( & trait_assoc_id) . copied ( )
1056
- } ) ( ) ;
964
+ // First, just so we won't ICE, check that the impl method generics match the trait method generics.
965
+ if !check_method_generics_are_structurally_compatible (
966
+ trait_method_generics. self_params ( ) ,
967
+ impl_method_generics. self_params ( ) ,
968
+ ) {
969
+ return Box :: default ( ) ;
970
+ }
1057
971
1058
- impl_assoc_id. unwrap_or_else ( || {
1059
- RpititImplAssocTyId :: new (
972
+ // The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
973
+ // then we equate the return type of the trait method with the return type of the impl method. The values
974
+ // of the inference vars now represent the value of the RPITIT assoc types.
975
+ let mut table = InferenceTable :: new ( db, db. trait_environment ( impl_method. into ( ) ) ) ;
976
+ let impl_method_placeholder_subst = impl_method_generics. placeholder_subst ( db) ;
977
+
978
+ let impl_method_ret = db
979
+ . callable_item_signature ( impl_method. into ( ) )
980
+ . substitute ( Interner , & impl_method_placeholder_subst)
981
+ . ret ( )
982
+ . clone ( ) ;
983
+ let impl_method_ret = table. normalize_associated_types_in ( impl_method_ret) ;
984
+
985
+ // Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
986
+ let trait_ref_placeholder_subst =
987
+ & impl_method_placeholder_subst. as_slice ( Interner ) [ impl_method_generics. len_self ( ) ..] ;
988
+ // We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
989
+ let impl_trait_ref = impl_datum
990
+ . binders
991
+ . as_ref ( )
992
+ . map ( |it| it. trait_ref . clone ( ) )
993
+ . substitute ( Interner , trait_ref_placeholder_subst) ;
994
+ let trait_to_impl_args = Substitution :: from_iter (
995
+ Interner ,
996
+ impl_method_placeholder_subst. as_slice ( Interner ) [ ..impl_method_generics. len_self ( ) ]
997
+ . iter ( )
998
+ . chain ( impl_trait_ref. substitution . as_slice ( Interner ) ) ,
999
+ ) ;
1000
+ let trait_method_ret = db
1001
+ . callable_item_signature ( trait_method_id. into ( ) )
1002
+ . substitute ( Interner , & trait_to_impl_args)
1003
+ . ret ( )
1004
+ . clone ( ) ;
1005
+ let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
1006
+ db,
1007
+ table : & mut table,
1008
+ trait_method_id,
1009
+ trait_rpitit_to_infer_var : FxHashMap :: default ( ) ,
1010
+ } ;
1011
+ let trait_method_ret =
1012
+ trait_method_ret. fold_with ( & mut rpitit_to_infer_var_folder, DebruijnIndex :: INNERMOST ) ;
1013
+ let trait_rpitit_to_infer_var = rpitit_to_infer_var_folder. trait_rpitit_to_infer_var ;
1014
+ let trait_method_ret = table. normalize_associated_types_in ( trait_method_ret) ;
1015
+
1016
+ table. resolve_obligations_as_possible ( ) ;
1017
+ // Even if unification fails, we want to continue. We will fill the RPITITs with error types.
1018
+ table. unify ( & trait_method_ret, & impl_method_ret) ;
1019
+ table. resolve_obligations_as_possible ( ) ;
1020
+
1021
+ return trait_rpitit_to_infer_var
1022
+ . into_iter ( )
1023
+ . map ( |( trait_assoc_id, infer_var) | {
1024
+ let impl_rpitit = table. resolve_completely ( infer_var) ;
1025
+ let impl_rpitit = impl_rpitit. fold_with (
1026
+ & mut PlaceholderToBoundVarFolder {
1060
1027
db,
1061
- RpititImplAssocTy {
1062
- impl_id,
1063
- trait_assoc : trait_assoc_id,
1064
- // In this situation, we don't know even that the trait and impl generics match, therefore
1065
- // the only binders we can give to comply with the trait's binders are the trait's binders.
1066
- // However, for impl associated types chalk wants only their own generics, excluding
1067
- // those of the impl (unlike in traits), therefore we filter them here.
1068
- value : Binders :: new (
1069
- VariableKinds :: from_iter (
1070
- Interner ,
1071
- & trait_assoc. bounds . binders . as_slice ( Interner )
1072
- [ ..trait_method_generics. len_self ( ) ] ,
1073
- ) ,
1074
- rust_ir:: AssociatedTyValueBound { ty : TyKind :: Error . intern ( Interner ) } ,
1075
- ) ,
1076
- } ,
1077
- )
1028
+ method : impl_method. into ( ) ,
1029
+ method_generics : impl_method_generics. self_params ( ) ,
1030
+ } ,
1031
+ DebruijnIndex :: INNERMOST ,
1032
+ ) ;
1033
+ let trait_assoc = trait_assoc_id. loc ( db) ;
1034
+ let impl_rpitit_binders = VariableKinds :: from_iter (
1035
+ Interner ,
1036
+ & trait_assoc. bounds . binders . as_slice ( Interner ) [ ..trait_method_generics. len ( ) ] ,
1037
+ ) ;
1038
+ let impl_rpitit = Binders :: new (
1039
+ impl_rpitit_binders,
1040
+ rust_ir:: AssociatedTyValueBound { ty : impl_rpitit } ,
1041
+ ) ;
1042
+ Arc :: new ( AssociatedTyValue {
1043
+ associated_ty_id : to_assoc_type_id_rpitit ( trait_assoc_id) ,
1044
+ impl_id : hir_def:: ImplId :: to_chalk ( impl_id, db) ,
1045
+ value : impl_rpitit,
1078
1046
} )
1079
1047
} )
1080
- . map ( to_assoc_type_value_id_rpitit ) ;
1048
+ . collect ( ) ;
1081
1049
1082
1050
#[ derive( chalk_derive:: FallibleTypeFolder ) ]
1083
1051
#[ has_interner( Interner ) ]
@@ -1292,11 +1260,38 @@ pub(crate) fn associated_ty_value_query(
1292
1260
}
1293
1261
AnyImplAssocType :: Rpitit ( assoc_type_id) => {
1294
1262
let assoc_type = assoc_type_id. loc ( db) ;
1295
- Arc :: new ( AssociatedTyValue {
1296
- impl_id : assoc_type. impl_id . to_chalk ( db) ,
1297
- associated_ty_id : to_assoc_type_id_rpitit ( assoc_type. trait_assoc ) ,
1298
- value : assoc_type. value . clone ( ) ,
1299
- } )
1263
+ let trait_assoc = assoc_type. trait_assoc . loc ( db) ;
1264
+ let all_method_assocs = impl_method_rpitit_values (
1265
+ db,
1266
+ assoc_type. impl_id ,
1267
+ trait_assoc. synthesized_from_method ,
1268
+ ) ;
1269
+ let trait_assoc_id = to_assoc_type_id_rpitit ( assoc_type. trait_assoc ) ;
1270
+ all_method_assocs
1271
+ . iter ( )
1272
+ . find ( |method_assoc| method_assoc. associated_ty_id == trait_assoc_id)
1273
+ . cloned ( )
1274
+ . unwrap_or_else ( || {
1275
+ let impl_id = hir_def:: ImplId :: to_chalk ( assoc_type. impl_id , db) ;
1276
+ let trait_method_generics =
1277
+ generics ( db. upcast ( ) , trait_assoc. synthesized_from_method . into ( ) ) ;
1278
+ Arc :: new ( AssociatedTyValue {
1279
+ associated_ty_id : trait_assoc_id,
1280
+ impl_id,
1281
+ // In this situation, we don't know even that the trait and impl generics match, therefore
1282
+ // the only binders we can give to comply with the trait's binders are the trait's binders.
1283
+ // However, for impl associated types chalk wants only their own generics, excluding
1284
+ // those of the impl (unlike in traits), therefore we filter them here.
1285
+ value : Binders :: new (
1286
+ VariableKinds :: from_iter (
1287
+ Interner ,
1288
+ & trait_assoc. bounds . binders . as_slice ( Interner )
1289
+ [ ..trait_method_generics. len_self ( ) ] ,
1290
+ ) ,
1291
+ rust_ir:: AssociatedTyValueBound { ty : TyKind :: Error . intern ( Interner ) } ,
1292
+ ) ,
1293
+ } )
1294
+ } )
1300
1295
}
1301
1296
}
1302
1297
}
0 commit comments