1
- use crate :: traits:: specialization_graph;
1
+ use crate :: traits:: specialization_graph:: { self , LeafDef , Node } ;
2
2
3
3
use super :: assembly:: structural_traits:: AsyncCallableRelevantTypes ;
4
4
use super :: assembly:: { self , structural_traits, Candidate } ;
@@ -9,7 +9,6 @@ use rustc_infer::infer::InferCtxt;
9
9
use rustc_infer:: traits:: query:: NoSolution ;
10
10
use rustc_infer:: traits:: solve:: inspect:: ProbeKind ;
11
11
use rustc_infer:: traits:: solve:: MaybeCause ;
12
- use rustc_infer:: traits:: specialization_graph:: LeafDef ;
13
12
use rustc_infer:: traits:: Reveal ;
14
13
use rustc_middle:: traits:: solve:: { CandidateSource , Certainty , Goal , QueryResult } ;
15
14
use rustc_middle:: traits:: BuiltinImplSource ;
@@ -189,8 +188,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
189
188
// In case the associated item is hidden due to specialization, we have to
190
189
// return ambiguity this would otherwise be incomplete, resulting in
191
190
// unsoundness during coherence (#105782).
192
- let Some ( assoc_def) = fetch_eligible_assoc_item_def (
193
- ecx,
191
+ let Some ( assoc_def) = ecx. fetch_eligible_assoc_item_def (
194
192
goal. param_env ,
195
193
goal_trait_ref,
196
194
goal. predicate . def_id ( ) ,
@@ -235,16 +233,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
235
233
//
236
234
// And then map these args to the args of the defining impl of `Assoc`, going
237
235
// from `[u32, u64]` to `[u32, i32, u64]`.
238
- let impl_args_with_gat =
239
- goal. predicate . alias . args . rebase_onto ( tcx, goal_trait_ref. def_id , impl_args) ;
240
- let args = ecx. translate_args (
241
- goal. param_env ,
242
- impl_def_id,
243
- impl_args_with_gat,
244
- assoc_def. defining_node ,
245
- ) ;
236
+ let associated_item_args =
237
+ ecx. translate_args ( & assoc_def, goal, impl_def_id, impl_args, impl_trait_ref) ?;
246
238
247
- if !tcx. check_args_compatible ( assoc_def. item . def_id , args ) {
239
+ if !tcx. check_args_compatible ( assoc_def. item . def_id , associated_item_args ) {
248
240
return error_response (
249
241
ecx,
250
242
"associated item has mismatched generic item arguments" ,
@@ -272,7 +264,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
272
264
ty:: AssocKind :: Fn => unreachable ! ( "we should never project to a fn" ) ,
273
265
} ;
274
266
275
- ecx. instantiate_normalizes_to_term ( goal, term. instantiate ( tcx, args ) ) ;
267
+ ecx. instantiate_normalizes_to_term ( goal, term. instantiate ( tcx, associated_item_args ) ) ;
276
268
ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
277
269
} )
278
270
}
@@ -889,38 +881,79 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
889
881
}
890
882
}
891
883
892
- /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
893
- ///
894
- /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
895
- /// diverge.
896
- #[ instrument( level = "trace" , skip( ecx, param_env) , ret) ]
897
- fn fetch_eligible_assoc_item_def < ' tcx > (
898
- ecx : & EvalCtxt < ' _ , InferCtxt < ' tcx > > ,
899
- param_env : ty:: ParamEnv < ' tcx > ,
900
- goal_trait_ref : ty:: TraitRef < ' tcx > ,
901
- trait_assoc_def_id : DefId ,
902
- impl_def_id : DefId ,
903
- ) -> Result < Option < LeafDef > , NoSolution > {
904
- let node_item =
905
- specialization_graph:: assoc_def ( ecx. interner ( ) , impl_def_id, trait_assoc_def_id)
906
- . map_err ( |ErrorGuaranteed { .. } | NoSolution ) ?;
907
-
908
- let eligible = if node_item. is_final ( ) {
909
- // Non-specializable items are always projectable.
910
- true
911
- } else {
912
- // Only reveal a specializable default if we're past type-checking
913
- // and the obligation is monomorphic, otherwise passes such as
914
- // transmute checking and polymorphic MIR optimizations could
915
- // get a result which isn't correct for all monomorphizations.
916
- if param_env. reveal ( ) == Reveal :: All {
917
- let poly_trait_ref = ecx. resolve_vars_if_possible ( goal_trait_ref) ;
918
- !poly_trait_ref. still_further_specializable ( )
884
+ impl < ' tcx > EvalCtxt < ' _ , InferCtxt < ' tcx > > {
885
+ fn translate_args (
886
+ & mut self ,
887
+ assoc_def : & LeafDef ,
888
+ goal : Goal < ' tcx , ty:: NormalizesTo < ' tcx > > ,
889
+ impl_def_id : DefId ,
890
+ impl_args : ty:: GenericArgsRef < ' tcx > ,
891
+ impl_trait_ref : rustc_type_ir:: TraitRef < TyCtxt < ' tcx > > ,
892
+ ) -> Result < ty:: GenericArgsRef < ' tcx > , NoSolution > {
893
+ let tcx = self . interner ( ) ;
894
+ Ok ( match assoc_def. defining_node {
895
+ Node :: Trait ( _) => goal. predicate . alias . args ,
896
+ Node :: Impl ( target_impl_def_id) => {
897
+ if target_impl_def_id == impl_def_id {
898
+ // Same impl, no need to fully translate, just a rebase from
899
+ // the trait is sufficient.
900
+ goal. predicate . alias . args . rebase_onto ( tcx, impl_trait_ref. def_id , impl_args)
901
+ } else {
902
+ let target_args = self . fresh_args_for_item ( target_impl_def_id) ;
903
+ let target_trait_ref = tcx
904
+ . impl_trait_ref ( target_impl_def_id)
905
+ . unwrap ( )
906
+ . instantiate ( tcx, target_args) ;
907
+ // Relate source impl to target impl by equating trait refs.
908
+ self . eq ( goal. param_env , impl_trait_ref, target_trait_ref) ?;
909
+ // Also add predicates since they may be needed to constrain the
910
+ // target impl's params.
911
+ self . add_goals (
912
+ GoalSource :: Misc ,
913
+ tcx. predicates_of ( target_impl_def_id)
914
+ . instantiate ( tcx, target_args)
915
+ . into_iter ( )
916
+ . map ( |( pred, _) | goal. with ( tcx, pred) ) ,
917
+ ) ;
918
+ goal. predicate . alias . args . rebase_onto ( tcx, impl_trait_ref. def_id , target_args)
919
+ }
920
+ }
921
+ } )
922
+ }
923
+
924
+ /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
925
+ ///
926
+ /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
927
+ /// diverge.
928
+ #[ instrument( level = "trace" , skip( self , param_env) , ret) ]
929
+ fn fetch_eligible_assoc_item_def (
930
+ & self ,
931
+ param_env : ty:: ParamEnv < ' tcx > ,
932
+ goal_trait_ref : ty:: TraitRef < ' tcx > ,
933
+ trait_assoc_def_id : DefId ,
934
+ impl_def_id : DefId ,
935
+ ) -> Result < Option < LeafDef > , NoSolution > {
936
+ let node_item =
937
+ specialization_graph:: assoc_def ( self . interner ( ) , impl_def_id, trait_assoc_def_id)
938
+ . map_err ( |ErrorGuaranteed { .. } | NoSolution ) ?;
939
+
940
+ let eligible = if node_item. is_final ( ) {
941
+ // Non-specializable items are always projectable.
942
+ true
919
943
} else {
920
- trace ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
921
- false
922
- }
923
- } ;
944
+ // Only reveal a specializable default if we're past type-checking
945
+ // and the obligation is monomorphic, otherwise passes such as
946
+ // transmute checking and polymorphic MIR optimizations could
947
+ // get a result which isn't correct for all monomorphizations.
948
+ if param_env. reveal ( ) == Reveal :: All {
949
+ let poly_trait_ref = self . resolve_vars_if_possible ( goal_trait_ref) ;
950
+ !poly_trait_ref. still_further_specializable ( )
951
+ } else {
952
+ trace ! ( ?node_item. item. def_id, "not eligible due to default" ) ;
953
+ false
954
+ }
955
+ } ;
924
956
925
- if eligible { Ok ( Some ( node_item) ) } else { Ok ( None ) }
957
+ if eligible { Ok ( Some ( node_item) ) } else { Ok ( None ) }
958
+ }
926
959
}
0 commit comments