diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1f342f10f8b17..0e79764a3e456 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -194,6 +194,16 @@ pub fn check_crate(tcx: TyCtxt<'_>) { { tcx.ensure_ok().typeck(item_def_id); } + }); + + // This has to be a second pass over the body owners, after every body has been + // type-checked above. `needs_coroutine_by_move_body_def_id` asks for `type_of`, and for a + // body owner nested inside a const argument's anon const that goes through `typeck` of the + // anon const, which needs the anon const's own type. That type is never computed, only fed + // while the enclosing body is type-checked. Doing this in the pass above lets the parallel + // front end reach the nested body owner first, computing (and caching) an error type for + // the anon const that then conflicts with the type fed later on. + tcx.par_hir_body_owners(|item_def_id| { // Ensure we generate the new `DefId` before finishing `check_crate`. // Afterwards we freeze the list of `DefId`s. if tcx.needs_coroutine_by_move_body_def_id(item_def_id.to_def_id()) { diff --git a/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.rs b/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.rs new file mode 100644 index 0000000000000..e10f46176ebb3 --- /dev/null +++ b/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.rs @@ -0,0 +1,12 @@ +//@ edition: 2024 +//@ compile-flags: -Zthreads=0 --crate-type lib + +#![allow(dead_code)] +#![allow(invalid_type_param_default)] + +fn f() { + f::<{ async || {} }>(); + //~^ ERROR mismatched types +} + +//@ normalize-stderr: "found `\{async closure@[^`]*\}`" -> "found `{async closure@...}`" diff --git a/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.stderr b/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.stderr new file mode 100644 index 0000000000000..33071f2a3a8df --- /dev/null +++ b/tests/ui/const-generics/anon-const-type-of-defaulted-param-issue-158818.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-defaulted-param-issue-158818.rs:8:11 + | +LL | f::<{ async || {} }>(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@$DIR/anon-const-type-of-defaulted-param-issue-158818.rs:8:11: 8:19}` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. +Future incompatibility report: Future breakage diagnostic: +warning: defaults for generic parameters are not allowed here + --> $DIR/anon-const-type-of-defaulted-param-issue-158818.rs:7:19 + | +LL | fn f() { + | ^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #36887 + diff --git a/tests/ui/const-generics/anon-const-type-of-issue-158818.rs b/tests/ui/const-generics/anon-const-type-of-issue-158818.rs new file mode 100644 index 0000000000000..3052ceefa4759 --- /dev/null +++ b/tests/ui/const-generics/anon-const-type-of-issue-158818.rs @@ -0,0 +1,69 @@ +// The type of a const argument's anon const is never computed, only fed while the enclosing body +// is type-checked. Under the parallel front end, `check_crate` used to ask for the `type_of` of a +// body owner nested inside such an anon const before that had happened, computing and caching an +// error type that then conflicted with the type fed later on. +// +// Each case below reaches the anon const through a different kind of path or position, none of +// which is resolved before the enclosing body is type-checked. They all live in one body so that +// the parallel front end cannot interleave their diagnostics. + +//@ edition: 2024 +//@ compile-flags: -Zthreads=0 --crate-type lib + +#![allow(dead_code)] + +struct Foo; +struct Tuple(u8); + +trait Trait { + fn assoc(); +} + +impl Trait for Foo<0> { + fn assoc() {} +} + +impl Foo { + fn inherent() {} +} + +mod submodule { + pub fn free() {} +} + +fn free() {} + +fn preceded() {} + +// The late-bound `'a` is not a generic parameter, leaving this function with fewer parameters +// than it declares. Elided late-bound lifetimes in the signature do the same. +fn late_bound<'a, const N: u8>(_: &'a ()) {} + +// `impl Sized` is a synthetic parameter, with no argument of its own. +fn synthetic(_: impl Sized) {} + +fn cases() { + free::<{ async || {} }>(); + //~^ ERROR mismatched types + submodule::free::<{ async || {} }>(); + //~^ ERROR mismatched types + preceded::(); + //~^ ERROR mismatched types + late_bound::<{ async || {} }>(&()); + //~^ ERROR mismatched types + synthetic::<{ async || {} }>(()); + //~^ ERROR mismatched types + as Trait>::assoc::<{ async || {} }>(); + //~^ ERROR mismatched types + Foo::<0>::inherent::<{ async || {} }>(); + //~^ ERROR mismatched types + let _ = Tuple::<{ async || {} }>(0); + //~^ ERROR mismatched types + + // Not a path expression at all: the const argument sits in a type annotation, and is only + // lowered once typeck reaches this statement. + let _: Foo<{ async || {} }>; + //~^ ERROR mismatched types +} + +//@ normalize-stderr: "\{async closure@[^`]*\}" -> "{async closure@...}" diff --git a/tests/ui/const-generics/anon-const-type-of-issue-158818.stderr b/tests/ui/const-generics/anon-const-type-of-issue-158818.stderr new file mode 100644 index 0000000000000..d0ee9786e294c --- /dev/null +++ b/tests/ui/const-generics/anon-const-type-of-issue-158818.stderr @@ -0,0 +1,84 @@ +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:46:14 + | +LL | free::<{ async || {} }>(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:48:25 + | +LL | submodule::free::<{ async || {} }>(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:50:22 + | +LL | preceded::(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:52:20 + | +LL | late_bound::<{ async || {} }>(&()); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:54:19 + | +LL | synthetic::<{ async || {} }>(()); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:56:34 + | +LL | as Trait>::assoc::<{ async || {} }>(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:58:28 + | +LL | Foo::<0>::inherent::<{ async || {} }>(); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:60:23 + | +LL | let _ = Tuple::<{ async || {} }>(0); + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error[E0308]: mismatched types + --> $DIR/anon-const-type-of-issue-158818.rs:65:18 + | +LL | let _: Foo<{ async || {} }>; + | ^^^^^^^^^^^ expected `u8`, found `{async closure@...}` + | + = note: expected type `u8` + found closure `{async closure@...}` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0308`.