Skip to main content

rustc_hir_typeck/
opaque_types.rs

1use rustc_hir::def::DefKind;
2use rustc_infer::traits::ObligationCause;
3use rustc_middle::ty::{
4    self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType,
5    TypeVisitableExt, 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    #[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(27u32),
                                    ::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))]
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    #[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(44u32),
                                    ::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))]
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(#[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)]
58enum UsageKind<'tcx> {
59    None,
60    NonDefiningUse(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>),
61    UnconstrainedHiddenType(ProvisionalHiddenType<'tcx>),
62    HasDefiningUse(DefinitionSiteHiddenType<'tcx>),
63}
64
65impl<'tcx> UsageKind<'tcx> {
66    fn merge(&mut self, other: UsageKind<'tcx>) {
67        match (&*self, &other) {
68            (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => ::core::panicking::panic("internal error: entered unreachable code")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>, ProvisionalHiddenType<'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        {
    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:97",
                        "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(97u32),
                        ::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);
98
99        let tcx = self.tcx;
100        let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
101        else {
102            ::core::panicking::panic("internal error: entered unreachable code");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                _ => {
    ::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:?}"),
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 = 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, DefinitionSiteHiddenType::new_error(tcx, guar));
195            self.set_tainted_by_errors(guar);
196        }
197    }
198
199    x;#[tracing::instrument(skip(self), ret)]
200    fn consider_opaque_type_use(
201        &self,
202        opaque_type_key: OpaqueTypeKey<'tcx>,
203        hidden_type: ProvisionalHiddenType<'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(DefinitionSiteHiddenType::new_error(
214                        self.tcx, guar,
215                    ));
216                }
217                _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
218            };
219        }
220
221        // We ignore uses of the opaque if they have any inference variables
222        // as this can frequently happen with recursive calls.
223        //
224        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
225        if hidden_type.ty.has_non_region_infer() {
226            return UsageKind::UnconstrainedHiddenType(hidden_type);
227        }
228
229        let cause = ObligationCause::misc(hidden_type.span, self.body_id);
230        let at = self.at(&cause, self.param_env);
231        let hidden_type = match solve::deeply_normalize(at, hidden_type) {
232            Ok(hidden_type) => hidden_type,
233            Err(errors) => {
234                let guar = self.err_ctxt().report_fulfillment_errors(errors);
235                ProvisionalHiddenType::new_error(self.tcx, guar)
236            }
237        };
238        let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
239            opaque_type_key,
240            self.tcx,
241            DefiningScopeKind::HirTypeck,
242        );
243        UsageKind::HasDefiningUse(hidden_type)
244    }
245
246    /// We may in theory add further uses of an opaque after cloning the opaque
247    /// types storage during writeback when computing the defining uses.
248    ///
249    /// Silently ignoring them is dangerous and could result in ICE or even in
250    /// unsoundness, so we make sure we catch such cases here. There's currently
251    /// no known code where this actually happens, even with the new solver which
252    /// does normalize types in writeback after cloning the opaque type storage.
253    ///
254    /// FIXME(@lcnr): I believe this should be possible in theory and would like
255    /// an actual test here. After playing around with this for an hour, I wasn't
256    /// able to do anything which didn't already try to normalize the opaque before
257    /// then, either allowing compilation to succeed or causing an ambiguity error.
258    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
259        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
260        for (key, hidden_type) in
261            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
262        {
263            let opaque_type_string = self.tcx.def_path_str(key.def_id);
264            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}`");
265            self.dcx().span_delayed_bug(hidden_type.span, msg);
266        }
267        let _ = self.take_opaque_types();
268    }
269}