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