@@ -12,15 +12,18 @@ use super::universal_regions::UniversalRegions;
12
12
use rustc:: hir:: def_id:: DefId ;
13
13
use rustc:: infer:: InferCtxt ;
14
14
use rustc:: infer:: NLLRegionVariableOrigin ;
15
+ use rustc:: infer:: RegionObligation ;
15
16
use rustc:: infer:: RegionVariableOrigin ;
16
17
use rustc:: infer:: SubregionOrigin ;
17
18
use rustc:: infer:: region_constraints:: { GenericKind , VarOrigins } ;
18
19
use rustc:: mir:: { ClosureOutlivesRequirement , ClosureOutlivesSubject , ClosureRegionRequirements ,
19
20
Location , Mir } ;
20
- use rustc:: ty:: { self , RegionVid } ;
21
+ use rustc:: traits:: ObligationCause ;
22
+ use rustc:: ty:: { self , RegionVid , TypeFoldable } ;
21
23
use rustc_data_structures:: indexed_vec:: IndexVec ;
22
24
use std:: fmt;
23
25
use std:: rc:: Rc ;
26
+ use syntax:: ast;
24
27
use syntax_pos:: Span ;
25
28
26
29
mod annotation;
@@ -361,7 +364,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
361
364
None
362
365
} ;
363
366
364
- self . check_type_tests ( infcx, mir) ;
367
+ self . check_type_tests ( infcx, mir, outlives_requirements . as_mut ( ) ) ;
365
368
366
369
self . check_universal_regions ( infcx, outlives_requirements. as_mut ( ) ) ;
367
370
@@ -439,21 +442,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
439
442
/// therefore add `end('a)` into the region for `'b` -- but we
440
443
/// have no evidence that `'b` outlives `'a`, so we want to report
441
444
/// an error.
442
- fn check_type_tests ( & self , infcx : & InferCtxt < ' _ , ' _ , ' tcx > , mir : & Mir < ' tcx > ) {
445
+ fn check_type_tests < ' gcx > (
446
+ & self ,
447
+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
448
+ mir : & Mir < ' tcx > ,
449
+ mut propagated_outlives_requirements : Option < & mut Vec < ClosureOutlivesRequirement < ' gcx > > > ,
450
+ ) {
443
451
let tcx = infcx. tcx ;
444
452
445
453
for type_test in & self . type_tests {
446
454
debug ! ( "check_type_test: {:?}" , type_test) ;
447
455
448
- if self . eval_region_test (
449
- mir,
450
- type_test. point ,
451
- type_test. lower_bound ,
452
- & type_test. test ,
453
- ) {
456
+ if self . eval_region_test ( mir, type_test. point , type_test. lower_bound , & type_test. test ) {
454
457
continue ;
455
458
}
456
459
460
+ if let Some ( propagated_outlives_requirements) = & mut propagated_outlives_requirements {
461
+ if self . try_promote_type_test ( infcx, type_test, propagated_outlives_requirements) {
462
+ continue ;
463
+ }
464
+ }
465
+
457
466
// Oh the humanity. Obviously we will do better than this error eventually.
458
467
tcx. sess . span_err (
459
468
type_test. span ,
@@ -462,6 +471,103 @@ impl<'tcx> RegionInferenceContext<'tcx> {
462
471
}
463
472
}
464
473
474
+ fn try_promote_type_test < ' gcx > (
475
+ & self ,
476
+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
477
+ type_test : & TypeTest < ' tcx > ,
478
+ propagated_outlives_requirements : & mut Vec < ClosureOutlivesRequirement < ' gcx > > ,
479
+ ) -> bool {
480
+ let tcx = infcx. tcx ;
481
+ let gcx = tcx. global_tcx ( ) ;
482
+
483
+ let TypeTest {
484
+ generic_kind,
485
+ lower_bound,
486
+ point : _,
487
+ span,
488
+ test : _,
489
+ } = type_test;
490
+
491
+ // TODO. For now, just fail to promote anything with a
492
+ // region. This is obviously too strict: we will for example
493
+ // fail to promote `<T as Foo<'static>>::Bar` to our
494
+ // caller. But it is always sound not to promote, that just
495
+ // means more errors, and ignoring regions is a convenient
496
+ // starting point. This is because we would want to promote to
497
+ // a type that references the region-vids of the closure, for
498
+ // which we have no global representation just now.
499
+ let generic_ty = generic_kind. to_ty ( tcx) ;
500
+ if generic_ty. has_free_regions ( ) {
501
+ return false ;
502
+ }
503
+ let generic_ty = gcx. lift ( & generic_ty) . unwrap ( ) ;
504
+
505
+ // Find some bounding subject-region R+ that is a super-region
506
+ // of the existing subject-region R. This should be a non-local, universal
507
+ // region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
508
+ let lower_bound_plus = self . promoted_type_test_bound ( * lower_bound) ;
509
+ assert ! ( self . universal_regions. is_universal_region( lower_bound_plus) ) ;
510
+ assert ! ( !self . universal_regions
511
+ . is_local_free_region( lower_bound_plus) ) ;
512
+
513
+ propagated_outlives_requirements. push ( ClosureOutlivesRequirement {
514
+ subject : ClosureOutlivesSubject :: Ty ( generic_ty) ,
515
+ outlived_free_region : lower_bound_plus,
516
+ blame_span : * span,
517
+ } ) ;
518
+ true
519
+ }
520
+
521
+ /// Here, `lower_bound` (henceforth, `'r`) represents the bound from
522
+ /// some type-test `T: 'r`. We are a closure and have found that
523
+ /// `T: 'r` is not locally satisfiable, so we want to propagate
524
+ /// this constraint to our creator. It is sound for us to do so
525
+ /// with some `'r+` known to our creator, where `'r+: 'r`.
526
+ ///
527
+ /// The tricky bit here: this region `'r` may contain (a) any
528
+ /// number of points in the CFG and (b) any number of `end('x)`
529
+ /// elements of universally quantified regions. To communicate with
530
+ /// our creator, however, we have to pick exactly one universally
531
+ /// quantified region -- in other words, exactly one `end('x)`
532
+ /// element -- that they understand and which will be `'r+`.
533
+ ///
534
+ /// We do this as follows:
535
+ ///
536
+ /// - Ignore the CFG points in `'r`. All universally quantified regions
537
+ /// include the CFG anyhow.
538
+ /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
539
+ /// a result `'y`.
540
+ /// - Finally, we take the non-local upper bound of `'y`.
541
+ fn promoted_type_test_bound ( & self , lower_bound : RegionVid ) -> RegionVid {
542
+ let inferred_values = self . inferred_values . as_ref ( ) . unwrap ( ) ;
543
+
544
+ debug ! (
545
+ "promoted_type_test_bound(lower_bound={:?}={})" ,
546
+ lower_bound,
547
+ inferred_values. region_value_str( lower_bound)
548
+ ) ;
549
+
550
+ // Find the smallest universal region that contains all other
551
+ // universal regions within `region`.
552
+ let mut lub = self . universal_regions . fr_fn_body ;
553
+ for ur in inferred_values. universal_regions_outlived_by ( lower_bound) {
554
+ lub = self . universal_regions . postdom_upper_bound ( lub, ur) ;
555
+ }
556
+
557
+ debug ! ( "promoted_type_test_bound: lub={:?}" , lub) ;
558
+
559
+ // Grow further to get smallest universal region known to
560
+ // creator.
561
+ let non_local_lub = self . universal_regions . non_local_upper_bound ( lub) ;
562
+
563
+ debug ! (
564
+ "promoted_type_test_bound: non_local_lub={:?}" ,
565
+ non_local_lub
566
+ ) ;
567
+
568
+ non_local_lub
569
+ }
570
+
465
571
/// Test if `test` is true when applied to `lower_bound` at
466
572
/// `point`, and returns true or false.
467
573
fn eval_region_test (
@@ -487,13 +593,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
487
593
. iter ( )
488
594
. any ( |& r| self . eval_outlives ( mir, r, lower_bound, point) ) ,
489
595
490
- RegionTest :: Any ( tests) => tests. iter ( ) . any ( |test| {
491
- self . eval_region_test ( mir , point , lower_bound , test )
492
- } ) ,
596
+ RegionTest :: Any ( tests) => tests
597
+ . iter ( )
598
+ . any ( |test| self . eval_region_test ( mir , point , lower_bound , test ) ) ,
493
599
494
- RegionTest :: All ( tests) => tests. iter ( ) . all ( |test| {
495
- self . eval_region_test ( mir , point , lower_bound , test )
496
- } ) ,
600
+ RegionTest :: All ( tests) => tests
601
+ . iter ( )
602
+ . all ( |test| self . eval_region_test ( mir , point , lower_bound , test ) ) ,
497
603
}
498
604
}
499
605
@@ -772,17 +878,18 @@ impl fmt::Debug for Constraint {
772
878
}
773
879
}
774
880
775
- pub trait ClosureRegionRequirementsExt {
881
+ pub trait ClosureRegionRequirementsExt < ' gcx > {
776
882
fn apply_requirements < ' tcx > (
777
883
& self ,
778
- infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
884
+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
885
+ body_id : ast:: NodeId ,
779
886
location : Location ,
780
887
closure_def_id : DefId ,
781
888
closure_substs : ty:: ClosureSubsts < ' tcx > ,
782
889
) ;
783
890
}
784
891
785
- impl < ' gcx > ClosureRegionRequirementsExt for ClosureRegionRequirements < ' gcx > {
892
+ impl < ' gcx > ClosureRegionRequirementsExt < ' gcx > for ClosureRegionRequirements < ' gcx > {
786
893
/// Given an instance T of the closure type, this method
787
894
/// instantiates the "extra" requirements that we computed for the
788
895
/// closure into the inference context. This has the effect of
@@ -797,7 +904,8 @@ impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> {
797
904
/// requirements.
798
905
fn apply_requirements < ' tcx > (
799
906
& self ,
800
- infcx : & InferCtxt < ' _ , ' _ , ' tcx > ,
907
+ infcx : & InferCtxt < ' _ , ' gcx , ' tcx > ,
908
+ body_id : ast:: NodeId ,
801
909
location : Location ,
802
910
closure_def_id : DefId ,
803
911
closure_substs : ty:: ClosureSubsts < ' tcx > ,
@@ -843,8 +951,15 @@ impl<'gcx> ClosureRegionRequirementsExt for ClosureRegionRequirements<'gcx> {
843
951
infcx. sub_regions ( origin, outlived_region, region) ;
844
952
}
845
953
846
- ClosureOutlivesSubject :: Ty ( _ty) => {
847
- bug ! ( "TODO not yet implemented -- closure outlives subject of a type" ) ;
954
+ ClosureOutlivesSubject :: Ty ( ty) => {
955
+ infcx. register_region_obligation (
956
+ body_id,
957
+ RegionObligation {
958
+ sup_type : ty,
959
+ sub_region : outlived_region,
960
+ cause : ObligationCause :: misc ( outlives_requirement. blame_span , body_id) ,
961
+ } ,
962
+ ) ;
848
963
}
849
964
}
850
965
}
0 commit comments