1- use rustc:: hir:: def_id:: DefId ;
21use rustc:: infer:: InferCtxt ;
32use rustc:: ty;
43use rustc_data_structures:: fx:: FxHashMap ;
4+ use rustc_hir:: def_id:: DefId ;
55use rustc_span:: Span ;
66
77use super :: RegionInferenceContext ;
88
99impl < ' tcx > RegionInferenceContext < ' tcx > {
1010 /// Resolve any opaque types that were encountered while borrow checking
1111 /// 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`.
1248 pub ( in crate :: borrow_check) fn infer_opaque_types (
1349 & self ,
1450 infcx : & InferCtxt < ' _ , ' tcx > ,
@@ -23,32 +59,46 @@ impl<'tcx> RegionInferenceContext<'tcx> {
2359 concrete_type, substs
2460 ) ;
2561
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] ;
4063 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 {
4265 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 ( || {
4468 infcx. tcx . sess . delay_span_bug (
4569 span,
4670 "opaque type with non-universal region substs" ,
4771 ) ;
4872 infcx. tcx . lifetimes . re_static
4973 } )
5074 }
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_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+ }
52102 } ) ;
53103
54104 debug ! (
0 commit comments