Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/ty/consts/valtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
48 changes: 47 additions & 1 deletion compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/const-generics/mgca/adt_expr_arg_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>() {
Expand Down
26 changes: 26 additions & 0 deletions tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.rs
Original file line number Diff line number Diff line change
@@ -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() {}
38 changes: 38 additions & 0 deletions tests/ui/const-generics/mgca/adt_expr_arg_tuple_expr_fail.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}

fn takes_tuple<const A: (u32, u32)>() {}
Expand Down
35 changes: 28 additions & 7 deletions tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs
Original file line number Diff line number Diff line change
@@ -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,
}

#[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<const N: Foo<u8>>() {}
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() {}
45 changes: 45 additions & 0 deletions tests/ui/const-generics/mgca/adt_expr_fields_type_check.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct Foo;

trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}

fn foo<const N: Foo>() {}
Expand All @@ -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`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@ 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`
|
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
Expand Down
Loading