Skip to main content

rustc_hir_typeck/
fallback.rs

1use std::cell::OnceCell;
2use std::ops::ControlFlow;
3
4use rustc_data_structures::fx::FxHashSet;
5use rustc_data_structures::graph::vec_graph::VecGraph;
6use rustc_data_structures::graph::{self};
7use rustc_data_structures::unord::{UnordMap, UnordSet};
8use rustc_hir as hir;
9use rustc_hir::HirId;
10use rustc_hir::attrs::DivergingFallbackBehavior;
11use rustc_hir::def::{DefKind, Res};
12use rustc_hir::def_id::DefId;
13use rustc_hir::intravisit::{InferKind, Visitor};
14use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
15use rustc_session::lint;
16use rustc_span::def_id::LocalDefId;
17use rustc_span::{DUMMY_SP, Span};
18use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
19use tracing::debug;
20
21use crate::{FnCtxt, errors};
22
23impl<'tcx> FnCtxt<'_, 'tcx> {
24    /// Performs type inference fallback, setting [`FnCtxt::diverging_fallback_has_occurred`]
25    /// if the never type fallback has occurred.
26    pub(super) fn type_inference_fallback(&self) {
27        {
    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/fallback.rs:27",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(27u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("type-inference-fallback start obligations: {0:#?}",
                                                    self.fulfillment_cx.borrow_mut().pending_obligations()) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
28            "type-inference-fallback start obligations: {:#?}",
29            self.fulfillment_cx.borrow_mut().pending_obligations()
30        );
31
32        // All type checking constraints were added, try to fallback unsolved variables.
33        self.select_obligations_where_possible(|_| {});
34
35        {
    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/fallback.rs:35",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(35u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("type-inference-fallback post selection obligations: {0:#?}",
                                                    self.fulfillment_cx.borrow_mut().pending_obligations()) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(
36            "type-inference-fallback post selection obligations: {:#?}",
37            self.fulfillment_cx.borrow_mut().pending_obligations()
38        );
39
40        let fallback_occurred = self.fallback_types();
41
42        if fallback_occurred {
43            // if fallback occurred, previously stalled goals may make progress again
44            self.select_obligations_where_possible(|_| {});
45        }
46    }
47
48    fn fallback_types(&self) -> bool {
49        // Check if we have any unresolved variables. If not, no need for fallback.
50        let unresolved_variables = self.unresolved_variables();
51
52        if unresolved_variables.is_empty() {
53            return false;
54        }
55
56        let (diverging_fallback, diverging_fallback_ty) =
57            self.calculate_diverging_fallback(&unresolved_variables);
58
59        // We do fallback in two passes, to try to generate
60        // better error messages.
61        // The first time, we do *not* replace opaque types.
62        let mut fallback_occurred = false;
63        for ty in unresolved_variables {
64            {
    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/fallback.rs:64",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(64u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("unsolved_variable = {0:?}",
                                                    ty) as &dyn Value))])
            });
    } else { ; }
};debug!("unsolved_variable = {:?}", ty);
65            fallback_occurred |=
66                self.fallback_if_possible(ty, &diverging_fallback, diverging_fallback_ty);
67        }
68
69        fallback_occurred
70    }
71
72    /// Tries to apply a fallback to `ty` if it is an unsolved variable.
73    ///
74    /// - Unconstrained ints are replaced with `i32`.
75    ///
76    /// - Unconstrained floats are replaced with `f64`.
77    ///
78    /// - Non-numerics may get replaced with `()` or `!`, depending on how they
79    ///   were categorized by [`Self::calculate_diverging_fallback`], crate's
80    ///   edition, and the setting of `#![rustc_never_type_options(fallback = ...)]`.
81    ///
82    /// Fallback becomes very dubious if we have encountered
83    /// type-checking errors. In that case, fallback to Error.
84    ///
85    /// Sets [`FnCtxt::diverging_fallback_has_occurred`] if never type fallback
86    /// is performed during this call.
87    fn fallback_if_possible(
88        &self,
89        ty: Ty<'tcx>,
90        diverging_fallback: &UnordSet<Ty<'tcx>>,
91        diverging_fallback_ty: Ty<'tcx>,
92    ) -> bool {
93        // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
94        // is an unsolved variable, and we determine its fallback
95        // based solely on how it was created, not what other type
96        // variables it may have been unified with since then.
97        //
98        // The reason this matters is that other attempts at fallback
99        // may (in principle) conflict with this fallback, and we wish
100        // to generate a type error in that case. (However, this
101        // actually isn't true right now, because we're only using the
102        // builtin fallback rules. This would be true if we were using
103        // user-supplied fallbacks. But it's still useful to write the
104        // code to detect bugs.)
105        //
106        // (Note though that if we have a general type variable `?T`
107        // that is then unified with an integer type variable `?I`
108        // that ultimately never gets resolved to a special integral
109        // type, `?T` is not considered unsolved, but `?I` is. The
110        // same is true for float variables.)
111        let fallback = match ty.kind() {
112            _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e),
113            ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
114            ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
115            _ if diverging_fallback.contains(&ty) => {
116                self.diverging_fallback_has_occurred.set(true);
117                diverging_fallback_ty
118            }
119            _ => return false,
120        };
121        {
    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/fallback.rs:121",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(121u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("fallback_if_possible(ty={0:?}): defaulting to `{1:?}`",
                                                    ty, fallback) as &dyn Value))])
            });
    } else { ; }
};debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
122
123        let span = ty.ty_vid().map_or(DUMMY_SP, |vid| self.infcx.type_var_origin(vid).span);
124        self.demand_eqtype(span, ty, fallback);
125        true
126    }
127
128    fn calculate_diverging_fallback(
129        &self,
130        unresolved_variables: &[Ty<'tcx>],
131    ) -> (UnordSet<Ty<'tcx>>, Ty<'tcx>) {
132        {
    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/fallback.rs:132",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(132u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("calculate_diverging_fallback({0:?})",
                                                    unresolved_variables) as &dyn Value))])
            });
    } else { ; }
};debug!("calculate_diverging_fallback({:?})", unresolved_variables);
133
134        let diverging_fallback_ty = match self.diverging_fallback_behavior {
135            DivergingFallbackBehavior::ToUnit => self.tcx.types.unit,
136            DivergingFallbackBehavior::ToNever => self.tcx.types.never,
137            DivergingFallbackBehavior::NoFallback => {
138                // the type doesn't matter, since no fallback will occur
139                return (UnordSet::new(), self.tcx.types.unit);
140            }
141        };
142
143        // Construct a coercion graph where an edge `A -> B` indicates
144        // a type variable is that is coerced
145        let coercion_graph = self.create_coercion_graph();
146
147        // Extract the unsolved type inference variable vids; note that some
148        // unsolved variables are integer/float variables and are excluded.
149        let unsolved_vids = unresolved_variables.iter().filter_map(|ty| ty.ty_vid());
150
151        // Compute the diverging root vids D -- that is, the root vid of
152        // those type variables that (a) are the target of a coercion from
153        // a `!` type and (b) have not yet been solved.
154        //
155        // These variables are the ones that are targets for fallback to
156        // either `!` or `()`.
157        let diverging_roots: UnordSet<ty::TyVid> = self
158            .diverging_type_vars
159            .borrow()
160            .items()
161            .map(|&ty| self.shallow_resolve(ty))
162            .filter_map(|ty| ty.ty_vid())
163            .map(|vid| self.root_var(vid))
164            .collect();
165        {
    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/fallback.rs:165",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(165u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("calculate_diverging_fallback: diverging_type_vars={0:?}",
                                                    self.diverging_type_vars.borrow()) as &dyn Value))])
            });
    } else { ; }
};debug!(
166            "calculate_diverging_fallback: diverging_type_vars={:?}",
167            self.diverging_type_vars.borrow()
168        );
169        {
    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/fallback.rs:169",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(169u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("calculate_diverging_fallback: diverging_roots={0:?}",
                                                    diverging_roots) as &dyn Value))])
            });
    } else { ; }
};debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
170
171        // Find all type variables that are reachable from a diverging
172        // type variable. These will typically default to `!`, unless
173        // we find later that they are *also* reachable from some
174        // other type variable outside this set.
175        let mut diverging_vids = ::alloc::vec::Vec::new()vec![];
176        for unsolved_vid in unsolved_vids {
177            let root_vid = self.root_var(unsolved_vid);
178            {
    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/fallback.rs:178",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(178u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("calculate_diverging_fallback: unsolved_vid={0:?} root_vid={1:?} diverges={2:?}",
                                                    unsolved_vid, root_vid, diverging_roots.contains(&root_vid))
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(
179                "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
180                unsolved_vid,
181                root_vid,
182                diverging_roots.contains(&root_vid),
183            );
184            if diverging_roots.contains(&root_vid) {
185                diverging_vids.push(unsolved_vid);
186
187                {
    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/fallback.rs:187",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(187u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("calculate_diverging_fallback: root_vid={0:?} reaches {1:?}",
                                                    root_vid,
                                                    graph::depth_first_search(&coercion_graph,
                                                            root_vid).collect::<Vec<_>>()) as &dyn Value))])
            });
    } else { ; }
};debug!(
188                    "calculate_diverging_fallback: root_vid={:?} reaches {:?}",
189                    root_vid,
190                    graph::depth_first_search(&coercion_graph, root_vid).collect::<Vec<_>>()
191                );
192            }
193        }
194
195        {
    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/fallback.rs:195",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(195u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("obligations: {0:#?}",
                                                    self.fulfillment_cx.borrow_mut().pending_obligations()) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations());
