rustc_infer/infer/opaque_types/
mod.rs

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