@@ -6,14 +6,13 @@ use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed};
6
6
use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , TyCtxtInferExt } ;
7
7
use rustc_lint_defs:: builtin:: UNCOVERED_PARAM_IN_PROJECTION ;
8
8
use rustc_middle:: ty:: {
9
- self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor , TypingMode ,
9
+ self , Ty , TyCtxt , TypeFlags , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
10
+ TypingMode ,
10
11
} ;
11
12
use rustc_middle:: { bug, span_bug} ;
12
- use rustc_span:: def_id:: { DefId , LocalDefId } ;
13
+ use rustc_span:: def_id:: LocalDefId ;
13
14
use rustc_span:: { Ident , Span } ;
14
- use rustc_trait_selection:: traits:: {
15
- self , InSelfTy , OrphanCheckErr , OrphanCheckMode , UncoveredTyParams ,
16
- } ;
15
+ use rustc_trait_selection:: traits:: { self , InSelfTy , OrphanCheckErr , OrphanCheckMode , UncoveredTy } ;
17
16
use tracing:: { debug, instrument} ;
18
17
19
18
use crate :: errors;
@@ -30,25 +29,34 @@ pub(crate) fn orphan_check_impl(
30
29
Ok ( ( ) ) => { }
31
30
Err ( err) => match orphan_check ( tcx, impl_def_id, OrphanCheckMode :: Compat ) {
32
31
Ok ( ( ) ) => match err {
33
- OrphanCheckErr :: UncoveredTyParams ( uncovered_ty_params) => {
34
- let hir_id = tcx. local_def_id_to_hir_id ( impl_def_id) ;
35
-
36
- for param_def_id in uncovered_ty_params. uncovered {
37
- let ident = tcx. item_ident ( param_def_id) ;
38
-
39
- tcx. node_span_lint (
40
- UNCOVERED_PARAM_IN_PROJECTION ,
41
- hir_id,
42
- ident. span ,
43
- |diag| {
44
- decorate_uncovered_ty_params_diag (
45
- diag,
46
- ident. span ,
47
- ident,
48
- uncovered_ty_params. local_ty ,
49
- )
32
+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, local_ty, in_self_ty } ) => {
33
+ let item = tcx. hir_expect_item ( impl_def_id) ;
34
+ let impl_ = item. expect_impl ( ) ;
35
+ let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
36
+
37
+ // FIXME: Dedupe!
38
+ // Given `impl<A, B> C<B> for D<A>`,
39
+ let span = match in_self_ty {
40
+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
41
+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
42
+ } ;
43
+
44
+ for ty in uncovered {
45
+ match ty {
46
+ UncoveredTyKind :: TyParam ( ident) => tcx. node_span_lint (
47
+ UNCOVERED_PARAM_IN_PROJECTION ,
48
+ item. hir_id ( ) ,
49
+ ident. span ,
50
+ |diag| decorate_uncovered_ty_diag ( diag, ident. span , ty, local_ty) ,
51
+ ) ,
52
+ // FIXME(fmease): This one is hard to explain ^^'
53
+ UncoveredTyKind :: Unknown => {
54
+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
55
+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
56
+ diag. emit ( ) ;
50
57
} ,
51
- ) ;
58
+ _ => bug ! ( ) ,
59
+ }
52
60
}
53
61
}
54
62
OrphanCheckErr :: NonLocalInputType ( _) => {
@@ -295,20 +303,13 @@ pub(crate) fn orphan_check_impl(
295
303
Ok ( ( ) )
296
304
}
297
305
298
- /// Checks the coherence orphan rules.
299
- ///
300
- /// `impl_def_id` should be the `DefId` of a trait impl.
301
- ///
302
- /// To pass, either the trait must be local, or else two conditions must be satisfied:
303
- ///
304
- /// 1. All type parameters in `Self` must be "covered" by some local type constructor.
305
- /// 2. Some local type must appear in `Self`.
306
+ /// Checks the coherence orphan rules for trait impl given by `impl_def_id`.
306
307
#[ instrument( level = "debug" , skip( tcx) , ret) ]
307
308
fn orphan_check < ' tcx > (
308
309
tcx : TyCtxt < ' tcx > ,
309
310
impl_def_id : LocalDefId ,
310
311
mode : OrphanCheckMode ,
311
- ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > > {
312
+ ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > > {
312
313
// We only accept this routine to be invoked on implementations
313
314
// of a trait, not inherent implementations.
314
315
let trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
@@ -361,15 +362,17 @@ fn orphan_check<'tcx>(
361
362
362
363
// (2) Try to map the remaining inference vars back to generic params.
363
364
result. map_err ( |err| match err {
364
- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
365
+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty , local_ty } ) => {
365
366
let mut collector =
366
- UncoveredTyParamCollector { infcx : & infcx, uncovered_params : Default :: default ( ) } ;
367
+ UncoveredTyCollector { infcx : & infcx, uncovered : Default :: default ( ) } ;
367
368
uncovered. visit_with ( & mut collector) ;
368
- // FIXME(fmease): This is very likely reachable.
369
- debug_assert ! ( !collector. uncovered_params. is_empty( ) ) ;
369
+ if collector. uncovered . is_empty ( ) {
370
+ collector. uncovered . insert ( UncoveredTyKind :: Unknown ) ;
371
+ }
370
372
371
- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams {
372
- uncovered : collector. uncovered_params ,
373
+ OrphanCheckErr :: UncoveredTy ( UncoveredTy {
374
+ uncovered : collector. uncovered ,
375
+ in_self_ty,
373
376
local_ty,
374
377
} )
375
378
}
@@ -397,14 +400,20 @@ fn emit_orphan_check_error<'tcx>(
397
400
tcx : TyCtxt < ' tcx > ,
398
401
trait_ref : ty:: TraitRef < ' tcx > ,
399
402
impl_def_id : LocalDefId ,
400
- err : traits :: OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > ,
403
+ err : OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > ,
401
404
) -> ErrorGuaranteed {
402
- match err {
403
- traits:: OrphanCheckErr :: NonLocalInputType ( tys) => {
404
- let item = tcx. hir_expect_item ( impl_def_id) ;
405
- let impl_ = item. expect_impl ( ) ;
406
- let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
405
+ let item = tcx. hir_expect_item ( impl_def_id) ;
406
+ let impl_ = item. expect_impl ( ) ;
407
+ let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
408
+
409
+ // Given `impl<A, B> C<B> for D<A>`,
410
+ let impl_trait_ref_span = |in_self_ty| match in_self_ty {
411
+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
412
+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
413
+ } ;
407
414
415
+ match err {
416
+ OrphanCheckErr :: NonLocalInputType ( tys) => {
408
417
let span = tcx. def_span ( impl_def_id) ;
409
418
let mut diag = tcx. dcx ( ) . create_err ( match trait_ref. self_ty ( ) . kind ( ) {
410
419
ty:: Adt ( ..) => errors:: OnlyCurrentTraits :: Outside { span, note : ( ) } ,
@@ -415,16 +424,11 @@ fn emit_orphan_check_error<'tcx>(
415
424
} ) ;
416
425
417
426
for & ( mut ty, in_self_ty) in & tys {
418
- // Given `impl<A, B> C<B> for D<A>`,
419
- let span = match in_self_ty {
420
- InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
421
- InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
422
- } ;
427
+ let span = impl_trait_ref_span ( in_self_ty) ;
428
+ let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
423
429
424
430
ty = tcx. erase_regions ( ty) ;
425
431
426
- let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
427
-
428
432
match * ty. kind ( ) {
429
433
ty:: Slice ( _) => {
430
434
if is_foreign {
@@ -484,73 +488,121 @@ fn emit_orphan_check_error<'tcx>(
484
488
485
489
diag. emit ( )
486
490
}
487
- traits:: OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
491
+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty, local_ty } ) => {
492
+ let span = impl_trait_ref_span ( in_self_ty) ;
493
+
488
494
let mut guar = None ;
489
- for param_def_id in uncovered {
490
- let ident = tcx. item_ident ( param_def_id) ;
491
- let mut diag = tcx. dcx ( ) . struct_span_err ( ident. span , "" ) ;
492
- decorate_uncovered_ty_params_diag ( & mut diag, ident. span , ident, local_ty) ;
495
+ for ty in uncovered {
496
+ let span = match ty {
497
+ UncoveredTyKind :: TyParam ( ident) => ident. span ,
498
+ _ => span,
499
+ } ;
500
+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
501
+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
493
502
guar. get_or_insert ( diag. emit ( ) ) ;
494
503
}
504
+ // This should not fail because we know that `uncovered` was non-empty at the point of
505
+ // iteration since it always contains a single `Unknown` if all else fails.
495
506
guar. unwrap ( )
496
507
}
497
508
}
498
509
}
499
510
500
- fn decorate_uncovered_ty_params_diag (
511
+ fn decorate_uncovered_ty_diag (
501
512
diag : & mut Diag < ' _ , impl EmissionGuarantee > ,
502
513
span : Span ,
503
- param : Ident ,
514
+ kind : UncoveredTyKind < ' _ > ,
504
515
local_ty : Option < Ty < ' _ > > ,
505
516
) {
517
+ let descr = match kind {
518
+ UncoveredTyKind :: TyParam ( ident) => Some ( ( "type parameter" , ident. to_string ( ) ) ) ,
519
+ UncoveredTyKind :: OpaqueTy ( ty) => Some ( ( "opaque type" , ty. to_string ( ) ) ) ,
520
+ UncoveredTyKind :: Unknown => None ,
521
+ } ;
522
+
506
523
diag. code ( rustc_errors:: E0210 ) ;
524
+ diag. span_label (
525
+ span,
526
+ match descr {
527
+ Some ( ( kind, _) ) => format ! ( "uncovered {kind}" ) ,
528
+ None => "contains an uncovered type" . into ( ) ,
529
+ } ,
530
+ ) ;
531
+
532
+ let subject = match & descr {
533
+ Some ( ( kind, ty) ) => format ! ( "{kind} `{ty}`" ) ,
534
+ None => "type parameters and opaque types" . into ( ) ,
535
+ } ;
536
+
537
+ let note = "\
538
+ implementing a foreign trait is only possible if \
539
+ at least one of the types for which it is implemented is local";
507
540
508
- let note = "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local" ;
509
541
if let Some ( local_ty) = local_ty {
510
- let msg = format ! (
511
- "type parameter `{param}` must be covered by another type when it appears before the first local type (`{local_ty}`)"
542
+ diag. primary_message ( format ! ( "{subject} must be covered by another type when it appears before the first local type (`{local_ty}`)" ) ) ;
543
+ diag. note ( format ! ( "{note},\n and no uncovered type parameters or opaque types appear before that first local type" ) ) ;
544
+ diag. note (
545
+ "in this case, 'before' refers to the following order: \
546
+ `impl<...> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last",
512
547
) ;
513
- diag. primary_message ( msg. clone ( ) ) ;
514
- diag. span_label ( span, msg) ;
515
- diag. note ( format ! (
516
- "{note}, and no uncovered type parameters appear before that first local type"
517
- ) ) ;
518
- diag. note ( "in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last" ) ;
519
548
} else {
520
- let msg = format ! (
521
- "type parameter `{param}` must be used as the type parameter for some local type"
522
- ) ;
523
- diag. primary_message ( format ! ( "{msg} (e.g., `MyStruct<{param}>`)" ) ) ;
524
- diag. span_label ( span, msg) ;
549
+ let example = descr. map ( |( _, ty) | format ! ( " (e.g., `MyStruct<{ty}>`)" ) ) . unwrap_or_default ( ) ;
550
+ diag. primary_message ( format ! (
551
+ "{subject} must be used as the argument to some local type{example}"
552
+ ) ) ;
525
553
diag. note ( note) ;
526
554
diag. note (
527
- "only traits defined in the current crate can be implemented for a type parameter" ,
555
+ "only traits defined in the current crate can be implemented for type parameters and opaque types"
528
556
) ;
529
557
}
530
558
}
531
559
532
- struct UncoveredTyParamCollector < ' cx , ' tcx > {
560
+ struct UncoveredTyCollector < ' cx , ' tcx > {
533
561
infcx : & ' cx InferCtxt < ' tcx > ,
534
- uncovered_params : FxIndexSet < DefId > ,
562
+ uncovered : UncoveredTys < ' tcx > ,
535
563
}
536
564
537
- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyParamCollector < ' _ , ' tcx > {
565
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyCollector < ' _ , ' tcx > {
538
566
fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
539
- if !ty. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
567
+ if !ty. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
540
568
return ;
541
569
}
542
- let ty:: Infer ( ty:: TyVar ( vid) ) = * ty. kind ( ) else {
543
- return ty. super_visit_with ( self ) ;
544
- } ;
545
- let origin = self . infcx . type_var_origin ( vid) ;
546
- if let Some ( def_id) = origin. param_def_id {
547
- self . uncovered_params . insert ( def_id) ;
570
+ match * ty. kind ( ) {
571
+ ty:: Infer ( ty:: TyVar ( vid) ) => {
572
+ if let Some ( def_id) = self . infcx . type_var_origin ( vid) . param_def_id {
573
+ let ident = self . infcx . tcx . item_ident ( def_id) ;
574
+ self . uncovered . insert ( UncoveredTyKind :: TyParam ( ident) ) ;
575
+ }
576
+ }
577
+ // This only works with the old solver. With the next solver, alias types like opaque
578
+ // types structurally normalize to an infer var that is "unresolvable" under coherence.
579
+ // Furthermore, the orphan checker returns the unnormalized type in such cases (with
580
+ // exception like for `Fundamental<?opaque>`) which would be Weak for TAITs and
581
+ // Projection for ATPITs.
582
+ // FIXME(fmease): One solution I could see working would be to reintroduce
583
+ // "TypeVarOriginKind::OpaqueTy(_)" and to stop OrphanChecker from
584
+ // remapping to the unnormalized type at all.
585
+ // FIXME(fmease): Should we just let uncovered Opaques take precedence over
586
+ // uncovered TyParams *inside* Opaques?
587
+ ty:: Alias ( ty:: Opaque , alias) if !alias. has_type_flags ( TypeFlags :: HAS_TY_INFER ) => {
588
+ self . uncovered . insert ( UncoveredTyKind :: OpaqueTy ( ty) ) ;
589
+ }
590
+ _ => ty. super_visit_with ( self ) ,
548
591
}
549
592
}
550
593
551
594
fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
552
- if ct. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
595
+ if ct. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
553
596
ct. super_visit_with ( self )
554
597
}
555
598
}
556
599
}
600
+
601
+ type UncoveredTys < ' tcx > = FxIndexSet < UncoveredTyKind < ' tcx > > ;
602
+
603
+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
604
+ enum UncoveredTyKind < ' tcx > {
605
+ TyParam ( Ident ) ,
606
+ OpaqueTy ( Ty < ' tcx > ) ,
607
+ Unknown ,
608
+ }
0 commit comments