Skip to content

Commit 99d2269

Browse files
committed
Introduce hir::ConstArgKind::Struct
1 parent 4ddc687 commit 99d2269

File tree

12 files changed

+214
-24
lines changed

12 files changed

+214
-24
lines changed

compiler/rustc_ast_lowering/src/index.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
281281
});
282282
}
283283

284+
fn visit_const_arg_expr_field(&mut self, field: &'hir ConstArgExprField<'hir>) {
285+
self.insert(field.span, field.hir_id, Node::ConstArgExprField(field));
286+
self.with_parent(field.hir_id, |this| {
287+
intravisit::walk_const_arg_expr_field(this, field);
288+
})
289+
}
290+
284291
fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) {
285292
self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt));
286293

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,6 +2408,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
24082408

24092409
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
24102410
}
2411+
ExprKind::Struct(se) => {
2412+
let path = self.lower_qpath(
2413+
expr.id,
2414+
&se.qself,
2415+
&se.path,
2416+
// FIXME(mgca): we may want this to be `Optional` instead, but
2417+
// we would also need to make sure that HIR ty lowering errors
2418+
// when these paths wind up in signatures.
2419+
ParamMode::Explicit,
2420+
AllowReturnTypeNotation::No,
2421+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
2422+
None,
2423+
);
2424+
2425+
let fields = self.arena.alloc_from_iter(se.fields.iter().map(|f| {
2426+
let hir_id = self.lower_node_id(f.id);
2427+
// FIXME(mgca): This might result in lowering attributes that
2428+
// then go unused as the `Target::ExprField` is not actually
2429+
// corresponding to `Node::ExprField`.
2430+
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
2431+
2432+
let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind {
2433+
let def_id = self.local_def_id(anon_const.id);
2434+
let def_kind = self.tcx.def_kind(def_id);
2435+
assert_eq!(DefKind::AnonConst, def_kind);
2436+
2437+
self.lower_anon_const_to_const_arg_direct(anon_const)
2438+
} else {
2439+
self.lower_expr_to_const_arg_direct(&f.expr)
2440+
};
2441+
2442+
&*self.arena.alloc(hir::ConstArgExprField {
2443+
hir_id,
2444+
field: self.lower_ident(f.ident),
2445+
expr: self.arena.alloc(expr),
2446+
span: self.lower_span(f.span),
2447+
})
2448+
}));
2449+
2450+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) }
2451+
}
24112452
ExprKind::Underscore => ConstArg {
24122453
hir_id: self.lower_node_id(expr.id),
24132454
kind: hir::ConstArgKind::Infer(expr.span, ()),

compiler/rustc_hir/src/hir.rs

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

495495
pub fn span(&self) -> Span {
496496
match self.kind {
497+
ConstArgKind::Struct(path, _) => path.span(),
497498
ConstArgKind::Path(path) => path.span(),
498499
ConstArgKind::Anon(anon) => anon.span,
499500
ConstArgKind::Error(span, _) => span,
@@ -513,13 +514,23 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
513514
/// However, in the future, we'll be using it for all of those.
514515
Path(QPath<'hir>),
515516
Anon(&'hir AnonConst),
517+
/// Represents construction of struct/struct variants
518+
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
516519
/// Error const
517520
Error(Span, ErrorGuaranteed),
518521
/// This variant is not always used to represent inference consts, sometimes
519522
/// [`GenericArg::Infer`] is used instead.
520523
Infer(Span, Unambig),
521524
}
522525

526+
#[derive(Clone, Copy, Debug, HashStable_Generic)]
527+
pub struct ConstArgExprField<'hir> {
528+
pub hir_id: HirId,
529+
pub span: Span,
530+
pub field: Ident,
531+
pub expr: &'hir ConstArg<'hir>,
532+
}
533+
523534
#[derive(Clone, Copy, Debug, HashStable_Generic)]
524535
pub struct InferArg {
525536
#[stable_hasher(ignore)]
@@ -4714,6 +4725,7 @@ pub enum Node<'hir> {
47144725
ConstArg(&'hir ConstArg<'hir>),
47154726
Expr(&'hir Expr<'hir>),
47164727
ExprField(&'hir ExprField<'hir>),
4728+
ConstArgExprField(&'hir ConstArgExprField<'hir>),
47174729
Stmt(&'hir Stmt<'hir>),
47184730
PathSegment(&'hir PathSegment<'hir>),
47194731
Ty(&'hir Ty<'hir>),
@@ -4773,6 +4785,7 @@ impl<'hir> Node<'hir> {
47734785
Node::AssocItemConstraint(c) => Some(c.ident),
47744786
Node::PatField(f) => Some(f.ident),
47754787
Node::ExprField(f) => Some(f.ident),
4788+
Node::ConstArgExprField(f) => Some(f.field),
47764789
Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident),
47774790
Node::Param(..)
47784791
| Node::AnonConst(..)

compiler/rustc_hir/src/intravisit.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ pub trait Visitor<'v>: Sized {
396396
fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result {
397397
walk_expr_field(self, field)
398398
}
399+
fn visit_const_arg_expr_field(&mut self, field: &'v ConstArgExprField<'v>) -> Self::Result {
400+
walk_const_arg_expr_field(self, field)
401+
}
399402
fn visit_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result {
400403
walk_ty_pat(self, p)
401404
}
@@ -954,6 +957,17 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField
954957
try_visit!(visitor.visit_ident(*ident));
955958
visitor.visit_expr(*expr)
956959
}
960+
961+
pub fn walk_const_arg_expr_field<'v, V: Visitor<'v>>(
962+
visitor: &mut V,
963+
field: &'v ConstArgExprField<'v>,
964+
) -> V::Result {
965+
let ConstArgExprField { hir_id, field, expr, span: _ } = field;
966+
try_visit!(visitor.visit_id(*hir_id));
967+
try_visit!(visitor.visit_ident(*field));
968+
visitor.visit_const_arg_unambig(*expr)
969+
}
970+
957971
/// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that
958972
/// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited
959973
pub enum InferKind<'hir> {
@@ -1068,6 +1082,15 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
10681082
let ConstArg { hir_id, kind } = const_arg;
10691083
try_visit!(visitor.visit_id(*hir_id));
10701084
match kind {
1085+
ConstArgKind::Struct(qpath, field_exprs) => {
1086+
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
1087+
1088+
for field_expr in *field_exprs {
1089+
try_visit!(visitor.visit_const_arg_expr_field(field_expr));
1090+
}
1091+
1092+
V::Result::output()
1093+
}
10711094
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()),
10721095
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
10731096
ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2263,6 +2263,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
22632263
)
22642264
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
22652265
}
2266+
hir::ConstArgKind::Struct(..) => {
2267+
span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg)
2268+
}
22662269
hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon),
22672270
hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span),
22682271
hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e),

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ impl<'a> State<'a> {
180180
Node::ConstArg(a) => self.print_const_arg(a),
181181
Node::Expr(a) => self.print_expr(a),
182182
Node::ExprField(a) => self.print_expr_field(a),
183+
// FIXME(mgca): proper printing for struct exprs
184+
Node::ConstArgExprField(_) => self.word("/* STRUCT EXPR */"),
183185
Node::Stmt(a) => self.print_stmt(a),
184186
Node::PathSegment(a) => self.print_path_segment(a),
185187
Node::Ty(a) => self.print_type(a),
@@ -1135,6 +1137,8 @@ impl<'a> State<'a> {
11351137

11361138
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
11371139
match &const_arg.kind {
1140+
// FIXME(mgca): proper printing for struct exprs
1141+
ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"),
11381142
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
11391143
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
11401144
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
@@ -1444,6 +1444,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14441444
hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind {
14451445
// Skip encoding defs for these as they should not have had a `DefId` created
14461446
hir::ConstArgKind::Error(..)
1447+
| hir::ConstArgKind::Struct(..)
14471448
| hir::ConstArgKind::Path(..)
14481449
| hir::ConstArgKind::Infer(..) => true,
14491450
hir::ConstArgKind::Anon(..) => false,

compiler/rustc_middle/src/hir/map.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ impl<'tcx> TyCtxt<'tcx> {
739739
Node::ConstArg(_) => node_str("const"),
740740
Node::Expr(_) => node_str("expr"),
741741
Node::ExprField(_) => node_str("expr field"),
742+
Node::ConstArgExprField(_) => node_str("const arg expr field"),
742743
Node::Stmt(_) => node_str("stmt"),
743744
Node::PathSegment(_) => node_str("path segment"),
744745
Node::Ty(_) => node_str("type"),
@@ -1007,6 +1008,7 @@ impl<'tcx> TyCtxt<'tcx> {
10071008
Node::ConstArg(const_arg) => const_arg.span(),
10081009
Node::Expr(expr) => expr.span,
10091010
Node::ExprField(field) => field.span,
1011+
Node::ConstArgExprField(field) => field.span,
10101012
Node::Stmt(stmt) => stmt.span,
10111013
Node::PathSegment(seg) => {
10121014
let ident_span = seg.ident.span;

compiler/rustc_middle/src/hir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ impl<'tcx> TyCtxt<'tcx> {
359359
| Node::Infer(_)
360360
| Node::WherePredicate(_)
361361
| Node::PreciseCapturingNonLifetimeArg(_)
362+
| Node::ConstArgExprField(_)
362363
| Node::OpaqueTy(_) => {
363364
unreachable!("no sub-expr expected for {parent_node:?}")
364365
}

compiler/rustc_resolve/src/def_collector.rs

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ use rustc_hir::def_id::LocalDefId;
1111
use rustc_middle::span_bug;
1212
use rustc_span::hygiene::LocalExpnId;
1313
use rustc_span::{Span, Symbol, sym};
14-
use tracing::debug;
14+
use tracing::{debug, instrument};
1515

16-
use crate::{ImplTraitContext, InvocationParent, Resolver};
16+
use crate::{ConstArgContext, ImplTraitContext, InvocationParent, Resolver};
1717

1818
pub(crate) fn collect_definitions(
1919
resolver: &mut Resolver<'_, '_>,
2020
fragment: &AstFragment,
2121
expansion: LocalExpnId,
2222
) {
2323
let invocation_parent = resolver.invocation_parents[&expansion];
24+
debug!("new fragment to visit with invocation_parent: {invocation_parent:?}");
2425
let mut visitor = DefCollector { resolver, expansion, invocation_parent };
2526
fragment.visit_with(&mut visitor);
2627
}
@@ -74,6 +75,12 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
7475
self.invocation_parent.impl_trait_context = orig_itc;
7576
}
7677

78+
fn with_const_arg<F: FnOnce(&mut Self)>(&mut self, ctxt: ConstArgContext, f: F) {
79+
let orig = mem::replace(&mut self.invocation_parent.const_arg_context, ctxt);
80+
f(self);
81+
self.invocation_parent.const_arg_context = orig;
82+
}
83+
7784
fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) {
7885
let index = |this: &Self| {
7986
index.unwrap_or_else(|| {
@@ -93,7 +100,10 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
93100
}
94101
}
95102

103+
#[instrument(level = "debug", skip(self))]
96104
fn visit_macro_invoc(&mut self, id: NodeId) {
105+
debug!(?self.invocation_parent);
106+
97107
let id = id.placeholder_to_expn_id();
98108
let old_parent = self.resolver.invocation_parents.insert(id, self.invocation_parent);
99109
assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation");
@@ -357,39 +367,84 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
357367
}
358368

359369
fn visit_anon_const(&mut self, constant: &'a AnonConst) {
360-
// `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so
361-
// to avoid affecting stable we have to feature gate the not creating
362-
// anon consts
363-
if let MgcaDisambiguation::Direct = constant.mgca_disambiguation
364-
&& self.resolver.tcx.features().min_generic_const_args()
365-
{
366-
visit::walk_anon_const(self, constant);
367-
return;
368-
}
369-
370-
let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
371-
self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
370+
match constant.mgca_disambiguation {
371+
// `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so
372+
// to avoid affecting stable we have to feature gate the not creating
373+
// anon consts
374+
_ if !self.resolver.tcx.features().min_generic_const_args() => {
375+
let parent =
376+
self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
377+
self.with_parent(parent, |this| visit::walk_anon_const(this, constant));
378+
}
379+
MgcaDisambiguation::Direct => self.with_const_arg(ConstArgContext::Direct, |this| {
380+
visit::walk_anon_const(this, constant);
381+
}),
382+
MgcaDisambiguation::AnonConst => {
383+
self.with_const_arg(ConstArgContext::NonDirect, |this| {
384+
let parent =
385+
this.create_def(constant.id, None, DefKind::AnonConst, constant.value.span);
386+
this.with_parent(parent, |this| visit::walk_anon_const(this, constant));
387+
})
388+
}
389+
};
372390
}
373391

392+
#[instrument(level = "debug", skip(self))]
374393
fn visit_expr(&mut self, expr: &'a Expr) {
375-
let parent_def = match expr.kind {
394+
debug!(?self.invocation_parent);
395+
396+
let parent_def = match &expr.kind {
376397
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
377398
ExprKind::Closure(..) | ExprKind::Gen(..) => {
378399
self.create_def(expr.id, None, DefKind::Closure, expr.span)
379400
}
380-
ExprKind::ConstBlock(ref constant) => {
381-
for attr in &expr.attrs {
382-
visit::walk_attribute(self, attr);
401+
ExprKind::ConstBlock(constant) => {
402+
// Under `min_generic_const_args` a `const { }` block sometimes
403+
// corresponds to an anon const rather than an inline const.
404+
let def_kind = match self.invocation_parent.const_arg_context {
405+
ConstArgContext::Direct => DefKind::AnonConst,
406+
ConstArgContext::NonDirect => DefKind::InlineConst,
407+
};
408+
409+
return self.with_const_arg(ConstArgContext::NonDirect, |this| {
410+
for attr in &expr.attrs {
411+
visit::walk_attribute(this, attr);
412+
}
413+
414+
let def = this.create_def(constant.id, None, def_kind, constant.value.span);
415+
this.with_parent(def, |this| visit::walk_anon_const(this, constant));
416+
});
417+
}
418+
419+
// Avoid overwriting `const_arg_context` as we may want to treat const blocks
420+
// as being anon consts if we are inside a const argument.
421+
ExprKind::Struct(_) => return visit::walk_expr(self, expr),
422+
// FIXME(mgca): we may want to handle block labels in some manner
423+
ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind {
424+
StmtKind::Let(..) | StmtKind::Item(..) | StmtKind::Semi(..) | StmtKind::Empty => {
425+
return self.with_const_arg(ConstArgContext::NonDirect, |this| {
426+
visit::walk_expr(this, expr)
427+
});
428+
}
429+
430+
// FIXME(mgca): this probably means that mac calls that expand
431+
// to semi'd const blocks are handled differently to just writing
432+
// out a semi'd const block.
433+
StmtKind::Expr(..) | StmtKind::MacCall(..) => {
434+
return visit::walk_expr(self, expr);
383435
}
384-
let def =
385-
self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span);
386-
self.with_parent(def, |this| visit::walk_anon_const(this, constant));
387-
return;
436+
},
437+
438+
_ => {
439+
return self.with_const_arg(ConstArgContext::NonDirect, |this| {
440+
visit::walk_expr(this, expr)
441+
});
388442
}
389-
_ => self.invocation_parent.parent_def,
390443
};
391444

392-
self.with_parent(parent_def, |this| visit::walk_expr(this, expr))
445+
self.with_const_arg(ConstArgContext::NonDirect, |this| {
446+
this.with_parent(parent_def, |this| visit::walk_expr(this, expr))
447+
})
393448
}
394449

395450
fn visit_ty(&mut self, ty: &'a Ty) {

0 commit comments

Comments
 (0)