Skip to main content

rustc_hir_typeck/
opaque_types.rs

1use rustc_hir::def::DefKind;
2use rustc_infer::traits::ObligationCause;
3use rustc_middle::bug;
4use rustc_middle::ty::{
5    self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType,
6    TypeVisitableExt, Unnormalized,
7};
8use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
9use rustc_trait_selection::opaque_types::{
10    NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
11};
12use rustc_trait_selection::solve;
13use tracing::{debug, instrument};
14
15use crate::FnCtxt;
16
17impl<'tcx> FnCtxt<'_, 'tcx> {
18    /// This takes all the opaque type uses during HIR typeck. It first computes
19    /// the hidden type by iterating over all defining uses.
20    ///
21    /// A use during HIR typeck is defining if all non-lifetime arguments are
22    /// unique generic parameters and the hidden type does not reference any
23    /// inference variables.
24    ///
25    /// It then uses these defining uses to guide inference for all other uses.
26    ///
27    /// Unlike `handle_opaque_type_uses_next`, this does not report errors.
28    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("try_handle_opaque_type_uses_next",
                                    "rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
                                    ::tracing_core::__macro_support::Option::Some(28u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
            self.compute_definition_site_hidden_types(opaque_types, false);
        }
    }
}#[instrument(level = "debug", skip(self))]
29    pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
30        // We clone the opaques instead of stealing them here as we still need
31        // to use them after fallback.
32        let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
33
34        self.compute_definition_site_hidden_types(opaque_types, false);
35    }
36
37    /// This takes all the opaque type uses during HIR typeck. It first computes
38    /// the concrete hidden type by iterating over all defining uses.
39    ///
40    /// A use during HIR typeck is defining if all non-lifetime arguments are
41    /// unique generic parameters and the hidden type does not reference any
42    /// inference variables.
43    ///
44    /// It then uses these defining uses to guide inference for all other uses.
45    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("handle_opaque_type_uses_next",
                                    "rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
                                    ::tracing_core::__macro_support::Option::Some(45u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
            let num_entries =
                self.inner.borrow_mut().opaque_types().num_entries();
            let prev =
                self.checked_opaque_types_storage_entries.replace(Some(num_entries));
            if true {
                match (&prev, &None) {
                    (left_val, right_val) => {
                        if !(*left_val == *right_val) {
                            let kind = ::core::panicking::AssertKind::Eq;
                            ::core::panicking::assert_failed(kind, &*left_val,
                                &*right_val, ::core::option::Option::None);
                        }
                    }
                };
            };
            self.compute_definition_site_hidden_types(opaque_types, true);
        }
    }
}#[instrument(level = "debug", skip(self))]
46    pub(super) fn handle_opaque_type_uses_next(&mut self) {
47        // We clone the opaques instead of stealing them here as they are still used for
48        // normalization in the next generation trait solver.
49        let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
50        let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
51        let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
52        debug_assert_eq!(prev, None);
53
54        self.compute_definition_site_hidden_types(opaque_types, true);
55    }
56}
57
58#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UsageKind<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for UsageKind<'tcx> {
    #[inline]
    fn clone(&self) -> UsageKind<'tcx> {
        let _: ::core::clone::AssertParamIsClone<OpaqueTypeKey<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ProvisionalHiddenType<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ProvisionalHiddenType<'tcx>>;
        let _:
                ::core::clone::AssertParamIsClone<DefinitionSiteHiddenType<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UsageKind<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            UsageKind::None => ::core::fmt::Formatter::write_str(f, "None"),
            UsageKind::NonDefiningUse(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "NonDefiningUse", __self_0, &__self_1),
            UsageKind::UnconstrainedHiddenType(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "UnconstrainedHiddenType", &__self_0),
            UsageKind::HasDefiningUse(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "HasDefiningUse", &__self_0),
        }
    }
}Debug)]
59enum UsageKind<'tcx> {
60    None,
61    NonDefiningUse(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>),
62    UnconstrainedHiddenType(ProvisionalHiddenType<'tcx>),
63    HasDefiningUse(DefinitionSiteHiddenType<'tcx>),
64}
65
66impl<'tcx> UsageKind<'tcx> {
67    fn merge(&mut self, other: UsageKind<'tcx>) {
68        match (&*self, &other) {
69            (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
70            (UsageKind::None, _) => *self = other,
71            // When mergining non-defining uses, prefer earlier ones. This means
72            // the error happens as early as possible.
73            (
74                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
75                UsageKind::NonDefiningUse(..),
76            ) => {}
77            // When merging unconstrained hidden types, we prefer later ones. This is
78            // used as in most cases, the defining use is the final return statement
79            // of our function, and other uses with defining arguments are likely not
80            // intended to be defining.
81            (
82                UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
83                UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
84            ) => *self = other,
85        }
86    }
87}
88
89impl<'tcx> FnCtxt<'_, 'tcx> {
90    fn compute_definition_site_hidden_types(
91        &mut self,
92        mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>,
93        error_on_missing_defining_use: bool,
94    ) {
95        for entry in opaque_types.iter_mut() {
96            *entry = self.resolve_vars_if_possible(*entry);
97        }
98        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/opaque_types.rs:98",
                        "rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
                        ::tracing_core::__macro_support::Option::Some(98u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
                        ::tracing_core::field::FieldSet::new(&["opaque_types"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&opaque_types)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?opaque_types);
99
100        let tcx = self.tcx;
101        let defining_opaque_types_and_generators = match self.typing_mode() {
102            ty::TypingMode::Analysis { defining_opaque_types_and_generators } => {
103                defining_opaque_types_and_generators
104            }
105            ty::TypingMode::Coherence
106            | ty::TypingMode::Borrowck { .. }
107            | ty::TypingMode::PostBorrowckAnalysis { .. }
108            | ty::TypingMode::PostAnalysis
109            | ty::TypingMode::Codegen => {
110                ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
111            }
112        };
113
114        for def_id in defining_opaque_types_and_generators {
115            match tcx.def_kind(def_id) {
116                DefKind::OpaqueTy => {}
117                DefKind::Closure => continue,
118                _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("not opaque or generator: {0:?}", def_id)));
}unreachable!("not opaque or generator: {def_id:?}"),
119            }
120
121            // We do actually need to check this the second pass (we can't just
122            // store this), because we can go from `UnconstrainedHiddenType` to
123            // `HasDefiningUse` (because of fallback)
124            let mut usage_kind = UsageKind::None;
125            for &(opaque_type_key, hidden_type) in &opaque_types {
126                if opaque_type_key.def_id != def_id {
127                    continue;
128                }
129
130                usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
131
132                if let UsageKind::HasDefiningUse(..) = usage_kind {
133                    break;
134                }
135            }
136
137            if let UsageKind::HasDefiningUse(ty) = usage_kind {
138                for &(opaque_type_key, hidden_type) in &opaque_types {
139                    if opaque_type_key.def_id != def_id {
140                        continue;
141                    }
142
143                    let expected = ty.ty.instantiate(tcx, opaque_type_key.args).skip_norm_wip();
144                    self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
145                }
146
147                // Being explicit here: it may be possible that we in a
148                // previous call to this function we did an insert, but this
149                // should be just fine, since they all get equated anyways and
150                // we shouldn't ever go from `HasDefiningUse` to anyway else.
151                let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
152            }
153
154            // If we're in `fn try_handle_opaque_type_uses_next` then do not
155            // report any errors.
156            if !error_on_missing_defining_use {
157                continue;
158            }
159
160            let guar = match usage_kind {
161                UsageKind::HasDefiningUse(_) => continue,
162                UsageKind::None => {
163                    if let Some(guar) = self.tainted_by_errors() {
164                        guar
165                    } else {
166                        report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
167                    }
168                }
169                UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
170                    report_item_does_not_constrain_error(
171                        self.tcx,
172                        self.body_id,
173                        def_id,
174                        Some((opaque_type_key, hidden_type.span)),
175                    )
176                }
177                UsageKind::UnconstrainedHiddenType(hidden_type) => {
178                    if let Some(guar) = self.tainted_by_errors() {
179                        guar
180                    } else {
181                        let infer_var = hidden_type
182                            .ty
183                            .walk()
184                            .filter_map(ty::GenericArg::as_term)
185                            .find(|term| term.is_infer())
186                            .unwrap_or_else(|| hidden_type.ty.into());
187                        self.err_ctxt()
188                            .emit_inference_failure_err(
189                                self.body_id,
190                                hidden_type.span,
191                                infer_var,
192                                TypeAnnotationNeeded::E0282,
193                                false,
194                            )
195                            .emit()
196                    }
197                }
198            };
199
200            self.typeck_results
201                .borrow_mut()
202                .hidden_types
203                .insert(def_id, DefinitionSiteHiddenType::new_error(tcx, guar));
204            self.set_tainted_by_errors(guar);
205        }
206    }
207
208    x;#[tracing::instrument(skip(self), ret)]
209    fn consider_opaque_type_use(
210        &self,
211        opaque_type_key: OpaqueTypeKey<'tcx>,
212        hidden_type: ProvisionalHiddenType<'tcx>,
213    ) -> UsageKind<'tcx> {
214        if let Err(err) = opaque_type_has_defining_use_args(
215            &self,
216            opaque_type_key,
217            hidden_type.span,
218            DefiningScopeKind::HirTypeck,
219        ) {
220            match err {
221                NonDefiningUseReason::Tainted(guar) => {
222                    return UsageKind::HasDefiningUse(DefinitionSiteHiddenType::new_error(
223                        self.tcx, guar,
224                    ));
225                }
226                _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
227            };
228        }
229
230        // We ignore uses of the opaque if they have any inference variables
231        // as this can frequently happen with recursive calls.
232        //
233        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
234        if hidden_type.ty.has_non_region_infer() {
235            return UsageKind::UnconstrainedHiddenType(hidden_type);
236        }
237
238        let cause = ObligationCause::misc(hidden_type.span, self.body_id);
239        let at = self.at(&cause, self.param_env);
240        let hidden_type = match solve::deeply_normalize(at, Unnormalized::new_wip(hidden_type)) {
241            Ok(hidden_type) => hidden_type,
242            Err(errors) => {
243                let guar = self.err_ctxt().report_fulfillment_errors(errors);
244                ProvisionalHiddenType::new_error(self.tcx, guar)
245            }
246        };
247        let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
248            opaque_type_key,
249            self.tcx,
250            DefiningScopeKind::HirTypeck,
251        );
252        UsageKind::HasDefiningUse(hidden_type)
253    }
254
255    /// We may in theory add further uses of an opaque after cloning the opaque
256    /// types storage during writeback when computing the defining uses.
257    ///
258    /// Silently ignoring them is dangerous and could result in ICE or even in
259    /// unsoundness, so we make sure we catch such cases here. There's currently
260    /// no known code where this actually happens, even with the new solver which
261    /// does normalize types in writeback after cloning the opaque type storage.
262    ///
263    /// FIXME(@lcnr): I believe this should be possible in theory and would like
264    /// an actual test here. After playing around with this for an hour, I wasn't
265    /// able to do anything which didn't already try to normalize the opaque before
266    /// then, either allowing compilation to succeed or causing an ambiguity error.
267    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
268        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
269        for (key, hidden_type) in
270            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
271        {
272            let opaque_type_string = self.tcx.def_path_str(key.def_id);
273            let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unexpected cyclic definition of `{0}`",
                opaque_type_string))
    })format!("unexpected cyclic definition of `{opaque_type_string}`");
274            self.dcx().span_delayed_bug(hidden_type.span, msg);
275        }
276        let _ = self.take_opaque_types();
277    }
278}