196
197        let mut diverging_fallback = UnordSet::with_capacity(diverging_vids.len());
198        let unsafe_infer_vars = OnceCell::new();
199
200        self.lint_obligations_broken_by_never_type_fallback_change(
201            &diverging_vids,
202            &coercion_graph,
203        );
204
205        for &diverging_vid in &diverging_vids {
206            let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
207            let root_vid = self.root_var(diverging_vid);
208
209            self.lint_never_type_fallback_flowing_into_unsafe_code(
210                &unsafe_infer_vars,
211                &coercion_graph,
212                root_vid,
213            );
214
215            diverging_fallback.insert(diverging_ty);
216        }
217
218        (diverging_fallback, diverging_fallback_ty)
219    }
220
221    fn lint_never_type_fallback_flowing_into_unsafe_code(
222        &self,
223        unsafe_infer_vars: &OnceCell<UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>>,
224        coercion_graph: &VecGraph<ty::TyVid, true>,
225        root_vid: ty::TyVid,
226    ) {
227        let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
228            let unsafe_infer_vars = compute_unsafe_infer_vars(self, self.body_id);
229            {
    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/fallback.rs:229",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(229u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["unsafe_infer_vars"],
                            ::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(&unsafe_infer_vars)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?unsafe_infer_vars);
230            unsafe_infer_vars
231        });
232
233        let affected_unsafe_infer_vars =
234            graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
235                .filter_map(|x| unsafe_infer_vars.get(&x).copied())
236                .collect::<Vec<_>>();
237
238        let sugg = self.try_to_suggest_annotations(&[root_vid], coercion_graph);
239
240        for (hir_id, span, reason) in affected_unsafe_infer_vars {
241            self.tcx.emit_node_span_lint(
242                lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
243                hir_id,
244                span,
245                match reason {
246                    UnsafeUseReason::Call => {
247                        errors::NeverTypeFallbackFlowingIntoUnsafe::Call { sugg: sugg.clone() }
248                    }
249                    UnsafeUseReason::Method => {
250                        errors::NeverTypeFallbackFlowingIntoUnsafe::Method { sugg: sugg.clone() }
251                    }
252                    UnsafeUseReason::Path => {
253                        errors::NeverTypeFallbackFlowingIntoUnsafe::Path { sugg: sugg.clone() }
254                    }
255                    UnsafeUseReason::UnionField => {
256                        errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField {
257                            sugg: sugg.clone(),
258                        }
259                    }
260                    UnsafeUseReason::Deref => {
261                        errors::NeverTypeFallbackFlowingIntoUnsafe::Deref { sugg: sugg.clone() }
262                    }
263                },
264            );
265        }
266    }
267
268    fn lint_obligations_broken_by_never_type_fallback_change(
269        &self,
270        diverging_vids: &[ty::TyVid],
271        coercions: &VecGraph<ty::TyVid, true>,
272    ) {
273        let DivergingFallbackBehavior::ToUnit = self.diverging_fallback_behavior else { return };
274
275        // Fallback happens if and only if there are diverging variables
276        if diverging_vids.is_empty() {
277            return;
278        }
279
280        // Returns errors which happen if fallback is set to `fallback`
281        let remaining_errors_if_fallback_to = |fallback| {
282            self.probe(|_| {
283                let obligations = self.fulfillment_cx.borrow().pending_obligations();
284                let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx);
285                ocx.register_obligations(obligations.iter().cloned());
286
287                for &diverging_vid in diverging_vids {
288                    let diverging_ty = Ty::new_var(self.tcx, diverging_vid);
289
290                    ocx.eq(&ObligationCause::dummy(), self.param_env, diverging_ty, fallback)
291                        .expect("expected diverging var to be unconstrained");
292                }
293
294                ocx.try_evaluate_obligations()
295            })
296        };
297
298        // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`,
299        // then this code will be broken by the never type fallback change.
300        let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit);
301        if unit_errors.is_empty()
302            && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never)
303            && let [never_error, ..] = never_errors.as_mut_slice()
304        {
305            self.adjust_fulfillment_error_for_expr_obligation(never_error);
306            let sugg = self.try_to_suggest_annotations(diverging_vids, coercions);
307            self.tcx.emit_node_span_lint(
308                lint::builtin::DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK,
309                self.tcx.local_def_id_to_hir_id(self.body_id),
310                self.tcx.def_span(self.body_id),
311                errors::DependencyOnUnitNeverTypeFallback {
312                    obligation_span: never_error.obligation.cause.span,
313                    obligation: never_error.obligation.predicate,
314                    sugg,
315                },
316            )
317        }
318    }
319
320    /// Returns a graph whose nodes are (unresolved) inference variables and where
321    /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
322    fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
323        let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations();
324        {
    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/fallback.rs:324",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(324u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("create_coercion_graph: pending_obligations={0:?}",
                                                    pending_obligations) as &dyn Value))])
            });
    } else { ; }
};debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
325        let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations
326            .into_iter()
327            .filter_map(|obligation| {
328                // The predicates we are looking for look like `Coerce(?A -> ?B)`.
329                // They will have no bound variables.
330                obligation.predicate.kind().no_bound_vars()
331            })
332            .filter_map(|atom| {
333                // We consider both subtyping and coercion to imply 'flow' from
334                // some position in the code `a` to a different position `b`.
335                // This is then used to determine which variables interact with
336                // live code, and as such must fall back to `()` to preserve
337                // soundness.
338                //
339                // In practice currently the two ways that this happens is
340                // coercion and subtyping.
341                let (a, b) = match atom {
342                    ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b),
343                    ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
344                        (a, b)
345                    }
346                    _ => return None,
347                };
348
349                let a_vid = self.root_vid(a)?;
350                let b_vid = self.root_vid(b)?;
351                Some((a_vid, b_vid))
352            })
353            .collect();
354        {
    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/fallback.rs:354",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(354u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::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(&format_args!("create_coercion_graph: coercion_edges={0:?}",
                                                    coercion_edges) as &dyn Value))])
            });
    } else { ; }
};debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges);
355        let num_ty_vars = self.num_ty_vars();
356
357        VecGraph::new(num_ty_vars, coercion_edges)
358    }
359
360    /// Given a set of diverging vids and coercions, walk the HIR to gather a
361    /// set of suggestions which can be applied to preserve fallback to unit.
362    fn try_to_suggest_annotations(
363        &self,
364        diverging_vids: &[ty::TyVid],
365        coercions: &VecGraph<ty::TyVid, true>,
366    ) -> errors::SuggestAnnotations {
367        let body =
368            self.tcx.hir_maybe_body_owned_by(self.body_id).expect("body id must have an owner");
369        // For each diverging var, look through the HIR for a place to give it
370        // a type annotation. We do this per var because we only really need one
371        // suggestion to influence a var to be `()`.
372        let suggestions = diverging_vids
373            .iter()
374            .copied()
375            .filter_map(|vid| {
376                let reachable_vids =
377                    graph::depth_first_search_as_undirected(coercions, vid).collect();
378                AnnotateUnitFallbackVisitor { reachable_vids, fcx: self }
379                    .visit_expr(body.value)
380                    .break_value()
381            })
382            .collect();
383        errors::SuggestAnnotations { suggestions }
384    }
385}
386
387/// Try to walk the HIR to find a place to insert a useful suggestion
388/// to preserve fallback to `()` in 2024.
389struct AnnotateUnitFallbackVisitor<'a, 'tcx> {
390    reachable_vids: FxHashSet<ty::TyVid>,
391    fcx: &'a FnCtxt<'a, 'tcx>,
392}
393impl<'tcx> AnnotateUnitFallbackVisitor<'_, 'tcx> {
394    // For a given path segment, if it's missing a turbofish, try to suggest adding
395    // one so we can constrain an argument to `()`. To keep the suggestion simple,
396    // we want to simply suggest `_` for all the other args. This (for now) only
397    // works when there are only type variables (and region variables, since we can
398    // elide them)...
399    fn suggest_for_segment(
400        &self,
401        arg_segment: &'tcx hir::PathSegment<'tcx>,
402        def_id: DefId,
403        id: HirId,
404    ) -> ControlFlow<errors::SuggestAnnotation> {
405        if arg_segment.args.is_none()
406            && let Some(all_args) = self.fcx.typeck_results.borrow().node_args_opt(id)
407            && let generics = self.fcx.tcx.generics_of(def_id)
408            && let args = all_args[generics.parent_count..].iter().zip(&generics.own_params)
409            // We can't turbofish consts :(
410            && args.clone().all(|(_, param)| #[allow(non_exhaustive_omitted_patterns)] match param.kind {
    ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Lifetime
        => true,
    _ => false,
}matches!(param.kind, ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Lifetime))
411        {
412            // We filter out APITs, which are not turbofished.
413            let non_apit_type_args = args.filter(|(_, param)| {
414                #[allow(non_exhaustive_omitted_patterns)] match param.kind {
    ty::GenericParamDefKind::Type { synthetic: false, .. } => true,
    _ => false,
}matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: false, .. })
415            });
416            let n_tys = non_apit_type_args.clone().count();
417            for (idx, (arg, _)) in non_apit_type_args.enumerate() {
418                if let Some(ty) = arg.as_type()
419                    && let Some(vid) = self.fcx.root_vid(ty)
420                    && self.reachable_vids.contains(&vid)
421                {
422                    return ControlFlow::Break(errors::SuggestAnnotation::Turbo(
423                        arg_segment.ident.span.shrink_to_hi(),
424                        n_tys,
425                        idx,
426                    ));
427                }
428            }
429        }
430        ControlFlow::Continue(())
431    }
432}
433impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
434    type Result = ControlFlow<errors::SuggestAnnotation>;
435
436    fn visit_infer(
437        &mut self,
438        inf_id: HirId,
439        inf_span: Span,
440        _kind: InferKind<'tcx>,
441    ) -> Self::Result {
442        // Try to replace `_` with `()`.
443        if let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(inf_id)
444            && let Some(vid) = self.fcx.root_vid(ty)
445            && self.reachable_vids.contains(&vid)
446            && inf_span.can_be_used_for_suggestions()
447        {
448            return ControlFlow::Break(errors::SuggestAnnotation::Unit(inf_span));
449        }
450
451        ControlFlow::Continue(())
452    }
453
454    fn visit_qpath(
455        &mut self,
456        qpath: &'tcx rustc_hir::QPath<'tcx>,
457        id: HirId,
458        span: Span,
459    ) -> Self::Result {
460        let arg_segment = match qpath {
461            hir::QPath::Resolved(_, path) => {
462                path.segments.last().expect("paths should have a segment")
463            }
464            hir::QPath::TypeRelative(_, segment) => segment,
465        };
466        // Alternatively, try to turbofish `::<_, (), _>`.
467        if let Some(def_id) = self.fcx.typeck_results.borrow().qpath_res(qpath, id).opt_def_id()
468            && span.can_be_used_for_suggestions()
469        {
470            self.suggest_for_segment(arg_segment, def_id, id)?;
471        }
472        hir::intravisit::walk_qpath(self, qpath, id)
473    }
474
475    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result {
476        if let hir::ExprKind::Closure(&hir::Closure { body, .. })
477        | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) = expr.kind
478        {
479            self.visit_body(self.fcx.tcx.hir_body(body))?;
480        }
481
482        // Try to suggest adding an explicit qself `()` to a trait method path.
483        // i.e. changing `Default::default()` to `<() as Default>::default()`.
484        if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
485            && let Res::Def(DefKind::AssocFn, def_id) = path.res
486            && self.fcx.tcx.trait_of_assoc(def_id).is_some()
487            && let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(expr.hir_id)
488            && let self_ty = args.type_at(0)
489            && let Some(vid) = self.fcx.root_vid(self_ty)
490            && self.reachable_vids.contains(&vid)
491            && let [.., trait_segment, _method_segment] = path.segments
492            && expr.span.can_be_used_for_suggestions()
493        {
494            let span = path.span.shrink_to_lo().to(trait_segment.ident.span);
495            return ControlFlow::Break(errors::SuggestAnnotation::Path(span));
496        }
497
498        // Or else, try suggesting turbofishing the method args.
499        if let hir::ExprKind::MethodCall(segment, ..) = expr.kind
500            && let Some(def_id) =
501                self.fcx.typeck_results.borrow().type_dependent_def_id(expr.hir_id)
502            && expr.span.can_be_used_for_suggestions()
503        {
504            self.suggest_for_segment(segment, def_id, expr.hir_id)?;
505        }
506
507        hir::intravisit::walk_expr(self, expr)
508    }
509
510    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) -> Self::Result {
511        // For a local, try suggest annotating the type if it's missing.
512        if let hir::LocalSource::Normal = local.source
513            && let None = local.ty
514            && let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id)
515            && let Some(vid) = self.fcx.root_vid(ty)
516            && self.reachable_vids.contains(&vid)
517            && local.span.can_be_used_for_suggestions()
518        {
519            return ControlFlow::Break(errors::SuggestAnnotation::Local(
520                local.pat.span.shrink_to_hi(),
521            ));
522        }
523        hir::intravisit::walk_local(self, local)
524    }
525}
526
527#[derive(#[automatically_derived]
impl ::core::fmt::Debug for UnsafeUseReason {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                UnsafeUseReason::Call => "Call",
                UnsafeUseReason::Method => "Method",
                UnsafeUseReason::Path => "Path",
                UnsafeUseReason::UnionField => "UnionField",
                UnsafeUseReason::Deref => "Deref",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for UnsafeUseReason { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UnsafeUseReason {
    #[inline]
    fn clone(&self) -> UnsafeUseReason { *self }
}Clone)]
528pub(crate) enum UnsafeUseReason {
529    Call,
530    Method,
531    Path,
532    UnionField,
533    Deref,
534}
535
536/// Finds all type variables which are passed to an `unsafe` operation.
537///
538/// For example, for this function `f`:
539/// ```ignore (demonstrative)
540/// fn f() {
541///     unsafe {
542///         let x /* ?X */ = core::mem::zeroed();
543///         //               ^^^^^^^^^^^^^^^^^^^ -- hir_id, span, reason
544///
545///         let y = core::mem::zeroed::<Option<_ /* ?Y */>>();
546///         //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- hir_id, span, reason
547///     }
548/// }
549/// ```
550///
551/// `compute_unsafe_infer_vars` will return `{ id(?X) -> (hir_id, span, Call) }`
552fn compute_unsafe_infer_vars<'a, 'tcx>(
553    fcx: &'a FnCtxt<'a, 'tcx>,
554    body_id: LocalDefId,
555) -> UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)> {
556    let body = fcx.tcx.hir_maybe_body_owned_by(body_id).expect("body id must have an owner");
557    let mut res = UnordMap::default();
558
559    struct UnsafeInferVarsVisitor<'a, 'tcx> {
560        fcx: &'a FnCtxt<'a, 'tcx>,
561        res: &'a mut UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>,
562    }
563
564    impl Visitor<'_> for UnsafeInferVarsVisitor<'_, '_> {
565        fn visit_expr(&mut self, ex: &'_ hir::Expr<'_>) {
566            let typeck_results = self.fcx.typeck_results.borrow();
567
568            match ex.kind {
569                hir::ExprKind::MethodCall(..) => {
570                    if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
571                        && let method_ty = self.fcx.tcx.type_of(def_id).instantiate_identity()
572                        && let sig = method_ty.fn_sig(self.fcx.tcx)
573                        && sig.safety().is_unsafe()
574                    {
575                        let mut collector = InferVarCollector {
576                            value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
577                            res: self.res,
578                        };
579
580                        // Collect generic arguments (incl. `Self`) of the method
581                        typeck_results
582                            .node_args(ex.hir_id)
583                            .types()
584                            .for_each(|t| t.visit_with(&mut collector));
585                    }
586                }
587
588                hir::ExprKind::Call(func, ..) => {
589                    let func_ty = typeck_results.expr_ty(func);
590
591                    if func_ty.is_fn()
592                        && let sig = func_ty.fn_sig(self.fcx.tcx)
593                        && sig.safety().is_unsafe()
594                    {
595                        let mut collector = InferVarCollector {
596                            value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
597                            res: self.res,
598                        };
599
600                        // Try collecting generic arguments of the function.
601                        // Note that we do this below for any paths (that don't have to be called),
602                        // but there we do it with a different span/reason.
603                        // This takes priority.
604                        typeck_results
605                            .node_args(func.hir_id)
606                            .types()
607                            .for_each(|t| t.visit_with(&mut collector));
608
609                        // Also check the return type, for cases like `returns_unsafe_fn_ptr()()`
610                        sig.output().visit_with(&mut collector);
611                    }
612                }
613
614                // Check paths which refer to functions.
615                // We do this, instead of only checking `Call` to make sure the lint can't be
616                // avoided by storing unsafe function in a variable.
617                hir::ExprKind::Path(_) => {
618                    let ty = typeck_results.expr_ty(ex);
619
620                    // If this path refers to an unsafe function, collect inference variables which may affect it.
621                    // `is_fn` excludes closures, but those can't be unsafe.
622                    if ty.is_fn()
623                        && let sig = ty.fn_sig(self.fcx.tcx)
624                        && sig.safety().is_unsafe()
625                    {
626                        let mut collector = InferVarCollector {
627                            value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
628                            res: self.res,
629                        };
630
631                        // Collect generic arguments of the function
632                        typeck_results
633                            .node_args(ex.hir_id)
634                            .types()
635                            .for_each(|t| t.visit_with(&mut collector));
636                    }
637                }
638
639                hir::ExprKind::Unary(hir::UnOp::Deref, pointer) => {
640                    if let ty::RawPtr(pointee, _) = typeck_results.expr_ty(pointer).kind() {
641                        pointee.visit_with(&mut InferVarCollector {
642                            value: (ex.hir_id, ex.span, UnsafeUseReason::Deref),
643                            res: self.res,
644                        });
645                    }
646                }
647
648                hir::ExprKind::Field(base, _) => {
649                    let base_ty = typeck_results.expr_ty(base);
650
651                    if base_ty.is_union() {
652                        typeck_results.expr_ty(ex).visit_with(&mut InferVarCollector {
653                            value: (ex.hir_id, ex.span, UnsafeUseReason::UnionField),
654                            res: self.res,
655                        });
656                    }
657                }
658
659                _ => (),
660            };
661
662            hir::intravisit::walk_expr(self, ex);
663        }
664    }
665
666    struct InferVarCollector<'r, V> {
667        value: V,
668        res: &'r mut UnordMap<ty::TyVid, V>,
669    }
670
671    impl<'tcx, V: Copy> ty::TypeVisitor<TyCtxt<'tcx>> for InferVarCollector<'_, V> {
672        fn visit_ty(&mut self, t: Ty<'tcx>) {
673            if let Some(vid) = t.ty_vid() {
674                _ = self.res.try_insert(vid, self.value);
675            } else {
676                t.super_visit_with(self)
677            }
678        }
679    }
680
681    UnsafeInferVarsVisitor { fcx, res: &mut res }.visit_expr(&body.value);
682
683    {
    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/fallback.rs:683",
                        "rustc_hir_typeck::fallback", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/fallback.rs"),
                        ::tracing_core::__macro_support::Option::Some(683u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::fallback"),
                        ::tracing_core::field::FieldSet::new(&["message", "res"],
                            ::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(&format_args!("collected the following unsafe vars for {0:?}",
                                                    body_id) as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&res) as
                                            &dyn Value))])
            });
    } else { ; }
};debug!(?res, "collected the following unsafe vars for {body_id:?}");
684
685    res
686}