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                    let infer_var = hidden_type
121                        .ty
122                        .walk()
123                        .filter_map(ty::GenericArg::as_term)
124                        .find(|term| term.is_infer())
125                        .unwrap_or_else(|| hidden_type.ty.into());
126                    self.err_ctxt()
127                        .emit_inference_failure_err(
128                            self.body_id,
129                            hidden_type.span,
130                            infer_var,
131                            TypeAnnotationNeeded::E0282,
132                            false,
133                        )
134                        .emit()
135                }
136                UsageKind::HasDefiningUse => continue,
137            };
138
139            self.typeck_results
140                .borrow_mut()
141                .concrete_opaque_types
142                .insert(def_id, OpaqueHiddenType::new_error(tcx, guar));
143            self.set_tainted_by_errors(guar);
144        }
145    }
146
147    fn consider_opaque_type_use(
148        &mut self,
149        opaque_type_key: OpaqueTypeKey<'tcx>,
150        hidden_type: OpaqueHiddenType<'tcx>,
151    ) -> UsageKind<'tcx> {
152        if let Err(err) = opaque_type_has_defining_use_args(
153            &self,
154            opaque_type_key,
155            hidden_type.span,
156            DefiningScopeKind::HirTypeck,
157        ) {
158            match err {
159                NonDefiningUseReason::Tainted(guar) => {
160                    self.typeck_results.borrow_mut().concrete_opaque_types.insert(
161                        opaque_type_key.def_id,
162                        OpaqueHiddenType::new_error(self.tcx, guar),
163                    );
164                    return UsageKind::HasDefiningUse;
165                }
166                _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
167            };
168        }
169
170        // We ignore uses of the opaque if they have any inference variables
171        // as this can frequently happen with recursive calls.
172        //
173        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
174        if hidden_type.ty.has_non_region_infer() {
175            return UsageKind::UnconstrainedHiddenType(hidden_type);
176        }
177
178        let cause = ObligationCause::misc(hidden_type.span, self.body_id);
179        let at = self.at(&cause, self.param_env);
180        let hidden_type = match solve::deeply_normalize(at, hidden_type) {
181            Ok(hidden_type) => hidden_type,
182            Err(errors) => {
183                let guar = self.err_ctxt().report_fulfillment_errors(errors);
184                OpaqueHiddenType::new_error(self.tcx, guar)
185            }
186        };
187        let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
188            opaque_type_key,
189            self.tcx,
190            DefiningScopeKind::HirTypeck,
191        );
192
193        let prev = self
194            .typeck_results
195            .borrow_mut()
196            .concrete_opaque_types
197            .insert(opaque_type_key.def_id, hidden_type);
198        assert!(prev.is_none());
199        UsageKind::HasDefiningUse
200    }
201
202    fn apply_computed_concrete_opaque_types(
203        &mut self,
204        opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
205    ) {
206        let tcx = self.tcx;
207        for &(key, hidden_type) in opaque_types {
208            let expected =
209                *self.typeck_results.borrow_mut().concrete_opaque_types.get(&key.def_id).unwrap();
210
211            let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
212            self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
213        }
214    }
215
216    /// We may in theory add further uses of an opaque after cloning the opaque
217    /// types storage during writeback when computing the defining uses.
218    ///
219    /// Silently ignoring them is dangerous and could result in ICE or even in
220    /// unsoundness, so we make sure we catch such cases here. There's currently
221    /// no known code where this actually happens, even with the new solver which
222    /// does normalize types in writeback after cloning the opaque type storage.
223    ///
224    /// FIXME(@lcnr): I believe this should be possible in theory and would like
225    /// an actual test here. After playing around with this for an hour, I wasn't
226    /// able to do anything which didn't already try to normalize the opaque before
227    /// then, either allowing compilation to succeed or causing an ambiguity error.
228    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
229        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
230        for (key, hidden_type) in
231            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
232        {
233            let opaque_type_string = self.tcx.def_path_str(key.def_id);
234            let msg = format!("unexpected cyclic definition of `{opaque_type_string}`");
235            self.dcx().span_delayed_bug(hidden_type.span, msg);
236        }
237        let _ = self.take_opaque_types();
238    }
239}