mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Rollup merge of #79051 - LeSeulArtichaut:if-let-guard, r=matthewjasper
Implement if-let match guards Implements rust-lang/rfcs#2294 (tracking issue: #51114). I probably should do a few more things before this can be merged: - [x] Add tests (added basic tests, more advanced tests could be done in the future?) - [x] Add lint for exhaustive if-let guard (comparable to normal if-let statements) - [x] Fix clippy However since this is a nightly feature maybe it's fine to land this and do those steps in follow-up PRs. Thanks a lot `@matthewjasper` ❤️ for helping me with lowering to MIR! Would you be interested in reviewing this? r? `@ghost` for now
This commit is contained in:
commit
1e1ba7c936
@ -505,14 +505,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||||
|
let pat = self.lower_pat(&arm.pat);
|
||||||
|
let guard = arm.guard.as_ref().map(|cond| {
|
||||||
|
if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind {
|
||||||
|
hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
|
||||||
|
} else {
|
||||||
|
hir::Guard::If(self.lower_expr(cond))
|
||||||
|
}
|
||||||
|
});
|
||||||
hir::Arm {
|
hir::Arm {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
attrs: self.lower_attrs(&arm.attrs),
|
attrs: self.lower_attrs(&arm.attrs),
|
||||||
pat: self.lower_pat(&arm.pat),
|
pat,
|
||||||
guard: match arm.guard {
|
guard,
|
||||||
Some(ref x) => Some(hir::Guard::If(self.lower_expr(x))),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
body: self.lower_expr(&arm.body),
|
body: self.lower_expr(&arm.body),
|
||||||
span: arm.span,
|
span: arm.span,
|
||||||
}
|
}
|
||||||
|
@ -1160,6 +1160,7 @@ pub struct Arm<'hir> {
|
|||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub enum Guard<'hir> {
|
pub enum Guard<'hir> {
|
||||||
If(&'hir Expr<'hir>),
|
If(&'hir Expr<'hir>),
|
||||||
|
IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
@ -1721,6 +1722,8 @@ pub enum MatchSource {
|
|||||||
IfDesugar { contains_else_clause: bool },
|
IfDesugar { contains_else_clause: bool },
|
||||||
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
|
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
|
||||||
IfLetDesugar { contains_else_clause: bool },
|
IfLetDesugar { contains_else_clause: bool },
|
||||||
|
/// An `if let _ = _ => { .. }` match guard.
|
||||||
|
IfLetGuardDesugar,
|
||||||
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
|
/// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
|
||||||
WhileDesugar,
|
WhileDesugar,
|
||||||
/// A `while let _ = _ { .. }` (which was desugared to a
|
/// A `while let _ = _ { .. }` (which was desugared to a
|
||||||
@ -1739,7 +1742,7 @@ impl MatchSource {
|
|||||||
use MatchSource::*;
|
use MatchSource::*;
|
||||||
match self {
|
match self {
|
||||||
Normal => "match",
|
Normal => "match",
|
||||||
IfDesugar { .. } | IfLetDesugar { .. } => "if",
|
IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if",
|
||||||
WhileDesugar | WhileLetDesugar => "while",
|
WhileDesugar | WhileLetDesugar => "while",
|
||||||
ForLoopDesugar => "for",
|
ForLoopDesugar => "for",
|
||||||
TryDesugar => "?",
|
TryDesugar => "?",
|
||||||
|
@ -1228,6 +1228,10 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
|
|||||||
if let Some(ref g) = arm.guard {
|
if let Some(ref g) = arm.guard {
|
||||||
match g {
|
match g {
|
||||||
Guard::If(ref e) => visitor.visit_expr(e),
|
Guard::If(ref e) => visitor.visit_expr(e),
|
||||||
|
Guard::IfLet(ref pat, ref e) => {
|
||||||
|
visitor.visit_pat(pat);
|
||||||
|
visitor.visit_expr(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visitor.visit_expr(&arm.body);
|
visitor.visit_expr(&arm.body);
|
||||||
|
@ -2002,6 +2002,15 @@ impl<'a> State<'a> {
|
|||||||
self.print_expr(&e);
|
self.print_expr(&e);
|
||||||
self.s.space();
|
self.s.space();
|
||||||
}
|
}
|
||||||
|
hir::Guard::IfLet(pat, e) => {
|
||||||
|
self.word_nbsp("if");
|
||||||
|
self.word_nbsp("let");
|
||||||
|
self.print_pat(&pat);
|
||||||
|
self.s.space();
|
||||||
|
self.word_space("=");
|
||||||
|
self.print_expr(&e);
|
||||||
|
self.s.space();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.word_space("=>");
|
self.word_space("=>");
|
||||||
|
@ -228,6 +228,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
guard: Option<&Guard<'tcx>>,
|
guard: Option<&Guard<'tcx>>,
|
||||||
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
|
fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
|
arm_span: Option<Span>,
|
||||||
arm_scope: Option<region::Scope>,
|
arm_scope: Option<region::Scope>,
|
||||||
) -> BasicBlock {
|
) -> BasicBlock {
|
||||||
if candidate.subcandidates.is_empty() {
|
if candidate.subcandidates.is_empty() {
|
||||||
@ -239,6 +240,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
guard,
|
guard,
|
||||||
fake_borrow_temps,
|
fake_borrow_temps,
|
||||||
scrutinee_span,
|
scrutinee_span,
|
||||||
|
arm_span,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -274,6 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
guard,
|
guard,
|
||||||
&fake_borrow_temps,
|
&fake_borrow_temps,
|
||||||
scrutinee_span,
|
scrutinee_span,
|
||||||
|
arm_span,
|
||||||
schedule_drops,
|
schedule_drops,
|
||||||
);
|
);
|
||||||
if arm_scope.is_none() {
|
if arm_scope.is_none() {
|
||||||
@ -436,6 +439,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
&fake_borrow_temps,
|
&fake_borrow_temps,
|
||||||
irrefutable_pat.span,
|
irrefutable_pat.span,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unit()
|
.unit()
|
||||||
}
|
}
|
||||||
@ -817,11 +821,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
/// For an example of a case where we set `otherwise_block`, even for an
|
/// For an example of a case where we set `otherwise_block`, even for an
|
||||||
/// exhaustive match consider:
|
/// exhaustive match consider:
|
||||||
///
|
///
|
||||||
|
/// ```rust
|
||||||
/// match x {
|
/// match x {
|
||||||
/// (true, true) => (),
|
/// (true, true) => (),
|
||||||
/// (_, false) => (),
|
/// (_, false) => (),
|
||||||
/// (false, true) => (),
|
/// (false, true) => (),
|
||||||
/// }
|
/// }
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// For this match, we check if `x.0` matches `true` (for the first
|
/// For this match, we check if `x.0` matches `true` (for the first
|
||||||
/// arm). If that's false, we check `x.1`. If it's `true` we check if
|
/// arm). If that's false, we check `x.1`. If it's `true` we check if
|
||||||
@ -935,11 +941,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
/// Link up matched candidates. For example, if we have something like
|
/// Link up matched candidates. For example, if we have something like
|
||||||
/// this:
|
/// this:
|
||||||
///
|
///
|
||||||
|
/// ```rust
|
||||||
/// ...
|
/// ...
|
||||||
/// Some(x) if cond => ...
|
/// Some(x) if cond => ...
|
||||||
/// Some(x) => ...
|
/// Some(x) => ...
|
||||||
/// Some(x) if cond => ...
|
/// Some(x) if cond => ...
|
||||||
/// ...
|
/// ...
|
||||||
|
/// ```
|
||||||
///
|
///
|
||||||
/// We generate real edges from:
|
/// We generate real edges from:
|
||||||
/// * `start_block` to the `prebinding_block` of the first pattern,
|
/// * `start_block` to the `prebinding_block` of the first pattern,
|
||||||
@ -1517,7 +1525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
/// Initializes each of the bindings from the candidate by
|
/// Initializes each of the bindings from the candidate by
|
||||||
/// moving/copying/ref'ing the source as appropriate. Tests the guard, if
|
/// moving/copying/ref'ing the source as appropriate. Tests the guard, if
|
||||||
/// any, and then branches to the arm. Returns the block for the case where
|
/// any, and then branches to the arm. Returns the block for the case where
|
||||||
/// the guard fails.
|
/// the guard succeeds.
|
||||||
///
|
///
|
||||||
/// Note: we do not check earlier that if there is a guard,
|
/// Note: we do not check earlier that if there is a guard,
|
||||||
/// there cannot be move bindings. We avoid a use-after-move by only
|
/// there cannot be move bindings. We avoid a use-after-move by only
|
||||||
@ -1529,6 +1537,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
guard: Option<&Guard<'tcx>>,
|
guard: Option<&Guard<'tcx>>,
|
||||||
fake_borrows: &Vec<(Place<'tcx>, Local)>,
|
fake_borrows: &Vec<(Place<'tcx>, Local)>,
|
||||||
scrutinee_span: Span,
|
scrutinee_span: Span,
|
||||||
|
arm_span: Option<Span>,
|
||||||
schedule_drops: bool,
|
schedule_drops: bool,
|
||||||
) -> BasicBlock {
|
) -> BasicBlock {
|
||||||
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
|
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
|
||||||
@ -1659,15 +1668,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the block to branch to if the guard fails; if there is no
|
let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
|
||||||
// guard, this block is simply unreachable
|
Guard::If(e) => {
|
||||||
let guard = match guard {
|
let e = self.hir.mirror(e.clone());
|
||||||
Guard::If(e) => self.hir.mirror(e.clone()),
|
let source_info = self.source_info(e.span);
|
||||||
|
(e.span, self.test_bool(block, e, source_info))
|
||||||
|
},
|
||||||
|
Guard::IfLet(pat, scrutinee) => {
|
||||||
|
let scrutinee_span = scrutinee.span();
|
||||||
|
let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span));
|
||||||
|
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
|
||||||
|
let wildcard = Pat::wildcard_from_ty(pat.ty);
|
||||||
|
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
|
||||||
|
let fake_borrow_temps =
|
||||||
|
self.lower_match_tree(block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate]);
|
||||||
|
self.declare_bindings(
|
||||||
|
None,
|
||||||
|
pat.span.to(arm_span.unwrap()),
|
||||||
|
pat,
|
||||||
|
ArmHasGuard(false),
|
||||||
|
Some((Some(&scrutinee_place), scrutinee.span())),
|
||||||
|
);
|
||||||
|
let post_guard_block = self.bind_pattern(
|
||||||
|
self.source_info(pat.span),
|
||||||
|
guard_candidate,
|
||||||
|
None,
|
||||||
|
&fake_borrow_temps,
|
||||||
|
scrutinee.span(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
|
||||||
|
(scrutinee_span, (post_guard_block, otherwise_post_guard_block))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let source_info = self.source_info(guard.span);
|
let source_info = self.source_info(guard_span);
|
||||||
let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span));
|
let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span));
|
||||||
let (post_guard_block, otherwise_post_guard_block) =
|
|
||||||
self.test_bool(block, guard, source_info);
|
|
||||||
let guard_frame = self.guard_context.pop().unwrap();
|
let guard_frame = self.guard_context.pop().unwrap();
|
||||||
debug!("Exiting guard building context with locals: {:?}", guard_frame);
|
debug!("Exiting guard building context with locals: {:?}", guard_frame);
|
||||||
|
|
||||||
|
@ -1197,6 +1197,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
arm.guard.as_ref(),
|
arm.guard.as_ref(),
|
||||||
&fake_borrow_temps,
|
&fake_borrow_temps,
|
||||||
scrutinee_span,
|
scrutinee_span,
|
||||||
|
Some(arm.span),
|
||||||
Some(arm.scope),
|
Some(arm.scope),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -776,10 +776,10 @@ impl ToBorrowKind for hir::Mutability {
|
|||||||
fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
|
fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
|
||||||
Arm {
|
Arm {
|
||||||
pattern: cx.pattern_from_hir(&arm.pat),
|
pattern: cx.pattern_from_hir(&arm.pat),
|
||||||
guard: match arm.guard {
|
guard: arm.guard.as_ref().map(|g| match g {
|
||||||
Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())),
|
hir::Guard::If(ref e) => Guard::If(e.to_ref()),
|
||||||
_ => None,
|
hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()),
|
||||||
},
|
}),
|
||||||
body: arm.body.to_ref(),
|
body: arm.body.to_ref(),
|
||||||
lint_level: LintLevel::Explicit(arm.hir_id),
|
lint_level: LintLevel::Explicit(arm.hir_id),
|
||||||
scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
|
scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
|
||||||
|
@ -344,6 +344,7 @@ crate struct Arm<'tcx> {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
crate enum Guard<'tcx> {
|
crate enum Guard<'tcx> {
|
||||||
If(ExprRef<'tcx>),
|
If(ExprRef<'tcx>),
|
||||||
|
IfLet(Pat<'tcx>, ExprRef<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -164,10 +164,20 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
|||||||
for arm in arms {
|
for arm in arms {
|
||||||
// Check the arm for some things unrelated to exhaustiveness.
|
// Check the arm for some things unrelated to exhaustiveness.
|
||||||
self.check_patterns(&arm.pat);
|
self.check_patterns(&arm.pat);
|
||||||
|
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
|
||||||
|
self.check_patterns(pat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cx = self.new_cx(scrut.hir_id);
|
let mut cx = self.new_cx(scrut.hir_id);
|
||||||
|
|
||||||
|
for arm in arms {
|
||||||
|
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
|
||||||
|
let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
|
||||||
|
check_if_let_guard(&mut cx, &tpat, pat.hir_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut have_errors = false;
|
let mut have_errors = false;
|
||||||
|
|
||||||
let arms: Vec<_> = arms
|
let arms: Vec<_> = arms
|
||||||
@ -360,12 +370,28 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::
|
|||||||
let msg = match source {
|
let msg = match source {
|
||||||
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
|
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
|
||||||
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
|
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
|
||||||
|
hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
lint.build(msg).emit()
|
lint.build(msg).emit()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_if_let_guard<'p, 'tcx>(
|
||||||
|
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||||
|
pat: &'p super::Pat<'tcx>,
|
||||||
|
pat_id: HirId,
|
||||||
|
) {
|
||||||
|
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
|
||||||
|
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty);
|
||||||
|
report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
|
||||||
|
|
||||||
|
if report.non_exhaustiveness_witnesses.is_empty() {
|
||||||
|
// The match is exhaustive, i.e. the if let pattern is irrefutable.
|
||||||
|
irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Report unreachable arms, if any.
|
/// Report unreachable arms, if any.
|
||||||
fn report_arm_reachability<'p, 'tcx>(
|
fn report_arm_reachability<'p, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||||
@ -390,6 +416,11 @@ fn report_arm_reachability<'p, 'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hir::MatchSource::IfLetGuardDesugar => {
|
||||||
|
assert_eq!(arm_index, 0);
|
||||||
|
unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None);
|
||||||
|
}
|
||||||
|
|
||||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||||
unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall);
|
unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall);
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,8 @@ impl NonConstExpr {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
|
||||||
|
|
||||||
// All other expressions are allowed.
|
// All other expressions are allowed.
|
||||||
Self::Loop(Loop | While | WhileLet)
|
Self::Loop(Loop | While | WhileLet)
|
||||||
| Self::Match(
|
| Self::Match(
|
||||||
|
@ -360,6 +360,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
|||||||
|
|
||||||
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
|
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
|
||||||
self.add_from_pat(&arm.pat);
|
self.add_from_pat(&arm.pat);
|
||||||
|
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
|
||||||
|
self.add_from_pat(pat);
|
||||||
|
}
|
||||||
intravisit::walk_arm(self, arm);
|
intravisit::walk_arm(self, arm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,10 +869,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
for arm in arms {
|
for arm in arms {
|
||||||
let body_succ = self.propagate_through_expr(&arm.body, succ);
|
let body_succ = self.propagate_through_expr(&arm.body, succ);
|
||||||
|
|
||||||
let guard_succ = self.propagate_through_opt_expr(
|
let guard_succ = arm.guard.as_ref().map_or(body_succ, |g| match g {
|
||||||
arm.guard.as_ref().map(|hir::Guard::If(e)| *e),
|
hir::Guard::If(e) => self.propagate_through_expr(e, body_succ),
|
||||||
body_succ,
|
hir::Guard::IfLet(pat, e) => {
|
||||||
);
|
let let_bind = self.define_bindings_in_pat(pat, body_succ);
|
||||||
|
self.propagate_through_expr(e, let_bind)
|
||||||
|
}
|
||||||
|
});
|
||||||
let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
|
let arm_succ = self.define_bindings_in_pat(&arm.pat, guard_succ);
|
||||||
self.merge_from_succ(ln, arm_succ);
|
self.merge_from_succ(ln, arm_succ);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// FIXME(60707): Consider removing hack with principled solution.
|
// FIXME(60707): Consider removing hack with principled solution.
|
||||||
self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {})
|
self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {})
|
||||||
} else {
|
} else {
|
||||||
self.demand_scrutinee_type(arms, scrut)
|
self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty())
|
||||||
};
|
};
|
||||||
|
|
||||||
// If there are no arms, that is a diverging match; a special case.
|
// If there are no arms, that is a diverging match; a special case.
|
||||||
@ -98,7 +98,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.diverges.set(Diverges::Maybe);
|
self.diverges.set(Diverges::Maybe);
|
||||||
match g {
|
match g {
|
||||||
hir::Guard::If(e) => {
|
hir::Guard::If(e) => {
|
||||||
self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {})
|
self.check_expr_has_type_or_error(e, tcx.types.bool, |_| {});
|
||||||
|
}
|
||||||
|
hir::Guard::IfLet(pat, e) => {
|
||||||
|
let scrutinee_ty = self.demand_scrutinee_type(
|
||||||
|
e,
|
||||||
|
pat.contains_explicit_ref_binding(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
self.check_pat_top(&pat, scrutinee_ty, None, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -450,8 +458,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
fn demand_scrutinee_type(
|
fn demand_scrutinee_type(
|
||||||
&self,
|
&self,
|
||||||
arms: &'tcx [hir::Arm<'tcx>],
|
|
||||||
scrut: &'tcx hir::Expr<'tcx>,
|
scrut: &'tcx hir::Expr<'tcx>,
|
||||||
|
contains_ref_bindings: Option<hir::Mutability>,
|
||||||
|
no_arms: bool,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
// Not entirely obvious: if matches may create ref bindings, we want to
|
// Not entirely obvious: if matches may create ref bindings, we want to
|
||||||
// use the *precise* type of the scrutinee, *not* some supertype, as
|
// use the *precise* type of the scrutinee, *not* some supertype, as
|
||||||
@ -505,17 +514,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// (once introduced) is populated by the time we get here.
|
// (once introduced) is populated by the time we get here.
|
||||||
//
|
//
|
||||||
// See #44848.
|
// See #44848.
|
||||||
let contains_ref_bindings = arms
|
|
||||||
.iter()
|
|
||||||
.filter_map(|a| a.pat.contains_explicit_ref_binding())
|
|
||||||
.max_by_key(|m| match *m {
|
|
||||||
hir::Mutability::Mut => 1,
|
|
||||||
hir::Mutability::Not => 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(m) = contains_ref_bindings {
|
if let Some(m) = contains_ref_bindings {
|
||||||
self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m))
|
self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m))
|
||||||
} else if arms.is_empty() {
|
} else if no_arms {
|
||||||
self.check_expr(scrut)
|
self.check_expr(scrut)
|
||||||
} else {
|
} else {
|
||||||
// ...but otherwise we want to use any supertype of the
|
// ...but otherwise we want to use any supertype of the
|
||||||
@ -546,3 +547,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
|
||||||
|
arms.iter().filter_map(|a| a.pat.contains_explicit_ref_binding()).max_by_key(|m| match *m {
|
||||||
|
hir::Mutability::Mut => 1,
|
||||||
|
hir::Mutability::Not => 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -246,6 +246,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
|
|||||||
Guard::If(ref e) => {
|
Guard::If(ref e) => {
|
||||||
self.visit_expr(e);
|
self.visit_expr(e);
|
||||||
}
|
}
|
||||||
|
Guard::IfLet(ref pat, ref e) => {
|
||||||
|
self.visit_pat(pat);
|
||||||
|
self.visit_expr(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scope_var_ids =
|
let mut scope_var_ids =
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
// Thus, `&'_ u8` should be included in type signature
|
// Thus, `&'_ u8` should be included in type signature
|
||||||
// of the underlying generator.
|
// of the underlying generator.
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
async fn f() -> u8 { 1 }
|
async fn f() -> u8 { 1 }
|
||||||
async fn foo() -> [bool; 10] { [false; 10] }
|
async fn foo() -> [bool; 10] { [false; 10] }
|
||||||
|
|
||||||
@ -36,8 +39,16 @@ async fn i(x: u8) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn j(x: u8) {
|
||||||
|
match x {
|
||||||
|
y if let (1, 42) = (f().await, y) => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = g(10);
|
let _ = g(10);
|
||||||
let _ = h(9);
|
let _ = h(9);
|
||||||
let _ = i(8);
|
let _ = i(8);
|
||||||
|
let _ = j(7);
|
||||||
}
|
}
|
||||||
|
10
src/test/ui/rfc-2294-if-let-guard/bindings.rs
Normal file
10
src/test/ui/rfc-2294-if-let-guard/bindings.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Some(None) {
|
||||||
|
Some(x) if let Some(y) = x => (x, y),
|
||||||
|
_ => y, //~ ERROR cannot find value `y`
|
||||||
|
}
|
||||||
|
y //~ ERROR cannot find value `y`
|
||||||
|
}
|
15
src/test/ui/rfc-2294-if-let-guard/bindings.stderr
Normal file
15
src/test/ui/rfc-2294-if-let-guard/bindings.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error[E0425]: cannot find value `y` in this scope
|
||||||
|
--> $DIR/bindings.rs:7:14
|
||||||
|
|
|
||||||
|
LL | _ => y,
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error[E0425]: cannot find value `y` in this scope
|
||||||
|
--> $DIR/bindings.rs:9:5
|
||||||
|
|
|
||||||
|
LL | y
|
||||||
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0425`.
|
@ -6,7 +6,6 @@ fn _if_let_guard() {
|
|||||||
match () {
|
match () {
|
||||||
() if let 0 = 1 => {}
|
() if let 0 = 1 => {}
|
||||||
//~^ ERROR `if let` guard is not implemented
|
//~^ ERROR `if let` guard is not implemented
|
||||||
//~| ERROR `let` expressions are not supported here
|
|
||||||
|
|
||||||
() if (let 0 = 1) => {}
|
() if (let 0 = 1) => {}
|
||||||
//~^ ERROR `let` expressions in this position are experimental
|
//~^ ERROR `let` expressions in this position are experimental
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: no rules expected the token `let`
|
error: no rules expected the token `let`
|
||||||
--> $DIR/feature-gate.rs:81:15
|
--> $DIR/feature-gate.rs:80:15
|
||||||
|
|
|
|
||||||
LL | macro_rules! use_expr {
|
LL | macro_rules! use_expr {
|
||||||
| --------------------- when calling this macro
|
| --------------------- when calling this macro
|
||||||
@ -17,7 +17,7 @@ LL | () if let 0 = 1 => {}
|
|||||||
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
|
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `if let` guard is not implemented
|
error[E0658]: `if let` guard is not implemented
|
||||||
--> $DIR/feature-gate.rs:77:12
|
--> $DIR/feature-gate.rs:76:12
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 => {}
|
LL | () if let 0 = 1 => {}
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
@ -26,7 +26,7 @@ LL | () if let 0 = 1 => {}
|
|||||||
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
|
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:11:16
|
--> $DIR/feature-gate.rs:10:16
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) => {}
|
LL | () if (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -35,7 +35,7 @@ LL | () if (let 0 = 1) => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:15:18
|
--> $DIR/feature-gate.rs:14:18
|
||||||
|
|
|
|
||||||
LL | () if (((let 0 = 1))) => {}
|
LL | () if (((let 0 = 1))) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -44,7 +44,7 @@ LL | () if (((let 0 = 1))) => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:19:23
|
--> $DIR/feature-gate.rs:18:23
|
||||||
|
|
|
|
||||||
LL | () if true && let 0 = 1 => {}
|
LL | () if true && let 0 = 1 => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -53,7 +53,7 @@ LL | () if true && let 0 = 1 => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:23:15
|
--> $DIR/feature-gate.rs:22:15
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && true => {}
|
LL | () if let 0 = 1 && true => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -62,7 +62,7 @@ LL | () if let 0 = 1 && true => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:27:16
|
--> $DIR/feature-gate.rs:26:16
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && true => {}
|
LL | () if (let 0 = 1) && true => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -71,7 +71,7 @@ LL | () if (let 0 = 1) && true => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:31:24
|
--> $DIR/feature-gate.rs:30:24
|
||||||
|
|
|
|
||||||
LL | () if true && (let 0 = 1) => {}
|
LL | () if true && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -80,7 +80,7 @@ LL | () if true && (let 0 = 1) => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:35:16
|
--> $DIR/feature-gate.rs:34:16
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -89,7 +89,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:35:31
|
--> $DIR/feature-gate.rs:34:31
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -98,7 +98,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:41:15
|
--> $DIR/feature-gate.rs:40:15
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -107,7 +107,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:41:28
|
--> $DIR/feature-gate.rs:40:28
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -116,7 +116,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:41:42
|
--> $DIR/feature-gate.rs:40:42
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -125,7 +125,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:41:55
|
--> $DIR/feature-gate.rs:40:55
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -134,7 +134,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:41:68
|
--> $DIR/feature-gate.rs:40:68
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -143,7 +143,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:53:15
|
--> $DIR/feature-gate.rs:52:15
|
||||||
|
|
|
|
||||||
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -152,7 +152,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:69:16
|
--> $DIR/feature-gate.rs:68:16
|
||||||
|
|
|
|
||||||
LL | use_expr!((let 0 = 1 && 0 == 0));
|
LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -161,7 +161,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: `let` expressions in this position are experimental
|
error[E0658]: `let` expressions in this position are experimental
|
||||||
--> $DIR/feature-gate.rs:72:16
|
--> $DIR/feature-gate.rs:71:16
|
||||||
|
|
|
|
||||||
LL | use_expr!((let 0 = 1));
|
LL | use_expr!((let 0 = 1));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -170,16 +170,7 @@ LL | use_expr!((let 0 = 1));
|
|||||||
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
= help: add `#![feature(let_chains)]` to the crate attributes to enable
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:7:15
|
--> $DIR/feature-gate.rs:10:16
|
||||||
|
|
|
||||||
LL | () if let 0 = 1 => {}
|
|
||||||
| ^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: only supported directly in conditions of `if`- and `while`-expressions
|
|
||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
|
||||||
--> $DIR/feature-gate.rs:11:16
|
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) => {}
|
LL | () if (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -188,7 +179,7 @@ LL | () if (let 0 = 1) => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:15:18
|
--> $DIR/feature-gate.rs:14:18
|
||||||
|
|
|
|
||||||
LL | () if (((let 0 = 1))) => {}
|
LL | () if (((let 0 = 1))) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -197,7 +188,7 @@ LL | () if (((let 0 = 1))) => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:19:23
|
--> $DIR/feature-gate.rs:18:23
|
||||||
|
|
|
|
||||||
LL | () if true && let 0 = 1 => {}
|
LL | () if true && let 0 = 1 => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -206,7 +197,7 @@ LL | () if true && let 0 = 1 => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:23:15
|
--> $DIR/feature-gate.rs:22:15
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && true => {}
|
LL | () if let 0 = 1 && true => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -215,7 +206,7 @@ LL | () if let 0 = 1 && true => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:27:16
|
--> $DIR/feature-gate.rs:26:16
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && true => {}
|
LL | () if (let 0 = 1) && true => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -224,7 +215,7 @@ LL | () if (let 0 = 1) && true => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:31:24
|
--> $DIR/feature-gate.rs:30:24
|
||||||
|
|
|
|
||||||
LL | () if true && (let 0 = 1) => {}
|
LL | () if true && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -233,7 +224,7 @@ LL | () if true && (let 0 = 1) => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:35:16
|
--> $DIR/feature-gate.rs:34:16
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -242,7 +233,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:35:31
|
--> $DIR/feature-gate.rs:34:31
|
||||||
|
|
|
|
||||||
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -251,7 +242,7 @@ LL | () if (let 0 = 1) && (let 0 = 1) => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:41:15
|
--> $DIR/feature-gate.rs:40:15
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -260,7 +251,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:41:28
|
--> $DIR/feature-gate.rs:40:28
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -269,7 +260,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:41:42
|
--> $DIR/feature-gate.rs:40:42
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -278,7 +269,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:41:55
|
--> $DIR/feature-gate.rs:40:55
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -287,7 +278,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:41:68
|
--> $DIR/feature-gate.rs:40:68
|
||||||
|
|
|
|
||||||
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -296,7 +287,7 @@ LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:53:15
|
--> $DIR/feature-gate.rs:52:15
|
||||||
|
|
|
|
||||||
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -305,7 +296,7 @@ LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:69:16
|
--> $DIR/feature-gate.rs:68:16
|
||||||
|
|
|
|
||||||
LL | use_expr!((let 0 = 1 && 0 == 0));
|
LL | use_expr!((let 0 = 1 && 0 == 0));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -314,7 +305,7 @@ LL | use_expr!((let 0 = 1 && 0 == 0));
|
|||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: `let` expressions are not supported here
|
error: `let` expressions are not supported here
|
||||||
--> $DIR/feature-gate.rs:72:16
|
--> $DIR/feature-gate.rs:71:16
|
||||||
|
|
|
|
||||||
LL | use_expr!((let 0 = 1));
|
LL | use_expr!((let 0 = 1));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
@ -322,6 +313,6 @@ LL | use_expr!((let 0 = 1));
|
|||||||
= note: only supported directly in conditions of `if`- and `while`-expressions
|
= note: only supported directly in conditions of `if`- and `while`-expressions
|
||||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||||
|
|
||||||
error: aborting due to 36 previous errors
|
error: aborting due to 35 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0658`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
34
src/test/ui/rfc-2294-if-let-guard/run-pass.rs
Normal file
34
src/test/ui/rfc-2294-if-let-guard/run-pass.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
enum Foo {
|
||||||
|
Bar,
|
||||||
|
Baz,
|
||||||
|
Qux(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(x: bool) -> Foo {
|
||||||
|
if x { Foo::Baz } else { Foo::Bar }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz(x: u8) -> Foo {
|
||||||
|
if x % 2 == 0 { Foo::Bar } else { Foo::Baz }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn qux(x: u8) -> Foo {
|
||||||
|
Foo::Qux(x.rotate_left(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Some((true, 3)) {
|
||||||
|
Some((x, _)) if let Foo::Bar = bar(x) => panic!(),
|
||||||
|
Some((_, x)) if let Foo::Baz = baz(x) => {},
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
match Some(42) {
|
||||||
|
Some(x) if let Foo::Qux(y) = qux(x) => assert_eq!(y, 84),
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
16
src/test/ui/rfc-2294-if-let-guard/typeck.rs
Normal file
16
src/test/ui/rfc-2294-if-let-guard/typeck.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
fn ok() -> Result<Option<bool>, ()> {
|
||||||
|
Ok(Some(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match ok() {
|
||||||
|
Ok(x) if let Err(_) = x => {},
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
Ok(x) if let 0 = x => {},
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
21
src/test/ui/rfc-2294-if-let-guard/typeck.stderr
Normal file
21
src/test/ui/rfc-2294-if-let-guard/typeck.stderr
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/typeck.rs:10:22
|
||||||
|
|
|
||||||
|
LL | Ok(x) if let Err(_) = x => {},
|
||||||
|
| ^^^^^^ expected enum `Option`, found enum `std::result::Result`
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<bool>`
|
||||||
|
found enum `std::result::Result<_, _>`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/typeck.rs:12:22
|
||||||
|
|
|
||||||
|
LL | Ok(x) if let 0 = x => {},
|
||||||
|
| ^ expected enum `Option`, found integer
|
||||||
|
|
|
||||||
|
= note: expected enum `Option<bool>`
|
||||||
|
found type `{integer}`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
22
src/test/ui/rfc-2294-if-let-guard/warns.rs
Normal file
22
src/test/ui/rfc-2294-if-let-guard/warns.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#![feature(if_let_guard)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
#[deny(irrefutable_let_patterns)]
|
||||||
|
fn irrefutable_let_guard() {
|
||||||
|
match Some(()) {
|
||||||
|
Some(x) if let () = x => {}
|
||||||
|
//~^ ERROR irrefutable if-let guard
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[deny(unreachable_patterns)]
|
||||||
|
fn unreachable_pattern() {
|
||||||
|
match Some(()) {
|
||||||
|
x if let None | None = x => {}
|
||||||
|
//~^ ERROR unreachable pattern
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
26
src/test/ui/rfc-2294-if-let-guard/warns.stderr
Normal file
26
src/test/ui/rfc-2294-if-let-guard/warns.stderr
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
error: irrefutable if-let guard
|
||||||
|
--> $DIR/warns.rs:7:24
|
||||||
|
|
|
||||||
|
LL | Some(x) if let () = x => {}
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/warns.rs:4:8
|
||||||
|
|
|
||||||
|
LL | #[deny(irrefutable_let_patterns)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/warns.rs:16:25
|
||||||
|
|
|
||||||
|
LL | x if let None | None = x => {}
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/warns.rs:13:8
|
||||||
|
|
|
||||||
|
LL | #[deny(unreachable_patterns)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -342,6 +342,10 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
|
|||||||
if let Some(ref guard) = arm.guard {
|
if let Some(ref guard) = arm.guard {
|
||||||
match guard {
|
match guard {
|
||||||
Guard::If(if_expr) => check_expr(cx, if_expr, bindings),
|
Guard::If(if_expr) => check_expr(cx, if_expr, bindings),
|
||||||
|
Guard::IfLet(guard_pat, guard_expr) => {
|
||||||
|
check_pat(cx, guard_pat, Some(*guard_expr), guard_pat.span, bindings);
|
||||||
|
check_expr(cx, guard_expr, bindings);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check_expr(cx, &arm.body, bindings);
|
check_expr(cx, &arm.body, bindings);
|
||||||
|
@ -372,6 +372,18 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
|
|||||||
self.current = if_expr_pat;
|
self.current = if_expr_pat;
|
||||||
self.visit_expr(if_expr);
|
self.visit_expr(if_expr);
|
||||||
},
|
},
|
||||||
|
hir::Guard::IfLet(ref if_let_pat, ref if_let_expr) => {
|
||||||
|
let if_let_pat_pat = self.next("pat");
|
||||||
|
let if_let_expr_pat = self.next("expr");
|
||||||
|
println!(
|
||||||
|
" if let Guard::IfLet(ref {}, ref {}) = {};",
|
||||||
|
if_let_pat_pat, if_let_expr_pat, guard_pat
|
||||||
|
);
|
||||||
|
self.current = if_let_expr_pat;
|
||||||
|
self.visit_expr(if_let_expr);
|
||||||
|
self.current = if_let_pat_pat;
|
||||||
|
self.visit_pat(if_let_pat);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.current = format!("{}[{}].pat", arms_pat, i);
|
self.current = format!("{}[{}].pat", arms_pat, i);
|
||||||
@ -730,6 +742,7 @@ fn desugaring_name(des: hir::MatchSource) -> String {
|
|||||||
"MatchSource::IfLetDesugar {{ contains_else_clause: {} }}",
|
"MatchSource::IfLetDesugar {{ contains_else_clause: {} }}",
|
||||||
contains_else_clause
|
contains_else_clause
|
||||||
),
|
),
|
||||||
|
hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(),
|
||||||
hir::MatchSource::IfDesugar { contains_else_clause } => format!(
|
hir::MatchSource::IfDesugar { contains_else_clause } => format!(
|
||||||
"MatchSource::IfDesugar {{ contains_else_clause: {} }}",
|
"MatchSource::IfDesugar {{ contains_else_clause: {} }}",
|
||||||
contains_else_clause
|
contains_else_clause
|
||||||
|
@ -169,6 +169,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
|||||||
fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
|
fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
|
(Guard::If(l), Guard::If(r)) => self.eq_expr(l, r),
|
||||||
|
(Guard::IfLet(lp, le), Guard::IfLet(rp, re)) => self.eq_pat(lp, rp) && self.eq_expr(le, re),
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,7 +671,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||||||
|
|
||||||
pub fn hash_guard(&mut self, g: &Guard<'_>) {
|
pub fn hash_guard(&mut self, g: &Guard<'_>) {
|
||||||
match g {
|
match g {
|
||||||
Guard::If(ref expr) => {
|
Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
|
||||||
self.hash_expr(expr);
|
self.hash_expr(expr);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -560,5 +560,10 @@ fn print_guard(cx: &LateContext<'_>, guard: &hir::Guard<'_>, indent: usize) {
|
|||||||
println!("{}If", ind);
|
println!("{}If", ind);
|
||||||
print_expr(cx, expr, indent + 1);
|
print_expr(cx, expr, indent + 1);
|
||||||
},
|
},
|
||||||
|
hir::Guard::IfLet(pat, expr) => {
|
||||||
|
println!("{}IfLet", ind);
|
||||||
|
print_pat(cx, pat, indent + 1);
|
||||||
|
print_expr(cx, expr, indent + 1);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user