Skip to content

Commit 04fd5fd

Browse files
first draft of init array syntax
This patch allows parsing of the syntax `init [ v1, v2, v3, .. ]` and certain level of type checking on HIR level. Signed-off-by: Xiangfei Ding <[email protected]>
1 parent 6b3ae3f commit 04fd5fd

File tree

146 files changed

+1624
-255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

146 files changed

+1624
-255
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,9 @@ impl Expr {
14741474
}
14751475
}
14761476

1477+
ExprKind::InitBlock(..) => ExprPrecedence::Jump,
1478+
ExprKind::InitTail(..) => ExprPrecedence::Jump,
1479+
14771480
ExprKind::Break(_ /*label*/, value)
14781481
| ExprKind::Ret(value)
14791482
| ExprKind::Yield(YieldKind::Prefix(value))
@@ -1595,6 +1598,19 @@ pub struct Closure {
15951598
pub fn_arg_span: Span,
15961599
}
15971600

1601+
#[derive(Clone, Encodable, Decodable, Debug)]
1602+
pub struct InitBlock {
1603+
pub init_kw_span: Span,
1604+
pub expr: P<Expr>,
1605+
pub fn_decl: P<FnDecl>,
1606+
}
1607+
1608+
#[derive(Clone, Encodable, Decodable, Debug)]
1609+
pub enum InitKind {
1610+
Free(P<Expr>),
1611+
Array(ThinVec<P<Expr>>),
1612+
}
1613+
15981614
/// Limit types of a range (inclusive or exclusive).
15991615
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
16001616
pub enum RangeLimits {
@@ -1712,6 +1728,10 @@ pub enum ExprKind {
17121728
Match(P<Expr>, ThinVec<Arm>, MatchKind),
17131729
/// A closure (e.g., `move |a, b, c| a + b + c`).
17141730
Closure(Box<Closure>),
1731+
/// An `init` block
1732+
InitBlock(P<InitBlock>),
1733+
/// An in-place initialization at the tail position of an `init` block
1734+
InitTail(P<InitKind>),
17151735
/// A block (`'label: { ... }`).
17161736
Block(P<Block>, Option<Label>),
17171737
/// An `async` block (`async move { ... }`),

compiler/rustc_ast/src/util/classify.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
128128
| Become(..)
129129
| Break(..)
130130
| Closure(..)
131+
| InitBlock(..)
132+
| InitTail(..)
131133
| ConstBlock(..)
132134
| Continue(..)
133135
| FormatArgs(..)
@@ -230,6 +232,8 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
230232
| Use(_, _)
231233
| Field(_, _)
232234
| Index(_, _, _)
235+
| InitBlock(_)
236+
| InitTail(_)
233237
| Underscore
234238
| Path(_, _)
235239
| Continue(_)

compiler/rustc_ast/src/visit.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,6 +1750,19 @@ macro_rules! common_visitor_and_walkers {
17501750
try_visit!(visit_span(vis, fn_decl_span));
17511751
try_visit!(visit_span(vis, fn_arg_span));
17521752
}
1753+
ExprKind::InitBlock(expr) => {
1754+
try_visit!(vis.visit_fn(
1755+
FnKind::Closure(&$($mut)?ClosureBinder::NotPresent, &$($mut)?None, &$($mut)?expr.fn_decl, &$($mut)?expr.expr),
1756+
*span,
1757+
*id,
1758+
));
1759+
}
1760+
ExprKind::InitTail(tail) => {
1761+
match **tail {
1762+
InitKind::Free(ref $($mut)? expr) => try_visit!(vis.visit_expr(expr)),
1763+
InitKind::Array(ref $($mut)? exprs) => try_visit!(visit_exprs(vis, exprs)),
1764+
}
1765+
}
17531766
ExprKind::Block(block, opt_label) => {
17541767
visit_opt!(vis, visit_label, opt_label);
17551768
try_visit!(vis.visit_block(block));

compiler/rustc_ast_lowering/src/block.rs

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -26,61 +26,81 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
2626
hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
2727
}
2828

29-
fn lower_stmts(
29+
fn lower_one_stmt(
3030
&mut self,
31-
mut ast_stmts: &[Stmt],
32-
) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
33-
let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
34-
let mut expr = None;
35-
while let [s, tail @ ..] = ast_stmts {
36-
match &s.kind {
37-
StmtKind::Let(local) => {
38-
let hir_id = self.lower_node_id(s.id);
39-
let local = self.lower_local(local);
40-
self.alias_attrs(hir_id, local.hir_id);
41-
let kind = hir::StmtKind::Let(local);
42-
let span = self.lower_span(s.span);
43-
stmts.push(hir::Stmt { hir_id, kind, span });
44-
}
45-
StmtKind::Item(it) => {
46-
stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
47-
|(i, item_id)| {
48-
let hir_id = match i {
49-
0 => self.lower_node_id(s.id),
50-
_ => self.next_id(),
51-
};
52-
let kind = hir::StmtKind::Item(item_id);
53-
let span = self.lower_span(s.span);
54-
hir::Stmt { hir_id, kind, span }
55-
},
56-
));
57-
}
58-
StmtKind::Expr(e) => {
59-
let e = self.lower_expr(e);
60-
if tail.is_empty() {
61-
expr = Some(e);
62-
} else {
63-
let hir_id = self.lower_node_id(s.id);
64-
self.alias_attrs(hir_id, e.hir_id);
65-
let kind = hir::StmtKind::Expr(e);
31+
s: &Stmt,
32+
at_tail: Option<&mut Option<&'hir hir::Expr<'hir>>>,
33+
hir_stmts: &mut impl Extend<hir::Stmt<'hir>>,
34+
) {
35+
match &s.kind {
36+
StmtKind::Let(local) => {
37+
let hir_id = self.lower_node_id(s.id);
38+
let local = self.lower_local(local);
39+
self.alias_attrs(hir_id, local.hir_id);
40+
let kind = hir::StmtKind::Let(local);
41+
let span = self.lower_span(s.span);
42+
hir_stmts.extend([hir::Stmt { hir_id, kind, span }]);
43+
}
44+
StmtKind::Item(it) => {
45+
hir_stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
46+
|(i, item_id)| {
47+
let hir_id = match i {
48+
0 => self.lower_node_id(s.id),
49+
_ => self.next_id(),
50+
};
51+
let kind = hir::StmtKind::Item(item_id);
6652
let span = self.lower_span(s.span);
67-
stmts.push(hir::Stmt { hir_id, kind, span });
68-
}
69-
}
70-
StmtKind::Semi(e) => {
53+
hir::Stmt { hir_id, kind, span }
54+
},
55+
));
56+
}
57+
StmtKind::Expr(e) => {
58+
if let Some(expr) = at_tail {
59+
let e = if self.is_in_init_tail {
60+
let hir_id = self.lower_node_id(s.id);
61+
let kind = self.lower_implicit_init_tail(e);
62+
self.arena.alloc(hir::Expr { hir_id, kind, span: s.span })
63+
} else {
64+
self.lower_expr(e)
65+
};
66+
*expr = Some(e);
67+
} else {
7168
let e = self.lower_expr(e);
7269
let hir_id = self.lower_node_id(s.id);
7370
self.alias_attrs(hir_id, e.hir_id);
74-
let kind = hir::StmtKind::Semi(e);
71+
let kind = hir::StmtKind::Expr(e);
7572
let span = self.lower_span(s.span);
76-
stmts.push(hir::Stmt { hir_id, kind, span });
73+
hir_stmts.extend([hir::Stmt { hir_id, kind, span }]);
7774
}
78-
StmtKind::Empty => {}
79-
StmtKind::MacCall(..) => panic!("shouldn't exist here"),
8075
}
81-
ast_stmts = tail;
76+
StmtKind::Semi(e) => {
77+
let e = self.lower_expr(e);
78+
let hir_id = self.lower_node_id(s.id);
79+
self.alias_attrs(hir_id, e.hir_id);
80+
let kind = hir::StmtKind::Semi(e);
81+
let span = self.lower_span(s.span);
82+
hir_stmts.extend([hir::Stmt { hir_id, kind, span }]);
83+
}
84+
StmtKind::Empty => {}
85+
StmtKind::MacCall(..) => panic!("shouldn't exist here"),
86+
}
87+
}
88+
89+
fn lower_stmts(
90+
&mut self,
91+
ast_stmts: &[Stmt],
92+
) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
93+
let mut hir_stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
94+
let mut expr = None;
95+
if let [stmts @ .., tail] = ast_stmts {
96+
self.enter_non_init_tail_lowering(|this| {
97+
for s in stmts {
98+
this.lower_one_stmt(s, None, &mut hir_stmts);
99+
}
100+
});
101+
self.lower_one_stmt(tail, Some(&mut expr), &mut hir_stmts);
82102
}
83-
(self.arena.alloc_from_iter(stmts), expr)
103+
(self.arena.alloc_from_iter(hir_stmts), expr)
84104
}
85105

