Rollup merge of #126620 - oli-obk:taint_errors, r=fee1-dead

Actually taint InferCtxt when a fulfillment error is emitted

And avoid checking the global error counter

fixes #122044
fixes #123255
fixes #123276
fixes #125799
This commit is contained in:
Matthias Krüger 2024-06-20 07:52:43 +02:00 committed by GitHub
commit e7be3562b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 595 additions and 238 deletions

View file

@ -2776,97 +2776,115 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut this = "this bound";
let mut note = None;
let mut help = None;
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
&& let ty::ClauseKind::Trait(trait_pred) = clause
{
let def_id = trait_pred.def_id();
let visible_item = if let Some(local) = def_id.as_local() {
// Check for local traits being reachable.
let vis = &tcx.resolutions(()).effective_visibilities;
// Account for non-`pub` traits in the root of the local crate.
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
vis.is_reachable(local) || is_locally_reachable
} else {
// Check for foreign traits being reachable.
tcx.visible_parent_map(()).get(&def_id).is_some()
};
if tcx.is_lang_item(def_id, LangItem::Sized) {
// Check if this is an implicit bound, even in foreign crates.
if tcx
.generics_of(item_def_id)
.own_params
.iter()
.any(|param| tcx.def_span(param.def_id) == span)
{
a = "an implicit `Sized`";
this = "the implicit `Sized` requirement on this type parameter";
}
if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Type(bounds, None),
..
})) = tcx.hir().get_if_local(item_def_id)
// Do not suggest relaxing if there is an explicit `Sized` obligation.
&& !bounds.iter()
.filter_map(|bound| bound.trait_ref())
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
{
let (span, separator) = if let [.., last] = bounds {
(last.span().shrink_to_hi(), " +")
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() {
match clause {
ty::ClauseKind::Trait(trait_pred) => {
let def_id = trait_pred.def_id();
let visible_item = if let Some(local) = def_id.as_local() {
// Check for local traits being reachable.
let vis = &tcx.resolutions(()).effective_visibilities;
// Account for non-`pub` traits in the root of the local crate.
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
vis.is_reachable(local) || is_locally_reachable
} else {
(generics.span.shrink_to_hi(), ":")
// Check for foreign traits being reachable.
tcx.visible_parent_map(()).get(&def_id).is_some()
};
err.span_suggestion_verbose(
span,
"consider relaxing the implicit `Sized` restriction",
format!("{separator} ?Sized"),
Applicability::MachineApplicable,
);
if tcx.is_lang_item(def_id, LangItem::Sized) {
// Check if this is an implicit bound, even in foreign crates.
if tcx
.generics_of(item_def_id)
.own_params
.iter()
.any(|param| tcx.def_span(param.def_id) == span)
{
a = "an implicit `Sized`";
this =
"the implicit `Sized` requirement on this type parameter";
}
if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Type(bounds, None),
..
})) = tcx.hir().get_if_local(item_def_id)
// Do not suggest relaxing if there is an explicit `Sized` obligation.
&& !bounds.iter()
.filter_map(|bound| bound.trait_ref())
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
{
let (span, separator) = if let [.., last] = bounds {
(last.span().shrink_to_hi(), " +")
} else {
(generics.span.shrink_to_hi(), ":")
};
err.span_suggestion_verbose(
span,
"consider relaxing the implicit `Sized` restriction",
format!("{separator} ?Sized"),
Applicability::MachineApplicable,
);
}
}
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
note = Some(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement it \
you also need to implement `{}`, which is not accessible; this is \
usually done to force you to use one of the provided types that \
already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
let impls_of = tcx.trait_impls_of(def_id);
let impls = impls_of
.non_blanket_impls()
.values()
.flatten()
.chain(impls_of.blanket_impls().iter())
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
let mut types = impls
.iter()
.map(|t| {
with_no_trimmed_paths!(format!(
" {}",
tcx.type_of(*t).instantiate_identity(),
))
})
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
format!("\nand {} others", len - 8)
} else {
String::new()
};
help = Some(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
}
}
}
}
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
note = Some(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement it \
you also need to implement `{}`, which is not accessible; this is \
usually done to force you to use one of the provided types that \
already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
let impls_of = tcx.trait_impls_of(def_id);
let impls = impls_of
.non_blanket_impls()
.values()
.flatten()
.chain(impls_of.blanket_impls().iter())
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
let mut types = impls
.iter()
.map(|t| {
with_no_trimmed_paths!(format!(
" {}",
tcx.type_of(*t).instantiate_identity(),
))
})
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
format!("\nand {} others", len - 8)
ty::ClauseKind::ConstArgHasType(..) => {
let descr =
format!("required by a const generic parameter in `{item_name}`");
if span.is_visible(sm) {
let msg = format!(
"required by this const generic parameter in `{short_item_name}`"
);
multispan.push_span_label(span, msg);
err.span_note(multispan, descr);
} else {
String::new()
};
help = Some(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
err.span_note(tcx.def_span(item_def_id), descr);
}
return;
}
_ => (),
}
};
}
let descr = format!("required by {a} bound in `{item_name}`");
if span.is_visible(sm) {
let msg = format!("required by {this} in `{short_item_name}`");

View file

@ -179,6 +179,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
let guar = self.report_fulfillment_error(error);
self.infcx.set_tainted_by_errors(guar);
reported = Some(guar);
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
@ -2686,22 +2687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
// Given some `ConstArgHasType(?x, usize)`, we should not emit an error such as
// "type annotations needed: cannot satisfy the constant `_` has type `usize`"
// Instead we should emit a normal error suggesting the user to turbofish the
// const parameter that is currently being inferred. Unfortunately we cannot
// nicely emit such an error so we delay an ICE incase nobody else reports it
// for us.
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
return self.tcx.sess.dcx().span_delayed_bug(
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
.emit_inference_failure_err(
obligation.cause.body_id,
span,
format!(
"`ambiguous ConstArgHasType({:?}, {:?}) unaccompanied by inference error`",
ct, ty
),
);
}
ct.into(),
ErrorCode::E0284,
true,
),
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
if term.is_infer() =>
{