Skip to content

Commit 83179ae

Browse files
author
Lukas Markeffsky
committed
clean up fulfillment error reporting
1 parent d7723b2 commit 83179ae

File tree

2 files changed

+70
-66
lines changed

2 files changed

+70
-66
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
589589
&self,
590590
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
591591
) {
592-
let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
593-
if !result.is_empty() {
594-
mutate_fulfillment_errors(&mut result);
595-
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
596-
self.err_ctxt().report_fulfillment_errors(result);
592+
let mut errors = self.fulfillment_cx.borrow_mut().select_where_possible(self);
593+
if !errors.is_empty() {
594+
mutate_fulfillment_errors(&mut errors);
595+
if errors.is_empty() {
596+
// We sometimes skip reporting fulfillment errors while constructing
597+
// a different error.
598+
self.dcx().span_delayed_bug(
599+
self.tcx.def_span(self.body_id),
600+
"skipped reporting fulfillment errors",
601+
);
602+
return;
603+
}
604+
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
605+
self.err_ctxt().report_fulfillment_errors(errors);
597606
}
598607
}
599608

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

Lines changed: 56 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,28 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
8080

8181
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
8282
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
83+
#[instrument(skip(self), level = "debug")]
8384
fn report_fulfillment_errors(
8485
&self,
8586
mut errors: Vec<FulfillmentError<'tcx>>,
8687
) -> ErrorGuaranteed {
88+
if errors.is_empty() {
89+
bug!("attempted to report fulfillment errors, but there we no errors");
90+
}
91+
8792
self.sub_relations
8893
.borrow_mut()
8994
.add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
9095

96+
let mut reported = None;
97+
98+
// We want to ignore desugarings when filtering errors: spans are equivalent even
99+
// if one is the result of a desugaring and the other is not.
100+
let strip_desugaring = |span: Span| {
101+
let expn_data = span.ctxt().outer_expn_data();
102+
if let ExpnKind::Desugaring(_) = expn_data.kind { expn_data.call_site } else { span }
103+
};
104+
91105
#[derive(Debug)]
92106
struct ErrorDescriptor<'tcx> {
93107
predicate: ty::Predicate<'tcx>,
@@ -98,40 +112,32 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
98112
.reported_trait_errors
99113
.borrow()
100114
.iter()
101-
.map(|(&span, predicates)| {
102-
(
103-
span,
104-
predicates
105-
.0
106-
.iter()
107-
.map(|&predicate| ErrorDescriptor { predicate, index: None })
108-
.collect(),
109-
)
115+
.map(|(&span, &(ref predicates, guar))| {
116+
reported = Some(guar);
117+
let span = strip_desugaring(span);
118+
let reported_errors = predicates
119+
.iter()
120+
.map(|&predicate| ErrorDescriptor { predicate, index: None })
121+
.collect();
122+
(span, reported_errors)
110123
})
111124
.collect();
112125

113126
// Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
114-
// with more relevant type information and hide redundant E0282 errors.
127+
// with more relevant type information and hide redundant E0282 ("type annotations needed") errors.
115128
errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
116129
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
117130
if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() =>
118131
{
119132
1
120133
}
121-
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
122134
ty::PredicateKind::Coerce(_) => 2,
135+
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
123136
_ => 0,
124137
});
125138

126139
for (index, error) in errors.iter().enumerate() {
127-
// We want to ignore desugarings here: spans are equivalent even
128-
// if one is the result of a desugaring and the other is not.
129-
let mut span = error.obligation.cause.span;
130-
let expn_data = span.ctxt().outer_expn_data();
131-
if let ExpnKind::Desugaring(_) = expn_data.kind {
132-
span = expn_data.call_site;
133-
}
134-
140+
let span = strip_desugaring(error.obligation.cause.span);
135141
error_map.entry(span).or_default().push(ErrorDescriptor {
136142
predicate: error.obligation.predicate,
137143
index: Some(index),
@@ -144,59 +150,48 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
144150
for (_, error_set) in error_map.iter() {
145151
// We want to suppress "duplicate" errors with the same span.
146152
for error in error_set {
147-
if let Some(index) = error.index {
148-
// Suppress errors that are either:
149-
// 1) strictly implied by another error.
150-
// 2) implied by an error with a smaller index.
151-
for error2 in error_set {
152-
if error2.index.is_some_and(|index2| is_suppressed[index2]) {
153-
// Avoid errors being suppressed by already-suppressed
154-
// errors, to prevent all errors from being suppressed
155-
// at once.
156-
continue;
157-
}
153+
let Some(index) = error.index else {
154+
continue;
155+
};
158156

159-
if self.error_implies(error2.predicate, error.predicate)
160-
&& !(error2.index >= error.index
161-
&& self.error_implies(error.predicate, error2.predicate))
162-
{
163-
info!("skipping {:?} (implied by {:?})", error, error2);
164-
is_suppressed[index] = true;
165-
break;
166-
}
157+
// Suppress errors that are either:
158+
// 1) strictly implied by another error.
159+
// 2) implied by an error with a smaller index.
160+
for error2 in error_set {
161+
if self.error_implies(error2.predicate, error.predicate)
162+
&& (!error2.index.is_some_and(|index2| index2 >= index)
163+
|| !self.error_implies(error.predicate, error2.predicate))
164+
{
165+
info!("skipping `{}` (implied by `{}`)", error.predicate, error2.predicate);
166+
is_suppressed[index] = true;
167+
break;
167168
}
168169
}
169170
}
170171
}
171172

172-
let mut reported = None;
173-
174173
for from_expansion in [false, true] {
175-
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
176-
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
177-
let guar = self.report_fulfillment_error(error);
178-
reported = Some(guar);
179-
// We want to ignore desugarings here: spans are equivalent even
180-
// if one is the result of a desugaring and the other is not.
181-
let mut span = error.obligation.cause.span;
182-
let expn_data = span.ctxt().outer_expn_data();
183-
if let ExpnKind::Desugaring(_) = expn_data.kind {
184-
span = expn_data.call_site;
185-
}
186-
self.reported_trait_errors
187-
.borrow_mut()
188-
.entry(span)
189-
.or_insert_with(|| (vec![], guar))
190-
.0
191-
.push(error.obligation.predicate);
174+
for (error, &suppressed) in iter::zip(&errors, &is_suppressed) {
175+
let span = error.obligation.cause.span;
176+
if suppressed || span.from_expansion() != from_expansion {
177+
continue;
192178
}
179+
180+
let guar = self.report_fulfillment_error(error);
181+
reported = Some(guar);
182+
183+
self.reported_trait_errors
184+
.borrow_mut()
185+
.entry(span)
186+
.or_insert_with(|| (vec![], guar))
187+
.0
188+
.push(error.obligation.predicate);
193189
}
194190
}
195191

196-
// It could be that we don't report an error because we have seen an `ErrorReported` from
197-
// another source. We should probably be able to fix most of these, but some are delayed
198-
// bugs that get a proper error after this function.
199-
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
192+
// If all errors are suppressed, then we must have reported at least one error
193+
// from a previous call to this function.
194+
reported.unwrap_or_else(|| bug!("failed to report fulfillment errors"))
200195
}
201196

202197
/// Reports that an overflow has occurred and halts compilation. We

0 commit comments

Comments
 (0)