Rollup merge of #120342 - oli-obk:track_errors6, r=nnethercote
Remove various `has_errors` or `err_count` uses follow up to https://github.com/rust-lang/rust/pull/119895 r? `@nnethercote` since you recently did something similar. There are so many more of these, but I wanted to get a PR out instead of growing the commit list indefinitely. The commits all work on their own and can be reviewed commit by commit.
This commit is contained in:
commit
b28e6f143e
9 changed files with 186 additions and 193 deletions
|
@ -139,7 +139,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||||
_ => {
|
_ => {
|
||||||
let expr = p.parse_expr()?;
|
let expr = p.parse_expr()?;
|
||||||
if !args.named_args().is_empty() {
|
if !args.named_args().is_empty() {
|
||||||
ecx.dcx().emit_err(errors::PositionalAfterNamed {
|
return Err(ecx.dcx().create_err(errors::PositionalAfterNamed {
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
args: args
|
args: args
|
||||||
.named_args()
|
.named_args()
|
||||||
|
@ -147,7 +147,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
|
||||||
.filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
|
.filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
|
||||||
.map(|(arg, n)| n.span.to(arg.expr.span))
|
.map(|(arg, n)| n.span.to(arg.expr.span))
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
|
args.add(FormatArgument { kind: FormatArgumentKind::Normal, expr });
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,8 @@ fn make_format_args(
|
||||||
}
|
}
|
||||||
use ArgRef::*;
|
use ArgRef::*;
|
||||||
|
|
||||||
|
let mut unnamed_arg_after_named_arg = false;
|
||||||
|
|
||||||
let mut lookup_arg = |arg: ArgRef<'_>,
|
let mut lookup_arg = |arg: ArgRef<'_>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
used_as: PositionUsedAs,
|
used_as: PositionUsedAs,
|
||||||
|
@ -352,6 +354,7 @@ fn make_format_args(
|
||||||
// For the moment capturing variables from format strings expanded from macros is
|
// For the moment capturing variables from format strings expanded from macros is
|
||||||
// disabled (see RFC #2795)
|
// disabled (see RFC #2795)
|
||||||
ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
|
ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
|
||||||
|
unnamed_arg_after_named_arg = true;
|
||||||
DummyResult::raw_expr(span, true)
|
DummyResult::raw_expr(span, true)
|
||||||
};
|
};
|
||||||
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
|
Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
|
||||||
|
@ -510,7 +513,8 @@ fn make_format_args(
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !unused.is_empty() {
|
let has_unused = !unused.is_empty();
|
||||||
|
if has_unused {
|
||||||
// If there's a lot of unused arguments,
|
// If there's a lot of unused arguments,
|
||||||
// let's check if this format arguments looks like another syntax (printf / shell).
|
// let's check if this format arguments looks like another syntax (printf / shell).
|
||||||
let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
|
let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
|
||||||
|
@ -529,7 +533,7 @@ fn make_format_args(
|
||||||
|
|
||||||
// Only check for unused named argument names if there are no other errors to avoid causing
|
// Only check for unused named argument names if there are no other errors to avoid causing
|
||||||
// too much noise in output errors, such as when a named argument is entirely unused.
|
// too much noise in output errors, such as when a named argument is entirely unused.
|
||||||
if invalid_refs.is_empty() && ecx.dcx().has_errors().is_none() {
|
if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg {
|
||||||
for &(index, span, used_as) in &numeric_refences_to_named_arg {
|
for &(index, span, used_as) in &numeric_refences_to_named_arg {
|
||||||
let (position_sp_to_replace, position_sp_for_msg) = match used_as {
|
let (position_sp_to_replace, position_sp_for_msg) = match used_as {
|
||||||
Placeholder(pspan) => (span, pspan),
|
Placeholder(pspan) => (span, pspan),
|
||||||
|
|
|
@ -485,7 +485,9 @@ pub fn compile_declarative_macro(
|
||||||
)
|
)
|
||||||
.pop()
|
.pop()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
valid &= check_lhs_nt_follows(sess, def, &tt);
|
// We don't handle errors here, the driver will abort
|
||||||
|
// after parsing/expansion. we can report every error in every macro this way.
|
||||||
|
valid &= check_lhs_nt_follows(sess, def, &tt).is_ok();
|
||||||
return tt;
|
return tt;
|
||||||
}
|
}
|
||||||
sess.dcx().span_bug(def.span, "wrong-structured lhs")
|
sess.dcx().span_bug(def.span, "wrong-structured lhs")
|
||||||
|
@ -589,18 +591,19 @@ pub fn compile_declarative_macro(
|
||||||
(mk_syn_ext(expander), rule_spans)
|
(mk_syn_ext(expander), rule_spans)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lhs_nt_follows(sess: &Session, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
|
fn check_lhs_nt_follows(
|
||||||
|
sess: &Session,
|
||||||
|
def: &ast::Item,
|
||||||
|
lhs: &mbe::TokenTree,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
// lhs is going to be like TokenTree::Delimited(...), where the
|
// lhs is going to be like TokenTree::Delimited(...), where the
|
||||||
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
|
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
|
||||||
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
|
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
|
||||||
check_matcher(sess, def, &delimited.tts)
|
check_matcher(sess, def, &delimited.tts)
|
||||||
} else {
|
} else {
|
||||||
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
|
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
|
||||||
sess.dcx().span_err(lhs.span(), msg);
|
Err(sess.dcx().span_err(lhs.span(), msg))
|
||||||
false
|
|
||||||
}
|
}
|
||||||
// we don't abort on errors on rejection, the driver will do that for us
|
|
||||||
// after parsing/expansion. we can report every error in every macro this way.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
|
fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
|
||||||
|
@ -675,12 +678,15 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_matcher(sess: &Session, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool {
|
fn check_matcher(
|
||||||
|
sess: &Session,
|
||||||
|
def: &ast::Item,
|
||||||
|
matcher: &[mbe::TokenTree],
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let first_sets = FirstSets::new(matcher);
|
let first_sets = FirstSets::new(matcher);
|
||||||
let empty_suffix = TokenSet::empty();
|
let empty_suffix = TokenSet::empty();
|
||||||
let err = sess.dcx().err_count();
|
check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?;
|
||||||
check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix);
|
Ok(())
|
||||||
err == sess.dcx().err_count()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
|
fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
|
||||||
|
@ -1020,11 +1026,13 @@ fn check_matcher_core<'tt>(
|
||||||
first_sets: &FirstSets<'tt>,
|
first_sets: &FirstSets<'tt>,
|
||||||
matcher: &'tt [mbe::TokenTree],
|
matcher: &'tt [mbe::TokenTree],
|
||||||
follow: &TokenSet<'tt>,
|
follow: &TokenSet<'tt>,
|
||||||
) -> TokenSet<'tt> {
|
) -> Result<TokenSet<'tt>, ErrorGuaranteed> {
|
||||||
use mbe::TokenTree;
|
use mbe::TokenTree;
|
||||||
|
|
||||||
let mut last = TokenSet::empty();
|
let mut last = TokenSet::empty();
|
||||||
|
|
||||||
|
let mut errored = Ok(());
|
||||||
|
|
||||||
// 2. For each token and suffix [T, SUFFIX] in M:
|
// 2. For each token and suffix [T, SUFFIX] in M:
|
||||||
// ensure that T can be followed by SUFFIX, and if SUFFIX may be empty,
|
// ensure that T can be followed by SUFFIX, and if SUFFIX may be empty,
|
||||||
// then ensure T can also be followed by any element of FOLLOW.
|
// then ensure T can also be followed by any element of FOLLOW.
|
||||||
|
@ -1068,7 +1076,7 @@ fn check_matcher_core<'tt>(
|
||||||
token::CloseDelim(d.delim),
|
token::CloseDelim(d.delim),
|
||||||
span.close,
|
span.close,
|
||||||
));
|
));
|
||||||
check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix);
|
check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?;
|
||||||
// don't track non NT tokens
|
// don't track non NT tokens
|
||||||
last.replace_with_irrelevant();
|
last.replace_with_irrelevant();
|
||||||
|
|
||||||
|
@ -1100,7 +1108,7 @@ fn check_matcher_core<'tt>(
|
||||||
// At this point, `suffix_first` is built, and
|
// At this point, `suffix_first` is built, and
|
||||||
// `my_suffix` is some TokenSet that we can use
|
// `my_suffix` is some TokenSet that we can use
|
||||||
// for checking the interior of `seq_rep`.
|
// for checking the interior of `seq_rep`.
|
||||||
let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix);
|
let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?;
|
||||||
if next.maybe_empty {
|
if next.maybe_empty {
|
||||||
last.add_all(&next);
|
last.add_all(&next);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1206,14 +1214,15 @@ fn check_matcher_core<'tt>(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err.emit();
|
errored = Err(err.emit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last
|
errored?;
|
||||||
|
Ok(last)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
|
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
|
||||||
|
|
|
@ -426,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.map(|vars| self.resolve_vars_if_possible(vars)),
|
.map(|vars| self.resolve_vars_if_possible(vars)),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.report_arg_errors(
|
self.set_tainted_by_errors(self.report_arg_errors(
|
||||||
compatibility_diagonal,
|
compatibility_diagonal,
|
||||||
formal_and_expected_inputs,
|
formal_and_expected_inputs,
|
||||||
provided_args,
|
provided_args,
|
||||||
|
@ -435,7 +435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn_def_id,
|
fn_def_id,
|
||||||
call_span,
|
call_span,
|
||||||
call_expr,
|
call_expr,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn_def_id: Option<DefId>,
|
fn_def_id: Option<DefId>,
|
||||||
call_span: Span,
|
call_span: Span,
|
||||||
call_expr: &'tcx hir::Expr<'tcx>,
|
call_expr: &'tcx hir::Expr<'tcx>,
|
||||||
) {
|
) -> ErrorGuaranteed {
|
||||||
// Next, let's construct the error
|
// Next, let's construct the error
|
||||||
let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
|
let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind {
|
||||||
hir::ExprKind::Call(
|
hir::ExprKind::Call(
|
||||||
|
@ -488,10 +488,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
// FIXME: taint after emitting errors and pass through an `ErrorGuaranteed`
|
|
||||||
self.set_tainted_by_errors(
|
|
||||||
tcx.dcx().span_delayed_bug(call_span, "no errors reported for args"),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get the argument span in the context of the call span so that
|
// Get the argument span in the context of the call span so that
|
||||||
// suggestions and labels are (more) correct when an arg is a
|
// suggestions and labels are (more) correct when an arg is a
|
||||||
|
@ -698,8 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Some(mismatch_idx),
|
Some(mismatch_idx),
|
||||||
is_method,
|
is_method,
|
||||||
);
|
);
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -723,11 +718,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
span_bug!(error_span, "expected errors from argument matrix");
|
span_bug!(error_span, "expected errors from argument matrix");
|
||||||
} else {
|
} else {
|
||||||
tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span });
|
return tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span });
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut reported = None;
|
||||||
errors.retain(|error| {
|
errors.retain(|error| {
|
||||||
let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
|
let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
|
||||||
error
|
error
|
||||||
|
@ -738,16 +733,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let trace =
|
let trace =
|
||||||
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
|
||||||
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
|
||||||
self.err_ctxt().report_and_explain_type_error(trace, *e).emit();
|
reported = Some(self.err_ctxt().report_and_explain_type_error(trace, *e).emit());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
// We're done if we found errors, but we already emitted them.
|
// We're done if we found errors, but we already emitted them.
|
||||||
if errors.is_empty() {
|
if let Some(reported) = reported {
|
||||||
return;
|
assert!(errors.is_empty());
|
||||||
|
return reported;
|
||||||
}
|
}
|
||||||
|
assert!(!errors.is_empty());
|
||||||
|
|
||||||
// Okay, now that we've emitted the special errors separately, we
|
// Okay, now that we've emitted the special errors separately, we
|
||||||
// are only left missing/extra/swapped and mismatched arguments, both
|
// are only left missing/extra/swapped and mismatched arguments, both
|
||||||
|
@ -804,8 +801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Some(expected_idx.as_usize()),
|
Some(expected_idx.as_usize()),
|
||||||
is_method,
|
is_method,
|
||||||
);
|
);
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
|
let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
|
||||||
|
@ -1253,7 +1249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_ptr_null_mut(
|
fn suggest_ptr_null_mut(
|
||||||
|
|
|
@ -45,14 +45,6 @@ pub struct FnCtxt<'a, 'tcx> {
|
||||||
/// eventually).
|
/// eventually).
|
||||||
pub(super) param_env: ty::ParamEnv<'tcx>,
|
pub(super) param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
/// Number of errors that had been reported when we started
|
|
||||||
/// checking this function. On exit, if we find that *more* errors
|
|
||||||
/// have been reported, we will skip regionck and other work that
|
|
||||||
/// expects the types within the function to be consistent.
|
|
||||||
// FIXME(matthewjasper) This should not exist, and it's not correct
|
|
||||||
// if type checking is run in parallel.
|
|
||||||
err_count_on_creation: usize,
|
|
||||||
|
|
||||||
/// If `Some`, this stores coercion information for returned
|
/// If `Some`, this stores coercion information for returned
|
||||||
/// expressions. If `None`, this is in a context where return is
|
/// expressions. If `None`, this is in a context where return is
|
||||||
/// inappropriate, such as a const expression.
|
/// inappropriate, such as a const expression.
|
||||||
|
@ -126,7 +118,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
FnCtxt {
|
FnCtxt {
|
||||||
body_id,
|
body_id,
|
||||||
param_env,
|
param_env,
|
||||||
err_count_on_creation: inh.tcx.dcx().err_count(),
|
|
||||||
ret_coercion: None,
|
ret_coercion: None,
|
||||||
ret_coercion_span: Cell::new(None),
|
ret_coercion_span: Cell::new(None),
|
||||||
coroutine_types: None,
|
coroutine_types: None,
|
||||||
|
@ -195,10 +186,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn errors_reported_since_creation(&self) -> bool {
|
|
||||||
self.dcx().err_count() > self.err_count_on_creation
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
|
||||||
|
|
|
@ -278,7 +278,8 @@ pub struct InferCtxt<'tcx> {
|
||||||
|
|
||||||
/// The set of predicates on which errors have been reported, to
|
/// The set of predicates on which errors have been reported, to
|
||||||
/// avoid reporting the same error twice.
|
/// avoid reporting the same error twice.
|
||||||
pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
|
pub reported_trait_errors:
|
||||||
|
RefCell<FxIndexMap<Span, (Vec<ty::Predicate<'tcx>>, ErrorGuaranteed)>>,
|
||||||
|
|
||||||
pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
|
pub reported_signature_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>,
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
obligation: PredicateObligation<'tcx>,
|
obligation: PredicateObligation<'tcx>,
|
||||||
root_obligation: &PredicateObligation<'tcx>,
|
root_obligation: &PredicateObligation<'tcx>,
|
||||||
error: &SelectionError<'tcx>,
|
error: &SelectionError<'tcx>,
|
||||||
);
|
) -> ErrorGuaranteed;
|
||||||
|
|
||||||
fn emit_specialized_closure_kind_error(
|
fn emit_specialized_closure_kind_error(
|
||||||
&self,
|
&self,
|
||||||
|
@ -107,7 +107,10 @@ pub trait TypeErrCtxtExt<'tcx> {
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
) -> Option<ErrorGuaranteed>;
|
) -> Option<ErrorGuaranteed>;
|
||||||
|
|
||||||
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool;
|
fn fn_arg_obligation(
|
||||||
|
&self,
|
||||||
|
obligation: &PredicateObligation<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed>;
|
||||||
|
|
||||||
fn try_conversion_context(
|
fn try_conversion_context(
|
||||||
&self,
|
&self,
|
||||||
|
@ -142,6 +145,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
(
|
(
|
||||||
span,
|
span,
|
||||||
predicates
|
predicates
|
||||||
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&predicate| ErrorDescriptor { predicate, index: None })
|
.map(|&predicate| ErrorDescriptor { predicate, index: None })
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -208,10 +212,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut reported = None;
|
||||||
|
|
||||||
for from_expansion in [false, true] {
|
for from_expansion in [false, true] {
|
||||||
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
|
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
|
||||||
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
|
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
|
||||||
self.report_fulfillment_error(error);
|
let guar = self.report_fulfillment_error(error);
|
||||||
|
reported = Some(guar);
|
||||||
// We want to ignore desugarings here: spans are equivalent even
|
// We want to ignore desugarings here: spans are equivalent even
|
||||||
// if one is the result of a desugaring and the other is not.
|
// if one is the result of a desugaring and the other is not.
|
||||||
let mut span = error.obligation.cause.span;
|
let mut span = error.obligation.cause.span;
|
||||||
|
@ -222,13 +229,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
self.reported_trait_errors
|
self.reported_trait_errors
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.entry(span)
|
.entry(span)
|
||||||
.or_default()
|
.or_insert_with(|| (vec![], guar))
|
||||||
|
.0
|
||||||
.push(error.obligation.predicate);
|
.push(error.obligation.predicate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.dcx().delayed_bug("expected fulfillment errors")
|
// It could be that we don't report an error because we have seen an `ErrorReported` from another source.
|
||||||
|
// We should probably be able to fix most of these, but some are delayed bugs that get a proper error
|
||||||
|
// after this function.
|
||||||
|
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports that an overflow has occurred and halts compilation. We
|
/// Reports that an overflow has occurred and halts compilation. We
|
||||||
|
@ -374,7 +385,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
mut obligation: PredicateObligation<'tcx>,
|
mut obligation: PredicateObligation<'tcx>,
|
||||||
root_obligation: &PredicateObligation<'tcx>,
|
root_obligation: &PredicateObligation<'tcx>,
|
||||||
error: &SelectionError<'tcx>,
|
error: &SelectionError<'tcx>,
|
||||||
) {
|
) -> ErrorGuaranteed {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
|
if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
|
||||||
|
@ -384,10 +395,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut span = obligation.cause.span;
|
let mut span = obligation.cause.span;
|
||||||
// FIXME: statically guarantee this by tainting after the diagnostic is emitted
|
|
||||||
self.set_tainted_by_errors(
|
|
||||||
tcx.dcx().span_delayed_bug(span, "`report_selection_error` did not emit an error"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut err = match *error {
|
let mut err = match *error {
|
||||||
SelectionError::Unimplemented => {
|
SelectionError::Unimplemented => {
|
||||||
|
@ -412,21 +419,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
kind: _,
|
kind: _,
|
||||||
} = *obligation.cause.code()
|
} = *obligation.cause.code()
|
||||||
{
|
{
|
||||||
self.report_extra_impl_obligation(
|
return self.report_extra_impl_obligation(
|
||||||
span,
|
span,
|
||||||
impl_item_def_id,
|
impl_item_def_id,
|
||||||
trait_item_def_id,
|
trait_item_def_id,
|
||||||
&format!("`{}`", obligation.predicate),
|
&format!("`{}`", obligation.predicate),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit()
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report a const-param specific error
|
// Report a const-param specific error
|
||||||
if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
|
if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()
|
||||||
{
|
{
|
||||||
self.report_const_param_not_wf(ty, &obligation).emit();
|
return self.report_const_param_not_wf(ty, &obligation).emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let bound_predicate = obligation.predicate.kind();
|
let bound_predicate = obligation.predicate.kind();
|
||||||
|
@ -436,22 +441,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
||||||
let trait_ref = trait_predicate.to_poly_trait_ref();
|
let trait_ref = trait_predicate.to_poly_trait_ref();
|
||||||
|
|
||||||
if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
|
if let Some(guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) {
|
||||||
return;
|
return guar;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(effects)
|
// FIXME(effects)
|
||||||
let predicate_is_const = false;
|
let predicate_is_const = false;
|
||||||
|
|
||||||
if self.dcx().has_errors().is_some()
|
if let Some(guar) = self.dcx().has_errors()
|
||||||
&& trait_predicate.references_error()
|
&& trait_predicate.references_error()
|
||||||
{
|
{
|
||||||
return;
|
return guar;
|
||||||
}
|
}
|
||||||
if self.fn_arg_obligation(&obligation) {
|
// Silence redundant errors on binding acccess that are already
|
||||||
// Silence redundant errors on binding acccess that are already
|
// reported on the binding definition (#56607).
|
||||||
// reported on the binding definition (#56607).
|
if let Err(guar) = self.fn_arg_obligation(&obligation) {
|
||||||
return;
|
return guar;
|
||||||
}
|
}
|
||||||
let mut file = None;
|
let mut file = None;
|
||||||
let (post_message, pre_message, type_def) = self
|
let (post_message, pre_message, type_def) = self
|
||||||
|
@ -515,7 +520,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
span,
|
span,
|
||||||
) {
|
) {
|
||||||
GetSafeTransmuteErrorAndReason::Silent => return,
|
GetSafeTransmuteErrorAndReason::Silent => return self.dcx().span_delayed_bug(span, "silent safe transmute error"),
|
||||||
GetSafeTransmuteErrorAndReason::Error {
|
GetSafeTransmuteErrorAndReason::Error {
|
||||||
err_msg,
|
err_msg,
|
||||||
safe_transmute_explanation,
|
safe_transmute_explanation,
|
||||||
|
@ -576,8 +581,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
have_alt_message,
|
have_alt_message,
|
||||||
) {
|
) {
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file_note.map(|note| err.note(note));
|
file_note.map(|note| err.note(note));
|
||||||
|
@ -680,13 +684,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
|
if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
|
if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_unsize {
|
if is_unsize {
|
||||||
|
@ -776,8 +778,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
Some(sym::Debug | sym::Display)
|
Some(sym::Debug | sym::Display)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
err.emit();
|
return err.emit();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
|
@ -912,8 +913,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
found_trait_ref,
|
found_trait_ref,
|
||||||
expected_trait_ref,
|
expected_trait_ref,
|
||||||
) {
|
) {
|
||||||
Some(err) => err,
|
Ok(err) => err,
|
||||||
None => return,
|
Err(guar) => return guar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -934,15 +935,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
|
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
|
||||||
match self.report_not_const_evaluatable_error(&obligation, span) {
|
match self.report_not_const_evaluatable_error(&obligation, span) {
|
||||||
Some(err) => err,
|
Ok(err) => err,
|
||||||
None => return,
|
Err(guar) => return guar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already reported in the query.
|
// Already reported in the query.
|
||||||
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) |
|
SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) |
|
||||||
// Already reported.
|
// Already reported.
|
||||||
Overflow(OverflowError::Error(_)) => return,
|
Overflow(OverflowError::Error(guar)) => return guar,
|
||||||
|
|
||||||
Overflow(_) => {
|
Overflow(_) => {
|
||||||
bug!("overflow should be handled before the `report_selection_error` path");
|
bug!("overflow should be handled before the `report_selection_error` path");
|
||||||
|
@ -951,7 +952,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||||
err.emit();
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_specialized_closure_kind_error(
|
fn emit_specialized_closure_kind_error(
|
||||||
|
@ -986,7 +987,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
fn fn_arg_obligation(
|
||||||
|
&self,
|
||||||
|
obligation: &PredicateObligation<'tcx>,
|
||||||
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
|
if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
|
||||||
obligation.cause.code()
|
obligation.cause.code()
|
||||||
&& let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id)
|
&& let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id)
|
||||||
|
@ -996,12 +1000,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
hir::Path { res: hir::def::Res::Local(hir_id), .. },
|
hir::Path { res: hir::def::Res::Local(hir_id), .. },
|
||||||
)) = arg.kind
|
)) = arg.kind
|
||||||
&& let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id)
|
&& let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id)
|
||||||
&& let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span)
|
&& let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)
|
||||||
&& preds.contains(&obligation.predicate)
|
&& preds.contains(&obligation.predicate)
|
||||||
{
|
{
|
||||||
return true;
|
return Err(*guar);
|
||||||
}
|
}
|
||||||
false
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
|
/// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
|
||||||
|
@ -1323,13 +1327,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
|
||||||
// `error` occurring implies that `cond` occurs.
|
// `error` occurring implies that `cond` occurs.
|
||||||
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
|
fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool;
|
||||||
|
|
||||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>);
|
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed;
|
||||||
|
|
||||||
fn report_projection_error(
|
fn report_projection_error(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
error: &MismatchedProjectionTypes<'tcx>,
|
error: &MismatchedProjectionTypes<'tcx>,
|
||||||
);
|
) -> ErrorGuaranteed;
|
||||||
|
|
||||||
fn maybe_detailed_projection_msg(
|
fn maybe_detailed_projection_msg(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1395,7 +1399,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
|
||||||
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
|
||||||
) -> PredicateObligation<'tcx>;
|
) -> PredicateObligation<'tcx>;
|
||||||
|
|
||||||
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>);
|
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed;
|
||||||
|
|
||||||
fn predicate_can_apply(
|
fn predicate_can_apply(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1512,13 +1516,13 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
|
||||||
|
|
||||||
fn report_not_const_evaluatable_error(
|
fn report_not_const_evaluatable_error(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Option<DiagnosticBuilder<'tcx>>;
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
|
@ -1564,7 +1568,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) {
|
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
|
||||||
if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
|
if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default()
|
||||||
== DumpSolverProofTree::OnError
|
== DumpSolverProofTree::OnError
|
||||||
{
|
{
|
||||||
|
@ -1572,31 +1576,29 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match error.code {
|
match error.code {
|
||||||
FulfillmentErrorCode::SelectionError(ref selection_error) => {
|
FulfillmentErrorCode::SelectionError(ref selection_error) => self
|
||||||
self.report_selection_error(
|
.report_selection_error(
|
||||||
error.obligation.clone(),
|
error.obligation.clone(),
|
||||||
&error.root_obligation,
|
&error.root_obligation,
|
||||||
selection_error,
|
selection_error,
|
||||||
);
|
),
|
||||||
}
|
|
||||||
FulfillmentErrorCode::ProjectionError(ref e) => {
|
FulfillmentErrorCode::ProjectionError(ref e) => {
|
||||||
self.report_projection_error(&error.obligation, e);
|
self.report_projection_error(&error.obligation, e)
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::Ambiguity { overflow: false } => {
|
FulfillmentErrorCode::Ambiguity { overflow: false } => {
|
||||||
self.maybe_report_ambiguity(&error.obligation);
|
self.maybe_report_ambiguity(&error.obligation)
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::Ambiguity { overflow: true } => {
|
FulfillmentErrorCode::Ambiguity { overflow: true } => {
|
||||||
self.report_overflow_no_abort(error.obligation.clone());
|
self.report_overflow_no_abort(error.obligation.clone())
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => {
|
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
|
||||||
self.report_mismatched_types(
|
.report_mismatched_types(
|
||||||
&error.obligation.cause,
|
&error.obligation.cause,
|
||||||
expected_found.expected,
|
expected_found.expected,
|
||||||
expected_found.found,
|
expected_found.found,
|
||||||
*err,
|
*err,
|
||||||
)
|
)
|
||||||
.emit();
|
.emit(),
|
||||||
}
|
|
||||||
FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => {
|
FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => {
|
||||||
let mut diag = self.report_mismatched_consts(
|
let mut diag = self.report_mismatched_consts(
|
||||||
&error.obligation.cause,
|
&error.obligation.cause,
|
||||||
|
@ -1620,11 +1622,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
diag.emit();
|
diag.emit()
|
||||||
}
|
|
||||||
FulfillmentErrorCode::Cycle(ref cycle) => {
|
|
||||||
self.report_overflow_obligation_cycle(cycle);
|
|
||||||
}
|
}
|
||||||
|
FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1633,11 +1633,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
error: &MismatchedProjectionTypes<'tcx>,
|
error: &MismatchedProjectionTypes<'tcx>,
|
||||||
) {
|
) -> ErrorGuaranteed {
|
||||||
let predicate = self.resolve_vars_if_possible(obligation.predicate);
|
let predicate = self.resolve_vars_if_possible(obligation.predicate);
|
||||||
|
|
||||||
if predicate.references_error() {
|
if let Err(e) = predicate.error_reported() {
|
||||||
return;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.probe(|_| {
|
self.probe(|_| {
|
||||||
|
@ -1802,8 +1802,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.note_obligation_cause(&mut diag, obligation);
|
self.note_obligation_cause(&mut diag, obligation);
|
||||||
diag.emit();
|
diag.emit()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_detailed_projection_msg(
|
fn maybe_detailed_projection_msg(
|
||||||
|
@ -2341,7 +2341,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) {
|
fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
|
||||||
// Unable to successfully determine, probably means
|
// Unable to successfully determine, probably means
|
||||||
// insufficient type information, but could mean
|
// insufficient type information, but could mean
|
||||||
// ambiguous impls. The latter *ought* to be a
|
// ambiguous impls. The latter *ought* to be a
|
||||||
|
@ -2361,8 +2361,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
let trait_ref = bound_predicate.rebind(data.trait_ref);
|
let trait_ref = bound_predicate.rebind(data.trait_ref);
|
||||||
debug!(?trait_ref);
|
debug!(?trait_ref);
|
||||||
|
|
||||||
if predicate.references_error() {
|
if let Err(e) = predicate.error_reported() {
|
||||||
return;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is kind of a hack: it frequently happens that some earlier
|
// This is kind of a hack: it frequently happens that some earlier
|
||||||
|
@ -2381,17 +2381,20 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
// check upstream for type errors and don't add the obligations to
|
// check upstream for type errors and don't add the obligations to
|
||||||
// begin with in those cases.
|
// begin with in those cases.
|
||||||
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
|
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
|
||||||
if let None = self.tainted_by_errors() {
|
match self.tainted_by_errors() {
|
||||||
let err = self.emit_inference_failure_err(
|
None => {
|
||||||
obligation.cause.body_id,
|
let err = self.emit_inference_failure_err(
|
||||||
span,
|
obligation.cause.body_id,
|
||||||
trait_ref.self_ty().skip_binder().into(),
|
span,
|
||||||
ErrorCode::E0282,
|
trait_ref.self_ty().skip_binder().into(),
|
||||||
false,
|
ErrorCode::E0282,
|
||||||
);
|
false,
|
||||||
err.stash(span, StashKey::MaybeForgetReturn);
|
);
|
||||||
|
err.stash(span, StashKey::MaybeForgetReturn);
|
||||||
|
return self.dcx().delayed_bug("stashed error never reported");
|
||||||
|
}
|
||||||
|
Some(e) => return e,
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typically, this ambiguity should only happen if
|
// Typically, this ambiguity should only happen if
|
||||||
|
@ -2450,19 +2453,21 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
|
if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
|
||||||
if self.tainted_by_errors().is_some() && subst.is_none() {
|
if let Some(e) = self.tainted_by_errors()
|
||||||
|
&& subst.is_none()
|
||||||
|
{
|
||||||
// If `subst.is_none()`, then this is probably two param-env
|
// If `subst.is_none()`, then this is probably two param-env
|
||||||
// candidates or impl candidates that are equal modulo lifetimes.
|
// candidates or impl candidates that are equal modulo lifetimes.
|
||||||
// Therefore, if we've already emitted an error, just skip this
|
// Therefore, if we've already emitted an error, just skip this
|
||||||
// one, since it's not particularly actionable.
|
// one, since it's not particularly actionable.
|
||||||
err.cancel();
|
err.cancel();
|
||||||
return;
|
return e;
|
||||||
}
|
}
|
||||||
self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
|
self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
|
||||||
} else {
|
} else {
|
||||||
if self.tainted_by_errors().is_some() {
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
err.cancel();
|
err.cancel();
|
||||||
return;
|
return e;
|
||||||
}
|
}
|
||||||
err.note(format!("cannot satisfy `{predicate}`"));
|
err.note(format!("cannot satisfy `{predicate}`"));
|
||||||
let impl_candidates = self
|
let impl_candidates = self
|
||||||
|
@ -2613,11 +2618,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||||
// Same hacky approach as above to avoid deluging user
|
// Same hacky approach as above to avoid deluging user
|
||||||
// with error messages.
|
// with error messages.
|
||||||
if arg.references_error()
|
|
||||||
|| self.dcx().has_errors().is_some()
|
if let Err(e) = arg.error_reported() {
|
||||||
|| self.tainted_by_errors().is_some()
|
return e;
|
||||||
{
|
}
|
||||||
return;
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if let Some(e) = self.dcx().has_errors() {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit_inference_failure_err(
|
self.emit_inference_failure_err(
|
||||||
|
@ -2630,12 +2639,15 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::PredicateKind::Subtype(data) => {
|
ty::PredicateKind::Subtype(data) => {
|
||||||
if data.references_error()
|
if let Err(e) = data.error_reported() {
|
||||||
|| self.dcx().has_errors().is_some()
|
return e;
|
||||||
|| self.tainted_by_errors().is_some()
|
}
|
||||||
{
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if let Some(e) = self.dcx().has_errors() {
|
||||||
// no need to overload user in such cases
|
// no need to overload user in such cases
|
||||||
return;
|
return e;
|
||||||
}
|
}
|
||||||
let SubtypePredicate { a_is_expected: _, a, b } = data;
|
let SubtypePredicate { a_is_expected: _, a, b } = data;
|
||||||
// both must be type variables, or the other would've been instantiated
|
// both must be type variables, or the other would've been instantiated
|
||||||
|
@ -2649,8 +2661,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
|
||||||
if predicate.references_error() || self.tainted_by_errors().is_some() {
|
if let Err(e) = predicate.error_reported() {
|
||||||
return;
|
return e;
|
||||||
|
}
|
||||||
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
let subst = data
|
let subst = data
|
||||||
.projection_ty
|
.projection_ty
|
||||||
|
@ -2681,8 +2696,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
|
ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
|
||||||
if predicate.references_error() || self.tainted_by_errors().is_some() {
|
if let Err(e) = predicate.error_reported() {
|
||||||
return;
|
return e;
|
||||||
|
}
|
||||||
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
let subst = data.walk().find(|g| g.is_non_region_infer());
|
let subst = data.walk().find(|g| g.is_non_region_infer());
|
||||||
if let Some(subst) = subst {
|
if let Some(subst) = subst {
|
||||||
|
@ -2707,8 +2725,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if self.dcx().has_errors().is_some() || self.tainted_by_errors().is_some() {
|
if let Some(e) = self.tainted_by_errors() {
|
||||||
return;
|
return e;
|
||||||
|
}
|
||||||
|
if let Some(e) = self.dcx().has_errors() {
|
||||||
|
// no need to overload user in such cases
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
struct_span_code_err!(
|
struct_span_code_err!(
|
||||||
self.dcx(),
|
self.dcx(),
|
||||||
|
@ -2721,7 +2743,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.note_obligation_cause(&mut err, obligation);
|
self.note_obligation_cause(&mut err, obligation);
|
||||||
err.emit();
|
err.emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn annotate_source_of_ambiguity(
|
fn annotate_source_of_ambiguity(
|
||||||
|
@ -3441,16 +3463,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed> {
|
||||||
let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
|
let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
|
||||||
let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
|
let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
|
||||||
|
|
||||||
if expected_trait_ref.self_ty().references_error() {
|
expected_trait_ref.self_ty().error_reported()?;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
|
let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
|
||||||
return None;
|
return Err(self.dcx().delayed_bug("bound vars outside binder"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let found_did = match *found_trait_ty.kind() {
|
let found_did = match *found_trait_ty.kind() {
|
||||||
|
@ -3464,7 +3484,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) {
|
if !self.reported_signature_mismatch.borrow_mut().insert((span, found_span)) {
|
||||||
// We check closures twice, with obligations flowing in different directions,
|
// We check closures twice, with obligations flowing in different directions,
|
||||||
// but we want to complain about them only once.
|
// but we want to complain about them only once.
|
||||||
return None;
|
return Err(self.dcx().span_delayed_bug(span, "already_reported"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut not_tupled = false;
|
let mut not_tupled = false;
|
||||||
|
@ -3493,7 +3513,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
// This shouldn't be common unless manually implementing one of the
|
// This shouldn't be common unless manually implementing one of the
|
||||||
// traits manually, but don't make it more confusing when it does
|
// traits manually, but don't make it more confusing when it does
|
||||||
// happen.
|
// happen.
|
||||||
Some(
|
Ok(
|
||||||
if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().coroutine_trait()
|
if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().coroutine_trait()
|
||||||
&& not_tupled
|
&& not_tupled
|
||||||
{
|
{
|
||||||
|
@ -3542,9 +3562,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
) -> Result<DiagnosticBuilder<'tcx>, ErrorGuaranteed> {
|
||||||
if !self.tcx.features().generic_const_exprs {
|
if !self.tcx.features().generic_const_exprs {
|
||||||
self.dcx()
|
let guar = self
|
||||||
|
.dcx()
|
||||||
.struct_span_err(span, "constant expression depends on a generic parameter")
|
.struct_span_err(span, "constant expression depends on a generic parameter")
|
||||||
// FIXME(const_generics): we should suggest to the user how they can resolve this
|
// FIXME(const_generics): we should suggest to the user how they can resolve this
|
||||||
// issue. However, this is currently not actually possible
|
// issue. However, this is currently not actually possible
|
||||||
|
@ -3554,7 +3575,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
// be reachable.
|
// be reachable.
|
||||||
.with_note("this may fail depending on what value the parameter takes")
|
.with_note("this may fail depending on what value the parameter takes")
|
||||||
.emit();
|
.emit();
|
||||||
return None;
|
return Err(guar);
|
||||||
}
|
}
|
||||||
|
|
||||||
match obligation.predicate.kind().skip_binder() {
|
match obligation.predicate.kind().skip_binder() {
|
||||||
|
@ -3569,13 +3590,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
)),
|
)),
|
||||||
_ => err.help("consider adding a `where` bound using this expression"),
|
_ => err.help("consider adding a `where` bound using this expression"),
|
||||||
};
|
};
|
||||||
Some(err)
|
Ok(err)
|
||||||
}
|
}
|
||||||
ty::ConstKind::Expr(_) => {
|
ty::ConstKind::Expr(_) => {
|
||||||
let err = self
|
let err = self
|
||||||
.dcx()
|
.dcx()
|
||||||
.struct_span_err(span, format!("unconstrained generic constant `{ct}`"));
|
.struct_span_err(span, format!("unconstrained generic constant `{ct}`"));
|
||||||
Some(err)
|
Ok(err)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
|
bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
|
||||||
|
|
|
@ -37,12 +37,6 @@ pub(super) fn check_cast<'tcx>(
|
||||||
let inherited = Inherited::new(cx.tcx, local_def_id);
|
let inherited = Inherited::new(cx.tcx, local_def_id);
|
||||||
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id);
|
let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id);
|
||||||
|
|
||||||
// If we already have errors, we can't be sure we can pointer cast.
|
|
||||||
assert!(
|
|
||||||
!fn_ctxt.errors_reported_since_creation(),
|
|
||||||
"Newly created FnCtxt contained errors"
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Ok(check) = cast::CastCheck::new(
|
if let Ok(check) = cast::CastCheck::new(
|
||||||
&fn_ctxt,
|
&fn_ctxt,
|
||||||
e,
|
e,
|
||||||
|
@ -53,17 +47,7 @@ pub(super) fn check_cast<'tcx>(
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
hir::Constness::NotConst,
|
hir::Constness::NotConst,
|
||||||
) {
|
) {
|
||||||
let res = check.do_check(&fn_ctxt);
|
check.do_check(&fn_ctxt).ok()
|
||||||
|
|
||||||
// do_check's documentation says that it might return Ok and create
|
|
||||||
// errors in the fcx instead of returning Err in some cases. Those cases
|
|
||||||
// should be filtered out before getting here.
|
|
||||||
assert!(
|
|
||||||
!fn_ctxt.errors_reported_since_creation(),
|
|
||||||
"`fn_ctxt` contained errors after cast check!"
|
|
||||||
);
|
|
||||||
|
|
||||||
res.ok()
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,5 @@ fn main() {}
|
||||||
|
|
||||||
fn f() -> impl Foo {
|
fn f() -> impl Foo {
|
||||||
//~^ ERROR the trait bound `i32: Foo` is not satisfied
|
//~^ ERROR the trait bound `i32: Foo` is not satisfied
|
||||||
//~| ERROR `report_selection_error` did not emit an error
|
|
||||||
1i32
|
1i32
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
error: `report_selection_error` did not emit an error
|
|
||||||
--> $DIR/eagerly-emit.rs:7:11
|
|
||||||
|
|
|
||||||
LL | fn f() -> impl Foo {
|
|
||||||
| ^^^^^^^^
|
|
||||||
|
|
||||||
error: trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging
|
error: trimmed_def_paths constructed but no error emitted; use `DelayDm` for lints or `with_no_trimmed_paths` for debugging
|
||||||
|
|
||||||
error[E0277]: the trait bound `i32: Foo` is not satisfied
|
error[E0277]: the trait bound `i32: Foo` is not satisfied
|
||||||
|
@ -11,7 +5,7 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied
|
||||||
|
|
|
|
||||||
LL | fn f() -> impl Foo {
|
LL | fn f() -> impl Foo {
|
||||||
| ^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
| ^^^^^^^^ the trait `Foo` is not implemented for `i32`
|
||||||
...
|
LL |
|
||||||
LL | 1i32
|
LL | 1i32
|
||||||
| ---- return type was inferred to be `i32` here
|
| ---- return type was inferred to be `i32` here
|
||||||
|
|
|
|
||||||
|
@ -21,8 +15,6 @@ help: this trait has no implementations, consider adding one
|
||||||
LL | trait Foo {}
|
LL | trait Foo {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: expected fulfillment errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue