Auto merge of #93368 - eddyb:diagbld-guarantee, r=estebank
rustc_errors: let `DiagnosticBuilder::emit` return a "guarantee of emission". That is, `DiagnosticBuilder` is now generic over the return type of `.emit()`, so we'll now have: * `DiagnosticBuilder<ErrorReported>` for error (incl. fatal/bug) diagnostics * can only be created via a `const L: Level`-generic constructor, that limits allowed variants via a `where` clause, so not even `rustc_errors` can accidentally bypass this limitation * asserts `diagnostic.is_error()` on emission, just in case the construction restriction was bypassed (e.g. by replacing the whole `Diagnostic` inside `DiagnosticBuilder`) * `.emit()` returns `ErrorReported`, as a "proof" token that `.emit()` was called (though note that this isn't a real guarantee until after completing the work on #69426) * `DiagnosticBuilder<()>` for everything else (warnings, notes, etc.) * can also be obtained from other `DiagnosticBuilder`s by calling `.forget_guarantee()` This PR is a companion to other ongoing work, namely: * #69426 and it's ongoing implementation: #93222 the API changes in this PR are needed to get statically-checked "only errors produce `ErrorReported` from `.emit()`", but doesn't itself provide any really strong guarantees without those other `ErrorReported` changes * #93244 would make the choices of API changes (esp. naming) in this PR fit better overall In order to be able to let `.emit()` return anything trustable, several changes had to be made: * `Diagnostic`'s `level` field is now private to `rustc_errors`, to disallow arbitrary "downgrade"s from "some kind of error" to "warning" (or anything else that doesn't cause compilation to fail) * it's still possible to replace the whole `Diagnostic` inside the `DiagnosticBuilder`, sadly, that's harder to fix, but it's unlikely enough that we can paper over it with asserts on `.emit()` * `.cancel()` now consumes `DiagnosticBuilder`, preventing `.emit()` calls on a cancelled diagnostic * it's also now done internally, through `DiagnosticBuilder`-private state, instead of having a `Level::Cancelled` variant that can be read (or worse, written) by the user * this removes a hazard of calling `.cancel()` on an error then continuing to attach details to it, and even expect to be able to `.emit()` it * warnings were switched to *only* `can_emit_warnings` on emission (instead of pre-cancelling early) * `struct_dummy` was removed (as it relied on a pre-`Cancelled` `Diagnostic`) * since `.emit()` doesn't consume the `DiagnosticBuilder` <sub>(I tried and gave up, it's much more work than this PR)</sub>, we have to make `.emit()` idempotent wrt the guarantees it returns * thankfully, `err.emit(); err.emit();` can return `ErrorReported` both times, as the second `.emit()` call has no side-effects *only* because the first one did do the appropriate emission * `&mut Diagnostic` is now used in a lot of function signatures, which used to take `&mut DiagnosticBuilder` (in the interest of not having to make those functions generic) * the APIs were already mostly identical, allowing for low-effort porting to this new setup * only some of the suggestion methods needed some rework, to have the extra `DiagnosticBuilder` functionality on the `Diagnostic` methods themselves (that change is also present in #93259) * `.emit()`/`.cancel()` aren't available, but IMO calling them from an "error decorator/annotator" function isn't a good practice, and can lead to strange behavior (from the caller's perspective) * `.downgrade_to_delayed_bug()` was added, letting you convert any `.is_error()` diagnostic into a `delay_span_bug` one (which works because in both cases the guarantees available are the same) This PR should ideally be reviewed commit-by-commit, since there is a lot of fallout in each. r? `@estebank` cc `@Manishearth` `@nikomatsakis` `@mark-i-m`
This commit is contained in:
commit
d4de1f230c
134 changed files with 1497 additions and 1143 deletions
|
@ -1070,8 +1070,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
.emit();
|
||||
}
|
||||
}
|
||||
let ill_formed =
|
||||
|span| struct_span_err!(self.r.session, span, E0466, "bad macro import").emit();
|
||||
let ill_formed = |span| {
|
||||
struct_span_err!(self.r.session, span, E0466, "bad macro import").emit();
|
||||
};
|
||||
match attr.meta() {
|
||||
Some(meta) => match meta.kind {
|
||||
MetaItemKind::Word => {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::ptr;
|
|||
use rustc_ast::{self as ast, Path};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
|
||||
|
@ -110,7 +110,7 @@ impl<'a> Resolver<'a> {
|
|||
&self,
|
||||
span: Span,
|
||||
resolution_error: ResolutionError<'_>,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
) -> DiagnosticBuilder<'_, ErrorReported> {
|
||||
match resolution_error {
|
||||
ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
|
||||
let mut err = struct_span_err!(
|
||||
|
@ -624,7 +624,10 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn report_vis_error(&self, vis_resolution_error: VisResolutionError<'_>) {
|
||||
crate fn report_vis_error(
|
||||
&self,
|
||||
vis_resolution_error: VisResolutionError<'_>,
|
||||
) -> ErrorReported {
|
||||
match vis_resolution_error {
|
||||
VisResolutionError::Relative2018(span, path) => {
|
||||
let mut err = self.session.struct_span_err(
|
||||
|
@ -1031,7 +1034,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
crate fn unresolved_macro_suggestions(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
err: &mut Diagnostic,
|
||||
macro_kind: MacroKind,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
ident: Ident,
|
||||
|
@ -1120,7 +1123,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
crate fn add_typo_suggestion(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
suggestion: Option<TypoSuggestion>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
|
@ -1817,7 +1820,7 @@ fn find_span_immediately_after_crate_name(
|
|||
crate fn show_candidates(
|
||||
definitions: &rustc_hir::definitions::Definitions,
|
||||
session: &Session,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
// This is `None` if all placement locations are inside expansions
|
||||
use_placement_span: Option<Span>,
|
||||
candidates: &[ImportSuggestion],
|
||||
|
|
|
@ -2001,13 +2001,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||
// into a single one.
|
||||
let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
|
||||
|
||||
parent_err.cancel();
|
||||
|
||||
err.message = take(&mut parent_err.message);
|
||||
err.code = take(&mut parent_err.code);
|
||||
err.children = take(&mut parent_err.children);
|
||||
|
||||
drop(parent_err);
|
||||
parent_err.cancel();
|
||||
|
||||
let def_id = this.parent_scope.module.nearest_parent_mod();
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ use rustc_ast::{
|
|||
};
|
||||
use rustc_ast_pretty::pprust::path_segment_to_string;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
||||
|
@ -133,7 +135,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
res: Option<Res>,
|
||||
) -> (DiagnosticBuilder<'a>, Vec<ImportSuggestion>) {
|
||||
) -> (DiagnosticBuilder<'a, ErrorReported>, Vec<ImportSuggestion>) {
|
||||
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
@ -606,11 +608,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
(err, candidates)
|
||||
}
|
||||
|
||||
fn detect_assoct_type_constraint_meant_as_path(
|
||||
&self,
|
||||
base_span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) {
|
||||
fn detect_assoct_type_constraint_meant_as_path(&self, base_span: Span, err: &mut Diagnostic) {
|
||||
let Some(ty) = self.diagnostic_metadata.current_type_path else { return; };
|
||||
let TyKind::Path(_, path) = &ty.kind else { return; };
|
||||
for segment in &path.segments {
|
||||
|
@ -675,11 +673,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
}
|
||||
|
||||
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
|
||||
fn restrict_assoc_type_in_where_clause(
|
||||
&mut self,
|
||||
span: Span,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
) -> bool {
|
||||
fn restrict_assoc_type_in_where_clause(&mut self, span: Span, err: &mut Diagnostic) -> bool {
|
||||
// Detect that we are actually in a `where` predicate.
|
||||
let (bounded_ty, bounds, where_span) =
|
||||
if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
|
@ -875,7 +869,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
/// Returns `true` if able to provide context-dependent help.
|
||||
fn smart_resolve_context_dependent_help(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
source: PathSource<'_>,
|
||||
res: Res,
|
||||
|
@ -885,7 +879,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
||||
let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.kind {
|
||||
let path_sep = |err: &mut Diagnostic, expr: &Expr| match expr.kind {
|
||||
ExprKind::Field(_, ident) => {
|
||||
err.span_suggestion(
|
||||
expr.span,
|
||||
|
@ -908,7 +902,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
_ => false,
|
||||
};
|
||||
|
||||
let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| {
|
||||
let find_span = |source: &PathSource<'_>, err: &mut Diagnostic| {
|
||||
match source {
|
||||
PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
|
||||
| PathSource::TupleStruct(span, _) => {
|
||||
|
@ -1066,7 +1060,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
})
|
||||
.unwrap_or(false)
|
||||
{
|
||||
err.delay_as_bug();
|
||||
err.downgrade_to_delayed_bug();
|
||||
// We already suggested changing `:` into `::` during parsing.
|
||||
return false;
|
||||
}
|
||||
|
@ -1435,7 +1429,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
start.to(sm.next_point(start))
|
||||
}
|
||||
|
||||
fn type_ascription_suggestion(&self, err: &mut DiagnosticBuilder<'_>, base_span: Span) -> bool {
|
||||
fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool {
|
||||
let sm = self.r.session.source_map();
|
||||
let base_snippet = sm.span_to_snippet(base_span);
|
||||
if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
|
||||
|
@ -1472,7 +1466,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
.borrow_mut()
|
||||
.insert(colon_sp)
|
||||
{
|
||||
err.delay_as_bug();
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
}
|
||||
if let Ok(base_snippet) = base_snippet {
|
||||
|
@ -1577,7 +1571,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
/// Adds a suggestion for using an enum's variant when an enum is used instead.
|
||||
fn suggest_using_enum_variant(
|
||||
&mut self,
|
||||
err: &mut DiagnosticBuilder<'a>,
|
||||
err: &mut Diagnostic,
|
||||
source: PathSource<'_>,
|
||||
def_id: DefId,
|
||||
span: Span,
|
||||
|
@ -1825,7 +1819,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
&self,
|
||||
spans: Vec<Span>,
|
||||
count: usize,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
) -> DiagnosticBuilder<'tcx, ErrorReported> {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
spans,
|
||||
|
@ -1910,7 +1904,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
/// Returns whether to add `'static` lifetime to the suggested lifetime list.
|
||||
crate fn report_elision_failure(
|
||||
&mut self,
|
||||
db: &mut DiagnosticBuilder<'_>,
|
||||
// FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
|
||||
db: &mut Diagnostic,
|
||||
params: &[ElisionFailureInfo],
|
||||
) -> bool {
|
||||
let mut m = String::new();
|
||||
|
@ -2059,7 +2054,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
|
||||
crate fn add_missing_lifetime_specifiers_label(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
mut spans_with_counts: Vec<(Span, usize)>,
|
||||
lifetime_names: &FxHashSet<Symbol>,
|
||||
lifetime_spans: Vec<Span>,
|
||||
|
@ -2090,7 +2085,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let suggest_existing =
|
||||
|err: &mut DiagnosticBuilder<'_>,
|
||||
|err: &mut Diagnostic,
|
||||
name: &str,
|
||||
formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| {
|
||||
if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) =
|
||||
|
@ -2174,7 +2169,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
let suggest_new = |err: &mut DiagnosticBuilder<'_>, suggs: Vec<Option<String>>| {
|
||||
let suggest_new = |err: &mut Diagnostic, suggs: Vec<Option<String>>| {
|
||||
for missing in self.missing_named_lifetime_spots.iter().rev() {
|
||||
let mut introduce_suggestion = vec![];
|
||||
let msg;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||
|
@ -1572,6 +1572,7 @@ fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shado
|
|||
name,
|
||||
orig.kind.desc()
|
||||
)
|
||||
.forget_guarantee()
|
||||
} else {
|
||||
// shadowing involving a label is only a warning, due to issues with
|
||||
// labels and lifetimes not being macro-hygienic.
|
||||
|
@ -1873,7 +1874,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
// or from `fn rah<'a>(T<'a>)` to `fn rah(T<'_>)`
|
||||
fn suggest_eliding_single_use_lifetime(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
def_id: DefId,
|
||||
lifetime: &hir::Lifetime,
|
||||
) {
|
||||
|
|
|
@ -40,7 +40,7 @@ use rustc_ast_pretty::pprust;
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
|
||||
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
|
||||
use rustc_hir::def::Namespace::*;
|
||||
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
|
||||
|
@ -713,7 +713,7 @@ struct PrivacyError<'a> {
|
|||
}
|
||||
|
||||
struct UseError<'a> {
|
||||
err: DiagnosticBuilder<'a>,
|
||||
err: DiagnosticBuilder<'a, ErrorReported>,
|
||||
/// Candidates which user could `use` to access the missing type.
|
||||
candidates: Vec<ImportSuggestion>,
|
||||
/// The `DefId` of the module to place the use-statements in.
|
||||
|
@ -3173,7 +3173,7 @@ impl<'a> Resolver<'a> {
|
|||
/// ```
|
||||
fn add_suggestion_for_rename_of_use(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
name: Symbol,
|
||||
import: &Import<'_>,
|
||||
binding_span: Span,
|
||||
|
@ -3252,7 +3252,7 @@ impl<'a> Resolver<'a> {
|
|||
/// as characters expected by span manipulations won't be present.
|
||||
fn add_suggestion_for_duplicate_nested_use(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
err: &mut Diagnostic,
|
||||
import: &Import<'_>,
|
||||
binding_span: Span,
|
||||
) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue