@@ -15,24 +15,24 @@ use rustc_data_structures::fx::FxIndexSet;
1515use rustc_errors:: codes:: * ;
1616use rustc_errors:: { Diag , EmissionGuarantee } ;
1717use rustc_hir:: def_id:: { DefId , LocalDefId } ;
18- use rustc_infer:: infer:: DefineOpaqueTypes ;
1918use rustc_middle:: bug;
2019use rustc_middle:: query:: LocalCrate ;
2120use rustc_middle:: ty:: print:: PrintTraitRefExt as _;
22- use rustc_middle:: ty:: {
23- self , GenericArgsRef , ImplSubject , Ty , TyCtxt , TypeVisitableExt , TypingMode ,
24- } ;
21+ use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt , TypeVisitableExt , TypingMode } ;
2522use rustc_session:: lint:: builtin:: { COHERENCE_LEAK_CHECK , ORDER_DEPENDENT_TRAIT_OBJECTS } ;
2623use rustc_span:: { DUMMY_SP , ErrorGuaranteed , Span , sym} ;
24+ use rustc_type_ir:: solve:: NoSolution ;
2725use specialization_graph:: GraphExt ;
2826use tracing:: { debug, instrument} ;
2927
30- use super :: { SelectionContext , util} ;
3128use crate :: error_reporting:: traits:: to_pretty_impl_header;
3229use crate :: errors:: NegativePositiveConflict ;
33- use crate :: infer:: { InferCtxt , InferOk , TyCtxtInferExt } ;
30+ use crate :: infer:: { InferCtxt , TyCtxtInferExt } ;
3431use crate :: traits:: select:: IntercrateAmbiguityCause ;
35- use crate :: traits:: { FutureCompatOverlapErrorKind , ObligationCause , ObligationCtxt , coherence} ;
32+ use crate :: traits:: {
33+ FutureCompatOverlapErrorKind , ObligationCause , ObligationCtxt , coherence,
34+ predicates_for_generics,
35+ } ;
3636
3737/// Information pertinent to an overlapping impl error.
3838#[ derive( Debug ) ]
@@ -87,9 +87,14 @@ pub fn translate_args<'tcx>(
8787 source_args : GenericArgsRef < ' tcx > ,
8888 target_node : specialization_graph:: Node ,
8989) -> GenericArgsRef < ' tcx > {
90- translate_args_with_cause ( infcx, param_env, source_impl, source_args, target_node, |_, _| {
91- ObligationCause :: dummy ( )
92- } )
90+ translate_args_with_cause (
91+ infcx,
92+ param_env,
93+ source_impl,
94+ source_args,
95+ target_node,
96+ & ObligationCause :: dummy ( ) ,
97+ )
9398}
9499
95100/// Like [translate_args], but obligations from the parent implementation
@@ -104,7 +109,7 @@ pub fn translate_args_with_cause<'tcx>(
104109 source_impl : DefId ,
105110 source_args : GenericArgsRef < ' tcx > ,
106111 target_node : specialization_graph:: Node ,
107- cause : impl Fn ( usize , Span ) -> ObligationCause < ' tcx > ,
112+ cause : & ObligationCause < ' tcx > ,
108113) -> GenericArgsRef < ' tcx > {
109114 debug ! (
110115 "translate_args({:?}, {:?}, {:?}, {:?})" ,
@@ -123,7 +128,7 @@ pub fn translate_args_with_cause<'tcx>(
123128 }
124129
125130 fulfill_implication ( infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
126- . unwrap_or_else ( |( ) | {
131+ . unwrap_or_else ( |_ | {
127132 bug ! (
128133 "When translating generic parameters from {source_impl:?} to \
129134 {target_impl:?}, the expected specialization failed to hold"
@@ -137,6 +142,84 @@ pub fn translate_args_with_cause<'tcx>(
137142 source_args. rebase_onto ( infcx. tcx , source_impl, target_args)
138143}
139144
145+ /// Attempt to fulfill all obligations of `target_impl` after unification with
146+ /// `source_trait_ref`. If successful, returns the generic parameters for *all* the
147+ /// generics of `target_impl`, including both those needed to unify with
148+ /// `source_trait_ref` and those whose identity is determined via a where
149+ /// clause in the impl.
150+ fn fulfill_implication < ' tcx > (
151+ infcx : & InferCtxt < ' tcx > ,
152+ param_env : ty:: ParamEnv < ' tcx > ,
153+ source_trait_ref : ty:: TraitRef < ' tcx > ,
154+ source_impl : DefId ,
155+ target_impl : DefId ,
156+ cause : & ObligationCause < ' tcx > ,
157+ ) -> Result < GenericArgsRef < ' tcx > , NoSolution > {
158+ debug ! (
159+ "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)" ,
160+ param_env, source_trait_ref, target_impl
161+ ) ;
162+
163+ let ocx = ObligationCtxt :: new ( infcx) ;
164+ let source_trait_ref = ocx. normalize ( cause, param_env, source_trait_ref) ;
165+
166+ if !ocx. select_all_or_error ( ) . is_empty ( ) {
167+ infcx. dcx ( ) . span_delayed_bug (
168+ infcx. tcx . def_span ( source_impl) ,
169+ format ! ( "failed to fully normalize {source_trait_ref}" ) ,
170+ ) ;
171+ return Err ( NoSolution ) ;
172+ }
173+
174+ let target_args = infcx. fresh_args_for_item ( DUMMY_SP , target_impl) ;
175+ let target_trait_ref = ocx. normalize (
176+ cause,
177+ param_env,
178+ infcx
179+ . tcx
180+ . impl_trait_ref ( target_impl)
181+ . expect ( "expected source impl to be a trait impl" )
182+ . instantiate ( infcx. tcx , target_args) ,
183+ ) ;
184+
185+ // do the impls unify? If not, no specialization.
186+ ocx. eq ( cause, param_env, source_trait_ref, target_trait_ref) ?;
187+
188+ // Now check that the source trait ref satisfies all the where clauses of the target impl.
189+ // This is not just for correctness; we also need this to constrain any params that may
190+ // only be referenced via projection predicates.
191+ let predicates = ocx. normalize (
192+ cause,
193+ param_env,
194+ infcx. tcx . predicates_of ( target_impl) . instantiate ( infcx. tcx , target_args) ,
195+ ) ;
196+ let obligations = predicates_for_generics ( |_, _| cause. clone ( ) , param_env, predicates) ;
197+ ocx. register_obligations ( obligations) ;
198+
199+ let errors = ocx. select_all_or_error ( ) ;
200+ if !errors. is_empty ( ) {
201+ // no dice!
202+ debug ! (
203+ "fulfill_implication: for impls on {:?} and {:?}, \
204+ could not fulfill: {:?} given {:?}",
205+ source_trait_ref,
206+ target_trait_ref,
207+ errors,
208+ param_env. caller_bounds( )
209+ ) ;
210+ return Err ( NoSolution ) ;
211+ }
212+
213+ debug ! (
214+ "fulfill_implication: an impl for {:?} specializes {:?}" ,
215+ source_trait_ref, target_trait_ref
216+ ) ;
217+
218+ // Now resolve the *generic parameters* we built for the target earlier, replacing
219+ // the inference variables inside with whatever we got from fulfillment.
220+ Ok ( infcx. resolve_vars_if_possible ( target_args) )
221+ }
222+
140223pub ( super ) fn specialization_enabled_in ( tcx : TyCtxt < ' _ > , _: LocalCrate ) -> bool {
141224 tcx. features ( ) . specialization ( ) || tcx. features ( ) . min_specialization ( )
142225}
@@ -182,99 +265,25 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
182265 return false ;
183266 }
184267
185- // create a parameter environment corresponding to a (placeholder) instantiation of impl1
186- let penv = tcx. param_env ( impl1_def_id) ;
268+ // create a parameter environment corresponding to an identity instantiation of impl1,
269+ // i.e. the most generic instantiation of impl1.
270+ let param_env = tcx. param_env ( impl1_def_id) ;
187271
188272 // Create an infcx, taking the predicates of impl1 as assumptions:
189273 let infcx = tcx. infer_ctxt ( ) . build ( TypingMode :: non_body_analysis ( ) ) ;
190274
191275 // Attempt to prove that impl2 applies, given all of the above.
192276 fulfill_implication (
193277 & infcx,
194- penv ,
278+ param_env ,
195279 impl1_trait_header. trait_ref . instantiate_identity ( ) ,
196280 impl1_def_id,
197281 impl2_def_id,
198- |_ , _| ObligationCause :: dummy ( ) ,
282+ & ObligationCause :: dummy ( ) ,
199283 )
200284 . is_ok ( )
201285}
202286
203- /// Attempt to fulfill all obligations of `target_impl` after unification with
204- /// `source_trait_ref`. If successful, returns the generic parameters for *all* the
205- /// generics of `target_impl`, including both those needed to unify with
206- /// `source_trait_ref` and those whose identity is determined via a where
207- /// clause in the impl.
208- fn fulfill_implication < ' tcx > (
209- infcx : & InferCtxt < ' tcx > ,
210- param_env : ty:: ParamEnv < ' tcx > ,
211- source_trait_ref : ty:: TraitRef < ' tcx > ,
212- source_impl : DefId ,
213- target_impl : DefId ,
214- error_cause : impl Fn ( usize , Span ) -> ObligationCause < ' tcx > ,
215- ) -> Result < GenericArgsRef < ' tcx > , ( ) > {
216- debug ! (
217- "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)" ,
218- param_env, source_trait_ref, target_impl
219- ) ;
220-
221- let ocx = ObligationCtxt :: new ( infcx) ;
222- let source_trait_ref = ocx. normalize ( & ObligationCause :: dummy ( ) , param_env, source_trait_ref) ;
223-
224- if !ocx. select_all_or_error ( ) . is_empty ( ) {
225- infcx. dcx ( ) . span_delayed_bug (
226- infcx. tcx . def_span ( source_impl) ,
227- format ! ( "failed to fully normalize {source_trait_ref}" ) ,
228- ) ;
229- }
230-
231- let source_trait_ref = infcx. resolve_vars_if_possible ( source_trait_ref) ;
232- let source_trait = ImplSubject :: Trait ( source_trait_ref) ;
233-
234- let selcx = SelectionContext :: new ( infcx) ;
235- let target_args = infcx. fresh_args_for_item ( DUMMY_SP , target_impl) ;
236- let ( target_trait, obligations) =
237- util:: impl_subject_and_oblig ( & selcx, param_env, target_impl, target_args, error_cause) ;
238-
239- // do the impls unify? If not, no specialization.
240- let Ok ( InferOk { obligations : more_obligations, .. } ) = infcx
241- . at ( & ObligationCause :: dummy ( ) , param_env)
242- // Ok to use `Yes`, as all the generic params are already replaced by inference variables,
243- // which will match the opaque type no matter if it is defining or not.
244- // Any concrete type that would match the opaque would already be handled by coherence rules,
245- // and thus either be ok to match here and already have errored, or it won't match, in which
246- // case there is no issue anyway.
247- . eq ( DefineOpaqueTypes :: Yes , source_trait, target_trait)
248- else {
249- debug ! ( "fulfill_implication: {:?} does not unify with {:?}" , source_trait, target_trait) ;
250- return Err ( ( ) ) ;
251- } ;
252-
253- // attempt to prove all of the predicates for impl2 given those for impl1
254- // (which are packed up in penv)
255- ocx. register_obligations ( obligations. chain ( more_obligations) ) ;
256-
257- let errors = ocx. select_all_or_error ( ) ;
258- if !errors. is_empty ( ) {
259- // no dice!
260- debug ! (
261- "fulfill_implication: for impls on {:?} and {:?}, \
262- could not fulfill: {:?} given {:?}",
263- source_trait,
264- target_trait,
265- errors,
266- param_env. caller_bounds( )
267- ) ;
268- return Err ( ( ) ) ;
269- }
270-
271- debug ! ( "fulfill_implication: an impl for {:?} specializes {:?}" , source_trait, target_trait) ;
272-
273- // Now resolve the *generic parameters* we built for the target earlier, replacing
274- // the inference variables inside with whatever we got from fulfillment.
275- Ok ( infcx. resolve_vars_if_possible ( target_args) )
276- }
277-
278287/// Query provider for `specialization_graph_of`.
279288pub ( super ) fn specialization_graph_provider (
280289 tcx : TyCtxt < ' _ > ,
0 commit comments