1
Fork 0

Auto merge of #126996 - oli-obk:do_not_count_errors, r=nnethercote

Automatically taint InferCtxt when errors are emitted

r? `@nnethercote`

Basically `InferCtxt::dcx` now returns a `DiagCtxt` that refers back to the `Cell<Option<ErrorGuaranteed>>` of the `InferCtxt` and thus when invoking `Diag::emit`, and the diagnostic is an error, we taint the `InferCtxt` directly.

That change on its own has no effect at all, because `InferCtxt` already tracks whether errors have been emitted by recording the global error count when it gets opened, and checking at the end whether the count changed. So I removed that error count check, which had a bit of fallout that I immediately fixed by invoking `InferCtxt::dcx` instead of `TyCtxt::dcx` in a bunch of places.

The remaining new errors are because an error was reported in another query, and never bubbled up. I think they are minor enough for this to be ok, and sometimes it actually improves diagnostics, by not silencing useful diagnostics anymore.

fixes #126485 (cc `@olafes)`

There are more improvements we can do (like tainting in hir ty lowering), but I would rather do that in follow up PRs, because it requires some refactorings.
This commit is contained in:
bors 2024-07-01 06:35:58 +00:00
commit 7b21c18fe4
77 changed files with 899 additions and 829 deletions

View file

