rustc_trait_selection/error_reporting/traits/
overflow.rs1use 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 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 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 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 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 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}