1
Fork 0

Rollup merge of #137913 - compiler-errors:struct-field-default-generic, r=BoxyUwU

Allow struct field default values to reference struct's generics

Right now, the default field value feature (https://github.com/rust-lang/rust/issues/132162) lowers anon consts whose types may reference ADT params that the const doesn't inherit.

This PR fixes this, so that these defaults can reference ADTs' generics, and sets the `generics_of` parenting up correctly.

There doesn't seem to be a good reason not to support this, since the anon const has a well-defined type from the field, and the anon const doesn't interact with the type system like generic parameter defaults do.

r? `````@boxyuwu````` or reassign

I could also make this into an error if this seems problematic (https://github.com/rust-lang/rust/compare/master...compiler-errors:rust:default-field-value-implicit-param?expand=1)...... but I'd rather make this work and register an open question on the tracking issue about validating that this is well-vetted.

Fixes #137896
This commit is contained in:
Jubilee 2025-03-04 19:37:01 -08:00 committed by GitHub
commit b3d7c1483d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 112 additions and 19 deletions

View file

@ -187,6 +187,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Some(parent_did)
}
Node::TyPat(_) => Some(parent_did),
// Field default values inherit the ADT's generics.
Node::Field(_) => Some(parent_did),
_ => None,
}
}

View file

@ -78,6 +78,7 @@ struct IsNeverPattern;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum AnonConstKind {
EnumDiscriminant,
FieldDefaultValue,
InlineConst,
ConstArg(IsRepeatExpr),
}
@ -1406,7 +1407,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
visit_opt!(self, visit_ident, ident);
try_visit!(self.visit_ty(ty));
if let Some(v) = &default {
self.resolve_anon_const(v, AnonConstKind::ConstArg(IsRepeatExpr::No));
self.resolve_anon_const(v, AnonConstKind::FieldDefaultValue);
}
}
}
@ -4659,6 +4660,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
AnonConstKind::EnumDiscriminant => {
ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant)
}
AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes,
AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
AnonConstKind::ConstArg(_) => {
if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg {

View file

@ -17,9 +17,9 @@ pub struct Bar {
#[derive(Default)]
pub struct Qux<const C: i32> {
bar: S = Self::S, //~ ERROR generic `Self` types are currently not permitted in anonymous constants
bar: S = Self::S,
baz: i32 = foo(),
bat: i32 = <Qux<{ C }> as T>::K, //~ ERROR generic parameters may not be used in const operations
bat: i32 = <Qux<{ C }> as T>::K,
bay: i32 = C,
}

View file

@ -6,27 +6,12 @@ LL | Variant {}
|
= help: consider a manual implementation of `Default`
error: generic parameters may not be used in const operations
--> $DIR/failures.rs:22:23
|
LL | bat: i32 = <Qux<{ C }> as T>::K,
| ^ cannot perform const operation using `C`
|
= help: const parameters may only be used as standalone arguments, i.e. `C`
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: default fields are not supported in tuple structs
--> $DIR/failures.rs:26:22
|
LL | pub struct Rak(i32 = 42);
| ^^ default fields are only supported on structs
error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/failures.rs:20:14
|
LL | bar: S = Self::S,
| ^^^^
error[E0277]: the trait bound `S: Default` is not satisfied
--> $DIR/failures.rs:14:5
|
@ -112,7 +97,7 @@ LL - let _ = Rak(.., 0);
LL + let _ = Rak(0);
|
error: aborting due to 9 previous errors
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0061, E0277, E0308.
For more information about an error, try `rustc --explain E0061`.

View file

@ -0,0 +1,29 @@
//@ build-pass
#![feature(default_field_values)]
struct W<const X: usize>;
impl<const X: usize> W<X> {
const fn new() -> Self { W }
}
struct Z<const X: usize> {
// No inference.
one: W<X> = W::<X>::new(),
// Inference works too.
two: W<X> = W::new(),
// An anon const that is too generic before substitution.
too_generic: usize = X + 1,
}
fn use_generically<const X: usize>() {
let x: Z<X> = Z { .. };
}
fn main() {
let x: Z<0> = Z { .. };
use_generically::<0>();
}

View file

@ -0,0 +1,23 @@
error[E0080]: evaluation of `Z::<1>::post_mono::{constant#0}` failed
--> $DIR/post-mono.rs:7:24
|
LL | post_mono: usize = X / 0,
| ^^^^^ attempt to divide `1_usize` by zero
note: erroneous constant encountered
--> $DIR/post-mono.rs:17:19
|
LL | let x: Z<1> = Z { .. };
| ^^^^^^^^
note: erroneous constant encountered
--> $DIR/post-mono.rs:17:19
|
LL | let x: Z<1> = Z { .. };
| ^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,29 @@
error[E0080]: evaluation of `Z::<1>::post_mono::{constant#0}` failed
--> $DIR/post-mono.rs:7:24
|
LL | post_mono: usize = X / 0,
| ^^^^^ attempt to divide `1_usize` by zero
note: erroneous constant encountered
--> $DIR/post-mono.rs:12:19
|
LL | let x: Z<X> = Z { .. };
| ^^^^^^^^
note: erroneous constant encountered
--> $DIR/post-mono.rs:12:19
|
LL | let x: Z<X> = Z { .. };
| ^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
note: the above error was encountered while instantiating `fn indirect::<1>`
--> $DIR/post-mono.rs:22:5
|
LL | indirect::<1>();
| ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,23 @@
//@ build-fail
//@ revisions: direct indirect
#![feature(default_field_values)]
struct Z<const X: usize> {
post_mono: usize = X / 0,
//~^ ERROR evaluation of `Z::<1>::post_mono::{constant#0}` failed
}
fn indirect<const X: usize>() {
let x: Z<X> = Z { .. };
}
#[cfg(direct)]
fn main() {
let x: Z<1> = Z { .. };
}
#[cfg(indirect)]
fn main() {
indirect::<1>();
}