Split LintExpectationId

`LintExpectationId` has two variants, `Unstable` and `Stable`. There are
some places where both variants are possible, but there are also places
where only one of `Unstable` or `Stable` is possible.

This commit encodes this into the type system by introducing
new types `UnstableLintExpectationId` and `StableLintExpectationId`. The
variants of `LintExpectationId` now enclose these. This makes it clearer
what values are possible where.

Other things of note:
- `LintLevelsProvider` gets an associated type and some method changes.
- `LintContext` gets an associated type.
- `LevelSpec` is made generic. `UnstableLevelSpec` and `StableLevelSpec`
  typedefs are added.
- The unstable types are now guaranteed by the type system to never be
  stably hashed. Previously this was a runtime check.
This commit is contained in:
Nicholas Nethercote
2026-05-15 17:58:21 +10:00
parent 40332688e0
commit 22cf1fb6fe
9 changed files with 210 additions and 160 deletions
@@ -2,7 +2,7 @@
use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
use rustc_errors::MultiSpan;
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
use rustc_middle::lint::LevelSpec;
use rustc_middle::lint::UnstableLevelSpec;
use rustc_session::impl_lint_pass;
use rustc_span::{FileName, Span};
use std::collections::BTreeMap;
@@ -51,7 +51,7 @@
struct Modules {
local_path: PathBuf,
spans: Vec<Span>,
lint_level_specs: Vec<LevelSpec>,
lint_level_specs: Vec<UnstableLevelSpec>,
}
#[derive(Default)]
@@ -96,7 +96,7 @@ fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
.zip(lint_level_specs)
.filter_map(|(span, level_spec)| {
if let Some(id) = level_spec.lint_id() {
cx.fulfill_expectation(id);
cx.fulfill_expectation(id.into());
}
(!matches!(level_spec.level(), Level::Allow | Level::Expect)).then_some(*span)