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                ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()
110            }
111        };
112
113        for def_id in defining_opaque_types_and_generators {
114            match tcx.def_kind(def_id) {
115                DefKind::OpaqueTy => {}
116                DefKind::Closure => continue,
117                _ => {
    ::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:?}"),
118            }
119
120            // We do actually need to check this the second pass (we can't just
121            // store this), because we can go from `UnconstrainedHiddenType` to
122            // `HasDefiningUse` (because of fallback)
123            let mut usage_kind = UsageKind::None;
124            for &(opaque_type_key, hidden_type) in &opaque_types {
125                if opaque_type_key.def_id != def_id {
126                    continue;
127                }
128
129                usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
130
131                if let UsageKind::HasDefiningUse(..) = usage_kind {
132                    break;
133                }
134            }
135
136            if let UsageKind::HasDefiningUse(ty) = usage_kind {
137                for &(opaque_type_key, hidden_type) in &opaque_types {
138                    if opaque_type_key.def_id != def_id {
139                        continue;
140                    }
141
142                    let expected = ty.ty.instantiate(tcx, opaque_type_key.args).skip_norm_wip();
143                    self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
144                }
145
146                // Being explicit here: it may be possible that we in a
147                // previous call to this function we did an insert, but this
148                // should be just fine, since they all get equated anyways and
149                // we shouldn't ever go from `HasDefiningUse` to anyway else.
150                let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
151            }
152
153            // If we're in `fn try_handle_opaque_type_uses_next` then do not
154            // report any errors.
155            if !error_on_missing_defining_use {
156                continue;
157            }
158
159            let guar = match usage_kind {
160                UsageKind::HasDefiningUse(_) => continue,
161                UsageKind::None => {
162                    if let Some(guar) = self.tainted_by_errors() {
163                        guar
164                    } else {
165                        report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
166                    }
167                }
168                UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
169                    report_item_does_not_constrain_error(
170                        self.tcx,
171                        self.body_id,
172                        def_id,
173                        Some((opaque_type_key, hidden_type.span)),
174                    )
175                }
176                UsageKind::UnconstrainedHiddenType(hidden_type) => {
177                    if let Some(guar) = self.tainted_by_errors() {
178                        guar
179                    } else {
180                        let infer_var = hidden_type
181                            .ty
182                            .walk()
183                            .filter_map(ty::GenericArg::as_term)
184                            .find(|term| term.is_infer())
185                            .unwrap_or_else(|| hidden_type.ty.into());
186                        self.err_ctxt()
187                            .emit_inference_failure_err(
188                                self.body_id,
189                                hidden_type.span,
190                                infer_var,
191                                TypeAnnotationNeeded::E0282,
192                                false,
193                            )
194                            .emit()
195                    }
196                }
197            };
198
199            self.typeck_results
200                .borrow_mut()
201                .hidden_types
202                .insert(def_id, DefinitionSiteHiddenType::new_error(tcx, guar));
203            self.set_tainted_by_errors(guar);
204        }
205    }
206
207    x;#[tracing::instrument(skip(self), ret)]
208    fn consider_opaque_type_use(
209        &self,
210        opaque_type_key: OpaqueTypeKey<'tcx>,
211        hidden_type: ProvisionalHiddenType<'tcx>,
212    ) -> UsageKind<'tcx> {
213        if let Err(err) = opaque_type_has_defining_use_args(
214            &self,
215            opaque_type_key,
216            hidden_type.span,
217            DefiningScopeKind::HirTypeck,
218        ) {
219            match err {
220                NonDefiningUseReason::Tainted(guar) => {
221                    return UsageKind::HasDefiningUse(DefinitionSiteHiddenType::new_error(
222                        self.tcx, guar,
223                    ));
224                }
225                _ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
226            };
227        }
228
229        // We ignore uses of the opaque if they have any inference variables
230        // as this can frequently happen with recursive calls.
231        //
232        // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
233        if hidden_type.ty.has_non_region_infer() {
234            return UsageKind::UnconstrainedHiddenType(hidden_type);
235        }
236
237        let cause = ObligationCause::misc(hidden_type.span, self.body_id);
238        let at = self.at(&cause, self.param_env);
239        let hidden_type = match solve::deeply_normalize(at, Unnormalized::new_wip(hidden_type)) {
240            Ok(hidden_type) => hidden_type,
241            Err(errors) => {
242                let guar = self.err_ctxt().report_fulfillment_errors(errors);
243                ProvisionalHiddenType::new_error(self.tcx, guar)
244            }
245        };
246        let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
247            opaque_type_key,
248            self.tcx,
249            DefiningScopeKind::HirTypeck,
250        );
251        UsageKind::HasDefiningUse(hidden_type)
252    }
253
254    /// We may in theory add further uses of an opaque after cloning the opaque
255    /// types storage during writeback when computing the defining uses.
256    ///
257    /// Silently ignoring them is dangerous and could result in ICE or even in
258    /// unsoundness, so we make sure we catch such cases here. There's currently
259    /// no known code where this actually happens, even with the new solver which
260    /// does normalize types in writeback after cloning the opaque type storage.
261    ///
262    /// FIXME(@lcnr): I believe this should be possible in theory and would like
263    /// an actual test here. After playing around with this for an hour, I wasn't
264    /// able to do anything which didn't already try to normalize the opaque before
265    /// then, either allowing compilation to succeed or causing an ambiguity error.
266    pub(super) fn detect_opaque_types_added_during_writeback(&self) {
267        let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
268        for (key, hidden_type) in
269            self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
270        {
271            let opaque_type_string = self.tcx.def_path_str(key.def_id);
272            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}`");
273            self.dcx().span_delayed_bug(hidden_type.span, msg);
274        }
275        let _ = self.take_opaque_types();
276    }
277}