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