@@ -19,11 +19,13 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
19
19
use rustc_middle:: hir:: nested_filter;
20
20
use rustc_middle:: middle:: stability:: EvalResult ;
21
21
use rustc_middle:: traits:: DefiningAnchor ;
22
+ use rustc_middle:: ty:: fold:: BottomUpFolder ;
22
23
use rustc_middle:: ty:: layout:: { LayoutError , MAX_SIMD_LANES } ;
23
24
use rustc_middle:: ty:: util:: { Discr , IntTypeExt } ;
24
25
use rustc_middle:: ty:: GenericArgKind ;
25
26
use rustc_middle:: ty:: {
26
- self , AdtDef , ParamEnv , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
27
+ self , AdtDef , ParamEnv , RegionKind , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
28
+ TypeVisitableExt ,
27
29
} ;
28
30
use rustc_session:: lint:: builtin:: { UNINHABITED_STATIC , UNSUPPORTED_CALLING_CONVENTIONS } ;
29
31
use rustc_span:: symbol:: sym;
@@ -34,6 +36,7 @@ use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplem
34
36
use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt as _;
35
37
use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
36
38
use rustc_trait_selection:: traits:: { self , ObligationCtxt , TraitEngine , TraitEngineExt as _} ;
39
+ use rustc_type_ir:: fold:: TypeFoldable ;
37
40
38
41
use std:: ops:: ControlFlow ;
39
42
@@ -437,7 +440,7 @@ fn check_opaque_meets_bounds<'tcx>(
437
440
// hidden type is well formed even without those bounds.
438
441
let predicate =
439
442
ty:: Binder :: dummy ( ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( hidden_ty. into ( ) ) ) ) ;
440
- ocx. register_obligation ( Obligation :: new ( tcx, misc_cause, param_env, predicate) ) ;
443
+ ocx. register_obligation ( Obligation :: new ( tcx, misc_cause. clone ( ) , param_env, predicate) ) ;
441
444
442
445
// Check that all obligations are satisfied by the implementation's
443
446
// version.
@@ -464,11 +467,179 @@ fn check_opaque_meets_bounds<'tcx>(
464
467
ocx. resolve_regions_and_report_errors ( defining_use_anchor, & outlives_env) ?;
465
468
}
466
469
}
467
- // Clean up after ourselves
468
- let _ = infcx. take_opaque_types ( ) ;
470
+ // Check that any hidden types found during wf checking match the hidden types that `type_of` sees.
471
+ for ( key, mut ty) in infcx. take_opaque_types ( ) {
472
+ ty. hidden_type . ty = infcx. resolve_vars_if_possible ( ty. hidden_type . ty ) ;
473
+ sanity_check_found_hidden_type ( tcx, key, ty. hidden_type , defining_use_anchor, origin) ?;
474
+ }
469
475
Ok ( ( ) )
470
476
}
471
477
478
+ fn sanity_check_found_hidden_type < ' tcx > (
479
+ tcx : TyCtxt < ' tcx > ,
480
+ key : ty:: OpaqueTypeKey < ' tcx > ,
481
+ mut ty : ty:: OpaqueHiddenType < ' tcx > ,
482
+ defining_use_anchor : LocalDefId ,
483
+ origin : & hir:: OpaqueTyOrigin ,
484
+ ) -> Result < ( ) , ErrorGuaranteed > {
485
+ if ty. ty . is_ty_var ( ) {
486
+ // Nothing was actually constrained.
487
+ return Ok ( ( ) ) ;
488
+ }
489
+ if let ty:: Alias ( ty:: Opaque , alias) = ty. ty . kind ( ) {
490
+ if alias. def_id == key. def_id . to_def_id ( ) && alias. args == key. args {
491
+ // Nothing was actually constrained, this is an opaque usage that was
492
+ // only discovered to be opaque after inference vars resolved.
493
+ return Ok ( ( ) ) ;
494
+ }
495
+ }
496
+ // Closures frequently end up containing erased lifetimes in their final representation.
497
+ // These correspond to lifetime variables that never got resolved, so we patch this up here.
498
+ ty. ty = ty. ty . fold_with ( & mut BottomUpFolder {
499
+ tcx,
500
+ ty_op : |t| t,
501
+ ct_op : |c| c,
502
+ lt_op : |l| match l. kind ( ) {
503
+ RegionKind :: ReVar ( _) => tcx. lifetimes . re_erased ,
504
+ _ => l,
505
+ } ,
506
+ } ) ;
507
+ // Get the hidden type.
508
+ let mut hidden_ty = tcx. type_of ( key. def_id ) . instantiate ( tcx, key. args ) ;
509
+ if let hir:: OpaqueTyOrigin :: FnReturn ( ..) | hir:: OpaqueTyOrigin :: AsyncFn ( ..) = origin {
510
+ if hidden_ty != ty. ty {
511
+ hidden_ty = find_and_apply_rpit_args (
512
+ tcx,
513
+ hidden_ty,
514
+ defining_use_anchor. to_def_id ( ) ,
515
+ key. def_id . to_def_id ( ) ,
516
+ ) ?;
517
+ }
518
+ }
519
+
520
+ // If the hidden types differ, emit a type mismatch diagnostic.
521
+ if hidden_ty == ty. ty {
522
+ Ok ( ( ) )
523
+ } else {
524
+ let span = tcx. def_span ( key. def_id ) ;
525
+ let other = ty:: OpaqueHiddenType { ty : hidden_ty, span } ;
526
+ Err ( ty. report_mismatch ( & other, key. def_id , tcx) . emit ( ) )
527
+ }
528
+ }
529
+
530
+ /// In case it is in a nested opaque type, find that opaque type's
531
+ /// usage in the function signature and use the generic arguments from the usage site.
532
+ /// We need to do because RPITs ignore the lifetimes of the function,
533
+ /// as they have their own copies of all the lifetimes they capture.
534
+ /// So the only way to get the lifetimes represented in terms of the function,
535
+ /// is to look how they are used in the function signature (or do some other fancy
536
+ /// recording of this mapping at ast -> hir lowering time).
537
+ ///
538
+ /// As an example:
539
+ /// ```text
540
+ /// trait Id {
541
+ /// type Assoc;
542
+ /// }
543
+ /// impl<'a> Id for &'a () {
544
+ /// type Assoc = &'a ();
545
+ /// }
546
+ /// fn func<'a>(x: &'a ()) -> impl Id<Assoc = impl Sized + 'a> { x }
547
+ /// // desugared to
548
+ /// fn func<'a>(x: &'a () -> Outer<'a> where <Outer<'a> as Id>::Assoc = Inner<'a> {
549
+ /// // Note that in contrast to other nested items, RPIT type aliases can
550
+ /// // access their parents' generics.
551
+ ///
552
+ /// // hidden type is `&'aDupOuter ()`
553
+ /// // During wfcheck the hidden type of `Inner<'aDupOuter>` is `&'a ()`, but
554
+ /// // `typeof(Inner<'aDupOuter>) = &'aDupOuter ()`.
555
+ /// // So we walk the signature of `func` to find the use of `Inner<'a>`
556
+ /// // and then use that to replace the lifetimes in the hidden type, obtaining
557
+ /// // `&'a ()`.
558
+ /// type Outer<'aDupOuter> = impl Id<Assoc = Inner<'aDupOuter>>;
559
+ ///
560
+ /// // hidden type is `&'aDupInner ()`
561
+ /// type Inner<'aDupInner> = impl Sized + 'aDupInner;
562
+ ///
563
+ /// x
564
+ /// }
565
+ /// ```
566
+ fn find_and_apply_rpit_args < ' tcx > (
567
+ tcx : TyCtxt < ' tcx > ,
568
+ mut hidden_ty : Ty < ' tcx > ,
569
+ function : DefId ,
570
+ opaque : DefId ,
571
+ ) -> Result < Ty < ' tcx > , ErrorGuaranteed > {
572
+ // Find use of the RPIT in the function signature and thus find the right args to
573
+ // convert it into the parameter space of the function signature. This is needed,
574
+ // because that's what `type_of` returns, against which we compare later.
575
+ let ret = tcx. fn_sig ( function) . instantiate_identity ( ) . output ( ) ;
576
+ struct Visitor < ' tcx > {
577
+ tcx : TyCtxt < ' tcx > ,
578
+ opaque : DefId ,
579
+ function : DefId ,
580
+ seen : FxHashSet < DefId > ,
581
+ }
582
+ impl < ' tcx > ty:: TypeVisitor < TyCtxt < ' tcx > > for Visitor < ' tcx > {
583
+ type BreakTy = GenericArgsRef < ' tcx > ;
584
+
585
+ #[ instrument( level = "trace" , skip( self ) , ret) ]
586
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
587
+ trace ! ( "{:#?}" , t. kind( ) ) ;
588
+ match t. kind ( ) {
589
+ ty:: Alias ( ty:: Opaque , alias) => {
590
+ trace ! ( ?alias. def_id) ;
591
+ if alias. def_id == self . opaque {
592
+ return ControlFlow :: Break ( alias. args ) ;
593
+ } else if self . seen . insert ( alias. def_id ) {
594
+ for clause in self
595
+ . tcx
596
+ . explicit_item_bounds ( alias. def_id )
597
+ . iter_instantiated_copied ( self . tcx , alias. args )
598
+ {
599
+ trace ! ( ?clause) ;
600
+ clause. visit_with ( self ) ?;
601
+ }
602
+ }
603
+ }
604
+ ty:: Alias ( ty:: Projection , alias) => {
605
+ if self . tcx . is_impl_trait_in_trait ( alias. def_id )
606
+ && self . tcx . impl_trait_in_trait_parent_fn ( alias. def_id ) == self . function
607
+ {
608
+ // If we're lowering to associated item, install the opaque type which is just
609
+ // the `type_of` of the trait's associated item. If we're using the old lowering
610
+ // strategy, then just reinterpret the associated type like an opaque :^)
611
+ self . tcx
612
+ . type_of ( alias. def_id )
613
+ . instantiate ( self . tcx , alias. args )
614
+ . visit_with ( self ) ?;
615
+ }
616
+ }
617
+ ty:: Alias ( ty:: Weak , alias) => {
618
+ self . tcx
619
+ . type_of ( alias. def_id )
620
+ . instantiate ( self . tcx , alias. args )
621
+ . visit_with ( self ) ?;
622
+ }
623
+ _ => ( ) ,
624
+ }
625
+
626
+ t. super_visit_with ( self )
627
+ }
628
+ }
629
+ if let ControlFlow :: Break ( args) =
630
+ ret. visit_with ( & mut Visitor { tcx, function, opaque, seen : Default :: default ( ) } )
631
+ {
632
+ trace ! ( ?args) ;
633
+ trace ! ( "expected: {hidden_ty:#?}" ) ;
634
+ hidden_ty = ty:: EarlyBinder :: bind ( hidden_ty) . instantiate ( tcx, args) ;
635
+ trace ! ( "expected: {hidden_ty:#?}" ) ;
636
+ } else {
637
+ tcx. sess
638
+ . delay_span_bug ( tcx. def_span ( function) , format ! ( "{ret:?} does not contain {opaque:?}" ) ) ;
639
+ }
640
+ Ok ( hidden_ty)
641
+ }
642
+
472
643
fn is_enum_of_nonnullable_ptr < ' tcx > (
473
644
tcx : TyCtxt < ' tcx > ,
474
645
adt_def : AdtDef < ' tcx > ,
0 commit comments