Skip to content
/ rust Public
forked from rust-lang/rust

Commit 6885bdf

Browse files
committed
Auto merge of rust-lang#150603 - Kivooeo:tuple-struct, r=BoxyUwU
MGCA: Support for tuple constructors r? BoxyUwU part of rust-lang#132980 fixes rust-lang#136379 fixes rust-lang#138132 i tried to keep implementation very minimal and it's very similar to how structs was implemented with small adjustments this does not make const constructor like None works, just something like Some(n) todo: * ~~tests~~ * write a better description (not sure if needed) * add more comments and FIXMEs from structs code
2 parents 451b7b6 + 05afcb6 commit 6885bdf

File tree

24 files changed

+537
-28
lines changed

24 files changed

+537
-28
lines changed

compiler/rustc_ast_lowering/src/lib.rs

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

23982398
match &expr.kind {
2399+
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
2400+
let qpath = self.lower_qpath(
2401+
func.id,
2402+
qself,
2403+
path,
2404+
ParamMode::Explicit,
2405+
AllowReturnTypeNotation::No,
2406+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
2407+
None,
2408+
);
2409+
2410+
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
2411+
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
2412+
let def_id = self.local_def_id(anon_const.id);
2413+
let def_kind = self.tcx.def_kind(def_id);
2414+
assert_eq!(DefKind::AnonConst, def_kind);
2415+
self.lower_anon_const_to_const_arg_direct(anon_const)
2416+
} else {
2417+
self.lower_expr_to_const_arg_direct(arg)
2418+
};
2419+
2420+
&*self.arena.alloc(const_arg)
2421+
}));
2422+
2423+
ConstArg {
2424+
hir_id: self.next_id(),
2425+
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
2426+
}
2427+
}
23992428
ExprKind::Path(qself, path) => {
24002429
let qpath = self.lower_qpath(
24012430
expr.id,
@@ -2460,7 +2489,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24602489
&& let StmtKind::Expr(expr) = &stmt.kind
24612490
&& matches!(
24622491
expr.kind,
2463-
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
2492+
ExprKind::Block(..)
2493+
| ExprKind::Path(..)
2494+
| ExprKind::Struct(..)
2495+
| ExprKind::Call(..)
24642496
)
24652497
{
24662498
return self.lower_expr_to_const_arg_direct(expr);

compiler/rustc_hir/src/hir.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
499499
match self.kind {
500500
ConstArgKind::Struct(path, _) => path.span(),
501501
ConstArgKind::Path(path) => path.span(),
502+
ConstArgKind::TupleCall(path, _) => path.span(),
502503
ConstArgKind::Anon(anon) => anon.span,
503504
ConstArgKind::Error(span, _) => span,
504505
ConstArgKind::Infer(span, _) => span,
@@ -519,6 +520,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
519520
Anon(&'hir AnonConst),
520521
/// Represents construction of struct/struct variants
521522
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
523+
/// Tuple constructor variant
524+
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
522525
/// Error const
523526
Error(Span, ErrorGuaranteed),
524527
/// This variant is not always used to represent inference consts, sometimes

compiler/rustc_hir/src/intravisit.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
10901090

10911091
V::Result::output()
10921092
}
1093+
ConstArgKind::TupleCall(qpath, args) => {
1094+
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
1095+
for arg in *args {
1096+
try_visit!(visitor.visit_const_arg_unambig(*arg));
1097+
}
1098+
V::Result::output()
1099+
}
10931100
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
10941101
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
10951102
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ pub enum PermitVariants {
314314
enum TypeRelativePath<'tcx> {
315315
AssocItem(DefId, GenericArgsRef<'tcx>),
316316
Variant { adt: Ty<'tcx>, variant_did: DefId },
317+
Ctor { ctor_def_id: DefId, args: GenericArgsRef<'tcx> },
317318
}
318319

319320
/// New-typed boolean indicating whether explicit late-bound lifetimes
@@ -1375,6 +1376,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13751376
let adt = self.check_param_uses_if_mcg(adt, span, false);
13761377
Ok((adt, DefKind::Variant, variant_did))
13771378
}
1379+
TypeRelativePath::Ctor { .. } => {
1380+
let e = tcx.dcx().span_err(span, "expected type, found tuple constructor");
1381+
Err(e)
1382+
}
13781383
}
13791384
}
13801385

@@ -1410,6 +1415,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14101415
let ct = self.check_param_uses_if_mcg(ct, span, false);
14111416
Ok(ct)
14121417
}
1418+
TypeRelativePath::Ctor { ctor_def_id, args } => {
1419+
return Ok(ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, ctor_def_id, args)));
1420+
}
14131421
// FIXME(mgca): implement support for this once ready to support all adt ctor expressions,
14141422
// not just const ctors
14151423
TypeRelativePath::Variant { .. } => {
@@ -1441,6 +1449,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14411449
.iter()
14421450
.find(|vd| tcx.hygienic_eq(segment.ident, vd.ident(tcx), adt_def.did()));
14431451
if let Some(variant_def) = variant_def {
1452+
// FIXME(mgca): do we want constructor resolutions to take priority over
1453+
// other possible resolutions?
1454+
if matches!(mode, LowerTypeRelativePathMode::Const)
1455+
&& let Some((CtorKind::Fn, ctor_def_id)) = variant_def.ctor
1456+
{
1457+
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
1458+
let _ = self.prohibit_generic_args(
1459+
slice::from_ref(segment).iter(),
1460+
GenericsArgsErrExtend::EnumVariant {
1461+
qself: hir_self_ty,
1462+
assoc_segment: segment,
1463+
adt_def,
1464+
},
1465+
);
1466+
let ty::Adt(_, enum_args) = self_ty.kind() else { unreachable!() };
1467+
return Ok(TypeRelativePath::Ctor { ctor_def_id, args: enum_args });
1468+
}
14441469
if let PermitVariants::Yes = mode.permit_variants() {
14451470
tcx.check_stability(variant_def.def_id, Some(qpath_hir_id), span, None);
14461471
let _ = self.prohibit_generic_args(
@@ -2349,12 +2374,106 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23492374
hir::ConstArgKind::Struct(qpath, inits) => {
23502375
self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span())
23512376
}
2377+
hir::ConstArgKind::TupleCall(qpath, args) => {
2378+
self.lower_const_arg_tuple_call(hir_id, qpath, args, const_arg.span())
2379+
}
23522380
hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon),
23532381
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
23542382
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),
23552383
}
23562384
}
23572385

