Rollup merge of #150713 - mgca-typeck-struct-fields, r=BoxyUwU
mgca: Type-check fields of struct expr const args Fixes rust-lang/rust#150623. Fixes rust-lang/rust#150712. Fixes rust-lang/rust#150714. Fixes rust-lang/rust#150734. r? @BoxyUwU
This commit is contained in:
commit
727688a8e4
10 changed files with 194 additions and 19 deletions
|
|
@ -191,8 +191,7 @@ impl<'tcx> Value<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
/// Destructures ADT constants into the constants of their fields.
|
||||
pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
|
||||
let fields = self.to_branch();
|
||||
|
||||
|
|
|
|||
|
|
@ -1051,7 +1051,53 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
| ty::ConstKind::Placeholder(..) => {
|
||||
// These variants are trivially WF, so nothing to do here.
|
||||
}
|
||||
ty::ConstKind::Value(..) => {
|
||||
ty::ConstKind::Value(val) => {
|
||||
// FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased
|
||||
if tcx.features().min_generic_const_args() {
|
||||
match val.ty.kind() {
|
||||
ty::Adt(adt_def, args) => {
|
||||
let adt_val = val.destructure_adt_const();
|
||||
let variant_def = adt_def.variant(adt_val.variant);
|
||||
let cause = self.cause(ObligationCauseCode::WellFormed(None));
|
||||
self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map(
|
||||
|(field_def, &field_val)| {
|
||||
let field_ty =
|
||||
tcx.type_of(field_def.did).instantiate(tcx, args);
|
||||
let predicate = ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
|
||||
);
|
||||
traits::Obligation::with_depth(
|
||||
tcx,
|
||||
cause.clone(),
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
predicate,
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
ty::Tuple(field_tys) => {
|
||||
let field_vals = val.to_branch();
|
||||
let cause = self.cause(ObligationCauseCode::WellFormed(None));
|
||||
self.out.extend(field_tys.iter().zip(field_vals).map(
|
||||
|(field_ty, &field_val)| {
|
||||
let predicate = ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
|
||||
);
|
||||
traits::Obligation::with_depth(
|
||||
tcx,
|
||||
cause.clone(),
|
||||
self.recursion_depth,
|
||||
self.param_env,
|
||||
predicate,
|
||||
)
|
||||
},
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Enforce that values are structurally-matchable.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ fn foo<const N: Option<u32>>() {}
|
|||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
const ASSOC: u32;
|
||||
}
|
||||
|
||||
fn bar<T: Trait, const N: u32>() {
|
||||
|
|
|
|||
26
tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs
Normal file
26
tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#![feature(min_generic_const_args, adt_const_params, unsized_const_params)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
}
|
||||
|
||||
fn takes_tuple<const A: (u32, u32)>() {}
|
||||
fn takes_nested_tuple<const A: (u32, (u32, u32))>() {}
|
||||
|
||||
fn generic_caller<T: Trait, const N: usize, const N2: u32>() {
|
||||
takes_tuple::<{ (N, N2) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u32`
|
||||
takes_tuple::<{ (N, T::ASSOC) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u32`
|
||||
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
|
||||
|
||||
takes_nested_tuple::<{ (N, (N, N2)) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u32`
|
||||
takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u32`
|
||||
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
error: the constant `N` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:13:21
|
||||
|
|
||||
LL | takes_tuple::<{ (N, N2) }>();
|
||||
| ^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: the constant `N` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
|
||||
|
|
||||
LL | takes_tuple::<{ (N, T::ASSOC) }>();
|
||||
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
|
||||
|
|
||||
LL | takes_tuple::<{ (N, T::ASSOC) }>();
|
||||
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: the constant `N` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:19:28
|
||||
|
|
||||
LL | takes_nested_tuple::<{ (N, (N, N2)) }>();
|
||||
| ^^^^^^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: the constant `N` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
|
||||
|
|
||||
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
|
||||
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
|
||||
|
|
||||
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
const ASSOC: u32;
|
||||
}
|
||||
|
||||
fn takes_tuple<const A: (u32, u32)>() {}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,38 @@
|
|||
//@ check-pass
|
||||
// FIXME(mgca): This should error
|
||||
|
||||
#![feature(min_generic_const_args, adt_const_params)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
|
||||
struct Foo<T> { field: T }
|
||||
struct S1<T> {
|
||||
f1: T,
|
||||
f2: isize,
|
||||
}
|
||||
|
||||
fn accepts<const N: Foo<u8>>() {}
|
||||
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
|
||||
struct S2<T>(T, isize);
|
||||
|
||||
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
|
||||
enum En<T> {
|
||||
Var1(bool, T),
|
||||
Var2 { field: i64 },
|
||||
}
|
||||
|
||||
fn accepts_1<const N: S1<u8>>() {}
|
||||
fn accepts_2<const N: S2<u8>>() {}
|
||||
fn accepts_3<const N: En<u8>>() {}
|
||||
|
||||
fn bar<const N: bool>() {
|
||||
// `N` is not of type `u8` but we don't actually check this anywhere yet
|
||||
accepts::<{ Foo::<u8> { field: N }}>();
|
||||
accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
|
||||
//~^ ERROR the constant `N` is not of type `u8`
|
||||
//~| ERROR the constant `N` is not of type `isize`
|
||||
accepts_2::<{ S2::<u8>(N, N) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u8`
|
||||
//~| ERROR the constant `N` is not of type `isize`
|
||||
accepts_3::<{ En::Var1::<u8>(N, N) }>();
|
||||
//~^ ERROR the constant `N` is not of type `u8`
|
||||
accepts_3::<{ En::Var2::<u8> { field: N } }>();
|
||||
//~^ ERROR the constant `N` is not of type `i64`
|
||||
accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
error: the constant `N` is not of type `u8`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:24:19
|
||||
|
|
||||
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
|
||||
|
||||
error: the constant `N` is not of type `isize`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:24:19
|
||||
|
|
||||
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool`
|
||||
|
||||
error: the constant `N` is not of type `u8`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:27:19
|
||||
|
|
||||
LL | accepts_2::<{ S2::<u8>(N, N) }>();
|
||||
| ^^^^^^^^^^^^^^ expected `u8`, found `bool`
|
||||
|
||||
error: the constant `N` is not of type `isize`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:27:19
|
||||
|
|
||||
LL | accepts_2::<{ S2::<u8>(N, N) }>();
|
||||
| ^^^^^^^^^^^^^^ expected `isize`, found `bool`
|
||||
|
||||
error: the constant `N` is not of type `u8`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:30:19
|
||||
|
|
||||
LL | accepts_3::<{ En::Var1::<u8>(N, N) }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
|
||||
|
||||
error: the constant `N` is not of type `i64`
|
||||
--> $DIR/adt_expr_fields_type_check.rs:32:19
|
||||
|
|
||||
LL | accepts_3::<{ En::Var2::<u8> { field: N } }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found `bool`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/adt_expr_fields_type_check.rs:34:51
|
||||
|
|
||||
LL | accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
|
||||
| ^^^^^ expected `i64`, found `bool`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
@ -9,7 +9,7 @@ struct Foo;
|
|||
|
||||
trait Trait {
|
||||
#[type_const]
|
||||
const ASSOC: usize;
|
||||
const ASSOC: u32;
|
||||
}
|
||||
|
||||
fn foo<const N: Foo>() {}
|
||||
|
|
@ -27,7 +27,7 @@ fn baz<T: Trait>() {
|
|||
fn main() {}
|
||||
|
||||
fn test_ice_missing_bound<T>() {
|
||||
foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
|
||||
foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
|
||||
//~^ ERROR the trait bound `T: Trait` is not satisfied
|
||||
//~| ERROR the constant `Option::<u32>::Some(_)` is not of type `Foo`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ LL | fn foo<const N: Foo>() {}
|
|||
error[E0277]: the trait bound `T: Trait` is not satisfied
|
||||
--> $DIR/printing_valtrees_supports_non_values.rs:30:5
|
||||
|
|
||||
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
||||
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
||||
|
|
||||
help: consider restricting type parameter `T` with trait `Trait`
|
||||
|
|
||||
|
|
@ -34,10 +34,10 @@ LL | fn test_ice_missing_bound<T: Trait>() {
|
|||
| +++++++
|
||||
|
||||
error: the constant `Option::<u32>::Some(_)` is not of type `Foo`
|
||||
--> $DIR/printing_valtrees_supports_non_values.rs:30:12
|
||||
--> $DIR/printing_valtrees_supports_non_values.rs:30:13
|
||||
|
|
||||
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
|
||||
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
|
||||
|
|
||||
note: required by a const generic parameter in `foo`
|
||||
--> $DIR/printing_valtrees_supports_non_values.rs:15:8
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue