]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/opaque_types.rs
Rollup merge of #103718 - matklad:infer-lazy, r=dtolnay
[rust.git] / compiler / rustc_middle / src / ty / opaque_types.rs
1 use crate::error::ConstNotUsedTraitAlias;
2 use crate::ty::fold::{TypeFolder, TypeSuperFoldable};
3 use crate::ty::subst::{GenericArg, GenericArgKind};
4 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
5 use rustc_data_structures::fx::FxHashMap;
6 use rustc_span::Span;
7
8 /// Converts generic params of a TypeFoldable from one
9 /// item's generics to another. Usually from a function's generics
10 /// list to the opaque type's own generics.
11 pub(super) struct ReverseMapper<'tcx> {
12     tcx: TyCtxt<'tcx>,
13     map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
14     /// see call sites to fold_kind_no_missing_regions_error
15     /// for an explanation of this field.
16     do_not_error: bool,
17
18     /// We do not want to emit any errors in typeck because
19     /// the spans in typeck are subpar at the moment.
20     /// Borrowck will do the same work again (this time with
21     /// lifetime information) and thus report better errors.
22     ignore_errors: bool,
23
24     /// Span of function being checked.
25     span: Span,
26 }
27
28 impl<'tcx> ReverseMapper<'tcx> {
29     pub(super) fn new(
30         tcx: TyCtxt<'tcx>,
31         map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
32         span: Span,
33         ignore_errors: bool,
34     ) -> Self {
35         Self { tcx, map, do_not_error: false, ignore_errors, span }
36     }
37
38     fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
39         assert!(!self.do_not_error);
40         self.do_not_error = true;
41         let kind = kind.fold_with(self);
42         self.do_not_error = false;
43         kind
44     }
45
46     fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
47         assert!(!self.do_not_error);
48         kind.fold_with(self)
49     }
50 }
51
52 impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
53     fn tcx(&self) -> TyCtxt<'tcx> {
54         self.tcx
55     }
56
57     #[instrument(skip(self), level = "debug")]
58     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
59         match *r {
60             // Ignore bound regions and `'static` regions that appear in the
61             // type, we only need to remap regions that reference lifetimes
62             // from the function declaration.
63             // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
64             ty::ReLateBound(..) | ty::ReStatic => return r,
65
66             // If regions have been erased (by writeback), don't try to unerase
67             // them.
68             ty::ReErased => return r,
69
70             // The regions that we expect from borrow checking.
71             ty::ReEarlyBound(_) | ty::ReFree(_) => {}
72
73             ty::RePlaceholder(_) | ty::ReVar(_) => {
74                 // All of the regions in the type should either have been
75                 // erased by writeback, or mapped back to named regions by
76                 // borrow checking.
77                 bug!("unexpected region kind in opaque type: {:?}", r);
78             }
79         }
80
81         match self.map.get(&r.into()).map(|k| k.unpack()) {
82             Some(GenericArgKind::Lifetime(r1)) => r1,
83             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
84             None if self.do_not_error => self.tcx.lifetimes.re_static,
85             None => {
86                 self.tcx
87                     .sess
88                     .struct_span_err(self.span, "non-defining opaque type use in defining scope")
89                     .span_label(
90                         self.span,
91                         format!(
92                             "lifetime `{}` is part of concrete type but not used in \
93                                  parameter list of the `impl Trait` type alias",
94                             r
95                         ),
96                     )
97                     .emit();
98
99                 self.tcx().lifetimes.re_static
100             }
101         }
102     }
103
104     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
105         match *ty.kind() {
106             ty::Closure(def_id, substs) => {
107                 // I am a horrible monster and I pray for death. When
108                 // we encounter a closure here, it is always a closure
109                 // from within the function that we are currently
110                 // type-checking -- one that is now being encapsulated
111                 // in an opaque type. Ideally, we would
112                 // go through the types/lifetimes that it references
113                 // and treat them just like we would any other type,
114                 // which means we would error out if we find any
115                 // reference to a type/region that is not in the
116                 // "reverse map".
117                 //
118                 // **However,** in the case of closures, there is a
119                 // somewhat subtle (read: hacky) consideration. The
120                 // problem is that our closure types currently include
121                 // all the lifetime parameters declared on the
122                 // enclosing function, even if they are unused by the
123                 // closure itself. We can't readily filter them out,
124                 // so here we replace those values with `'empty`. This
125                 // can't really make a difference to the rest of the
126                 // compiler; those regions are ignored for the
127                 // outlives relation, and hence don't affect trait
128                 // selection or auto traits, and they are erased
129                 // during codegen.
130
131                 let generics = self.tcx.generics_of(def_id);
132                 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
133                     if index < generics.parent_count {
134                         // Accommodate missing regions in the parent kinds...
135                         self.fold_kind_no_missing_regions_error(kind)
136                     } else {
137                         // ...but not elsewhere.
138                         self.fold_kind_normally(kind)
139                     }
140                 }));
141
142                 self.tcx.mk_closure(def_id, substs)
143             }
144
145             ty::Generator(def_id, substs, movability) => {
146                 let generics = self.tcx.generics_of(def_id);
147                 let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
148                     if index < generics.parent_count {
149                         // Accommodate missing regions in the parent kinds...
150                         self.fold_kind_no_missing_regions_error(kind)
151                     } else {
152                         // ...but not elsewhere.
153                         self.fold_kind_normally(kind)
154                     }
155                 }));
156
157                 self.tcx.mk_generator(def_id, substs, movability)
158             }
159
160             ty::Param(param) => {
161                 // Look it up in the substitution list.
162                 match self.map.get(&ty.into()).map(|k| k.unpack()) {
163                     // Found it in the substitution list; replace with the parameter from the
164                     // opaque type.
165                     Some(GenericArgKind::Type(t1)) => t1,
166                     Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
167                     None => {
168                         debug!(?param, ?self.map);
169                         if !self.ignore_errors {
170                             self.tcx
171                                 .sess
172                                 .struct_span_err(
173                                     self.span,
174                                     &format!(
175                                         "type parameter `{}` is part of concrete type but not \
176                                           used in parameter list for the `impl Trait` type alias",
177                                         ty
178                                     ),
179                                 )
180                                 .emit();
181                         }
182
183                         self.tcx().ty_error()
184                     }
185                 }
186             }
187
188             _ => ty.super_fold_with(self),
189         }
190     }
191
192     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
193         trace!("checking const {:?}", ct);
194         // Find a const parameter
195         match ct.kind() {
196             ty::ConstKind::Param(..) => {
197                 // Look it up in the substitution list.
198                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
199                     // Found it in the substitution list, replace with the parameter from the
200                     // opaque type.
201                     Some(GenericArgKind::Const(c1)) => c1,
202                     Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
203                     None => {
204                         if !self.ignore_errors {
205                             self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
206                                 ct: ct.to_string(),
207                                 span: self.span,
208                             });
209                         }
210
211                         self.tcx().const_error(ct.ty())
212                     }
213                 }
214             }
215
216             _ => ct,
217         }
218     }
219 }