rustc_infer/infer/opaque_types/
mod.rs

1use hir::def_id::{DefId, LocalDefId};
2use rustc_hir as hir;
3use rustc_middle::bug;
4use rustc_middle::traits::ObligationCause;
5use rustc_middle::traits::solve::Goal;
6use rustc_middle::ty::error::{ExpectedFound, TypeError};
7use rustc_middle::ty::{
8    self, BottomUpFolder, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
9    TypeVisitableExt,
10};
11use rustc_span::Span;
12use tracing::{debug, instrument};
13
14use super::{DefineOpaqueTypes, RegionVariableOrigin};
15use crate::errors::OpaqueHiddenTypeDiag;
16use crate::infer::{InferCtxt, InferOk};
17use crate::traits::{self, Obligation, PredicateObligations};
18
19mod table;
20
21pub use table::{OpaqueTypeStorage, OpaqueTypeStorageEntries, OpaqueTypeTable};
22
23impl<'tcx> InferCtxt<'tcx> {
24    /// This is a backwards compatibility hack to prevent breaking changes from
25    /// lazy TAIT around RPIT handling.
26    pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
27        &self,
28        value: T,
29        body_id: LocalDefId,
30        span: Span,
31        param_env: ty::ParamEnv<'tcx>,
32    ) -> InferOk<'tcx, T> {
33        // We handle opaque types differently in the new solver.
34        if self.next_trait_solver() {
35            return InferOk { value, obligations: PredicateObligations::new() };
36        }
37
38        if !value.has_opaque_types() {
39            return InferOk { value, obligations: PredicateObligations::new() };
40        }
41
42        let mut obligations = PredicateObligations::new();
43        let value = value.fold_with(&mut BottomUpFolder {
44            tcx: self.tcx,
45            lt_op: |lt| lt,
46            ct_op: |ct| ct,
47            ty_op: |ty| match *ty.kind() {
48                ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
49                    if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
50                {
51                    let def_span = self.tcx.def_span(def_id);
52                    let span = if span.contains(def_span) { def_span } else { span };
53                    let ty_var = self.next_ty_var(span);
54                    obligations.extend(
55                        self.handle_opaque_type(ty, ty_var, span, param_env)
56                            .unwrap()
57                            .into_iter()
58                            .map(|goal| {
59                                Obligation::new(
60                                    self.tcx,
61                                    ObligationCause::new(
62                                        span,
63                                        body_id,
64                                        traits::ObligationCauseCode::OpaqueReturnType(None),
65                                    ),
66                                    goal.param_env,
67                                    goal.predicate,
68                                )
69                            }),
70                    );
71                    ty_var
72                }
73                _ => ty,
74            },
75        });
76        InferOk { value, obligations }
77    }
78
79    pub fn handle_opaque_type(
80        &self,
81        a: Ty<'tcx>,
82        b: Ty<'tcx>,
83        span: Span,
84        param_env: ty::ParamEnv<'tcx>,
85    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
86        debug_assert!(!self.next_trait_solver());
87        let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
88            ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
89                let def_id = def_id.expect_local();
90                if let ty::TypingMode::Coherence = self.typing_mode() {
91                    // See comment on `insert_hidden_type` for why this is sufficient in coherence
92                    return Some(self.register_hidden_type(
93                        OpaqueTypeKey { def_id, args },
94                        span,
95                        param_env,
96                        b,
97                    ));
98                }
99                // Check that this is `impl Trait` type is
100                // declared by `parent_def_id` -- i.e., one whose
101                // value we are inferring. At present, this is
102                // always true during the first phase of
103                // type-check, but not always true later on during
104                // NLL. Once we support named opaque types more fully,
105                // this same scenario will be able to arise during all phases.
106                //
107                // Here is an example using type alias `impl Trait`
108                // that indicates the distinction we are checking for:
109                //
110                // ```rust
111                // mod a {
112                //   pub type Foo = impl Iterator;
113                //   pub fn make_foo() -> Foo { .. }
114                // }
115                //
116                // mod b {
117                //   fn foo() -> a::Foo { a::make_foo() }
118                // }
119                // ```
120                //
121                // Here, the return type of `foo` references an
122                // `Opaque` indeed, but not one whose value is
123                // presently being inferred. You can get into a
124                // similar situation with closure return types
125                // today:
126                //
127                // ```rust
128                // fn foo() -> impl Iterator { .. }
129                // fn bar() {
130                //     let x = || foo(); // returns the Opaque assoc with `foo`
131                // }
132                // ```
133                if !self.can_define_opaque_ty(def_id) {
134                    return None;
135                }
136
137                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
138                    // We could accept this, but there are various ways to handle this situation,
139                    // and we don't want to make a decision on it right now. Likely this case is so
140                    // super rare anyway, that no one encounters it in practice. It does occur
141                    // however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where
142                    // it is of no concern, so we only check for TAITs.
143                    if self.can_define_opaque_ty(b_def_id)
144                        && matches!(
145                            self.tcx.opaque_ty_origin(b_def_id),
146                            hir::OpaqueTyOrigin::TyAlias { .. }
147                        )
148                    {
149                        self.dcx().emit_err(OpaqueHiddenTypeDiag {
150                            span,
151                            hidden_type: self.tcx.def_span(b_def_id),
152                            opaque_type: self.tcx.def_span(def_id),
153                        });
154                    }
155                }
156                Some(self.register_hidden_type(OpaqueTypeKey { def_id, args }, span, param_env, b))
157            }
158            _ => None,
159        };
160        if let Some(res) = process(a, b) {
161            res
162        } else if let Some(res) = process(b, a) {
163            res
164        } else {
165            let (a, b) = self.resolve_vars_if_possible((a, b));
166            Err(TypeError::Sorts(ExpectedFound::new(a, b)))
167        }
168    }
169}
170
171impl<'tcx> InferCtxt<'tcx> {
172    #[instrument(skip(self), level = "debug")]
173    fn register_hidden_type(
174        &self,
175        opaque_type_key: OpaqueTypeKey<'tcx>,
176        span: Span,
177        param_env: ty::ParamEnv<'tcx>,
178        hidden_ty: Ty<'tcx>,
179    ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
180        let mut goals = Vec::new();
181
182        self.insert_hidden_type(opaque_type_key, span, param_env, hidden_ty, &mut goals)?;
183
184        self.add_item_bounds_for_hidden_type(
185            opaque_type_key.def_id.to_def_id(),
186            opaque_type_key.args,
187            param_env,
188            hidden_ty,
189            &mut goals,
190        );
191
192        Ok(goals)
193    }
194
195    /// Insert a hidden type into the opaque type storage, making sure
196    /// it hasn't previously been defined. This does not emit any
197    /// constraints and it's the responsibility of the caller to make
198    /// sure that the item bounds of the opaque are checked.
199    pub fn register_hidden_type_in_storage(
200        &self,
201        opaque_type_key: OpaqueTypeKey<'tcx>,
202        hidden_ty: OpaqueHiddenType<'tcx>,
203    ) -> Option<Ty<'tcx>> {
204        self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty)
205    }
206
207    /// Insert a hidden type into the opaque type storage, equating it
208    /// with any previous entries if necessary.
209    ///
210    /// This **does not** add the item bounds of the opaque as nested
211    /// obligations. That is only necessary when normalizing the opaque
212    /// itself, not when getting the opaque type constraints from
213    /// somewhere else.
214    pub fn insert_hidden_type(
215        &self,
216        opaque_type_key: OpaqueTypeKey<'tcx>,
217        span: Span,
218        param_env: ty::ParamEnv<'tcx>,
219        hidden_ty: Ty<'tcx>,
220        goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
221    ) -> Result<(), TypeError<'tcx>> {
222        let tcx = self.tcx;
223        // Ideally, we'd get the span where *this specific `ty` came
224        // from*, but right now we just use the span from the overall
225        // value being folded. In simple cases like `-> impl Foo`,
226        // these are the same span, but not in cases like `-> (impl
227        // Foo, impl Bar)`.
228        match self.typing_mode() {
229            ty::TypingMode::Coherence => {
230                // During intercrate we do not define opaque types but instead always
231                // force ambiguity unless the hidden type is known to not implement
232                // our trait.
233                goals.push(Goal::new(tcx, param_env, ty::PredicateKind::Ambiguous));
234            }
235            ty::TypingMode::Analysis { .. } => {
236                let prev = self
237                    .inner
238                    .borrow_mut()
239                    .opaque_types()
240                    .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
241                if let Some(prev) = prev {
242                    goals.extend(
243                        self.at(&ObligationCause::dummy_with_span(span), param_env)
244                            .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
245                            .obligations
246                            .into_iter()
247                            .map(|obligation| obligation.as_goal()),
248                    );
249                }
250            }
251            ty::TypingMode::Borrowck { .. } => {
252                let prev = self
253                    .inner
254                    .borrow_mut()
255                    .opaque_types()
256                    .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
257
258                // We either equate the new hidden type with the previous entry or with the type
259                // inferred by HIR typeck.
260                let actual = prev.unwrap_or_else(|| {
261                    let actual = tcx
262                        .type_of_opaque_hir_typeck(opaque_type_key.def_id)
263                        .instantiate(self.tcx, opaque_type_key.args);
264                    let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
265                        ty::ReErased => {
266                            self.next_region_var(RegionVariableOrigin::MiscVariable(span))
267                        }
268                        _ => re,
269                    });
270                    actual
271                });
272
273                goals.extend(
274                    self.at(&ObligationCause::dummy_with_span(span), param_env)
275                        .eq(DefineOpaqueTypes::Yes, hidden_ty, actual)?
276                        .obligations
277                        .into_iter()
278                        .map(|obligation| obligation.as_goal()),
279                );
280            }
281            mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
282                bug!("insert hidden type in {mode:?}")
283            }
284        }
285
286        Ok(())
287    }
288
289    pub fn add_item_bounds_for_hidden_type(
290        &self,
291        def_id: DefId,
292        args: ty::GenericArgsRef<'tcx>,
293        param_env: ty::ParamEnv<'tcx>,
294        hidden_ty: Ty<'tcx>,
295        goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
296    ) {
297        let tcx = self.tcx;
298        // Require that the hidden type is well-formed. We have to
299        // make sure we wf-check the hidden type to fix #114728.
300        //
301        // However, we don't check that all types are well-formed.
302        // We only do so for types provided by the user or if they are
303        // "used", e.g. for method selection.
304        //
305        // This means we never check the wf requirements of the hidden
306        // type during MIR borrowck, causing us to infer the wrong
307        // lifetime for its member constraints which then results in
308        // unexpected region errors.
309        goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
310
311        let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
312            clause.fold_with(&mut BottomUpFolder {
313                tcx,
314                ty_op: |ty| match *ty.kind() {
315                    // We can't normalize associated types from `rustc_infer`,
316                    // but we can eagerly register inference variables for them.
317                    // FIXME(RPITIT): Don't replace RPITITs with inference vars.
318                    // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
319                    ty::Alias(ty::Projection, projection_ty)
320                        if !projection_ty.has_escaping_bound_vars()
321                            && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
322                            && !self.next_trait_solver() =>
323                    {
324                        let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
325                        goals.push(Goal::new(
326                            self.tcx,
327                            param_env,
328                            ty::PredicateKind::Clause(ty::ClauseKind::Projection(
329                                ty::ProjectionPredicate {
330                                    projection_term: projection_ty.into(),
331                                    term: ty_var.into(),
332                                },
333                            )),
334                        ));
335                        ty_var
336                    }
337                    // Replace all other mentions of the same opaque type with the hidden type,
338                    // as the bounds must hold on the hidden type after all.
339                    ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, args: args2, .. })
340                        if def_id == def_id2 && args == args2 =>
341                    {
342                        hidden_ty
343                    }
344                    _ => ty,
345                },
346                lt_op: |lt| lt,
347                ct_op: |ct| ct,
348            })
349        };
350
351        let item_bounds = tcx.explicit_item_bounds(def_id);
352        for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
353            let predicate = replace_opaques_in(predicate, goals);
354
355            // Require that the predicate holds for the concrete type.
356            debug!(?predicate);
357            goals.push(Goal::new(self.tcx, param_env, predicate));
358        }
359
360        // If this opaque is being defined and it's conditionally const,
361        if self.tcx.is_conditionally_const(def_id) {
362            let item_bounds = tcx.explicit_implied_const_bounds(def_id);
363            for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
364                let predicate = replace_opaques_in(
365                    predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
366                    goals,
367                );
368
369                // Require that the predicate holds for the concrete type.
370                debug!(?predicate);
371                goals.push(Goal::new(self.tcx, param_env, predicate));
372            }
373        }
374    }
375}