Skip to content

Commit 6c3d391

Browse files
committed
Auto merge of #64508 - Centril:or-pat-hir, r=matthewjasper
or-patterns: Push `PatKind/PatternKind::Or` at top level to HIR & HAIR Following up on work in #64111, #63693, and #61708, in this PR: - We change `hair::Arm.patterns: Vec<Pattern<'_>>` into `hir::Arm.pattern: Pattern<'_>`. - `fn hair::Arm::top_pats_hack` is introduced as a temporary crutch in MIR building to avoid more changes. - We change `hir::Arm.pats: HirVec<P<Pat>>` into `hir::Arm.pat: P<Pat>`. - The hacks in `rustc::hir::lowering` are removed since the representation hack is no longer necessary. - In some places, `fn hir::Arm::top_pats_hack` is introduced to leave some things as future work. - Misc changes: HIR pretty printing is adjusted to behave uniformly wrt. top/inner levels, rvalue promotion is adjusted, regionck, and dead_code is also. - Type checking is adjusted to uniformly handle or-patterns at top/inner levels. To make things compile, `p_0 | ... | p_n` is redefined as a "reference pattern" in [`fn is_non_ref_pat`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_typeck/check/struct.FnCtxt.html#method.is_non_ref_pat) for now. This is done so that reference types are not eagerly stripped from the `expected: Ty<'tcx>`. - Liveness is adjusted wrt. the `unused_variables` and `unused_assignments` lints to handle top/inner levels uniformly and the handling of `fn` parameters, `let` locals, and `match` arms are unified in this respect. This is not tested for now as exhaustiveness checks are reachable and will ICE. - In `check_match`, checking `@` and by-move bindings is adjusted. However, exhaustiveness checking is not adjusted the moment and is handled by @dlrobertson in #63688. - AST borrowck (`construct.rs`) is not adjusted as AST borrowck will be removed soon. r? @matthewjasper cc @dlrobertson @varkor @oli-obk
2 parents 66bf391 + 0918dc4 commit 6c3d391

File tree

22 files changed

+373
-485
lines changed

22 files changed

+373
-485
lines changed

src/librustc/hir/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
11031103

