Overhaul how stashed diagnostics work, again.

Stashed errors used to be counted as errors, but could then be
cancelled, leading to `ErrorGuaranteed` soundness holes. #120828 changed
that, closing the soundness hole. But it introduced other difficulties
because you sometimes have to account for pending stashed errors when
making decisions about whether errors have occured/will occur and it's
easy to overlook these.

This commit aims for a middle ground.
- Stashed errors (not warnings) are counted immediately as emitted
  errors, avoiding the possibility of forgetting to consider them.
- The ability to cancel (or downgrade) stashed errors is eliminated, by
  disallowing the use of `steal_diagnostic` with errors, and introducing
  the more restrictive methods `try_steal_{modify,replace}_and_emit_err`
  that can be used instead.

Other things:
- `DiagnosticBuilder::stash` and `DiagCtxt::stash_diagnostic` now both
  return `Option<ErrorGuaranteed>`, which enables the removal of two
  `delayed_bug` calls and one `Ty::new_error_with_message` call. This is
  possible because we store error guarantees in
  `DiagCtxt::stashed_diagnostics`.
- Storing the guarantees also saves us having to maintain a counter.
- Calls to the `stashed_err_count` method are no longer necessary
  alongside calls to `has_errors`, which is a nice simplification, and
  eliminates two more `span_delayed_bug` calls and one FIXME comment.
- Tests are added for three of the four fixed PRs mentioned below.
- `issue-121108.rs`'s output improved slightly, omitting a non-useful
  error message.

Fixes #121451.
Fixes #121477.
Fixes #121504.
Fixes #121508.
This commit is contained in:
Nicholas Nethercote
2024-02-26 15:21:01 +11:00
parent ec25d6db53
commit 260ae70140
29 changed files with 406 additions and 295 deletions

View File

@@ -847,17 +847,15 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
opaque_def_id: LocalDefId,
tcx: TyCtxt<'tcx>,
) -> Result<Diag<'tcx>, ErrorGuaranteed> {
if let Some(diag) = tcx
.sess
.dcx()
.steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
{
// We used to cancel here for slightly better error messages, but
// cancelling stashed diagnostics is no longer allowed because it
// causes problems when tracking whether errors have actually
// occurred.
diag.emit();
}
// We used to cancel here for slightly better error messages, but
// cancelling stashed diagnostics is no longer allowed because it
// causes problems when tracking whether errors have actually
// occurred.
tcx.sess.dcx().try_steal_modify_and_emit_err(
tcx.def_span(opaque_def_id),
StashKey::OpaqueHiddenTypeMismatch,
|_err| {},
);
(self.ty, other.ty).error_reported()?;
// Found different concrete types for the opaque type.
let sub_diag = if self.span == other.span {