@ -139,7 +139,7 @@ pub struct TypeErrCtxt<'a, 'tcx> {
}
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub fn dcx(&self) -> DiagCtxtHandle<'tcx> {
pub fn dcx(&self) -> DiagCtxtHandle<'a> {
self.infcx.dcx()
}
@ -305,16 +305,17 @@ fn label_msg_span(
}
}
#[instrument(level = "trace", skip(tcx))]
pub fn unexpected_hidden_region_diagnostic<'tcx>(
tcx: TyCtxt<'tcx>,
#[instrument(level = "trace", skip(infcx))]
pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>(
infcx: &'a InferCtxt<'tcx>,
generic_param_scope: LocalDefId,
span: Span,
hidden_ty: Ty<'tcx>,
hidden_region: ty::Region<'tcx>,
opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
) -> Diag<'tcx> {
let mut err = tcx.dcx().create_err(errors::OpaqueCapturesLifetime {
) -> Diag<'a> {
let tcx = infcx.tcx;
let mut err = infcx.dcx().create_err(errors::OpaqueCapturesLifetime {
span,
opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
@ -436,7 +437,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub fn report_region_errors(
&self,
generic_param_scope: LocalDefId,
@ -2206,7 +2207,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&self,
trace: TypeTrace<'tcx>,
terr: TypeError<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
let span = trace.cause.span();
@ -2215,7 +2216,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
span,
self.type_error_additional_suggestions(&trace, terr),
);
let mut diag = self.tcx.dcx().create_err(failure_code);
let mut diag = self.dcx().create_err(failure_code);
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
diag
}
@ -2357,14 +2358,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
origin: Option<SubregionOrigin<'tcx>>,
bound_kind: GenericKind<'tcx>,
sub: Region<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
if let Some(SubregionOrigin::CompareImplItemObligation {
span,
impl_item_def_id,
trait_item_def_id,
}) = origin
{
return self.report_extra_impl_obligation(
return self.infcx.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
@ -2790,7 +2791,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
}
impl<'tcx> InferCtxt<'tcx> {
fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'tcx> {
fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_> {
let br_string = |br: ty::BoundRegionKind| {
let mut s = match br {
ty::BrNamed(_, name) => name.to_string(),
@ -2829,7 +2830,7 @@ impl<'tcx> InferCtxt<'tcx> {
};
struct_span_code_err!(
self.tcx.dcx(),
self.dcx(),
var_origin.span(),
E0495,
"cannot infer an appropriate lifetime{} due to conflicting requirements",

View file

@ -391,7 +391,7 @@ impl<'tcx> InferCtxt<'tcx> {
span: Span,
arg_data: InferenceDiagnosticsData,
error_code: TypeAnnotationNeeded,
) -> Diag<'tcx> {
) -> Diag<'_> {
let source_kind = "other";
let source_name = "";
let failure_span = None;
@ -436,7 +436,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
#[instrument(level = "debug", skip(self, error_code))]
pub fn emit_inference_failure_err(
&self,
@ -445,7 +445,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
arg: GenericArg<'tcx>,
error_code: TypeAnnotationNeeded,
should_label_span: bool,
) -> Diag<'tcx> {
) -> Diag<'a> {
let arg = self.resolve_vars_if_possible(arg);
let arg_data = self.extract_inference_diagnostics_data(arg, None);
@ -453,7 +453,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
// If we don't have any typeck results we're outside
// of a body, so we won't be able to get better info
// here.
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code);
};
let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg);
@ -465,7 +465,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
let Some(InferSource { span, kind }) = local_visitor.infer_source else {
return self.bad_inference_failure_err(failure_span, arg_data, error_code);
return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code);
};
let (source_kind, name, path) = kind.ty_localized_msg(self);

View file

@ -14,7 +14,7 @@ use rustc_span::symbol::kw;
use super::ObligationCauseAsDiagArg;
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) {
match *origin {
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
@ -79,7 +79,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
let mut err = match origin {
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
@ -245,7 +245,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
})
}
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
let mut err = self.report_extra_impl_obligation(
let mut err = self.infcx.report_extra_impl_obligation(
span,
impl_item_def_id,
trait_item_def_id,
@ -378,7 +378,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
placeholder_origin: SubregionOrigin<'tcx>,
sub: Region<'tcx>,
sup: Region<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
// I can't think how to do better than this right now. -nikomatsakis
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {

View file

@ -684,8 +684,8 @@ impl<'tcx> InferOk<'tcx, ()> {
}
impl<'tcx> InferCtxt<'tcx> {
pub fn dcx(&self) -> DiagCtxtHandle<'tcx> {
self.tcx.dcx()
pub fn dcx(&self) -> DiagCtxtHandle<'_> {
self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
}
pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
@ -1089,19 +1089,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// inference variables, regionck errors).
#[must_use = "this method does not have any side effects"]
pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
if let Some(guar) = self.tainted_by_errors.get() {
Some(guar)
} else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation {
// Errors reported since this infcx was made. Lint errors are
// excluded to avoid some being swallowed in the presence of
// non-lint errors. (It's arguable whether or not this exclusion is
// important.)
let guar = self.dcx().has_errors().unwrap();
self.set_tainted_by_errors(guar);
Some(guar)
} else {
None
}
self.tainted_by_errors.get()
}
/// Set the "tainted by errors" flag to true. We call this when we
@ -1328,8 +1316,7 @@ impl<'tcx> InferCtxt<'tcx> {
bug!("`{value:?}` is not fully resolved");
}
if value.has_infer_regions() {
let guar =
self.tcx.dcx().delayed_bug(format!("`{value:?}` is not fully resolved"));
let guar = self.dcx().delayed_bug(format!("`{value:?}` is not fully resolved"));
Ok(self.tcx.fold_regions(value, |re, _| {
if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re }
}))
@ -1607,7 +1594,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// [Note-Type-error-reporting]
// An invariant is that anytime the expected or actual type is Error (the special
// error type, meaning that an error occurred when typechecking this expression),
@ -1623,9 +1610,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
sp: Span,
mk_diag: M,
actual_ty: Ty<'tcx>,
) -> Diag<'tcx>
) -> Diag<'a>
where
M: FnOnce(String) -> Diag<'tcx>,
M: FnOnce(String) -> Diag<'a>,
{
let actual_ty = self.resolve_vars_if_possible(actual_ty);
debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
@ -1646,7 +1633,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: TypeError<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err)
}
@ -1656,7 +1643,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
expected: ty::Const<'tcx>,
actual: ty::Const<'tcx>,
err: TypeError<'tcx>,
) -> Diag<'tcx> {
) -> Diag<'a> {
self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err)
}
}

View file

@ -156,7 +156,7 @@ impl<'tcx> InferCtxt<'tcx> {
if self.can_define_opaque_ty(b_def_id)
&& self.tcx.is_type_alias_impl_trait(b_def_id)
{
self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
self.dcx().emit_err(OpaqueHiddenTypeDiag {
span,
hidden_type: self.tcx.def_span(b_def_id),
opaque_type: self.tcx.def_span(def_id),

View file

@ -12,15 +12,15 @@ use std::fmt;
use std::iter;
impl<'tcx> InferCtxt<'tcx> {
pub fn report_extra_impl_obligation(
&self,
pub fn report_extra_impl_obligation<'a>(
&'a self,
error_span: Span,
impl_item_def_id: LocalDefId,
trait_item_def_id: DefId,
requirement: &dyn fmt::Display,
) -> Diag<'tcx> {
) -> Diag<'a> {
let mut err = struct_span_code_err!(
self.tcx.dcx(),
self.dcx(),
error_span,
E0276,
"impl has stricter requirements than trait"