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};
9use rustc_session::Limit;
10use rustc_span::Span;
11use rustc_type_ir::Upcast;
12use tracing::debug;
13
14use crate::error_reporting::TypeErrCtxt;
15
16pub enum OverflowCause<'tcx> {
17 DeeplyNormalize(ty::AliasTerm<'tcx>),
18 TraitSolver(ty::Predicate<'tcx>),
19}
20
21pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
22 tcx: TyCtxt<'tcx>,
23 err: &mut Diag<'_, G>,
24) {
25 let suggested_limit = match tcx.recursion_limit() {
26 Limit(0) => Limit(2),
27 limit => limit * 2,
28 };
29 err.help(format!(
30 "consider increasing the recursion limit by adding a \
31 `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
32 suggested_limit,
33 tcx.crate_name(LOCAL_CRATE),
34 ));
35}
36
37impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
38 pub fn report_overflow_error(
45 &self,
46 cause: OverflowCause<'tcx>,
47 span: Span,
48 suggest_increasing_limit: bool,
49 mutate: impl FnOnce(&mut Diag<'_>),
50 ) -> ! {
51 let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
52 mutate(&mut err);
53 err.emit().raise_fatal();
54 }
55
56 pub fn build_overflow_error(
57 &self,
58 cause: OverflowCause<'tcx>,
59 span: Span,
60 suggest_increasing_limit: bool,
61 ) -> Diag<'a> {
62 fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
63 where
64 T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
65 {
66 let s = value.to_string();
67 if s.len() > 50 {
68 let mut cx: FmtPrinter<'_, '_> =
71 FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
72 value.print(&mut cx).unwrap();
73 cx.into_buffer()
74 } else {
75 s
76 }
77 }
78
79 let mut err = match cause {
80 OverflowCause::DeeplyNormalize(alias_term) => {
81 let alias_term = self.resolve_vars_if_possible(alias_term);
82 let kind = alias_term.kind(self.tcx).descr();
83 let alias_str = with_short_path(self.tcx, alias_term);
84 struct_span_code_err!(
85 self.dcx(),
86 span,
87 E0275,
88 "overflow normalizing the {kind} `{alias_str}`",
89 )
90 }
91 OverflowCause::TraitSolver(predicate) => {
92 let predicate = self.resolve_vars_if_possible(predicate);
93 match predicate.kind().skip_binder() {
94 ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
95 | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
96 struct_span_code_err!(
97 self.dcx(),
98 span,
99 E0275,
100 "overflow assigning `{a}` to `{b}`",
101 )
102 }
103 _ => {
104 let pred_str = with_short_path(self.tcx, predicate);
105 struct_span_code_err!(
106 self.dcx(),
107 span,
108 E0275,
109 "overflow evaluating the requirement `{pred_str}`",
110 )
111 }
112 }
113 }
114 };
115
116 if suggest_increasing_limit {
117 suggest_new_overflow_limit(self.tcx, &mut err);
118 }
119
120 err
121 }
122
123 pub fn report_overflow_obligation<T>(
130 &self,
131 obligation: &Obligation<'tcx, T>,
132 suggest_increasing_limit: bool,
133 ) -> !
134 where
135 T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
136 {
137 let predicate = obligation.predicate.clone().upcast(self.tcx);
138 let predicate = self.resolve_vars_if_possible(predicate);
139 self.report_overflow_error(
140 OverflowCause::TraitSolver(predicate),
141 obligation.cause.span,
142 suggest_increasing_limit,
143 |err| {
144 self.note_obligation_cause_code(
145 obligation.cause.body_id,
146 err,
147 predicate,
148 obligation.param_env,
149 obligation.cause.code(),
150 &mut vec![],
151 &mut Default::default(),
152 );
153 },
154 );
155 }
156
157 pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
163 let cycle = self.resolve_vars_if_possible(cycle.to_owned());
164 assert!(!cycle.is_empty());
165
166 debug!(?cycle, "report_overflow_error_cycle");
167
168 self.report_overflow_obligation(
171 cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
172 false,
173 );
174 }
175
176 pub fn report_overflow_no_abort(
177 &self,
178 obligation: PredicateObligation<'tcx>,
179 suggest_increasing_limit: bool,
180 ) -> ErrorGuaranteed {
181 let obligation = self.resolve_vars_if_possible(obligation);
182 let mut err = self.build_overflow_error(
183 OverflowCause::TraitSolver(obligation.predicate),
184 obligation.cause.span,
185 suggest_increasing_limit,
186 );
187 self.note_obligation_cause(&mut err, &obligation);
188 self.point_at_returns_when_relevant(&mut err, &obligation);
189 err.emit()
190 }
191}