11041104
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
11051105
visitor.visit_id(arm.hir_id);
1106-
walk_list!(visitor, visit_pat, &arm.pats);
1106+
visitor.visit_pat(&arm.pat);
11071107
if let Some(ref g) = arm.guard {
11081108
match g {
11091109
Guard::If(ref e) => visitor.visit_expr(e),

src/librustc/hir/lowering.rs

-29
Original file line numberDiff line numberDiff line change
@@ -434,35 +434,6 @@ impl<'a> LoweringContext<'a> {
434434
visit::walk_pat(self, p)
435435
}
436436

437-
// HACK(or_patterns; Centril | dlrobertson): Avoid creating
438-
// HIR nodes for `PatKind::Or` for the top level of a `ast::Arm`.
439-
// This is a temporary hack that should go away once we push down
440-
// `arm.pats: HirVec<P<Pat>>` -> `arm.pat: P<Pat>` to HIR. // Centril
441-
fn visit_arm(&mut self, arm: &'tcx Arm) {
442-
match &arm.pat.node {
443-
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
444-
_ => self.visit_pat(&arm.pat),
445-
}
446-
walk_list!(self, visit_expr, &arm.guard);
447-
self.visit_expr(&arm.body);
448-
walk_list!(self, visit_attribute, &arm.attrs);
449-
}
450-
451-
// HACK(or_patterns; Centril | dlrobertson): Same as above. // Centril
452-
fn visit_expr(&mut self, e: &'tcx Expr) {
453-
if let ExprKind::Let(pat, scrutinee) = &e.node {
454-
walk_list!(self, visit_attribute, e.attrs.iter());
455-
match &pat.node {
456-
PatKind::Or(pats) => pats.iter().for_each(|p| self.visit_pat(p)),
457-
_ => self.visit_pat(&pat),
458-
}
459-
self.visit_expr(scrutinee);
460-
self.visit_expr_post(e);
461-
return;
462-
}
463-
visit::walk_expr(self, e)
464-
}
465-
466437
fn visit_item(&mut self, item: &'tcx Item) {
467438
let hir_id = self.lctx.allocate_hir_id_counter(item.id);
468439

src/librustc/hir/lowering/expr.rs

+19-32
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,14 @@ impl LoweringContext<'_> {
247247
// 4. The return type of the block is `bool` which seems like what the user wanted.
248248
let scrutinee = self.lower_expr(scrutinee);
249249
let then_arm = {
250-
let pat = self.lower_pat_top_hack(pat);
250+
let pat = self.lower_pat(pat);
251251
let expr = self.expr_bool(span, true);
252252
self.arm(pat, P(expr))
253253
};
254254
let else_arm = {
255255
let pat = self.pat_wild(span);
256256
let expr = self.expr_bool(span, false);
257-
self.arm(hir_vec![pat], P(expr))
257+
self.arm(pat, P(expr))
258258
};
259259
hir::ExprKind::Match(
260260
P(scrutinee),
@@ -278,15 +278,15 @@ impl LoweringContext<'_> {
278278
None => (self.expr_block_empty(span), false),
279279
Some(els) => (self.lower_expr(els), true),
280280
};
281-
let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
281+
let else_arm = self.arm(else_pat, P(else_expr));
282282

283283
// Handle then + scrutinee:
284284
let then_expr = self.lower_block_expr(then);
285285
let (then_pat, scrutinee, desugar) = match cond.node {
286286
// `<pat> => <then>`:
287287
ExprKind::Let(ref pat, ref scrutinee) => {
288288
let scrutinee = self.lower_expr(scrutinee);
289-
let pat = self.lower_pat_top_hack(pat);
289+
let pat = self.lower_pat(pat);
290290
(pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause })
291291
}
292292
// `true => <then>`:
@@ -303,7 +303,7 @@ impl LoweringContext<'_> {
303303
// let temporaries live outside of `cond`.
304304
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
305305
let pat = self.pat_bool(span, true);
306-
(hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause })
306+
(pat, cond, hir::MatchSource::IfDesugar { contains_else_clause })
307307
}
308308
};
309309
let then_arm = self.arm(then_pat, P(then_expr));
@@ -327,7 +327,7 @@ impl LoweringContext<'_> {
327327
let else_arm = {
328328
let else_pat = self.pat_wild(span);
329329
let else_expr = self.expr_break(span, ThinVec::new());
330-
self.arm(hir_vec![else_pat], else_expr)
330+
self.arm(else_pat, else_expr)
331331
};
332332

333333
// Handle then + scrutinee:
@@ -343,7 +343,7 @@ impl LoweringContext<'_> {
343343
// }
344344
// }
345345
let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
346-
let pat = self.lower_pat_top_hack(pat);
346+
let pat = self.lower_pat(pat);
347347
(pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
348348
}
349349
_ => {
@@ -371,7 +371,7 @@ impl LoweringContext<'_> {
371371
let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
372372
// `true => <then>`:
373373
let pat = self.pat_bool(span, true);
374-
(hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
374+
(pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
375375
}
376376
};
377377
let then_arm = self.arm(then_pat, P(then_expr));
@@ -424,7 +424,7 @@ impl LoweringContext<'_> {
424424
hir::Arm {
425425
hir_id: self.next_id(),
426426
attrs: self.lower_attrs(&arm.attrs),
427-
pats: self.lower_pat_top_hack(&arm.pat),
427+
pat: self.lower_pat(&arm.pat),
428428
guard: match arm.guard {
429429
Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))),
430430
_ => None,
@@ -434,16 +434,6 @@ impl LoweringContext<'_> {
434434
}
435435
}
436436

437-
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
438-
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
439-
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
440-
fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec<P<hir::Pat>> {
441-
match pat.node {
442-
PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(),
443-
_ => hir_vec![self.lower_pat(pat)],
444-
}
445-
}
446-
447437
pub(super) fn make_async_expr(
448438
&mut self,
449439
capture_clause: CaptureBy,
@@ -592,7 +582,7 @@ impl LoweringContext<'_> {
592582
);
593583
P(this.expr(await_span, expr_break, ThinVec::new()))
594584
});
595-
self.arm(hir_vec![ready_pat], break_x)
585+
self.arm(ready_pat, break_x)
596586
};
597587

