Skip to content
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//@ edition: 2024
//@ compile-flags: -Zthreads=0 --crate-type lib

#![allow(dead_code)]
#![allow(invalid_type_param_default)]

fn f<const N: u8, T = ()>() {
f::<{ async || {} }>();
//~^ ERROR mismatched types
}

//@ normalize-stderr: "found `\{async closure@[^`]*\}`" -> "found `{async closure@...}`"
Original file line number Diff line number Diff line change
@@ -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<const N: u8, T = ()>() {
| ^^^^^^
|
= 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 <https://github.com/rust-lang/rust/issues/36887>

69 changes: 69 additions & 0 deletions tests/ui/const-generics/anon-const-type-of-issue-158818.rs
Original file line number Diff line number Diff line change
@@ -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<const N: u8>;
struct Tuple<const N: u8>(u8);

trait Trait {
fn assoc<const N: u8>();
}

impl Trait for Foo<0> {
fn assoc<const N: u8>() {}
}

impl<const N: u8> Foo<N> {
fn inherent<const M: u8>() {}
}

mod submodule {
pub fn free<const N: u8>() {}
}

fn free<const N: u8>() {}

fn preceded<T, const N: u8>() {}

// 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<const N: u8>(_: impl Sized) {}

fn cases() {
free::<{ async || {} }>();
//~^ ERROR mismatched types
submodule::free::<{ async || {} }>();
//~^ ERROR mismatched types
preceded::<u8, { async || {} }>();
//~^ ERROR mismatched types
late_bound::<{ async || {} }>(&());
//~^ ERROR mismatched types
synthetic::<{ async || {} }>(());
//~^ ERROR mismatched types
<Foo<0> 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@...}"
84 changes: 84 additions & 0 deletions tests/ui/const-generics/anon-const-type-of-issue-158818.stderr
Original file line number Diff line number Diff line change
@@ -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::<u8, { 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: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 | <Foo<0> 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`.
Loading