Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8738543

Browse files
committedJul 8, 2024·
Split out fulfillment error reporting a bit more
1 parent 739861e commit 8738543

File tree

6 files changed

+221
-206
lines changed

6 files changed

+221
-206
lines changed
 

‎compiler/rustc_hir_typeck/src/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use rustc_span::symbol::sym;
5959
use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP};
6060
use rustc_target::spec::abi::Abi;
6161
use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
62-
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
62+
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _;
6363
use rustc_trait_selection::infer::InferCtxtExt as _;
6464
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
6565
use rustc_trait_selection::traits::{

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

+9-195
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use super::ambiguity::TypeErrCtxtAmbiguityExt as _;
21
use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
32
use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
43
use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
5-
use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt;
64
use crate::errors::{
75
AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
86
};
@@ -12,12 +10,12 @@ use crate::infer::{self, InferCtxt};
1210
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
1311
use crate::traits::NormalizeExt;
1412
use crate::traits::{
15-
elaborate, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
16-
ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation,
17-
SelectionError, SignatureMismatch, TraitNotObjectSafe,
13+
elaborate, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
14+
ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch,
15+
TraitNotObjectSafe,
1816
};
1917
use core::ops::ControlFlow;
20-
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
18+
use rustc_data_structures::fx::FxHashMap;
2119
use rustc_data_structures::unord::UnordSet;
2220
use rustc_errors::codes::*;
2321
use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart};
@@ -44,138 +42,17 @@ use rustc_middle::ty::{
4442
};
4543
use rustc_middle::{bug, span_bug};
4644
use rustc_span::symbol::sym;
47-
use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP};
45+
use rustc_span::{BytePos, Span, Symbol, DUMMY_SP};
4846
use std::borrow::Cow;
49-
use std::iter;
5047

5148
use super::{
5249
ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
5350
};
5451

5552
pub use rustc_infer::traits::error_reporting::*;
5653

57-
#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
54+
#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)]
5855
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
59-
fn report_fulfillment_errors(
60-
&self,
61-
mut errors: Vec<FulfillmentError<'tcx>>,
62-
) -> ErrorGuaranteed {
63-
self.sub_relations
64-
.borrow_mut()
65-
.add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
66-
67-
#[derive(Debug)]
68-
struct ErrorDescriptor<'tcx> {
69-
predicate: ty::Predicate<'tcx>,
70-
index: Option<usize>, // None if this is an old error
71-
}
72-
73-
let mut error_map: FxIndexMap<_, Vec<_>> = self
74-
.reported_trait_errors
75-
.borrow()
76-
.iter()
77-
.map(|(&span, predicates)| {
78-
(
79-
span,
80-
predicates
81-
.0
82-
.iter()
83-
.map(|&predicate| ErrorDescriptor { predicate, index: None })
84-
.collect(),
85-
)
86-
})
87-
.collect();
88-
89-
// Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
90-
// with more relevant type information and hide redundant E0282 errors.
91-
errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
92-
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
93-
if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
94-
{
95-
1
96-
}
97-
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
98-
ty::PredicateKind::Coerce(_) => 2,
99-
_ => 0,
100-
});
101-
102-
for (index, error) in errors.iter().enumerate() {
103-
// We want to ignore desugarings here: spans are equivalent even
104-
// if one is the result of a desugaring and the other is not.
105-
let mut span = error.obligation.cause.span;
106-
let expn_data = span.ctxt().outer_expn_data();
107-
if let ExpnKind::Desugaring(_) = expn_data.kind {
108-
span = expn_data.call_site;
109-
}
110-
111-
error_map.entry(span).or_default().push(ErrorDescriptor {
112-
predicate: error.obligation.predicate,
113-
index: Some(index),
114-
});
115-
}
116-
117-
// We do this in 2 passes because we want to display errors in order, though
118-
// maybe it *is* better to sort errors by span or something.
119-
let mut is_suppressed = vec![false; errors.len()];
120-
for (_, error_set) in error_map.iter() {
121-
// We want to suppress "duplicate" errors with the same span.
122-
for error in error_set {
123-
if let Some(index) = error.index {
124-
// Suppress errors that are either:
125-
// 1) strictly implied by another error.
126-
// 2) implied by an error with a smaller index.
127-
for error2 in error_set {
128-
if error2.index.is_some_and(|index2| is_suppressed[index2]) {
129-
// Avoid errors being suppressed by already-suppressed
130-
// errors, to prevent all errors from being suppressed
131-
// at once.
132-
continue;
133-
}
134-
135-
if self.error_implies(error2.predicate, error.predicate)
136-
&& !(error2.index >= error.index
137-
&& self.error_implies(error.predicate, error2.predicate))
138-
{
139-
info!("skipping {:?} (implied by {:?})", error, error2);
140-
is_suppressed[index] = true;
141-
break;
142-
}
143-
}
144-
}
145-
}
146-
}
147-
148-
let mut reported = None;
149-
150-
for from_expansion in [false, true] {
151-
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
152-
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
153-
let guar = self.report_fulfillment_error(error);
154-
self.infcx.set_tainted_by_errors(guar);
155-
reported = Some(guar);
156-
// We want to ignore desugarings here: spans are equivalent even
157-
// if one is the result of a desugaring and the other is not.
158-
let mut span = error.obligation.cause.span;
159-
let expn_data = span.ctxt().outer_expn_data();
160-
if let ExpnKind::Desugaring(_) = expn_data.kind {
161-
span = expn_data.call_site;
162-
}
163-
self.reported_trait_errors
164-
.borrow_mut()
165-
.entry(span)
166-
.or_insert_with(|| (vec![], guar))
167-
.0
168-
.push(error.obligation.predicate);
169-
}
170-
}
171-
}
172-
173-
// It could be that we don't report an error because we have seen an `ErrorReported` from
174-
// another source. We should probably be able to fix most of these, but some are delayed
175-
// bugs that get a proper error after this function.
176-
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
177-
}
178-
17956
/// The `root_obligation` parameter should be the `root_obligation` field
18057
/// from a `FulfillmentError`. If no `FulfillmentError` is available,
18158
/// then it should be the same as `obligation`.
@@ -803,7 +680,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
803680
self.point_at_returns_when_relevant(&mut err, &obligation);
804681
err.emit()
805682
}
683+
}
806684

