@@ -82,10 +82,14 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
8282use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
8383use rustc_trait_selection:: traits:: { self , translate_args_with_cause, wf, ObligationCtxt } ;
8484
85- pub ( super ) fn check_min_specialization ( tcx : TyCtxt < ' _ > , impl_def_id : LocalDefId ) {
85+ pub ( super ) fn check_min_specialization (
86+ tcx : TyCtxt < ' _ > ,
87+ impl_def_id : LocalDefId ,
88+ ) -> Result < ( ) , ErrorGuaranteed > {
8689 if let Some ( node) = parent_specialization_node ( tcx, impl_def_id) {
87- check_always_applicable ( tcx, impl_def_id, node) ;
90+ check_always_applicable ( tcx, impl_def_id, node) ? ;
8891 }
92+ Ok ( ( ) )
8993}
9094
9195fn parent_specialization_node ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId ) -> Option < Node > {
@@ -109,52 +113,69 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
109113
110114/// Check that `impl1` is a sound specialization
111115#[ instrument( level = "debug" , skip( tcx) ) ]
112- fn check_always_applicable ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node ) {
116+ fn check_always_applicable (
117+ tcx : TyCtxt < ' _ > ,
118+ impl1_def_id : LocalDefId ,
119+ impl2_node : Node ,
120+ ) -> Result < ( ) , ErrorGuaranteed > {
113121 let span = tcx. def_span ( impl1_def_id) ;
114- check_has_items ( tcx, impl1_def_id, impl2_node, span) ;
115-
116- if let Ok ( ( impl1_args, impl2_args) ) = get_impl_args ( tcx, impl1_def_id, impl2_node) {
117- let impl2_def_id = impl2_node. def_id ( ) ;
118- debug ! ( ?impl2_def_id, ?impl2_args) ;
119-
120- let parent_args = if impl2_node. is_from_trait ( ) {
121- impl2_args. to_vec ( )
122- } else {
123- unconstrained_parent_impl_args ( tcx, impl2_def_id, impl2_args)
124- } ;
125-
126- check_constness ( tcx, impl1_def_id, impl2_node, span) ;
127- check_static_lifetimes ( tcx, & parent_args, span) ;
128- check_duplicate_params ( tcx, impl1_args, & parent_args, span) ;
129- check_predicates ( tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span) ;
130- }
122+ let mut res = check_has_items ( tcx, impl1_def_id, impl2_node, span) ;
123+
124+ let ( impl1_args, impl2_args) = get_impl_args ( tcx, impl1_def_id, impl2_node) ?;
125+ let impl2_def_id = impl2_node. def_id ( ) ;
126+ debug ! ( ?impl2_def_id, ?impl2_args) ;
127+
128+ let parent_args = if impl2_node. is_from_trait ( ) {
129+ impl2_args. to_vec ( )
130+ } else {
131+ unconstrained_parent_impl_args ( tcx, impl2_def_id, impl2_args)
132+ } ;
133+
134+ res = res. and ( check_constness ( tcx, impl1_def_id, impl2_node, span) ) ;
135+ res = res. and ( check_static_lifetimes ( tcx, & parent_args, span) ) ;
136+ res = res. and ( check_duplicate_params ( tcx, impl1_args, & parent_args, span) ) ;
137+ res = res. and ( check_predicates ( tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span) ) ;
138+
139+ res
131140}
132141
133- fn check_has_items ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node , span : Span ) {
142+ fn check_has_items (
143+ tcx : TyCtxt < ' _ > ,
144+ impl1_def_id : LocalDefId ,
145+ impl2_node : Node ,
146+ span : Span ,
147+ ) -> Result < ( ) , ErrorGuaranteed > {
134148 if let Node :: Impl ( impl2_id) = impl2_node
135149 && tcx. associated_item_def_ids ( impl1_def_id) . is_empty ( )
136150 {
137151 let base_impl_span = tcx. def_span ( impl2_id) ;
138- tcx. dcx ( ) . emit_err ( errors:: EmptySpecialization { span, base_impl_span } ) ;
152+ return Err ( tcx. dcx ( ) . emit_err ( errors:: EmptySpecialization { span, base_impl_span } ) ) ;
139153 }
154+ Ok ( ( ) )
140155}
141156
142157/// Check that the specializing impl `impl1` is at least as const as the base
143158/// impl `impl2`
144- fn check_constness ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node , span : Span ) {
159+ fn check_constness (
160+ tcx : TyCtxt < ' _ > ,
161+ impl1_def_id : LocalDefId ,
162+ impl2_node : Node ,
163+ span : Span ,
164+ ) -> Result < ( ) , ErrorGuaranteed > {
145165 if impl2_node. is_from_trait ( ) {
146166 // This isn't a specialization
147- return ;
167+ return Ok ( ( ) ) ;
148168 }
149169
150170 let impl1_constness = tcx. constness ( impl1_def_id. to_def_id ( ) ) ;
151171 let impl2_constness = tcx. constness ( impl2_node. def_id ( ) ) ;
152172
153173 if let hir:: Constness :: Const = impl2_constness {
154174 if let hir:: Constness :: NotConst = impl1_constness {
155- tcx. dcx ( ) . emit_err ( errors:: ConstSpecialize { span } ) ;
175+ return Err ( tcx. dcx ( ) . emit_err ( errors:: ConstSpecialize { span } ) ) ;
156176 }
157177 }
178+ Ok ( ( ) )
158179}
159180
160181/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
@@ -290,15 +311,17 @@ fn check_duplicate_params<'tcx>(
290311 impl1_args : GenericArgsRef < ' tcx > ,
291312 parent_args : & Vec < GenericArg < ' tcx > > ,
292313 span : Span ,
293- ) {
314+ ) -> Result < ( ) , ErrorGuaranteed > {
294315 let mut base_params = cgp:: parameters_for ( parent_args, true ) ;
295316 base_params. sort_by_key ( |param| param. 0 ) ;
296317 if let ( _, [ duplicate, ..] ) = base_params. partition_dedup ( ) {
297318 let param = impl1_args[ duplicate. 0 as usize ] ;
298- tcx. dcx ( )
319+ return Err ( tcx
320+ . dcx ( )
299321 . struct_span_err ( span, format ! ( "specializing impl repeats parameter `{param}`" ) )
300- . emit ( ) ;
322+ . emit ( ) ) ;
301323 }
324+ Ok ( ( ) )
302325}
303326
304327/// Check that `'static` lifetimes are not introduced by the specializing impl.
@@ -313,10 +336,11 @@ fn check_static_lifetimes<'tcx>(
313336 tcx : TyCtxt < ' tcx > ,
314337 parent_args : & Vec < GenericArg < ' tcx > > ,
315338 span : Span ,
316- ) {
339+ ) -> Result < ( ) , ErrorGuaranteed > {
317340 if tcx. any_free_region_meets ( parent_args, |r| r. is_static ( ) ) {
318- tcx. dcx ( ) . emit_err ( errors:: StaticSpecialize { span } ) ;
341+ return Err ( tcx. dcx ( ) . emit_err ( errors:: StaticSpecialize { span } ) ) ;
319342 }
343+ Ok ( ( ) )
320344}
321345
322346/// Check whether predicates on the specializing impl (`impl1`) are allowed.
@@ -337,7 +361,7 @@ fn check_predicates<'tcx>(
337361 impl2_node : Node ,
338362 impl2_args : GenericArgsRef < ' tcx > ,
339363 span : Span ,
340- ) {
364+ ) -> Result < ( ) , ErrorGuaranteed > {
341365 let impl1_predicates: Vec < _ > = traits:: elaborate (
342366 tcx,
343367 tcx. predicates_of ( impl1_def_id) . instantiate ( tcx, impl1_args) . into_iter ( ) ,
@@ -399,14 +423,16 @@ fn check_predicates<'tcx>(
399423 }
400424 impl2_predicates. extend ( traits:: elaborate ( tcx, always_applicable_traits) ) ;
401425
426+ let mut res = Ok ( ( ) ) ;
402427 for ( clause, span) in impl1_predicates {
403428 if !impl2_predicates
404429 . iter ( )
405430 . any ( |pred2| trait_predicates_eq ( tcx, clause. as_predicate ( ) , * pred2, span) )
406431 {
407- check_specialization_on ( tcx, clause, span)
432+ res = res . and ( check_specialization_on ( tcx, clause, span) )
408433 }
409434 }
435+ res
410436}
411437
412438/// Checks if some predicate on the specializing impl (`predicate1`) is the same
@@ -443,37 +469,43 @@ fn trait_predicates_eq<'tcx>(
443469}
444470
445471#[ instrument( level = "debug" , skip( tcx) ) ]
446- fn check_specialization_on < ' tcx > ( tcx : TyCtxt < ' tcx > , clause : ty:: Clause < ' tcx > , span : Span ) {
472+ fn check_specialization_on < ' tcx > (
473+ tcx : TyCtxt < ' tcx > ,
474+ clause : ty:: Clause < ' tcx > ,
475+ span : Span ,
476+ ) -> Result < ( ) , ErrorGuaranteed > {
447477 match clause. kind ( ) . skip_binder ( ) {
448478 // Global predicates are either always true or always false, so we
449479 // are fine to specialize on.
450- _ if clause. is_global ( ) => ( ) ,
480+ _ if clause. is_global ( ) => Ok ( ( ) ) ,
451481 // We allow specializing on explicitly marked traits with no associated
452482 // items.
453483 ty:: ClauseKind :: Trait ( ty:: TraitPredicate { trait_ref, polarity : _ } ) => {
454- if ! matches ! (
484+ if matches ! (
455485 trait_specialization_kind( tcx, clause) ,
456486 Some ( TraitSpecializationKind :: Marker )
457487 ) {
458- tcx. dcx ( )
488+ Ok ( ( ) )
489+ } else {
490+ Err ( tcx
491+ . dcx ( )
459492 . struct_span_err (
460493 span,
461494 format ! (
462495 "cannot specialize on trait `{}`" ,
463496 tcx. def_path_str( trait_ref. def_id) ,
464497 ) ,
465498 )
466- . emit ( ) ;
499+ . emit ( ) )
467500 }
468501 }
469- ty:: ClauseKind :: Projection ( ty:: ProjectionPredicate { projection_ty, term } ) => {
470- tcx. dcx ( )
471- . struct_span_err (
472- span,
473- format ! ( "cannot specialize on associated type `{projection_ty} == {term}`" , ) ,
474- )
475- . emit ( ) ;
476- }
502+ ty:: ClauseKind :: Projection ( ty:: ProjectionPredicate { projection_ty, term } ) => Err ( tcx
503+ . dcx ( )
504+ . struct_span_err (
505+ span,
506+ format ! ( "cannot specialize on associated type `{projection_ty} == {term}`" , ) ,
507+ )
508+ . emit ( ) ) ,
477509 ty:: ClauseKind :: ConstArgHasType ( ..) => {
478510 // FIXME(min_specialization), FIXME(const_generics):
479511 // It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
@@ -483,12 +515,12 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
483515 // While we do not support constructs like `<T, const N: T>` there is probably no risk of
484516 // soundness bugs, but when we support generic const parameter types this will need to be
485517 // revisited.
518+ Ok ( ( ) )
486519 }
487- _ => {
488- tcx. dcx ( )
489- . struct_span_err ( span, format ! ( "cannot specialize on predicate `{clause}`" ) )
490- . emit ( ) ;
491- }
520+ _ => Err ( tcx
521+ . dcx ( )
522+ . struct_span_err ( span, format ! ( "cannot specialize on predicate `{clause}`" ) )
523+ . emit ( ) ) ,
492524 }
493525}
494526
0 commit comments