rustc_middle/ty/
opaque_types.rs

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