Skip to content

Commit c6684b7

Browse files
committed
MGCA: Support tuple expressions as direct const arguments
1 parent 56f24e0 commit c6684b7

10 files changed

Lines changed: 134 additions & 10 deletions

File tree

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2396,6 +2396,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23962396
};
23972397

23982398
match &expr.kind {
2399+
ExprKind::Tup(exprs) => {
2400+
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
2401+
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
2402+
let def_id = self.local_def_id(anon_const.id);
2403+
let def_kind = self.tcx.def_kind(def_id);
2404+
assert_eq!(DefKind::AnonConst, def_kind);
2405+
2406+
self.lower_anon_const_to_const_arg_direct(anon_const)
2407+
} else {
2408+
self.lower_expr_to_const_arg_direct(&expr)
2409+
};
2410+
2411+
&*self.arena.alloc(expr)
2412+
}));
2413+
2414+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(expr.span, exprs) }
2415+
}
23992416
ExprKind::Path(qself, path) => {
24002417
let qpath = self.lower_qpath(
24012418
expr.id,
@@ -2460,7 +2477,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24602477
&& let StmtKind::Expr(expr) = &stmt.kind
24612478
&& matches!(
24622479
expr.kind,
2463-
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
2480+
ExprKind::Block(..)
2481+
| ExprKind::Path(..)
2482+
| ExprKind::Struct(..)
2483+
| ExprKind::Tup(..)
24642484
)
24652485
{
24662486
return self.lower_expr_to_const_arg_direct(expr);

compiler/rustc_hir/src/hir.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
497497

498498
pub fn span(&self) -> Span {
499499
match self.kind {
500+
ConstArgKind::Tup(span, ..) => span,
500501
ConstArgKind::Struct(path, _) => path.span(),
501502
ConstArgKind::Path(path) => path.span(),
502503
ConstArgKind::Anon(anon) => anon.span,
@@ -510,6 +511,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
510511
#[derive(Clone, Copy, Debug, HashStable_Generic)]
511512
#[repr(u8, C)]
512513
pub enum ConstArgKind<'hir, Unambig = ()> {
514+
Tup(Span, &'hir [&'hir ConstArg<'hir, Unambig>]),
513515
/// **Note:** Currently this is only used for bare const params
514516
/// (`N` where `fn foo<const N: usize>(...)`),
515517
/// not paths to any const (`N` where `const N: usize = ...`).

compiler/rustc_hir/src/intravisit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,10 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
10811081
let ConstArg { hir_id, kind } = const_arg;
10821082
try_visit!(visitor.visit_id(*hir_id));
10831083
match kind {
1084+
ConstArgKind::Tup(_, exprs) => {
1085+
walk_list!(visitor, visit_const_arg, *exprs);
1086+
V::Result::output()
1087+
}
10841088
ConstArgKind::Struct(qpath, field_exprs) => {
10851089
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
10861090

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ pub enum FeedConstTy<'a, 'tcx> {
268268
/// The list of generic args is used to instantiate the parameters
269269
/// used by the type of the const param specified by `DefId`.
270270
Param(DefId, &'a [ty::GenericArg<'tcx>]),
271+
/// The type is of one field of the top const param that we are
272+
/// supplying this (anon) const arg to.
273+
Field(Ty<'tcx>),
271274
/// Don't feed the type.
272275
No,
273276
}
@@ -2193,10 +2196,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
21932196
) -> Const<'tcx> {
21942197
let tcx = self.tcx();
21952198

2196-
if let FeedConstTy::Param(param_def_id, args) = feed
2197-
&& let hir::ConstArgKind::Anon(anon) = &const_arg.kind
2199+
if let hir::ConstArgKind::Anon(anon) = &const_arg.kind
2200+
&& !matches!(feed, FeedConstTy::No)
21982201
{
2199-
let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args);
2202+
let anon_const_type = if let FeedConstTy::Param(param_def_id, args) = feed {
2203+
tcx.type_of(param_def_id).instantiate(tcx, args)
2204+
} else if let FeedConstTy::Field(ty) = feed {
2205+
ty
2206+
} else {
2207+
bug!("unexpected feed const ty: {:?}", feed)
2208+
};
22002209

22012210
// FIXME(generic_const_parameter_types): Ideally we remove these errors below when
22022211
// we have the ability to intermix typeck of anon const const args with the parent
@@ -2238,14 +2247,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22382247
return ty::Const::new_error(tcx, e);
22392248
}
22402249

2241-
tcx.feed_anon_const_type(
2242-
anon.def_id,
2243-
ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)),
2244-
);
2250+
tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(anon_const_type));
22452251
}
22462252

22472253
let hir_id = const_arg.hir_id;
22482254
match const_arg.kind {
2255+
hir::ConstArgKind::Tup(span, exprs) => self.lower_const_arg_tup(exprs, feed, span),
22492256
hir::ConstArgKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
22502257
debug!(?maybe_qself, ?path);
22512258
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
@@ -2272,6 +2279,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22722279
}
22732280
}
22742281

2282+
fn lower_const_arg_tup(
2283+
&self,
2284+
exprs: &'tcx [&'tcx hir::ConstArg<'tcx>],
2285+
feed: FeedConstTy<'_, 'tcx>,
2286+
span: Span,
2287+
) -> Const<'tcx> {
2288+
let tcx = self.tcx();
2289+
2290+
// FIXME(mgca): support nested const tuples?
2291+
let ty = if let FeedConstTy::Param(did, args) = feed {
2292+
tcx.type_of(did).instantiate(tcx, args)
2293+
} else if let FeedConstTy::Field(ty) = feed {
2294+
ty
2295+
} else {
2296+
return Const::new_error_with_message(tcx, span, "unsupported const tuple");
2297+
};
2298+
2299+
let ty::Tuple(tys) = ty.kind() else {
2300+
return Const::new_error_with_message(tcx, span, "const tuple must have a tuple type");
2301+
};
2302+
2303+
let exprs = exprs
2304+
.iter()
2305+
.zip(tys.iter())
2306+
.map(|(expr, ty)| self.lower_const_arg(expr, FeedConstTy::Field(ty)))
2307+
.collect::<Vec<_>>();
2308+
2309+
let valtree = ty::ValTree::from_branches(tcx, exprs);
2310+
ty::Const::new_value(tcx, valtree, ty)
2311+
}
2312+
22752313
fn lower_const_arg_struct(
22762314
&self,
22772315
hir_id: HirId,

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,16 @@ impl<'a> State<'a> {
11371137

11381138
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
11391139
match &const_arg.kind {
1140+
ConstArgKind::Tup(_, exprs) => {
1141+
self.popen();
1142+
self.commasep_cmnt(
1143+
Inconsistent,
1144+
exprs,
1145+
|s, arg| s.print_const_arg(arg),
1146+
|arg| arg.span(),
1147+
);
1148+
self.pclose();
1149+
}
11401150
// FIXME(mgca): proper printing for struct exprs
11411151
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
11421152
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14411441
// Skip encoding defs for these as they should not have had a `DefId` created
14421442
hir::ConstArgKind::Error(..)
14431443
| hir::ConstArgKind::Struct(..)
1444+
| hir::ConstArgKind::Tup(..)
14441445
| hir::ConstArgKind::Path(..)
14451446
| hir::ConstArgKind::Infer(..) => true,
14461447
hir::ConstArgKind::Anon(..) => false,

compiler/rustc_resolve/src/def_collector.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
419419

420420
// Avoid overwriting `const_arg_context` as we may want to treat const blocks
421421
// as being anon consts if we are inside a const argument.
422-
ExprKind::Struct(_) => return visit::walk_expr(self, expr),
422+
ExprKind::Struct(_) | ExprKind::Tup(..) => return visit::walk_expr(self, expr),
423423
// FIXME(mgca): we may want to handle block labels in some manner
424424
ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind {
425425
// FIXME(mgca): this probably means that mac calls that expand

src/librustdoc/clean/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,10 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind
323323
// FIXME(mgca): proper printing :3
324324
ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() }
325325
}
326+
hir::ConstArgKind::Tup(..) => {
327+
// FIXME(mgca): proper printing :3
328+
ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() }
329+
}
326330
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
327331
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
328332
}
@@ -1804,7 +1808,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
18041808
let ct = cx.tcx.normalize_erasing_regions(typing_env, ct);
18051809
print_const(cx, ct)
18061810
}
1807-
hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => {
1811+
hir::ConstArgKind::Struct(..)
1812+
| hir::ConstArgKind::Path(..)
1813+
| hir::ConstArgKind::Tup(..) => {
18081814
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
18091815
print_const(cx, ct)
18101816
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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: u32, const N2: u32>() {
13+
takes_tuple::<{ (N, N2) }>();
14+
takes_tuple::<{ (N, T::ASSOC) }>();
15+
takes_tuple::<{ (N, N + 1) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block
16+
17+
takes_nested_tuple::<{ (N, (N, N2)) }>();
18+
takes_nested_tuple::<{ (N, (N, T::ASSOC)) }>();
19+
takes_nested_tuple::<{ (N, (N, N + 1)) }>(); //~ ERROR complex const arguments must be placed inside of a `const` block
20+
takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>(); //~ ERROR generic parameters may not be used in const operations
21+
}
22+
23+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: complex const arguments must be placed inside of a `const` block
2+
--> $DIR/adt_expr_arg_tuple_expr.rs:15:25
3+
|
4+
LL | takes_tuple::<{ (N, N + 1) }>();
5+
| ^^^^^
6+
7+
error: complex const arguments must be placed inside of a `const` block
8+
--> $DIR/adt_expr_arg_tuple_expr.rs:19:36
9+
|
10+
LL | takes_nested_tuple::<{ (N, (N, N + 1)) }>();
11+
| ^^^^^
12+
13+
error: generic parameters may not be used in const operations
14+
--> $DIR/adt_expr_arg_tuple_expr.rs:20:44
15+
|
16+
LL | takes_nested_tuple::<{ (N, (N, const { N + 1 })) }>();
17+
| ^
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)