Skip to main content

rustc_trait_selection/error_reporting/traits/
overflow.rs

1use std::fmt;
2
3use rustc_errors::{Diag, E0275, ErrorGuaranteed, struct_span_code_err};
4use rustc_hir::def::Namespace;
5use rustc_hir::def_id::LOCAL_CRATE;
6use rustc_infer::traits::{Obligation, PredicateObligation};
7use rustc_middle::ty::print::{FmtPrinter, Print};
8use rustc_middle::ty::{self, TyCtxt, Upcast};
9use rustc_span::Span;
10use rustc_structures::Limit;
11use tracing::debug;
12
13use crate::error_reporting::TypeErrCtxt;
14
15pub enum OverflowCause<'tcx> {
16    DeeplyNormalize(ty::AliasTerm<'tcx>),
17    TraitSolver(ty::Predicate<'tcx>),
18}
19
20pub fn suggest_new_overflow_limit<'tcx>(tcx: TyCtxt<'tcx>, err: &mut Diag<'_>) {
21    let suggested_limit = match tcx.recursion_limit() {
22        Limit(0) => Limit(2),
23        limit => limit * 2,
24    };
25    err.help(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider increasing the recursion limit by adding a `#![recursion_limit = \"{0}\"]` attribute to your crate (`{1}`)",
                suggested_limit, tcx.crate_name(LOCAL_CRATE)))
    })format!(
26        "consider increasing the recursion limit by adding a \
27         `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
28        suggested_limit,
29        tcx.crate_name(LOCAL_CRATE),
30    ));
31}
32
33impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
34    /// Reports that an overflow has occurred and halts compilation. We
35    /// halt compilation unconditionally because it is important that
36    /// overflows never be masked -- they basically represent computations
37    /// whose result could not be truly determined and thus we can't say
38    /// if the program type checks or not -- and they are unusual
39    /// occurrences in any case.
40    pub fn report_overflow_error(
41        &self,
42        cause: OverflowCause<'tcx>,
43        span: Span,
44        suggest_increasing_limit: bool,
45        mutate: impl FnOnce(&mut Diag<'_>),
46    ) -> ! {
47        let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
48        mutate(&mut err);
49        err.emit_err().raise_fatal();
50    }
51
52    pub fn build_overflow_error(
53        &self,
54        cause: OverflowCause<'tcx>,
55        span: Span,
56        suggest_increasing_limit: bool,
57    ) -> Diag<'a> {
58        fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
59        where
60            T: fmt::Display + for<'b> Print<FmtPrinter<'b, 'tcx>>,
61        {
62            let s = value.to_string();
63            if s.len() > 50 {
64                // We don't need to save the type to a file, we will be talking about this type already
65                // in a separate note when we explain the obligation, so it will be available that way.
66                let mut p: FmtPrinter<'_, '_> =
67                    FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(6));
68                value.print(&mut p).unwrap();
69                p.into_buffer()
70            } else {
71                s
72            }
73        }
74
75        let mut err = match cause {
76            OverflowCause::DeeplyNormalize(alias_term) => {
77                let alias_term = self.deeply_resolve_ignoring_regions(alias_term);
78                let kind = alias_term.kind.descr();
79                let alias_str = with_short_path(self.tcx, alias_term);
80                {
    self.dcx().struct_span_err(span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("overflow normalizing the {0} `{1}`",
                            kind, alias_str))
                })).with_code(E0275)
}struct_span_code_err!(
81                    self.dcx(),
82                    span,
83                    E0275,
84                    "overflow normalizing the {kind} `{alias_str}`",
85                )
86            }
87            OverflowCause::TraitSolver(predicate) => {
88                let predicate = self.deeply_resolve_ignoring_regions(predicate);
89                match predicate.kind().skip_binder() {
90                    ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
91                    | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
92                        {
    self.dcx().struct_span_err(span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("overflow assigning `{0}` to `{1}`",
                            a, b))
                })).with_code(E0275)
}struct_span_code_err!(
93                            self.dcx(),
94                            span,
95                            E0275,
96                            "overflow assigning `{a}` to `{b}`",
97                        )
98                    }
99                    ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
100                        let term = with_short_path(self.tcx, term);
101                        {
    self.dcx().struct_span_err(span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("overflow evaluating whether `{0}` is well-formed",
                            term))
                })).with_code(E0275)
}struct_span_code_err!(
102                            self.dcx(),
103                            span,
104                            E0275,
105                            "overflow evaluating whether `{term}` is well-formed",
106                        )
107                    }
108                    _ => {
109                        let pred_str = with_short_path(self.tcx, predicate);
110                        {
    self.dcx().struct_span_err(span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("overflow evaluating the requirement `{0}`",
                            pred_str))
                })).with_code(E0275)
}struct_span_code_err!(
111                            self.dcx(),
112                            span,
113                            E0275,
114                            "overflow evaluating the requirement `{pred_str}`",
115                        )
116                    }
117                }
118            }
119        };
120
121        if suggest_increasing_limit {
122            suggest_new_overflow_limit(self.tcx, &mut err);
123        }
124
125        err
126    }
127
128    /// Reports that an overflow has occurred and halts compilation. We
129    /// halt compilation unconditionally because it is important that
130    /// overflows never be masked -- they basically represent computations
131    /// whose result could not be truly determined and thus we can't say
132    /// if the program type checks or not -- and they are unusual
133    /// occurrences in any case.
134    pub fn report_overflow_obligation<T>(
135        &self,
136        obligation: &Obligation<'tcx, T>,
137        suggest_increasing_limit: bool,
138    ) -> !
139    where
140        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
141    {
142        let predicate = obligation.predicate.clone().upcast(self.tcx);
143        let predicate = self.deeply_resolve_ignoring_regions(predicate);
144        self.report_overflow_error(
145            OverflowCause::TraitSolver(predicate),
146            obligation.cause.span,
147            suggest_increasing_limit,
148            |err| {
149                self.note_obligation_cause_code(
150                    obligation.cause.body_def_id,
151                    err,
152                    predicate,
153                    obligation.param_env,
154                    obligation.cause.code(),
155                    &mut ::alloc::vec::Vec::new()vec![],
156                    &mut Default::default(),
157                );
158            },
159        );
160    }
161
162    /// Reports that a cycle was detected which led to overflow and halts
163    /// compilation. This is equivalent to `report_overflow_obligation` except
164    /// that we can give a more helpful error message (and, in particular,
165    /// we do not suggest increasing the overflow limit, which is not
166    /// going to help).
167    pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
168        let cycle = self.deeply_resolve_ignoring_regions(cycle.to_owned());
169        if !!cycle.is_empty() {
    ::core::panicking::panic("assertion failed: !cycle.is_empty()")
};assert!(!cycle.is_empty());
170
171        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs:171",
                        "rustc_trait_selection::error_reporting::traits::overflow",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs"),
                        ::tracing_core::__macro_support::Option::Some(171u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::error_reporting::traits::overflow"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("cycle")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("cycle");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("report_overflow_error_cycle")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cycle)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!(?cycle, "report_overflow_error_cycle");
172
173        // The 'deepest' obligation is most likely to have a useful
174        // cause 'backtrace'
175        self.report_overflow_obligation(
176            cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
177            false,
178        );
179    }
180
181    pub fn report_overflow_no_abort(
182        &self,
183        obligation: PredicateObligation<'tcx>,
184        suggest_increasing_limit: bool,
185    ) -> ErrorGuaranteed {
186        let obligation = self.deeply_resolve_ignoring_regions(obligation);
187        let mut err = self.build_overflow_error(
188            OverflowCause::TraitSolver(obligation.predicate),
189            obligation.cause.span,
190            suggest_increasing_limit,
191        );
192        self.note_obligation_cause(&mut err, &obligation);
193        err.emit_err()
194    }
195}