1
- use rustc:: hir:: def_id:: DefId ;
2
1
use rustc:: infer:: InferCtxt ;
3
2
use rustc:: ty;
4
3
use rustc_data_structures:: fx:: FxHashMap ;
4
+ use rustc_hir:: def_id:: DefId ;
5
5
use rustc_span:: Span ;
6
6
7
7
use super :: RegionInferenceContext ;
8
8
9
9
impl < ' tcx > RegionInferenceContext < ' tcx > {
10
10
/// Resolve any opaque types that were encountered while borrow checking
11
11
/// this item. This is then used to get the type in the `type_of` query.
12
+ ///
13
+ /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
14
+ /// This is lowered to give HIR something like
15
+ ///
16
+ /// type _Return<'_a> = impl Sized + '_a;
17
+ /// fn f<'a>(x: &'a i32) -> _Return<'a> { x }
18
+ ///
19
+ /// When checking the return type record the type from the return and the
20
+ /// type used in the return value. In this case they might be `_Return<'1>`
21
+ /// and `&'2 i32` respectively.
22
+ ///
23
+ /// Once we to this method, we have completed region inference and want to
24
+ /// call `infer_opaque_definition_from_instantiation` to get the inferred
25
+ /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
26
+ /// compares lifetimes directly, so we need to map the inference variables
27
+ /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
28
+ ///
29
+ /// First we map all the lifetimes in the concrete type to an equal
30
+ /// universal region that occurs in the concrete type's substs, in this case
31
+ /// this would result in `&'1 i32`. We only consider regions in the substs
32
+ /// in case there is an equal region that does not. For example, this should
33
+ /// be allowed:
34
+ /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
35
+ ///
36
+ /// Then we map the regions in both the type and the subst to their
37
+ /// `external_name` giving `concrete_type = &'a i32, substs = ['a]`. This
38
+ /// will then allow `infer_opaque_definition_from_instantiation` to
39
+ /// determine that `_Return<'_a> = &'_a i32`.
40
+ ///
41
+ /// There's a slight complication around closures. Given
42
+ /// `fn f<'a: 'a>() { || {} }` the closure's type is something like
43
+ /// `f::<'a>::{{closure}}`. The region parameter from f is essentially
44
+ /// ignored by type checking so ends up being inferred to an empty region.
45
+ /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
46
+ /// which has no `external_name` in which case we use `'empty` as the
47
+ /// region to pass to `infer_opaque_definition_from_instantiation`.
12
48
pub ( in crate :: borrow_check) fn infer_opaque_types (
13
49
& self ,
14
50
infcx : & InferCtxt < ' _ , ' tcx > ,
@@ -23,32 +59,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23
59
concrete_type, substs
24
60
) ;
25
61
26
- // Map back to "concrete" regions so that errors in
27
- // `infer_opaque_definition_from_instantiation` can show
28
- // sensible region names.
29
- let universal_concrete_type =
30
- infcx. tcx . fold_regions ( & concrete_type, & mut false , |region, _| match region {
31
- & ty:: ReVar ( vid) => {
32
- let universal_bound = self . universal_upper_bound ( vid) ;
33
- self . definitions [ universal_bound]
34
- . external_name
35
- . filter ( |_| self . eval_equal ( universal_bound, vid) )
36
- . unwrap_or ( infcx. tcx . lifetimes . re_empty )
37
- }
38
- concrete => concrete,
39
- } ) ;
62
+ let mut subst_regions = vec ! [ self . universal_regions. fr_static] ;
40
63
let universal_substs =
41
- infcx. tcx . fold_regions ( & substs, & mut false , |region, _| match region {
64
+ infcx. tcx . fold_regions ( & substs, & mut false , |region, _| match * region {
42
65
ty:: ReVar ( vid) => {
43
- self . definitions [ * vid] . external_name . unwrap_or_else ( || {
66
+ subst_regions. push ( vid) ;
67
+ self . definitions [ vid] . external_name . unwrap_or_else ( || {
44
68
infcx. tcx . sess . delay_span_bug (
45
69
span,
46
70
"opaque type with non-universal region substs" ,
47
71
) ;
48
72
infcx. tcx . lifetimes . re_static
49
73
} )
50
74
}
51
- concrete => concrete,
75
+ _ => {
76
+ infcx. tcx . sess . delay_span_bug (
77
+ span,
78
+ & format ! ( "unexpected concrete region in borrowck: {:?}" , region) ,
79
+ ) ;
80
+ region
81
+ }
82
+ } ) ;
83
+
84
+ subst_regions. sort ( ) ;
85
+ subst_regions. dedup ( ) ;
86
+
87
+ let universal_concrete_type =
88
+ infcx. tcx . fold_regions ( & concrete_type, & mut false , |region, _| match * region {
89
+ ty:: ReVar ( vid) => subst_regions
90
+ . iter ( )
91
+ . find ( |ur_vid| self . eval_equal ( vid, * * ur_vid) )
92
+ . and_then ( |ur_vid| self . definitions [ * ur_vid] . external_name )
93
+ . unwrap_or ( infcx. tcx . lifetimes . re_root_empty ) ,
94
+ ty:: ReLateBound ( ..) => region,
95
+ _ => {
96
+ infcx. tcx . sess . delay_span_bug (
97
+ span,
98
+ & format ! ( "unexpected concrete region in borrowck: {:?}" , region) ,
99
+ ) ;
100
+ region
101
+ }
52
102
} ) ;
53
103
54
104
debug ! (
0 commit comments