rustc_hir_typeck/
opaque_types.rs

1use rustc_hir::def::DefKind;
2use rustc_infer::traits::ObligationCause;
3use rustc_middle::ty::{
4    self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt,
5    TypingMode,
6};
7use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
8use rustc_trait_selection::opaque_types::{
9    NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
10};
11use rustc_trait_selection::solve;
12use tracing::{debug, instrument};
13
14use crate::FnCtxt;
15
16impl<'tcx> FnCtxt<'_, 'tcx> {
17    /// This takes all the opaque type uses during HIR typeck. It first computes
18    /// the hidden type by iterating over all defining uses.
19    ///
20    /// A use during HIR typeck is defining if all non-lifetime arguments are
21    /// unique generic parameters and the hidden type does not reference any
22    /// inference variables.
23    ///
24    /// It then uses these defining uses to guide inference for all other uses.
25    ///
26    /// Unlike `handle_opaque_type_uses_next`, this does not report errors.
27    #[instrument(level = "debug", skip(self))]
28    pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
29        // We clone the opaques instead of stealing them here as we still need
30        // to use them after fallback.
31        let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
32
33        self.compute_definition_site_hidden_types(opaque_types, false);
34    }
35
36    /// This takes all the opaque type uses during HIR typeck. It first computes
37    /// the concrete hidden type by iterating over all defining uses.
38    ///
39    /// A use during HIR typeck is defining if all non-lifetime arguments are
40    /// unique generic parameters and the hidden type does not reference any
41    /// inference variables.
42    ///
43    /// It then uses these defining uses to guide inference for all other uses.
44    #[instrument(level = "debug", skip(self))]
45    pub(super) fn handle_opaque_type_uses_next(&mut self) {
46        // We clone the opaques instead of stealing them here as they are still used for
47        // normalization in the next generation trait solver.
48        let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
49        let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
50        let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
51        debug_assert_eq!(prev, None);
52
53        self.compute_definition_site_hidden_types(opaque_types, true);
54    }
55}
56
57#[derive(Copy, Clone, Debug)]
58enum UsageKind<'tcx> {
59    None,
60    NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
61    UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
62    HasDefiningUse(OpaqueHiddenType<'tcx>),
63}
64
65impl<'tcx> UsageKind<'tcx> {
66    fn merge(&mut self, other: UsageKind<'tcx>) {
67        match (&*self, &other) {
68            (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
69            (UsageKind::None, _) => *self = other,
70            // When mergining non-defining uses, prefer earlier ones. This means
71            // the error happens as early as possible.
72            (
73                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
74                UsageKind::NonDefiningUse(..),
75            ) => {}
76            // When merging unconstrained hidden types, we prefer later ones. This is
77            // used as in most cases, the defining use is the final return statement
78            // of our function, and other uses with defining arguments are likely not
79            // intended to be defining.
80            (
81                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
82                UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
83            ) => *self = other,
84        }
85    }
86}
87
88impl<'tcx> FnCtxt<'_, 'tcx> {
89    fn compute_definition_site_hidden_types(
90        &mut self,
91        mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
92        error_on_missing_defining_use: bool,
93    ) {
94        for entry in opaque_types.iter_mut() {
95            *entry = self.resolve_vars_if_possible(*entry);
96        }
97        debug!(?opaque_types);
98
99        let tcx = self.tcx;
100        let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
101        else {
102            unreachable!();
103        };
104
105        for def_id in defining_opaque_types_and_generators {
106            match tcx.def_kind(def_id) {
107                DefKind::OpaqueTy => {}
108                DefKind::Closure => continue,
109                _ => unreachable!("not opaque or generator: {def_id:?}"),
110            }
111
112            // We do actually need to check this the second pass (we can't just
113            // store this), because we can go from `UnconstrainedHiddenType` to
114            // `HasDefiningUse` (because of fallback)
115            let mut usage_kind = UsageKind::None;
116            for &(opaque_type_key, hidden_type) in &opaque_types {
117                if opaque_type_key.def_id != def_id {
118                    continue;
119                }
120
121                usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
122
123                if let UsageKind::HasDefiningUse(..) = usage_kind {
124                    break;
125                }
126            }
127
128            if let UsageKind::HasDefiningUse(ty) = usage_kind {
129                for &(opaque_type_key, hidden_type) in &opaque_types {
130                    if opaque_type_key.def_id != def_id {
131                        continue;
132                    }
133
134                    let expected = EarlyBinder::bind(ty.ty).instantiate(tcx, opaque_type_key.args);
135                    self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
136                }
137
138                // Being explicit here: it may be possible that we in a
139                // previous call to this function we did an insert, but this
140                // should be just fine, since they all get equated anyways and
141                // we shouldn't ever go from `HasDefiningUse` to anyway else.
142                let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
143            }
144
145            // If we're in `fn try_handle_opaque_type_uses_next` then do not
146            // report any errors.
147            if !error_on_missing_defining_use {
148                continue;
149            }
150
151            let guar = match usage_kind {
152                UsageKind::HasDefiningUse(_) => continue,
153                UsageKind::None => {
154                    if let Some(guar) = self.tainted_by_errors() {
155                        guar
156                    } else {
157                        report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
158                    }
159                }
160                UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
161                    report_item_does_not_constrain_error(
162                        self.tcx,
163                        self.body_id,
164                        def_id,
165                        Some((opaque_type_key, hidden_type.span)),
166                    )
167                }
168                UsageKind::UnconstrainedHiddenType(hidden_type) => {
169                    if let Some(guar) = self.tainted_by_errors() {
170                        guar
171                    } else {
172                        let infer_var = hidden_type
173                            .ty
174                            .walk()
175                            .filter_map(ty::GenericArg::as_term)
176                            .find(|term| term.is_infer())
177                            .unwrap_or_else(|| hidden_type.ty.into());
178                        self.err_ctxt()
179                            .emit_inference_failure_err(
180                                self.body_id,
181                                hidden_type.span,
182                                infer_var,
183                                TypeAnnotationNeeded::E0282,
184                                false,
185                            )
186                            .emit()
187                    }
188                }
189            };
190
191            self.typeck_results
192                .borrow_mut()
193                .hidden_types
194                .insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
195            self.set_tainted_by_errors(guar);
196        }
197    }
198
199    #[tracing::instrument(skip(self), ret)]
200    fn consider_opaque_type_use(
201        &self,
202        opaque_type_key: OpaqueTypeKey<'tcx>,
203        hidden_type: OpaqueHiddenType<'tcx>,
204    ) -> UsageKind<'tcx> {
205        if let Err(err) = opaque_type_has_defining_use_args(
206            &self,
207            opaque_type_key,
208            hidden_type.span,
209            DefiningScopeKind::HirTypeck,
210        ) {
211            match err {
212                NonDefiningUseReason::Tainted(guar) => {
213                    return UsageKind::HasDefiningUse(OpaqueHiddenType::new_error(self.tcx, guar));
214                }
215                _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
216            };
217        }
218
219        // We ignore uses of the opaque if they have any inference variables
220        // as this can frequently happen with recursive calls.
221        //
222        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
223        if hidden_type.ty.has_non_region_infer() {
224            return UsageKind::UnconstrainedHiddenType(hidden_type);
225        }
226
227        let cause = ObligationCause::misc(hidden_type.span, self.body_id);
228        let at = self.at(&cause, self.param_env);
229        let hidden_type = match solve::deeply_normalize(at, hidden_type) {
230            Ok(hidden_type) => hidden_type,
231            Err(errors) => {
232                let guar = self.err_ctxt().report_fulfillment_errors(errors);
233                OpaqueHiddenType::new_error(self.tcx, guar)
234            }
235        };
236        let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
237            opaque_type_key,
238            self.tcx,
239            DefiningScopeKind::HirTypeck,
240        );
241        UsageKind::HasDefiningUse(hidden_type)
242    }
243
244    /// We may in theory add further uses of an opaque after cloning the opaque
245    /// types storage during writeback when computing the defining uses.
246    ///
247    /// Silently ignoring them is dangerous and could result in ICE or even in
248    /// unsoundness, so we make sure we catch such cases here. There's currently
249    /// no known code where this actually happens, even with the new solver which
250    /// does normalize types in writeback after cloning the opaque type storage.
251    ///
252    /// FIXME(@lcnr): I believe this should be possible in theory and would like
253    /// an actual test here. After playing around with this for an hour, I wasn't
254    /// able to do anything which didn't already try to normalize the opaque before
255    /// then, either allowing compilation to succeed or causing an ambiguity error.
256    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
257        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
258        for (key, hidden_type) in
259            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
260        {
261            let opaque_type_string = self.tcx.def_path_str(key.def_id);
262            let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
263            self.dcx().span_delayed_bug(hidden_type.span, msg);
264        }
265        let _ = self.take_opaque_types();
266    }
267}