86106
/// Return an `ImplTraitContext` that allows impl trait in bindings if

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
244244
*fn_arg_span,
245245
),
246246
},
247+
ExprKind::InitBlock(block) => self.lower_expr_init_block(
248+
e.id,
249+
block.init_kw_span,
250+
&block.fn_decl,
251+
&block.expr,
252+
),
253+
ExprKind::InitTail(kind) => self.lower_expr_init_tail(kind),
247254
ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => {
248255
let desugaring_kind = match genblock_kind {
249256
GenBlockKind::Async => hir::CoroutineDesugaring::Async,
@@ -1250,6 +1257,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
12501257
hir::ExprKind::Closure(c)
12511258
}
12521259

1260+
fn lower_expr_init_block(
1261+
&mut self,
1262+
init_id: NodeId,
1263+
init_kw_span: Span,
1264+
fn_decl: &FnDecl,
1265+
body: &Expr,
1266+
) -> hir::ExprKind<'hir> {
1267+
let def_id = self.local_def_id(init_id);
1268+
1269+
let body_id = self.with_new_scopes(body.span, move |this| {
1270+
this.enter_init_tail_lowering(|this| {
1271+
this.lower_fn_body(fn_decl, None, |this| this.lower_expr_mut(body))
1272+
})
1273+
});
1274+
let block = self.arena.alloc(hir::InitBlock {
1275+
def_id,
1276+
body: body_id,
1277+
init_kw_span,
1278+
fn_decl: self.arena.alloc(hir::FnDecl {
1279+
inputs: &[],
1280+
output: hir::FnRetTy::DefaultReturn(body.span),
1281+
c_variadic: false,
1282+
implicit_self: hir::ImplicitSelfKind::None,
1283+
lifetime_elision_allowed: false,
1284+
}),
1285+
});
1286+
hir::ExprKind::InitBlock(block)
1287+
}
1288+
12531289
/// Destructure the LHS of complex assignments.
12541290
/// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.
12551291
fn lower_expr_assign(
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use rustc_ast::ptr::P as AstP;
2+
use rustc_ast::*;
3+
use rustc_hir as hir;
4+
5+
use super::LoweringContext;
6+
7+
impl<'hir> LoweringContext<'_, 'hir> {
8+
pub(crate) fn lower_free_expr_init_tail(&mut self, expr: &Expr) -> hir::ExprKind<'hir> {
9+
if let ExprKind::Block(block, label) = &expr.kind {
10+
self.lower_block_init_tail(block, *label)
11+
} else {
12+
let expr = self.lower_expr(expr);
13+
hir::ExprKind::InitTail(self.arena.alloc(hir::InitKind::Free(expr)))
14+
}
15+
}
16+
17+
/// This lower machine transforms a block expression within a in-place initialisation context
18+
pub(crate) fn lower_block_init_tail(
19+
&mut self,
20+
block: &Block,
21+
label: Option<Label>,
22+
) -> hir::ExprKind<'hir> {
23+
let block = self.enter_init_tail_lowering(|this| this.lower_block(block, false));
24+
hir::ExprKind::InitTail(self.arena.alloc(hir::InitKind::Block(block, label)))
25+
}
26+
27+
pub(crate) fn lower_implicit_init_tail(&mut self, expr: &Expr) -> hir::ExprKind<'hir> {
28+
match &expr.kind {
29+
ExprKind::Block(block, label) => self.lower_block_init_tail(block, *label),
30+
ExprKind::Array(exprs) => self.lower_array_init_tail(&exprs[..]),
31+
ExprKind::Struct(_) | ExprKind::Repeat(_, _) | ExprKind::Call(_, _) => {
32+
todo!(
33+
"pinit: these are cases we still need to implement,
34+
especially Call *must* be lowered to a `struct` init tail expr,
35+
and block-style `struct` supports non-member fields so that computation
36+
and initialisation can interleave"
37+
)
38+
}
39+
_ => self.lower_free_expr_init_tail(expr),
40+
}
41+
}
42+
43+
pub(crate) fn lower_array_init_tail(&mut self, exprs: &[AstP<Expr>]) -> hir::ExprKind<'hir> {
44+
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
45+
let hir_id = self.next_id();
46+
let span = expr.span;
47+
self.lower_attrs(hir_id, &expr.attrs, span);
48+
let kind = self.lower_implicit_init_tail(expr);
49+
hir::Expr { hir_id, kind, span }
50+
}));
51+
hir::ExprKind::InitTail(self.arena.alloc(hir::InitKind::Array(exprs)))
52+
}
53+
54+
pub(crate) fn lower_expr_init_tail(&mut self, kind: &InitKind) -> hir::ExprKind<'hir> {
55+
match kind {
56+
InitKind::Free(expr) => self.lower_free_expr_init_tail(expr),
57+
InitKind::Array(exprs) => self.lower_array_init_tail(exprs),
58+
}
59+
}
60+
}

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ mod errors;
8282
mod expr;
8383
mod format;
8484
mod index;
85+
mod init;
8586
mod item;
8687
mod pat;
8788
mod path;
@@ -120,6 +121,7 @@ struct LoweringContext<'a, 'hir> {
120121
catch_scope: Option<HirId>,
121122
loop_scope: Option<HirId>,
122123
is_in_loop_condition: bool,
124+
is_in_init_tail: bool,
123125
is_in_dyn_type: bool,
124126

125127
current_hir_id_owner: hir::OwnerId,
@@ -173,6 +175,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
173175
catch_scope: None,
174176
loop_scope: None,
175177
is_in_loop_condition: false,
178+
is_in_init_tail: false,
176179
is_in_dyn_type: false,
177180
coroutine_kind: None,
178181
task_context: None,
@@ -886,27 +889,50 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
886889
fn with_new_scopes<T>(&mut self, scope_span: Span, f: impl FnOnce(&mut Self) -> T) -> T {
887890
let current_item = self.current_item;
888891
self.current_item = Some(scope_span);
889-
892+
let was_in_init_tail = self.is_in_init_tail;
893+
self.is_in_init_tail = false;
890894
let was_in_loop_condition = self.is_in_loop_condition;
891895
self.is_in_loop_condition = false;
892896

893897
let old_contract = self.contract_ensures.take();
894898

895899
let catch_scope = self.catch_scope.take();
896900
let loop_scope = self.loop_scope.take();
901+
897902
let ret = f(self);
903+
898904
self.catch_scope = catch_scope;
899905
self.loop_scope = loop_scope;
900-
901906
self.contract_ensures = old_contract;
902-
907+
self.is_in_init_tail = was_in_init_tail;
903908
self.is_in_loop_condition = was_in_loop_condition;
904-
905909
self.current_item = current_item;
906910

907911
ret
908912
}
909913

914+
/// Signal from the lowering context that the tail value of a current block
915+
/// should be in-place initialised and should be lowered as an `init` tail.
916+
#[inline]
917+
fn enter_init_tail_lowering<T>(&mut self, lowering: impl FnOnce(&mut Self) -> T) -> T {
918+
let was_in_init_tail = self.is_in_init_tail;
919+
self.is_in_init_tail = true;
920+
let ret = lowering(self);
921+
self.is_in_init_tail = was_in_init_tail;
922+
ret
923+
}
924+
925+
/// Signal from the lowering context that blocks in statements of a current block
926+
/// shall not be in-place initialised.
927+
#[inline]
928+
fn enter_non_init_tail_lowering<T>(&mut self, lowering: impl FnOnce(&mut Self) -> T) -> T {
929+
let was_in_init_tail = self.is_in_init_tail;
930+
self.is_in_init_tail = false;
931+
let ret = lowering(self);
932+
self.is_in_init_tail = was_in_init_tail;
933+
ret
934+
}
935+
910936
fn lower_attrs(
911937
&mut self,
912938
id: HirId,

0 commit comments

Comments
 (0)