@@ -367,26 +367,29 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
367
367
let impl_sig = ocx. normalize (
368
368
& norm_cause,
369
369
param_env,
370
- infcx. replace_bound_vars_with_fresh_vars (
371
- return_span,
372
- infer:: HigherRankedType ,
373
- tcx. fn_sig ( impl_m. def_id ) ,
374
- ) ,
370
+ tcx. liberate_late_bound_regions ( impl_m. def_id , tcx. fn_sig ( impl_m. def_id ) ) ,
375
371
) ;
372
+ debug ! ( ?impl_sig) ;
376
373
let impl_return_ty = impl_sig. output ( ) ;
377
374
378
375
// Normalize the trait signature with liberated bound vars, passing it through
379
376
// the ImplTraitInTraitCollector, which gathers all of the RPITITs and replaces
380
377
// them with inference variables.
381
378
// We will use these inference variables to collect the hidden types of RPITITs.
382
379
let mut collector = ImplTraitInTraitCollector :: new ( & ocx, return_span, param_env, impl_m_hir_id) ;
383
- let unnormalized_trait_sig = tcx
384
- . liberate_late_bound_regions (
385
- impl_m. def_id ,
380
+ let unnormalized_trait_sig = infcx
381
+ . replace_bound_vars_with_fresh_vars (
382
+ return_span,
383
+ infer:: HigherRankedType ,
386
384
tcx. bound_fn_sig ( trait_m. def_id ) . subst ( tcx, trait_to_placeholder_substs) ,
387
385
)
388
386
. fold_with ( & mut collector) ;
387
+ if collector. types . is_empty ( ) {
388
+ return Ok ( & * tcx. arena . alloc ( FxHashMap :: default ( ) ) ) ;
389
+ }
390
+
389
391
let trait_sig = ocx. normalize ( & norm_cause, param_env, unnormalized_trait_sig) ;
392
+ debug ! ( ?trait_sig) ;
390
393
let trait_return_ty = trait_sig. output ( ) ;
391
394
392
395
let wf_tys = FxIndexSet :: from_iter (
@@ -422,7 +425,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
422
425
}
423
426
}
424
427
425
- debug ! ( ?trait_sig , ?impl_sig , "equating function signatures" ) ;
428
+ debug ! ( "equating function signatures" ) ;
426
429
427
430
let trait_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( trait_sig) ) ;
428
431
let impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( impl_sig) ) ;
@@ -461,86 +464,167 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
461
464
462
465
// Finally, resolve all regions. This catches wily misuses of
463
466
// lifetime parameters.
467
+ debug ! ( "check_region_obligations" ) ;
464
468
let outlives_environment = OutlivesEnvironment :: with_bounds (
465
469
param_env,
466
470
Some ( infcx) ,
467
471
infcx. implied_bounds_tys ( param_env, impl_m_hir_id, wf_tys) ,
468
472
) ;
473
+ debug ! ( region_bound_pairs=?outlives_environment. region_bound_pairs( ) ) ;
469
474
infcx. check_region_obligations_and_report_errors (
470
475
impl_m. def_id . expect_local ( ) ,
471
476
& outlives_environment,
472
477
) ;
473
478
479
+ debug ! ( "resolve collected" ) ;
474
480
let mut collected_tys = FxHashMap :: default ( ) ;
475
- for ( def_id, ( ty, substs) ) in collector. types {
476
- match infcx. fully_resolve ( ty) {
477
- Ok ( ty) => {
478
- // `ty` contains free regions that we created earlier while liberating the
479
- // trait fn signature. However, projection normalization expects `ty` to
480
- // contains `def_id`'s early-bound regions.
481
- let id_substs = InternalSubsts :: identity_for_item ( tcx, def_id) ;
482
- debug ! ( ?id_substs, ?substs) ;
483
- let map: FxHashMap < ty:: GenericArg < ' tcx > , ty:: GenericArg < ' tcx > > =
484
- std:: iter:: zip ( substs, id_substs) . collect ( ) ;
485
- debug ! ( ?map) ;
486
-
487
- // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
488
- // region substs that are synthesized during AST lowering. These are substs
489
- // that are appended to the parent substs (trait and trait method). However,
490
- // we're trying to infer the unsubstituted type value of the RPITIT inside
491
- // the *impl*, so we can later use the impl's method substs to normalize
492
- // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
493
- //
494
- // Due to the design of RPITITs, during AST lowering, we have no idea that
495
- // an impl method corresponds to a trait method with RPITITs in it. Therefore,
496
- // we don't have a list of early-bound region substs for the RPITIT in the impl.
497
- // Since early region parameters are index-based, we can't just rebase these
498
- // (trait method) early-bound region substs onto the impl, and there's no
499
- // guarantee that the indices from the trait substs and impl substs line up.
500
- // So to fix this, we subtract the number of trait substs and add the number of
501
- // impl substs to *renumber* these early-bound regions to their corresponding
502
- // indices in the impl's substitutions list.
503
- //
504
- // Also, we only need to account for a difference in trait and impl substs,
505
- // since we previously enforce that the trait method and impl method have the
506
- // same generics.
507
- let num_trait_substs = trait_to_impl_substs. len ( ) ;
508
- let num_impl_substs = tcx. generics_of ( impl_m. container_id ( tcx) ) . params . len ( ) ;
509
- let ty = tcx. fold_regions ( ty, |region, _| {
510
- match region. kind ( ) {
511
- // Remap all free regions, which correspond to late-bound regions in the function.
512
- ty:: ReFree ( _) => { }
513
- // Remap early-bound regions as long as they don't come from the `impl` itself.
514
- ty:: ReEarlyBound ( ebr) if tcx. parent ( ebr. def_id ) != impl_m. container_id ( tcx) => { }
515
- _ => return region,
516
- }
517
- let Some ( ty:: ReEarlyBound ( e) ) = map. get ( & region. into ( ) ) . map ( |r| r. expect_region ( ) . kind ( ) )
518
- else {
519
- tcx
520
- . sess
521
- . delay_span_bug (
522
- return_span,
523
- "expected ReFree to map to ReEarlyBound"
524
- ) ;
525
- return tcx. lifetimes . re_static ;
526
- } ;
527
- tcx. mk_region ( ty:: ReEarlyBound ( ty:: EarlyBoundRegion {
528
- def_id : e. def_id ,
529
- name : e. name ,
530
- index : ( e. index as usize - num_trait_substs + num_impl_substs) as u32 ,
531
- } ) )
532
- } ) ;
533
- debug ! ( %ty) ;
534
- collected_tys. insert ( def_id, ty) ;
481
+ for ( def_id, ( raw_ty, substs) ) in collector. types {
482
+ debug ! ( ?def_id) ;
483
+
484
+ let substs = match infcx. fully_resolve ( substs) {
485
+ Ok ( substs) => substs,
486
+ Err ( err) => {
487
+ collected_tys. insert (
488
+ def_id,
489
+ tcx. ty_error_with_message (
490
+ return_span,
491
+ & format ! ( "could not fully resolve: {substs:?} => {err:?}" ) ,
492
+ ) ,
493
+ ) ;
494
+ continue ;
535
495
}
496
+ } ;
497
+ debug ! ( ?substs) ;
498
+
499
+ let raw_ty = match infcx. fully_resolve ( raw_ty) {
500
+ Ok ( raw_ty) => raw_ty,
536
501
Err ( err) => {
537
- let reported = tcx. sess . delay_span_bug (
538
- return_span,
539
- format ! ( "could not fully resolve: {ty} => {err:?}" ) ,
502
+ collected_tys. insert (
503
+ def_id,
504
+ tcx. ty_error_with_message (
505
+ return_span,
506
+ & format ! ( "could not fully resolve: {raw_ty} => {err:?}" ) ,
507
+ ) ,
540
508
) ;
541
- collected_tys . insert ( def_id , tcx . ty_error_with_guaranteed ( reported ) ) ;
509
+ continue ;
542
510
}
511
+ } ;
512
+ debug ! ( ?raw_ty) ;
513
+
514
+ // `raw_ty` contains free regions that we created earlier while liberating the
515
+ // trait fn signature. However, projection normalization expects `raw_ty` to
516
+ // contains `def_id`'s early-bound regions.
517
+ let id_substs = InternalSubsts :: identity_for_item ( tcx, def_id) ;
518
+ debug ! ( ?id_substs, ?substs) ;
519
+
520
+ let variances = tcx. variances_of ( def_id) ;
521
+ debug ! ( ?variances) ;
522
+
523
+ // Opaque types may only use regions that are bound. So for
524
+ // ```rust
525
+ // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b;
526
+ // ```
527
+ // we may not use `'c` in the hidden type.
528
+ let map: FxHashMap < ty:: GenericArg < ' tcx > , ty:: GenericArg < ' tcx > > =
529
+ std:: iter:: zip ( substs, id_substs)
530
+ . filter ( |( _, v) | {
531
+ let ty:: GenericArgKind :: Lifetime ( lt) = v. unpack ( ) else { return true } ;
532
+ let ty:: ReEarlyBound ( ebr) = lt. kind ( ) else { bug ! ( ) } ;
533
+ variances[ ebr. index as usize ] == ty:: Variance :: Invariant
534
+ } )
535
+ . collect ( ) ;
536
+ debug ! ( ?map) ;
537
+
538
+ // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
539
+ // region substs that are synthesized during AST lowering. These are substs
540
+ // that are appended to the parent substs (trait and trait method). However,
541
+ // we're trying to infer the unsubstituted type value of the RPITIT inside
542
+ // the *impl*, so we can later use the impl's method substs to normalize
543
+ // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`).
544
+ //
545
+ // Due to the design of RPITITs, during AST lowering, we have no idea that
546
+ // an impl method corresponds to a trait method with RPITITs in it. Therefore,
547
+ // we don't have a list of early-bound region substs for the RPITIT in the impl.
548
+ // Since early region parameters are index-based, we can't just rebase these
549
+ // (trait method) early-bound region substs onto the impl, and there's no
550
+ // guarantee that the indices from the trait substs and impl substs line up.
551
+ // So to fix this, we subtract the number of trait substs and add the number of
552
+ // impl substs to *renumber* these early-bound regions to their corresponding
553
+ // indices in the impl's substitutions list.
554
+ //
555
+ // Also, we only need to account for a difference in trait and impl substs,
556
+ // since we previously enforce that the trait method and impl method have the
557
+ // same generics.
558
+ let num_trait_substs = trait_to_impl_substs. len ( ) ;
559
+ let num_impl_substs = tcx. generics_of ( impl_m. def_id ) . parent_count ;
560
+ debug ! ( ?num_trait_substs, ?num_impl_substs) ;
561
+
562
+ let mut bad_regions = vec ! [ ] ;
563
+
564
+ let ty = tcx. fold_regions ( raw_ty, |region, _| {
565
+ debug ! ( ?region) ;
566
+ match region. kind ( ) {
567
+ // Remap all free regions, which correspond to late-bound regions in the function.
568
+ ty:: ReFree ( _) => { }
569
+ // Remap early-bound regions as long as they don't come from the `impl` itself.
570
+ ty:: ReEarlyBound ( ebr) if ( ebr. index as usize ) >= num_impl_substs => { }
571
+ _ => return region,
572
+ }
573
+ debug ! ( mapped = ?map. get( & region. into( ) ) ) ;
574
+ let Some ( ty:: ReEarlyBound ( e) ) = map. get ( & region. into ( ) ) . map ( |r| r. expect_region ( ) . kind ( ) )
575
+ else {
576
+ bad_regions. push ( region) ;
577
+ return tcx. lifetimes . re_static ;
578
+ } ;
579
+ tcx. mk_region ( ty:: ReEarlyBound ( ty:: EarlyBoundRegion {
580
+ def_id : e. def_id ,
581
+ name : e. name ,
582
+ index : ( e. index as usize - num_trait_substs + num_impl_substs) as u32 ,
583
+ } ) )
584
+ } ) ;
585
+
586
+ if !bad_regions. is_empty ( ) {
587
+ let mut err = tcx. sess . struct_span_err (
588
+ return_span,
589
+ "`impl` item return type captures lifetime that doesn't appear in `trait` item bounds" ,
590
+ ) ;
591
+ for r in bad_regions {
592
+ let span = match r. kind ( ) {
593
+ ty:: ReEarlyBound ( ebr) => tcx. def_span ( ebr. def_id ) ,
594
+ ty:: ReFree ( fr) => fr. bound_region . opt_span ( tcx) . unwrap ( ) ,
595
+ _ => bug ! ( ) ,
596
+ } ;
597
+ let name = if r. has_name ( ) {
598
+ format ! ( "lifetime `{r}`" )
599
+ } else {
600
+ "the anonymous lifetime" . to_string ( )
601
+ } ;
602
+ err. span_label ( span, format ! ( "type `{raw_ty}` captures {name} defined here" ) ) ;
603
+ }
604
+
605
+ let generics = tcx. generics_of ( def_id) ;
606
+ match & generics. params [ ..] {
607
+ [ ] => {
608
+ err. span_label ( tcx. def_span ( def_id) , "type declared not to capture lifetimes" ) ;
609
+ }
610
+ [ param] => {
611
+ err. span_label (
612
+ tcx. def_span ( param. def_id ) ,
613
+ "type can only capture this lifetime" ,
614
+ ) ;
615
+ }
616
+ params => {
617
+ err. span_labels (
618
+ params. iter ( ) . map ( |param| tcx. def_span ( param. def_id ) ) ,
619
+ "type can only capture lifetimes enumerated here" ,
620
+ ) ;
621
+ }
622
+ } ;
623
+ err. emit ( ) ;
543
624
}
625
+
626
+ debug ! ( ?ty) ;
627
+ collected_tys. insert ( def_id, ty) ;
544
628
}
545
629
546
630
Ok ( & * tcx. arena . alloc ( collected_tys) )
0 commit comments