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