598588
// `::std::task::Poll::Pending => {}`
@@ -603,7 +593,7 @@ impl LoweringContext<'_> {
603593
hir_vec![],
604594
);
605595
let empty_block = P(self.expr_block_empty(span));
606-
self.arm(hir_vec![pending_pat], empty_block)
596+
self.arm(pending_pat, empty_block)
607597
};
608598

609599
let inner_match_stmt = {
@@ -645,7 +635,7 @@ impl LoweringContext<'_> {
645635
});
646636

647637
// mut pinned => loop { ... }
648-
let pinned_arm = self.arm(hir_vec![pinned_pat], loop_expr);
638+
let pinned_arm = self.arm(pinned_pat, loop_expr);
649639

650640
// match <expr> {
651641
// mut pinned => loop { .. }
@@ -1079,15 +1069,15 @@ impl LoweringContext<'_> {
10791069
ThinVec::new(),
10801070
));
10811071
let some_pat = self.pat_some(pat.span, val_pat);
1082-
self.arm(hir_vec![some_pat], assign)
1072+
self.arm(some_pat, assign)
10831073
};
10841074

10851075
// `::std::option::Option::None => break`
10861076
let break_arm = {
10871077
let break_expr =
10881078
self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
10891079
let pat = self.pat_none(e.span);
1090-
self.arm(hir_vec![pat], break_expr)
1080+
self.arm(pat, break_expr)
10911081
};
10921082

10931083
// `mut iter`
@@ -1158,7 +1148,7 @@ impl LoweringContext<'_> {
11581148
});
11591149

11601150
// `mut iter => { ... }`
1161-
let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
1151+
let iter_arm = self.arm(iter_pat, loop_expr);
11621152

11631153
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
11641154
let into_iter_expr = {
@@ -1244,7 +1234,7 @@ impl LoweringContext<'_> {
12441234
ThinVec::from(attrs.clone()),
12451235
));
12461236
let ok_pat = self.pat_ok(span, val_pat);
1247-
self.arm(hir_vec![ok_pat], val_expr)
1237+
self.arm(ok_pat, val_expr)
12481238
};
12491239

12501240
// `Err(err) => #[allow(unreachable_code)]
@@ -1279,7 +1269,7 @@ impl LoweringContext<'_> {
12791269
};
12801270

12811271
let err_pat = self.pat_err(try_span, err_local);
1282-
self.arm(hir_vec![err_pat], ret_expr)
1272+
self.arm(err_pat, ret_expr)
12831273
};
12841274

12851275
hir::ExprKind::Match(
@@ -1474,14 +1464,11 @@ impl LoweringContext<'_> {
14741464
}
14751465
}
14761466

