Auto merge of #53815 - F001:if-let-guard, r=petrochenkov
refactor match guard This is the first step to implement RFC 2294: if-let-guard. Tracking issue: https://github.com/rust-lang/rust/issues/51114 The second step should be introducing another variant `IfLet` in the Guard enum. I separated them into 2 PRs for the convenience of reviewers. r? @petrochenkov
This commit is contained in:
commit
28bcffead7
@ -488,8 +488,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
||||
// expression to target
|
||||
let guard_start = self.add_dummy_node(&[pat_exit]);
|
||||
// Visit the guard expression
|
||||
let guard_exit = self.expr(&guard, guard_start);
|
||||
|
||||
let guard_exit = match guard {
|
||||
hir::Guard::If(ref e) => self.expr(e, guard_start),
|
||||
};
|
||||
// #47295: We used to have very special case code
|
||||
// here for when a pair of arms are both formed
|
||||
// solely from constants, and if so, not add these
|
||||
|
@ -1102,7 +1102,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
|
||||
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
|
||||
walk_list!(visitor, visit_pat, &arm.pats);
|
||||
walk_list!(visitor, visit_expr, &arm.guard);
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
Guard::If(ref e) => visitor.visit_expr(e),
|
||||
}
|
||||
}
|
||||
visitor.visit_expr(&arm.body);
|
||||
walk_list!(visitor, visit_attribute, &arm.attrs);
|
||||
}
|
||||
|
@ -1054,7 +1054,10 @@ impl<'a> LoweringContext<'a> {
|
||||
hir::Arm {
|
||||
attrs: self.lower_attrs(&arm.attrs),
|
||||
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
|
||||
guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
|
||||
guard: match arm.guard {
|
||||
Some(Guard::If(ref x)) => Some(hir::Guard::If(P(self.lower_expr(x)))),
|
||||
_ => None,
|
||||
},
|
||||
body: P(self.lower_expr(&arm.body)),
|
||||
}
|
||||
}
|
||||
|
@ -1204,10 +1204,15 @@ impl DeclKind {
|
||||
pub struct Arm {
|
||||
pub attrs: HirVec<Attribute>,
|
||||
pub pats: HirVec<P<Pat>>,
|
||||
pub guard: Option<P<Expr>>,
|
||||
pub guard: Option<Guard>,
|
||||
pub body: P<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum Guard {
|
||||
If(P<Expr>),
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Field {
|
||||
pub id: NodeId,
|
||||
|
@ -1949,10 +1949,14 @@ impl<'a> State<'a> {
|
||||
self.print_pat(&p)?;
|
||||
}
|
||||
self.s.space()?;
|
||||
if let Some(ref e) = arm.guard {
|
||||
self.word_space("if")?;
|
||||
self.print_expr(&e)?;
|
||||
self.s.space()?;
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
hir::Guard::If(e) => {
|
||||
self.word_space("if")?;
|
||||
self.print_expr(&e)?;
|
||||
self.s.space()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.word_space("=>")?;
|
||||
|
||||
|
@ -493,6 +493,10 @@ impl_stable_hash_for!(struct hir::Arm {
|
||||
body
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum hir::Guard {
|
||||
If(expr),
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct hir::Field {
|
||||
id -> _,
|
||||
ident,
|
||||
|
@ -792,7 +792,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
if let Some(ref guard) = arm.guard {
|
||||
self.consume_expr(&guard);
|
||||
match guard {
|
||||
hir::Guard::If(ref e) => self.consume_expr(e),
|
||||
}
|
||||
}
|
||||
|
||||
self.consume_expr(&arm.body);
|
||||
|
@ -1030,7 +1030,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
let body_succ =
|
||||
self.propagate_through_expr(&arm.body, succ);
|
||||
let guard_succ =
|
||||
self.propagate_through_opt_expr(arm.guard.as_ref().map(|e| &**e), body_succ);
|
||||
self.propagate_through_opt_expr(
|
||||
arm.guard.as_ref().map(|g|
|
||||
match g {
|
||||
hir::Guard::If(e) => &**e,
|
||||
}),
|
||||
body_succ);
|
||||
// only consider the first pattern; any later patterns must have
|
||||
// the same bindings, and we also consider the first pattern to be
|
||||
// the "authoritative" set of ids
|
||||
|
@ -885,8 +885,10 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
|
||||
fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
|
||||
visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
|
||||
|
||||
if let Some(ref expr) = arm.guard {
|
||||
visitor.terminating_scopes.insert(expr.hir_id.local_id);
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
hir::Guard::If(ref expr) => visitor.terminating_scopes.insert(expr.hir_id.local_id),
|
||||
};
|
||||
}
|
||||
|
||||
intravisit::walk_arm(visitor, arm);
|
||||
|
@ -453,7 +453,7 @@ pub struct Candidate<'pat, 'tcx:'pat> {
|
||||
bindings: Vec<Binding<'tcx>>,
|
||||
|
||||
// ...and the guard must be evaluated...
|
||||
guard: Option<ExprRef<'tcx>>,
|
||||
guard: Option<Guard<'tcx>>,
|
||||
|
||||
// ...and then we branch to arm with this index.
|
||||
arm_index: usize,
|
||||
@ -998,7 +998,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
// the block to branch to if the guard fails; if there is no
|
||||
// guard, this block is simply unreachable
|
||||
let guard = self.hir.mirror(guard);
|
||||
let guard = match guard {
|
||||
Guard::If(e) => self.hir.mirror(e),
|
||||
};
|
||||
let source_info = self.source_info(guard.span);
|
||||
let cond = unpack!(block = self.as_local_operand(block, guard));
|
||||
if autoref {
|
||||
|
@ -837,7 +837,10 @@ impl ToBorrowKind for hir::Mutability {
|
||||
fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
|
||||
Arm {
|
||||
patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
|
||||
guard: arm.guard.to_ref(),
|
||||
guard: match arm.guard {
|
||||
Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
|
||||
_ => None,
|
||||
},
|
||||
body: arm.body.to_ref(),
|
||||
// BUG: fix this
|
||||
lint_level: LintLevel::Inherited,
|
||||
|
@ -316,11 +316,16 @@ pub struct FruInfo<'tcx> {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Arm<'tcx> {
|
||||
pub patterns: Vec<Pattern<'tcx>>,
|
||||
pub guard: Option<ExprRef<'tcx>>,
|
||||
pub guard: Option<Guard<'tcx>>,
|
||||
pub body: ExprRef<'tcx>,
|
||||
pub lint_level: LintLevel,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Guard<'tcx> {
|
||||
If(ExprRef<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LogicalOp {
|
||||
And,
|
||||
|
@ -208,7 +208,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
}
|
||||
(pattern, &**pat)
|
||||
}).collect(),
|
||||
arm.guard.as_ref().map(|e| &**e)
|
||||
arm.guard.as_ref().map(|g| match g {
|
||||
hir::Guard::If(ref e) => &**e,
|
||||
})
|
||||
)).collect();
|
||||
|
||||
// Bail out early if inlining failed.
|
||||
@ -575,12 +577,19 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
/// assign.
|
||||
///
|
||||
/// FIXME: this should be done by borrowck.
|
||||
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
|
||||
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Guard) {
|
||||
let mut checker = MutationChecker {
|
||||
cx,
|
||||
};
|
||||
ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
|
||||
.walk_expr(guard);
|
||||
match guard {
|
||||
hir::Guard::If(expr) =>
|
||||
ExprUseVisitor::new(&mut checker,
|
||||
cx.tcx,
|
||||
cx.param_env,
|
||||
cx.region_scope_tree,
|
||||
cx.tables,
|
||||
None).walk_expr(expr),
|
||||
};
|
||||
}
|
||||
|
||||
struct MutationChecker<'a, 'tcx: 'a> {
|
||||
|
@ -577,7 +577,7 @@ fn check_expr_kind<'a, 'tcx>(
|
||||
for index in hirvec_arm.iter() {
|
||||
let _ = v.check_expr(&*index.body);
|
||||
match index.guard {
|
||||
Some(ref expr) => {
|
||||
Some(hir::Guard::If(ref expr)) => {
|
||||
let _ = v.check_expr(&expr);
|
||||
},
|
||||
None => {},
|
||||
|
@ -2701,7 +2701,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
|
||||
// This has to happen *after* we determine which pat_idents are variants
|
||||
self.check_consistent_bindings(&arm.pats);
|
||||
|
||||
walk_list!(self, visit_expr, &arm.guard);
|
||||
match arm.guard {
|
||||
Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
|
||||
_ => {}
|
||||
}
|
||||
self.visit_expr(&arm.body);
|
||||
|
||||
self.ribs[ValueNS].pop();
|
||||
|
@ -1663,7 +1663,10 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
||||
|
||||
fn visit_arm(&mut self, arm: &'l ast::Arm) {
|
||||
self.process_var_decl_multi(&arm.pats);
|
||||
walk_list!(self, visit_expr, &arm.guard);
|
||||
match arm.guard {
|
||||
Some(ast::Guard::If(ref expr)) => self.visit_expr(expr),
|
||||
_ => {}
|
||||
}
|
||||
self.visit_expr(&arm.body);
|
||||
}
|
||||
|
||||
|
@ -663,9 +663,11 @@ https://doc.rust-lang.org/reference/types.html#trait-objects");
|
||||
};
|
||||
|
||||
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
|
||||
if let Some(ref e) = arm.guard {
|
||||
if let Some(ref g) = arm.guard {
|
||||
self.diverges.set(pats_diverge);
|
||||
self.check_expr_has_type_or_error(e, tcx.types.bool);
|
||||
match g {
|
||||
hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool),
|
||||
};
|
||||
}
|
||||
|
||||
self.diverges.set(pats_diverge);
|
||||
|
@ -857,10 +857,15 @@ pub struct Local {
|
||||
pub struct Arm {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub pats: Vec<P<Pat>>,
|
||||
pub guard: Option<P<Expr>>,
|
||||
pub guard: Option<Guard>,
|
||||
pub body: P<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum Guard {
|
||||
If(P<Expr>),
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub struct Field {
|
||||
pub ident: Ident,
|
||||
|
@ -118,6 +118,10 @@ pub trait Folder : Sized {
|
||||
noop_fold_arm(a, self)
|
||||
}
|
||||
|
||||
fn fold_guard(&mut self, g: Guard) -> Guard {
|
||||
noop_fold_guard(g, self)
|
||||
}
|
||||
|
||||
fn fold_pat(&mut self, p: P<Pat>) -> P<Pat> {
|
||||
noop_fold_pat(p, self)
|
||||
}
|
||||
@ -354,11 +358,17 @@ pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
|
||||
Arm {
|
||||
attrs: fold_attrs(attrs, fld),
|
||||
pats: pats.move_map(|x| fld.fold_pat(x)),
|
||||
guard: guard.map(|x| fld.fold_expr(x)),
|
||||
guard: guard.map(|x| fld.fold_guard(x)),
|
||||
body: fld.fold_expr(body),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_fold_guard<T: Folder>(g: Guard, fld: &mut T) -> Guard {
|
||||
match g {
|
||||
Guard::If(e) => Guard::If(fld.fold_expr(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
|
||||
TypeBinding {
|
||||
id: fld.new_id(b.id),
|
||||
|
@ -12,7 +12,7 @@ use rustc_target::spec::abi::{self, Abi};
|
||||
use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy};
|
||||
use ast::{GenericBound, TraitBoundModifier};
|
||||
use ast::Unsafety;
|
||||
use ast::{Mod, AnonConst, Arg, Arm, Attribute, BindingMode, TraitItemKind};
|
||||
use ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
|
||||
use ast::Block;
|
||||
use ast::{BlockCheckMode, CaptureBy, Movability};
|
||||
use ast::{Constness, Crate};
|
||||
@ -3533,7 +3533,7 @@ impl<'a> Parser<'a> {
|
||||
self.eat(&token::BinOp(token::Or));
|
||||
let pats = self.parse_pats()?;
|
||||
let guard = if self.eat_keyword(keywords::If) {
|
||||
Some(self.parse_expr()?)
|
||||
Some(Guard::If(self.parse_expr()?))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -2702,10 +2702,14 @@ impl<'a> State<'a> {
|
||||
self.print_outer_attributes(&arm.attrs)?;
|
||||
self.print_pats(&arm.pats)?;
|
||||
self.s.space()?;
|
||||
if let Some(ref e) = arm.guard {
|
||||
self.word_space("if")?;
|
||||
self.print_expr(e)?;
|
||||
self.s.space()?;
|
||||
if let Some(ref g) = arm.guard {
|
||||
match g {
|
||||
ast::Guard::If(ref e) => {
|
||||
self.word_space("if")?;
|
||||
self.print_expr(e)?;
|
||||
self.s.space()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.word_space("=>")?;
|
||||
|
||||
|
@ -819,7 +819,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
|
||||
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
|
||||
walk_list!(visitor, visit_pat, &arm.pats);
|
||||
walk_list!(visitor, visit_expr, &arm.guard);
|
||||
if let Some(ref g) = &arm.guard {
|
||||
match g {
|
||||
Guard::If(ref e) => visitor.visit_expr(e),
|
||||
}
|
||||
}
|
||||
visitor.visit_expr(&arm.body);
|
||||
walk_list!(visitor, visit_attribute, &arm.attrs);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user