diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index 813492a041..a6a198f865 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -23034,7 +23034,20 @@ fn collect_unresolved_types( // rustc will later fail to find. That disagreement between the two // resolvers is worth its own repair; this check works around it // rather than pretending it is not there. - let emitter_knows = RustCodegen::t27_type_to_rust(&base) != base; + // The emitter answers for the spellings it REWRITES (`int` -> + // `i32`) and passes through the ones already valid in Rust -- so + // `usize`, `isize` and `char` came back unchanged and read as + // undeclared types. That was 565 of the 1045 remaining warnings, + // every one of them on `usize`, every one false. + // + // `int_value_bits(&base).is_some()` was tried here as a second + // oracle and REMOVED: it answers for `usize` and `isize` and not + // for `char`, so the explicit list below is needed anyway, and with + // the list present dropping `int_value_bits` changes nothing -- + // measured, the test still passes and the corpus count is + // unchanged. Three names is the whole gap. + let emitter_knows = RustCodegen::t27_type_to_rust(&base) != base + || matches!(base.as_str(), "char" | "usize" | "isize"); if !declared.contains(&base) && !type_params.contains(&base) && !emitter_knows diff --git a/bootstrap/stage0/FROZEN_HASH b/bootstrap/stage0/FROZEN_HASH index d1b759268a..e1b63647d5 100644 --- a/bootstrap/stage0/FROZEN_HASH +++ b/bootstrap/stage0/FROZEN_HASH @@ -1 +1 @@ -fa7f44546531946823206c2f9796e8ada32a3efb9ffaa7f150e92da623084a89 bootstrap/src/compiler.rs +9c910e4dfae29326a04b20dc9889ecdf33a42849d8bb754bfbebedcaff2e1efb bootstrap/src/compiler.rs diff --git a/bootstrap/tests/unknown_type.rs b/bootstrap/tests/unknown_type.rs index 2459b15dfb..3c6ad368a4 100644 --- a/bootstrap/tests/unknown_type.rs +++ b/bootstrap/tests/unknown_type.rs @@ -155,3 +155,31 @@ fn a_type_that_arrives_through_an_import_is_not_unknown() { warned.join("\n") ); } + +/// A spelling the emitter passes through unchanged is not an unknown type. +/// +/// The first oracle was "does the Rust emitter REWRITE this name" -- true for +/// `int` -> `i32`, and false for `usize`, `isize` and `char`, which are already +/// valid Rust and come back unchanged. That read as undeclared: **565 of the +/// 1045 remaining warnings, every one of them on `usize`**. +/// +/// `int_value_bits` answers the right question -- does this spelling have a +/// width -- regardless of which target it is spelled for. +#[test] +fn a_spelling_already_valid_in_the_target_is_not_unknown() { + let w = unknown_types( + "module m {\n struct S { a: usize, b: isize, c: char, }\n}\n", + ); + assert!(w.is_empty(), "primitive spellings must not warn: {w:?}"); +} + +#[test] +fn a_genuinely_undeclared_name_still_warns_beside_them() { + // The control for the test above: widening the known set must not widen it + // to everything. `Nope` has no width, no rewrite and no declaration. + let w = unknown_types( + "module m {\n struct S { a: usize, b: Nope, }\n}\n", + ); + assert_eq!(w.len(), 1, "exactly the undeclared one, got {w:?}"); + assert!(w[0].contains("Nope"), "{}", w[0]); +} diff --git a/docs/now/2026-09-08-the-oracle-answered-only-for-names-it-rewrites.md b/docs/now/2026-09-08-the-oracle-answered-only-for-names-it-rewrites.md new file mode 100644 index 0000000000..5910eab1af --- /dev/null +++ b/docs/now/2026-09-08-the-oracle-answered-only-for-names-it-rewrites.md @@ -0,0 +1,9 @@ +# NOW -- The oracle answered only for names it rewrites (2026-09-08) + +## The oracle answered only for names it rewrites (Refs #3412, #3408) + +- My unknown-type check asked the Rust emitter "do you know this name", and the emitter answers by REWRITING (`int` -> `i32`). Spellings already valid in Rust -- `usize`, `isize`, `char` -- come back unchanged, so the test read them as undeclared. **565 of the 1045 remaining warnings, every one on `usize`, every one false.** Second false-positive class in my own check in as many passes, and again found by measuring my own output. +- Fixed by naming the three. Corpus: `unknown type` **1045 -> 478**, all warnings **1570 -> 1003**, exit codes unchanged at 573/78. Across both passes my own false positives fall **1283 -> 478**, a 63% cut, with the exit code of `check` never changing for any of 651 specs. +- `int_value_bits(&base).is_some()` was added as a second oracle and then **REMOVED**. Mutation showed why: dropping the explicit list makes `char` warn and the test fail; dropping `int_value_bits` changes nothing, because the list already covers `usize` and `isize`. Second redundant guard removed rather than shipped in as many passes, and by the same rule -- if I cannot make a test tell the difference, it is decoration. +- What remains is real: `Result` 69, `Float` 60, `String` 53, `Int` 32, `Trit` 26, `Bool` 23. Those names are declared by nothing. +- Sized for the next pass: only **6 specs** still warn on `Trit`, and **4 of them carry zero `use` lines**. One import line in `specs/ar/restraint.t27` takes its emitted Rust from 30 rustc errors to 19.