1477-
/// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns
1478-
/// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready
1479-
/// to deal with it. This should by fixed by pushing it down to HIR and then HAIR.
1480-
fn arm(&mut self, pats: HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
1467+
fn arm(&mut self, pat: P<hir::Pat>, expr: P<hir::Expr>) -> hir::Arm {
14811468
hir::Arm {
14821469
hir_id: self.next_id(),
14831470
attrs: hir_vec![],
1484-
pats,
1471+
pat,
14851472
guard: None,
14861473
span: expr.span,
14871474
body: expr,

src/librustc/hir/mod.rs

+57-29
Original file line numberDiff line numberDiff line change
@@ -882,44 +882,61 @@ impl fmt::Debug for Pat {
882882

883883
impl Pat {
884884
// FIXME(#19596) this is a workaround, but there should be a better way
885-
fn walk_<G>(&self, it: &mut G) -> bool
886-
where G: FnMut(&Pat) -> bool
887-
{
885+
fn walk_short_(&self, it: &mut impl FnMut(&Pat) -> bool) -> bool {
888886
if !it(self) {
889887
return false;
890888
}
891889

892-
match self.node {
893-
PatKind::Binding(.., Some(ref p)) => p.walk_(it),
894-
PatKind::Struct(_, ref fields, _) => {
895-
fields.iter().all(|field| field.pat.walk_(it))
896-
}
897-
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
898-
s.iter().all(|p| p.walk_(it))
899-
}
900-
PatKind::Or(ref pats) => pats.iter().all(|p| p.walk_(it)),
901-
PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
902-
s.walk_(it)
903-
}
904-
PatKind::Slice(ref before, ref slice, ref after) => {
890+
use PatKind::*;
891+
match &self.node {
892+
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
893+
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
894+
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
895+
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
896+
Slice(before, slice, after) => {
905897
before.iter()
906898
.chain(slice.iter())
907899
.chain(after.iter())
908-
.all(|p| p.walk_(it))
900+
.all(|p| p.walk_short_(it))
909901
}
910-
PatKind::Wild |
911-
PatKind::Lit(_) |
912-
PatKind::Range(..) |
913-
PatKind::Binding(..) |
914-
PatKind::Path(_) => {
915-
true
902+
}
903+
}
904+
905+
/// Walk the pattern in left-to-right order,
906+
/// short circuiting (with `.all(..)`) if `false` is returned.
907+
///
908+
/// Note that when visiting e.g. `Tuple(ps)`,
909+
/// if visiting `ps[0]` returns `false`,
910+
/// then `ps[1]` will not be visited.
911+
pub fn walk_short(&self, mut it: impl FnMut(&Pat) -> bool) -> bool {
912+
self.walk_short_(&mut it)
913+
}
914+
915+
// FIXME(#19596) this is a workaround, but there should be a better way
916+
fn walk_(&self, it: &mut impl FnMut(&Pat) -> bool) {
917+
if !it(self) {
918+
return;
919+
}
920+
921+
use PatKind::*;
922+
match &self.node {
923+
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {},
924+
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
925+
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
926+
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
927+
Slice(before, slice, after) => {
928+
before.iter()
929+
.chain(slice.iter())
930+
.chain(after.iter())
931+
.for_each(|p| p.walk_(it))
916932
}
917933
}
918934
}
919935

920-
pub fn walk<F>(&self, mut it: F) -> bool
921-
where F: FnMut(&Pat) -> bool
922-
{
936+
/// Walk the pattern in left-to-right order.
937+
///
938+
/// If `it(pat)` returns `false`, the children are not visited.
939+
pub fn walk(&self, mut it: impl FnMut(&Pat) -> bool) {
923940
self.walk_(&mut it)
924941
}
925942
}
@@ -1259,21 +1276,32 @@ pub struct Local {
12591276
}
12601277

12611278
/// Represents a single arm of a `match` expression, e.g.
1262-
/// `<pats> (if <guard>) => <body>`.
1279+
/// `<pat> (if <guard>) => <body>`.
12631280
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
12641281
pub struct Arm {
12651282
#[stable_hasher(ignore)]
12661283
pub hir_id: HirId,
12671284
pub span: Span,
12681285
pub attrs: HirVec<Attribute>,
1269-
/// Multiple patterns can be combined with `|`
1270-
pub pats: HirVec<P<Pat>>,
1286+
/// If this pattern and the optional guard matches, then `body` is evaluated.
1287+
pub pat: P<Pat>,
12711288
/// Optional guard clause.
12721289
pub guard: Option<Guard>,
12731290
/// The expression the arm evaluates to if this arm matches.
12741291
pub body: P<Expr>,
12751292
}
12761293

1294+
impl Arm {
1295+
// HACK(or_patterns; Centril | dlrobertson): Remove this and
1296+
// correctly handle each case in which this method is used.
1297+
pub fn top_pats_hack(&self) -> &[P<Pat>] {
1298+
match &self.pat.node {
1299+
PatKind::Or(pats) => pats,
1300+
_ => std::slice::from_ref(&self.pat),
1301+
}
1302+
}
1303+
}
1304+
12771305
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
12781306
pub enum Guard {
12791307
If(P<Expr>),

0 commit comments

Comments
 (0)