]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/opaque_types.rs
Hide lifetimes of `impl Trait` in force trimmed paths
[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::def_id::DefId;
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     }
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(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     }
92 }
93
94 impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
95     fn tcx(&self) -> TyCtxt<'tcx> {
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
112             // The regions that we expect from borrow checking.
113             ty::ReEarlyBound(_) | ty::ReFree(_) => {}
114
115             ty::RePlaceholder(_) | ty::ReVar(_) => {
116                 // All of the regions in the type should either have been
117                 // erased by writeback, or mapped back to named regions by
118                 // borrow checking.
119                 bug!("unexpected region kind in opaque type: {:?}", r);
120             }
121         }
122
123         match self.map.get(&r.into()).map(|k| k.unpack()) {
124             Some(GenericArgKind::Lifetime(r1)) => r1,
125             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
126             None if self.do_not_error => self.tcx.lifetimes.re_static,
127             None => {
128                 self.tcx
129                     .sess
130                     .struct_span_err(self.span, "non-defining opaque type use in defining scope")
131                     .span_label(
132                         self.span,
133                         format!(
134                             "lifetime `{}` is part of concrete type but not used in \
135                                  parameter list of the `impl Trait` type alias",
136                             r
137                         ),
138                     )
139                     .emit();
140
141                 self.tcx().lifetimes.re_static
142             }
143         }
144     }
145
146     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
147         match *ty.kind() {
148             ty::Closure(def_id, substs) => {
149                 let substs = self.fold_closure_substs(def_id, substs);
150                 self.tcx.mk_closure(def_id, substs)
151             }
152
153             ty::Generator(def_id, substs, movability) => {
154                 let substs = self.fold_closure_substs(def_id, substs);
155                 self.tcx.mk_generator(def_id, substs, movability)
156             }
157
158             ty::GeneratorWitnessMIR(def_id, substs) => {
159                 let substs = self.fold_closure_substs(def_id, substs);
160                 self.tcx.mk_generator_witness_mir(def_id, substs)
161             }
162
163             ty::Param(param) => {
164                 // Look it up in the substitution list.
165                 match self.map.get(&ty.into()).map(|k| k.unpack()) {
166                     // Found it in the substitution list; replace with the parameter from the
167                     // opaque type.
168                     Some(GenericArgKind::Type(t1)) => t1,
169                     Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
170                     None => {
171                         debug!(?param, ?self.map);
172                         if !self.ignore_errors {
173                             self.tcx
174                                 .sess
175                                 .struct_span_err(
176                                     self.span,
177                                     &format!(
178                                         "type parameter `{}` is part of concrete type but not \
179                                           used in parameter list for the `impl Trait` type alias",
180                                         ty
181                                     ),
182                                 )
183                                 .emit();
184                         }
185
186                         self.tcx().ty_error()
187                     }
188                 }
189             }
190
191             _ => ty.super_fold_with(self),
192         }
193     }
194
195     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
196         trace!("checking const {:?}", ct);
197         // Find a const parameter
198         match ct.kind() {
199             ty::ConstKind::Param(..) => {
200                 // Look it up in the substitution list.
201                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
202                     // Found it in the substitution list, replace with the parameter from the
203                     // opaque type.
204                     Some(GenericArgKind::Const(c1)) => c1,
205                     Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
206                     None => {
207                         if !self.ignore_errors {
208                             self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
209                                 ct: ct.to_string(),
210                                 span: self.span,
211                             });
212                         }
213
214                         self.tcx().const_error(ct.ty())
215                     }
216                 }
217             }
218
219             _ => ct,
220         }
221     }
222 }