mgca: Type-check fields of tuple expr const args

This commit is contained in:
Noah Lev 2026-01-08 11:09:07 -08:00
parent a9749be514
commit 1c2cb16e82
5 changed files with 109 additions and 24 deletions

View file

@ -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();

View file

@ -1053,27 +1053,49 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
}
ty::ConstKind::Value(val) => {
// FIXME(mgca): no need to feature-gate once valtree lifetimes are not erased
if tcx.features().min_generic_const_args()
&& let ty::Adt(adt_def, args) = val.ty.kind()
{
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,
)
},
));
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.

View 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() {}

View file

@ -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

View file

@ -5,7 +5,7 @@
trait Trait {
#[type_const]
const ASSOC: usize;
const ASSOC: u32;
}
fn takes_tuple<const A: (u32, u32)>() {}