@@ -82,10 +82,14 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
82
82
use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
83
83
use rustc_trait_selection:: traits:: { self , translate_args_with_cause, wf, ObligationCtxt } ;
84
84
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 > {
86
89
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) ? ;
88
91
}
92
+ Ok ( ( ) )
89
93
}
90
94
91
95
fn 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
109
113
110
114
/// Check that `impl1` is a sound specialization
111
115
#[ 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 > {
113
121
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
131
140
}
132
141
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 > {
134
148
if let Node :: Impl ( impl2_id) = impl2_node
135
149
&& tcx. associated_item_def_ids ( impl1_def_id) . is_empty ( )
136
150
{
137
151
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 } ) ) ;
139
153
}
154
+ Ok ( ( ) )
140
155
}
141
156
142
157
/// Check that the specializing impl `impl1` is at least as const as the base
143
158
/// 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 > {
145
165
if impl2_node. is_from_trait ( ) {
146
166
// This isn't a specialization
147
- return ;
167
+ return Ok ( ( ) ) ;
148
168
}
149
169
150
170
let impl1_constness = tcx. constness ( impl1_def_id. to_def_id ( ) ) ;
151
171
let impl2_constness = tcx. constness ( impl2_node. def_id ( ) ) ;
152
172
153
173
if let hir:: Constness :: Const = impl2_constness {
154
174
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 } ) ) ;
156
176
}
157
177
}
178
+ Ok ( ( ) )
158
179
}
159
180
160
181
/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two
@@ -290,15 +311,17 @@ fn check_duplicate_params<'tcx>(
290
311
impl1_args : GenericArgsRef < ' tcx > ,
291
312
parent_args : & Vec < GenericArg < ' tcx > > ,
292
313
span : Span ,
293
- ) {
314
+ ) -> Result < ( ) , ErrorGuaranteed > {
294
315
let mut base_params = cgp:: parameters_for ( parent_args, true ) ;
295
316
base_params. sort_by_key ( |param| param. 0 ) ;
296
317
if let ( _, [ duplicate, ..] ) = base_params. partition_dedup ( ) {
297
318
let param = impl1_args[ duplicate. 0 as usize ] ;
298
- tcx. dcx ( )
319
+ return Err ( tcx
320
+ . dcx ( )
299
321
. struct_span_err ( span, format ! ( "specializing impl repeats parameter `{param}`" ) )
300
- . emit ( ) ;
322
+ . emit ( ) ) ;
301
323
}
324
+ Ok ( ( ) )
302
325
}
303
326
304
327
/// Check that `'static` lifetimes are not introduced by the specializing impl.
@@ -313,10 +336,11 @@ fn check_static_lifetimes<'tcx>(
313
336
tcx : TyCtxt < ' tcx > ,
314
337
parent_args : & Vec < GenericArg < ' tcx > > ,
315
338
span : Span ,
316
- ) {
339
+ ) -> Result < ( ) , ErrorGuaranteed > {
317
340
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 } ) ) ;
319
342
}
343
+ Ok ( ( ) )
320
344
}
321
345
322
346
/// Check whether predicates on the specializing impl (`impl1`) are allowed.
@@ -337,7 +361,7 @@ fn check_predicates<'tcx>(
337
361
impl2_node : Node ,
338
362
impl2_args : GenericArgsRef < ' tcx > ,
339
363
span : Span ,
340
- ) {
364
+ ) -> Result < ( ) , ErrorGuaranteed > {
341
365
let impl1_predicates: Vec < _ > = traits:: elaborate (
342
366
tcx,
343
367
tcx. predicates_of ( impl1_def_id) . instantiate ( tcx, impl1_args) . into_iter ( ) ,
@@ -399,14 +423,16 @@ fn check_predicates<'tcx>(
399
423
}
400
424
impl2_predicates. extend ( traits:: elaborate ( tcx, always_applicable_traits) ) ;
401
425
426
+ let mut res = Ok ( ( ) ) ;
402
427
for ( clause, span) in impl1_predicates {
403
428
if !impl2_predicates
404
429
. iter ( )
405
430
. any ( |pred2| trait_predicates_eq ( tcx, clause. as_predicate ( ) , * pred2, span) )
406
431
{
407
- check_specialization_on ( tcx, clause, span)
432
+ res = res . and ( check_specialization_on ( tcx, clause, span) )
408
433
}
409
434
}
435
+ res
410
436
}
411
437
412
438
/// Checks if some predicate on the specializing impl (`predicate1`) is the same
@@ -443,37 +469,43 @@ fn trait_predicates_eq<'tcx>(
443
469
}
444
470
445
471
#[ 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 > {
447
477
match clause. kind ( ) . skip_binder ( ) {
448
478
// Global predicates are either always true or always false, so we
449
479
// are fine to specialize on.
450
- _ if clause. is_global ( ) => ( ) ,
480
+ _ if clause. is_global ( ) => Ok ( ( ) ) ,
451
481
// We allow specializing on explicitly marked traits with no associated
452
482
// items.
453
483
ty:: ClauseKind :: Trait ( ty:: TraitPredicate { trait_ref, polarity : _ } ) => {
454
- if ! matches ! (
484
+ if matches ! (
455
485
trait_specialization_kind( tcx, clause) ,
456
486
Some ( TraitSpecializationKind :: Marker )
457
487
) {
458
- tcx. dcx ( )
488
+ Ok ( ( ) )
489
+ } else {
490
+ Err ( tcx
491
+ . dcx ( )
459
492
. struct_span_err (
460
493
span,
461
494
format ! (
462
495
"cannot specialize on trait `{}`" ,
463
496
tcx. def_path_str( trait_ref. def_id) ,
464
497
) ,
465
498
)
466
- . emit ( ) ;
499
+ . emit ( ) )
467
500
}
468
501
}
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 ( ) ) ,
477
509
ty:: ClauseKind :: ConstArgHasType ( ..) => {
478
510
// FIXME(min_specialization), FIXME(const_generics):
479
511
// 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
483
515
// While we do not support constructs like `<T, const N: T>` there is probably no risk of
484
516
// soundness bugs, but when we support generic const parameter types this will need to be
485
517
// revisited.
518
+ Ok ( ( ) )
486
519
}
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 ( ) ) ,
492
524
}
493
525
}
494
526
0 commit comments