Skip to content

Commit 3723c18

Browse files
authored
Rollup merge of rust-lang#150713 - mgca-typeck-struct-fields, r=BoxyUwU
mgca: Type-check fields of struct expr const args Fixes rust-lang#150623. Fixes rust-lang#150712. Fixes rust-lang#150714. Fixes rust-lang#150734. r? @BoxyUwU
2 parents 5b90c63 + 1c2cb16 commit 3723c18

10 files changed

Lines changed: 194 additions & 19 deletions

compiler/rustc_middle/src/ty/consts/valtree.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,7 @@ impl<'tcx> Value<'tcx> {
191191
}
192192
}
193193

194-
/// Destructures array, ADT or tuple constants into the constants
195-
/// of their fields.
194+
/// Destructures ADT constants into the constants of their fields.
196195
pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
197196
let fields = self.to_branch();
198197

compiler/rustc_trait_selection/src/traits/wf.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,53 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
10511051
| ty::ConstKind::Placeholder(..) => {
10521052
// These variants are trivially WF, so nothing to do here.
10531053
}
1054-
ty::ConstKind::Value(..) => {
1054+
ty::ConstKind::Value(val) => {
1055+
// FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased
1056+
if tcx.features().min_generic_const_args() {
1057+
match val.ty.kind() {
1058+
ty::Adt(adt_def, args) => {
1059+
let adt_val = val.destructure_adt_const();
1060+
let variant_def = adt_def.variant(adt_val.variant);
1061+
let cause = self.cause(ObligationCauseCode::WellFormed(None));
1062+
self.out.extend(variant_def.fields.iter().zip(adt_val.fields).map(
1063+
|(field_def, &field_val)| {
1064+
let field_ty =
1065+
tcx.type_of(field_def.did).instantiate(tcx, args);
1066+
let predicate = ty::PredicateKind::Clause(
1067+
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
1068+
);
1069+
traits::Obligation::with_depth(
1070+
tcx,
1071+
cause.clone(),
1072+
self.recursion_depth,
1073+
self.param_env,
1074+
predicate,
1075+
)
1076+
},
1077+
));
1078+
}
1079+
ty::Tuple(field_tys) => {
1080+
let field_vals = val.to_branch();
1081+
let cause = self.cause(ObligationCauseCode::WellFormed(None));
1082+
self.out.extend(field_tys.iter().zip(field_vals).map(
1083+
|(field_ty, &field_val)| {
1084+
let predicate = ty::PredicateKind::Clause(
1085+
ty::ClauseKind::ConstArgHasType(field_val, field_ty),
1086+
);
1087+
traits::Obligation::with_depth(
1088+
tcx,
1089+
cause.clone(),
1090+
self.recursion_depth,
1091+
self.param_env,
1092+
predicate,
1093+
)
1094+
},
1095+
));
1096+
}
1097+
_ => {}
1098+
}
1099+
}
1100+
10551101
// FIXME: Enforce that values are structurally-matchable.
10561102
}
10571103
}

tests/ui/const-generics/mgca/adt_expr_arg_simple.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn foo<const N: Option<u32>>() {}
1212

1313
trait Trait {
1414
#[type_const]
15-
const ASSOC: usize;
15+
const ASSOC: u32;
1616
}
1717

1818
fn bar<T: Trait, const N: u32>() {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(min_generic_const_args, adt_const_params, unsized_const_params)]
2+
#![expect(incomplete_features)]
3+
4+
trait Trait {
5+
#[type_const]
6+
const ASSOC: usize;
7+
}
8+
9+
fn takes_tuple<const A: (u32, u32)>() {}
10+
fn takes_nested_tuple<const A: (u32, (u32, u32))>() {}
11+
12+
fn generic_caller<T: Trait, const N: usize, const N2: u32>() {
13+
takes_tuple::<{ (N, N2) }>();
14+
//~^ ERROR the constant `N` is not of type `u32`
15+
takes_tuple::<{ (N, T::ASSOC) }>();
16+
//~^ ERROR the constant `N` is not of type `u32`
17+
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
18+
19+
takes_nested_tuple::<{ (N, (N, N2)) }>();
20+
//~^ ERROR the constant `N` is not of type `u32`
21+
takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
22+
//~^ ERROR the constant `N` is not of type `u32`
23+
//~| ERROR the constant `<T as Trait>::ASSOC` is not of type `u32`
24+
}
25+
26+
fn main() {}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: the constant `N` is not of type `u32`
2+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:13:21
3+
|
4+
LL | takes_tuple::<{ (N, N2) }>();
5+
| ^^^^^^^ expected `u32`, found `usize`
6+
7+
error: the constant `N` is not of type `u32`
8+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
9+
|
10+
LL | takes_tuple::<{ (N, T::ASSOC) }>();
11+
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
12+
13+
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
14+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:15:21
15+
|
16+
LL | takes_tuple::<{ (N, T::ASSOC) }>();
17+
| ^^^^^^^^^^^^^ expected `u32`, found `usize`
18+
19+
error: the constant `N` is not of type `u32`
20+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:19:28
21+
|
22+
LL | takes_nested_tuple::<{ (N, (N, N2)) }>();
23+
| ^^^^^^^^^^^^ expected `u32`, found `usize`
24+
25+
error: the constant `N` is not of type `u32`
26+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
27+
|
28+
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
29+
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
30+
31+
error: the constant `<T as Trait>::ASSOC` is not of type `u32`
32+
--> $DIR/adt_expr_arg_tuple_expr_fail.rs:21:28
33+
|
34+
LL | takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
35+
| ^^^^^^^^^^^^^^^^^^ expected `u32`, found `usize`
36+
37+
error: aborting due to 6 previous errors
38+

tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_simple.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
trait Trait {
77
#[type_const]
8-
const ASSOC: usize;
8+
const ASSOC: u32;
99
}
1010

1111
fn takes_tuple<const A: (u32, u32)>() {}
Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
1-
//@ check-pass
2-
// FIXME(mgca): This should error
3-
41
#![feature(min_generic_const_args, adt_const_params)]
52
#![expect(incomplete_features)]
63

74
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
8-
struct Foo<T> { field: T }
5+
struct S1<T> {
6+
f1: T,
7+
f2: isize,
8+
}
9+
10+
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
11+
struct S2<T>(T, isize);
12+
13+
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
14+
enum En<T> {
15+
Var1(bool, T),
16+
Var2 { field: i64 },
17+
}
918

10-
fn accepts<const N: Foo<u8>>() {}
19+
fn accepts_1<const N: S1<u8>>() {}
20+
fn accepts_2<const N: S2<u8>>() {}
21+
fn accepts_3<const N: En<u8>>() {}
1122

1223
fn bar<const N: bool>() {
13-
// `N` is not of type `u8` but we don't actually check this anywhere yet
14-
accepts::<{ Foo::<u8> { field: N }}>();
24+
accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
25+
//~^ ERROR the constant `N` is not of type `u8`
26+
//~| ERROR the constant `N` is not of type `isize`
27+
accepts_2::<{ S2::<u8>(N, N) }>();
28+
//~^ ERROR the constant `N` is not of type `u8`
29+
//~| ERROR the constant `N` is not of type `isize`
30+
accepts_3::<{ En::Var1::<u8>(N, N) }>();
31+
//~^ ERROR the constant `N` is not of type `u8`
32+
accepts_3::<{ En::Var2::<u8> { field: N } }>();
33+
//~^ ERROR the constant `N` is not of type `i64`
34+
accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
35+
//~^ ERROR mismatched types
1536
}
1637

1738
fn main() {}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
error: the constant `N` is not of type `u8`
2+
--> $DIR/adt_expr_fields_type_check.rs:24:19
3+
|
4+
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
6+
7+
error: the constant `N` is not of type `isize`
8+
--> $DIR/adt_expr_fields_type_check.rs:24:19
9+
|
10+
LL | accepts_1::<{ S1::<u8> { f1: N, f2: N } }>();
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool`
12+
13+
error: the constant `N` is not of type `u8`
14+
--> $DIR/adt_expr_fields_type_check.rs:27:19
15+
|
16+
LL | accepts_2::<{ S2::<u8>(N, N) }>();
17+
| ^^^^^^^^^^^^^^ expected `u8`, found `bool`
18+
19+
error: the constant `N` is not of type `isize`
20+
--> $DIR/adt_expr_fields_type_check.rs:27:19
21+
|
22+
LL | accepts_2::<{ S2::<u8>(N, N) }>();
23+
| ^^^^^^^^^^^^^^ expected `isize`, found `bool`
24+
25+
error: the constant `N` is not of type `u8`
26+
--> $DIR/adt_expr_fields_type_check.rs:30:19
27+
|
28+
LL | accepts_3::<{ En::Var1::<u8>(N, N) }>();
29+
| ^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `bool`
30+
31+
error: the constant `N` is not of type `i64`
32+
--> $DIR/adt_expr_fields_type_check.rs:32:19
33+
|
34+
LL | accepts_3::<{ En::Var2::<u8> { field: N } }>();
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i64`, found `bool`
36+
37+
error[E0308]: mismatched types
38+
--> $DIR/adt_expr_fields_type_check.rs:34:51
39+
|
40+
LL | accepts_3::<{ En::Var2::<u8> { field: const { false } } }>();
41+
| ^^^^^ expected `i64`, found `bool`
42+
43+
error: aborting due to 7 previous errors
44+
45+
For more information about this error, try `rustc --explain E0308`.

tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ struct Foo;
99

1010
trait Trait {
1111
#[type_const]
12-
const ASSOC: usize;
12+
const ASSOC: u32;
1313
}
1414

1515
fn foo<const N: Foo>() {}
@@ -27,7 +27,7 @@ fn baz<T: Trait>() {
2727
fn main() {}
2828

2929
fn test_ice_missing_bound<T>() {
30-
foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
30+
foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
3131
//~^ ERROR the trait bound `T: Trait` is not satisfied
3232
//~| ERROR the constant `Option::<u32>::Some(_)` is not of type `Foo`
3333
}

tests/ui/const-generics/mgca/printing_valtrees_supports_non_values.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ LL | fn foo<const N: Foo>() {}
2525
error[E0277]: the trait bound `T: Trait` is not satisfied
2626
--> $DIR/printing_valtrees_supports_non_values.rs:30:5
2727
|
28-
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
28+
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
3030
|
3131
help: consider restricting type parameter `T` with trait `Trait`
3232
|
3333
LL | fn test_ice_missing_bound<T: Trait>() {
3434
| +++++++
3535

3636
error: the constant `Option::<u32>::Some(_)` is not of type `Foo`
37-
--> $DIR/printing_valtrees_supports_non_values.rs:30:12
37+
--> $DIR/printing_valtrees_supports_non_values.rs:30:13
3838
|
39-
LL | foo::<{Option::Some::<u32>{0: <T as Trait>::ASSOC}}>();
40-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
39+
LL | foo::<{ Option::Some::<u32> { 0: <T as Trait>::ASSOC } }>();
40+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Foo`, found `Option<u32>`
4141
|
4242
note: required by a const generic parameter in `foo`
4343
--> $DIR/printing_valtrees_supports_non_values.rs:15:8

0 commit comments

Comments
 (0)