2386+
fn lower_const_arg_tuple_call(
2387+
&self,
2388+
hir_id: HirId,
2389+
qpath: hir::QPath<'tcx>,
2390+
args: &'tcx [&'tcx hir::ConstArg<'tcx>],
2391+
span: Span,
2392+
) -> Const<'tcx> {
2393+
let tcx = self.tcx();
2394+
2395+
let non_adt_or_variant_res = || {
2396+
let e = tcx.dcx().span_err(span, "tuple constructor with invalid base path");
2397+
ty::Const::new_error(tcx, e)
2398+
};
2399+
2400+
let ctor_const = match qpath {
2401+
hir::QPath::Resolved(maybe_qself, path) => {
2402+
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
2403+
self.lower_resolved_const_path(opt_self_ty, path, hir_id)
2404+
}
2405+
hir::QPath::TypeRelative(hir_self_ty, segment) => {
2406+
let self_ty = self.lower_ty(hir_self_ty);
2407+
match self.lower_type_relative_const_path(
2408+
self_ty,
2409+
hir_self_ty,
2410+
segment,
2411+
hir_id,
2412+
span,
2413+
) {
2414+
Ok(c) => c,
2415+
Err(_) => return non_adt_or_variant_res(),
2416+
}
2417+
}
2418+
};
2419+
2420+
let Some(value) = ctor_const.try_to_value() else {
2421+
return non_adt_or_variant_res();
2422+
};
2423+
2424+
let (adt_def, adt_args, variant_did) = match value.ty.kind() {
2425+
ty::FnDef(def_id, fn_args)
2426+
if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(*def_id) =>
2427+
{
2428+
let parent_did = tcx.parent(*def_id);
2429+
let enum_did = tcx.parent(parent_did);
2430+
(tcx.adt_def(enum_did), fn_args, parent_did)
2431+
}
2432+
ty::FnDef(def_id, fn_args)
2433+
if let DefKind::Ctor(CtorOf::Struct, _) = tcx.def_kind(*def_id) =>
2434+
{
2435+
let parent_did = tcx.parent(*def_id);
2436+
(tcx.adt_def(parent_did), fn_args, parent_did)
2437+
}
2438+
_ => return non_adt_or_variant_res(),
2439+
};
2440+
2441+
let variant_def = adt_def.variant_with_id(variant_did);
2442+
let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32();
2443+
2444+
if args.len() != variant_def.fields.len() {
2445+
let e = tcx.dcx().span_err(
2446+
span,
2447+
format!(
2448+
"tuple constructor has {} arguments but {} were provided",
2449+
variant_def.fields.len(),
2450+
args.len()
2451+
),
2452+
);
2453+
return ty::Const::new_error(tcx, e);
2454+
}
2455+
2456+
let fields = variant_def
2457+
.fields
2458+
.iter()
2459+
.zip(args)
2460+
.map(|(field_def, arg)| {
2461+
self.lower_const_arg(arg, FeedConstTy::Param(field_def.did, adt_args))
2462+
})
2463+
.collect::<Vec<_>>();
2464+
2465+
let opt_discr_const = if adt_def.is_enum() {
2466+
let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into());
2467+
Some(ty::Const::new_value(tcx, valtree, tcx.types.u32))
2468+
} else {
2469+
None
2470+
};
2471+
2472+
let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields));
2473+
let adt_ty = Ty::new_adt(tcx, adt_def, adt_args);
2474+
ty::Const::new_value(tcx, valtree, adt_ty)
2475+
}
2476+
23582477
fn lower_const_arg_struct(
23592478
&self,
23602479
hir_id: HirId,
@@ -2486,6 +2605,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
24862605
let args = self.lower_generic_args_of_path_segment(span, did, segment);
24872606
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
24882607
}
2608+
Res::Def(DefKind::Ctor(_, CtorKind::Fn), did) => {
2609+
assert_eq!(opt_self_ty, None);
2610+
let [leading_segments @ .., segment] = path.segments else { bug!() };
2611+
let _ = self
2612+
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
2613+
let parent_did = tcx.parent(did);
2614+
let generics_did = if let DefKind::Ctor(CtorOf::Variant, _) = tcx.def_kind(did) {
2615+
tcx.parent(parent_did)
2616+
} else {
2617+
parent_did
2618+
};
2619+
let args = self.lower_generic_args_of_path_segment(span, generics_did, segment);
2620+
ty::Const::zero_sized(tcx, Ty::new_fn_def(tcx, did, args))
2621+
}
24892622
Res::Def(DefKind::AssocConst, did) => {
24902623
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
24912624
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
@@ -2521,9 +2654,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
25212654
DefKind::Mod
25222655
| DefKind::Enum
25232656
| DefKind::Variant
2524-
| DefKind::Ctor(CtorOf::Variant, CtorKind::Fn)
25252657
| DefKind::Struct
2526-
| DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
25272658
| DefKind::OpaqueTy
25282659
| DefKind::TyAlias
25292660
| DefKind::TraitAlias

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ impl<'a> State<'a> {
11391139
match &const_arg.kind {
11401140
// FIXME(mgca): proper printing for struct exprs
11411141
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
1142+
ConstArgKind::TupleCall(..) => self.word("/* TUPLE CALL */"),
11421143
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
11431144
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
11441145
ConstArgKind::Error(_, _) => self.word("/*ERROR*/"),

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::TupleCall(..)
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::Call(..) => 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: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@ 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::TupleCall(..) => {
327+
ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() }
328+
}
326329
hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
327330
hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
328331
}
@@ -1804,7 +1807,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
18041807
let ct = cx.tcx.normalize_erasing_regions(typing_env, ct);
18051808
print_const(cx, ct)
18061809
}
1807-
hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => {
1810+
hir::ConstArgKind::Struct(..)
1811+
| hir::ConstArgKind::Path(..)
1812+
| hir::ConstArgKind::TupleCall(..) => {
18081813
let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No);
18091814
print_const(cx, ct)
18101815
}

src/tools/clippy/clippy_lints/src/utils/author.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
320320
self.body(field!(anon_const.body));
321321
},
322322
ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"),
323+
ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"),
323324
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
324325
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
325326
}

src/tools/clippy/clippy_utils/src/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
11401140
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
11411141
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
11421142
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
1143-
ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
1143+
ConstArgKind::Struct(..) | ConstArgKind::TupleCall(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
11441144
None
11451145
},
11461146
},

0 commit comments

Comments
 (0)