@@ -352,12 +352,7 @@ fn check_opaque_type_parameter_valid<'tcx>(
352
352
opaque_type_key : OpaqueTypeKey < ' tcx > ,
353
353
span : Span ,
354
354
) -> Result < ( ) , ErrorGuaranteed > {
355
- let opaque_ty_hir = tcx. hir ( ) . expect_item ( opaque_type_key. def_id ) ;
356
- let is_ty_alias = match opaque_ty_hir. expect_opaque_ty ( ) . origin {
357
- OpaqueTyOrigin :: TyAlias { .. } => true ,
358
- OpaqueTyOrigin :: AsyncFn ( ..) | OpaqueTyOrigin :: FnReturn ( ..) => false ,
359
- } ;
360
-
355
+ let opaque_env = LazyOpaqueTyEnv :: new ( tcx, opaque_type_key. def_id ) ;
361
356
let opaque_generics = tcx. generics_of ( opaque_type_key. def_id ) ;
362
357
let mut seen_params: FxIndexMap < _ , Vec < _ > > = FxIndexMap :: default ( ) ;
363
358
for ( i, arg) in opaque_type_key. iter_captured_args ( tcx) {
@@ -367,20 +362,17 @@ fn check_opaque_type_parameter_valid<'tcx>(
367
362
368
363
let arg_is_param = match arg. unpack ( ) {
369
364
GenericArgKind :: Type ( ty) => matches ! ( ty. kind( ) , ty:: Param ( _) ) ,
370
- GenericArgKind :: Lifetime ( lt) => match is_ty_alias {
371
- true => matches ! ( * lt, ty:: ReEarlyBound ( _) | ty:: ReFree ( _) ) ,
372
- // FIXME(#111935, #113916): For RPIT, we currently accept ReStatic as well.
373
- // This is a back-compat hack, see the issue for more.
374
- false => matches ! ( * lt, ty:: ReEarlyBound ( _) | ty:: ReFree ( _) | ty:: ReStatic ) ,
375
- } ,
365
+ GenericArgKind :: Lifetime ( lt) => {
366
+ matches ! ( * lt, ty:: ReEarlyBound ( _) | ty:: ReFree ( _) )
367
+ || ( lt. is_static ( ) && opaque_env. param_equal_static ( i) )
368
+ }
376
369
GenericArgKind :: Const ( ct) => matches ! ( ct. kind( ) , ty:: ConstKind :: Param ( _) ) ,
377
370
} ;
378
371
379
372
if arg_is_param {
380
- // FIXME(#113916): For RPIT, we can't currently check for unique lifetime
381
- // params, see that issue for more. We limit this to TAIT for now.
382
- if is_ty_alias {
383
- seen_params. entry ( arg) . or_default ( ) . push ( i) ;
373
+ let seen_where = seen_params. entry ( arg) . or_default ( ) ;
374
+ if !seen_where. first ( ) . is_some_and ( |& prev_i| opaque_env. params_equal ( i, prev_i) ) {
375
+ seen_where. push ( i) ;
384
376
}
385
377
} else {
386
378
// Prevent `fn foo() -> Foo<u32>` from being defining.
@@ -413,3 +405,81 @@ fn check_opaque_type_parameter_valid<'tcx>(
413
405
414
406
Ok ( ( ) )
415
407
}
408
+
409
+ struct LazyOpaqueTyEnv < ' tcx > {
410
+ tcx : TyCtxt < ' tcx > ,
411
+ def_id : LocalDefId ,
412
+ canonical_args : std:: cell:: Cell < Option < ty:: GenericArgsRef < ' tcx > > > ,
413
+ }
414
+
415
+ impl < ' tcx > LazyOpaqueTyEnv < ' tcx > {
416
+ pub fn new ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) -> Self {
417
+ Self { tcx, def_id, canonical_args : std:: cell:: Cell :: new ( None ) }
418
+ }
419
+
420
+ pub fn param_equal_static ( & self , param_index : usize ) -> bool {
421
+ self . get_canonical_args ( ) [ param_index] . expect_region ( ) . is_static ( )
422
+ }
423
+
424
+ pub fn params_equal ( & self , param1 : usize , param2 : usize ) -> bool {
425
+ let canonical_args = self . get_canonical_args ( ) ;
426
+ canonical_args[ param1] == canonical_args[ param2]
427
+ }
428
+
429
+ fn get_canonical_args ( & self ) -> ty:: GenericArgsRef < ' tcx > {
430
+ use rustc_hir as hir;
431
+ use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
432
+ use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
433
+
434
+ if let Some ( canonical_args) = self . canonical_args . get ( ) {
435
+ return canonical_args;
436
+ }
437
+
438
+ let & Self { tcx, def_id, .. } = self ;
439
+ let origin = tcx. opaque_type_origin ( def_id) ;
440
+ let defining_use_anchor = match origin {
441
+ hir:: OpaqueTyOrigin :: FnReturn ( did) | hir:: OpaqueTyOrigin :: AsyncFn ( did) => did,
442
+ hir:: OpaqueTyOrigin :: TyAlias { .. } => tcx. impl_trait_parent ( def_id) ,
443
+ } ;
444
+ let param_env = tcx. param_env ( defining_use_anchor) ;
445
+
446
+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
447
+ let ocx = ObligationCtxt :: new ( & infcx) ;
448
+
449
+ let args = match origin {
450
+ hir:: OpaqueTyOrigin :: FnReturn ( parent) | hir:: OpaqueTyOrigin :: AsyncFn ( parent) => {
451
+ GenericArgs :: identity_for_item ( tcx, parent) . extend_to (
452
+ tcx,
453
+ def_id. to_def_id ( ) ,
454
+ |param, _| {
455
+ tcx. map_rpit_lifetime_to_fn_lifetime ( param. def_id . expect_local ( ) ) . into ( )
456
+ } ,
457
+ )
458
+ }
459
+ hir:: OpaqueTyOrigin :: TyAlias { .. } => GenericArgs :: identity_for_item ( tcx, def_id) ,
460
+ } ;
461
+
462
+ let wf_tys = ocx. assumed_wf_types ( param_env, defining_use_anchor) . unwrap_or_else ( |_| {
463
+ tcx. sess . delay_span_bug ( tcx. def_span ( def_id) , "error getting implied bounds" ) ;
464
+ Default :: default ( )
465
+ } ) ;
466
+ let implied_bounds = infcx. implied_bounds_tys ( param_env, defining_use_anchor, wf_tys) ;
467
+ let outlives_env = OutlivesEnvironment :: with_bounds ( param_env, implied_bounds) ;
468
+
469
+ let mut seen = vec ! [ tcx. lifetimes. re_static] ;
470
+ let canonical_args = tcx. fold_regions ( args, |r1, _| {
471
+ if let Some ( & r2) = seen. iter ( ) . find ( |& & r2| {
472
+ let free_regions = outlives_env. free_region_map ( ) ;
473
+ free_regions. sub_free_regions ( tcx, r1, r2)
474
+ && free_regions. sub_free_regions ( tcx, r2, r1)
475
+ } ) {
476
+ r2
477
+ } else {
478
+ seen. push ( r1) ;
479
+ r1
480
+ }
481
+ } ) ;
482
+ self . canonical_args . set ( Some ( canonical_args) ) ;
483
+ canonical_args
484
+ }
485
+ }
0 commit comments