rustc_trait_selection/error_reporting/traits/
overflow.rs

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