685+
#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)]
686+
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
807687
fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool {
808688
let mut base_cause = obligation.cause.code().clone();
809689
let mut applied_do_not_recommend = false;
@@ -1324,72 +1204,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13241204
}
13251205
}
13261206

1327-
#[instrument(skip(self), level = "debug")]
1328-
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
1329-
let mut error = FulfillmentError {
1330-
obligation: error.obligation.clone(),
1331-
code: error.code.clone(),
1332-
root_obligation: error.root_obligation.clone(),
1333-
};
1334-
if matches!(
1335-
error.code,
1336-
FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
1337-
| FulfillmentErrorCode::Project(_)
1338-
) && self.apply_do_not_recommend(&mut error.obligation)
1339-
{
1340-
error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
1341-
}
1342-
1343-
match error.code {
1344-
FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
1345-
error.obligation.clone(),
1346-
&error.root_obligation,
1347-
selection_error,
1348-
),
1349-
FulfillmentErrorCode::Project(ref e) => {
1350-
self.report_projection_error(&error.obligation, e)
1351-
}
1352-
FulfillmentErrorCode::Ambiguity { overflow: None } => {
1353-
self.maybe_report_ambiguity(&error.obligation)
1354-
}
1355-
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
1356-
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
1357-
}
1358-
FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
1359-
.report_mismatched_types(
1360-
&error.obligation.cause,
1361-
expected_found.expected,
1362-
expected_found.found,
1363-
*err,
1364-
)
1365-
.emit(),
1366-
FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
1367-
let mut diag = self.report_mismatched_consts(
1368-
&error.obligation.cause,
1369-
expected_found.expected,
1370-
expected_found.found,
1371-
*err,
1372-
);
1373-
let code = error.obligation.cause.code().peel_derives().peel_match_impls();
1374-
if let ObligationCauseCode::WhereClause(..)
1375-
| ObligationCauseCode::WhereClauseInExpr(..) = code
1376-
{
1377-
self.note_obligation_cause_code(
1378-
error.obligation.cause.body_id,
1379-
&mut diag,
1380-
error.obligation.predicate,
1381-
error.obligation.param_env,
1382-
code,
1383-
&mut vec![],
1384-
&mut Default::default(),
1385-
);
1386-
}
1387-
diag.emit()
1388-
}
1389-
FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
1390-
}
1391-
}
1392-
13931207
#[instrument(level = "debug", skip_all)]
13941208
fn report_projection_error(
13951209
&self,

‎compiler/rustc_trait_selection/src/error_reporting/traits/infer_ctxt_ext.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// FIXME(error_reporting): This should be made into private methods on `TypeErrCtxt`.
2+
13
use crate::infer::InferCtxt;
24
use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
35
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};

0 commit comments

Comments
 (0)
Please sign in to comment.