diff --git a/src/doc/reference.md b/src/doc/reference.md index c34a136a68e88..4ad64576e1588 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2503,6 +2503,8 @@ The currently implemented features of the reference compiler are: * `if_let` - Allows use of the `if let` syntax. +* `while_let` - Allows use of the `while let` syntax. + * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics are inherently unstable and no promise about them is made. @@ -3509,6 +3511,18 @@ of a condition expression it expects a refutable let statement. If the value of expression on the right hand side of the let statement matches the pattern, the corresponding block will execute, otherwise flow proceeds to the first `else` block that follows. +### While let loops + +```{.ebnf .gram} +while_let_expr : "while" "let" pat '=' expr '{' block '}' ; +``` + +A `while let` loop is semantically identical to a `while` loop but in place of a +condition expression it expects a refutable let statement. If the value of the +expression on the right hand side of the let statement matches the pattern, the +loop body block executes and control returns to the pattern matching statement. +Otherwise, the while expression completes. + ### Return expressions ```{.ebnf .gram} diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index b39c415216837..0ccfc7e80f606 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -150,5 +150,6 @@ register_diagnostics!( E0161, E0162, E0163, - E0164 + E0164, + E0165 ) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e0e16390e353f..988b128e31d5c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1082,7 +1082,8 @@ impl LintPass for UnnecessaryParens { ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true), ast::ExprMatch(ref head, _, source) => match source { ast::MatchNormal => (head, "`match` head expression", true), - ast::MatchIfLetDesugar => (head, "`if let` head expression", true) + ast::MatchIfLetDesugar => (head, "`if let` head expression", true), + ast::MatchWhileLetDesugar => (head, "`while let` head expression", true), }, ast::ExprRet(Some(ref value)) => (value, "`return` value", false), ast::ExprAssign(_, ref value) => (value, "assigned value", false), diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index a9a3981ab5fc8..b573c4e59487a 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -259,6 +259,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { expr_exit } + ast::ExprWhileLet(..) => { + self.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); + } + ast::ExprForLoop(ref pat, ref head, ref body, _) => { // // [pred] diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 297640707687c..3976574aef9c0 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -261,20 +261,32 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[(Vec
>, Option<&Expr>)], source
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => {
- if source == MatchIfLetDesugar {
- if printed_if_let_err {
- // we already printed an irrefutable if-let pattern error.
- // We don't want two, that's just confusing.
- } else {
+ match source {
+ MatchIfLetDesugar => {
+ if printed_if_let_err {
+ // we already printed an irrefutable if-let pattern error.
+ // We don't want two, that's just confusing.
+ } else {
+ // find the first arm pattern so we can use its span
+ let &(ref first_arm_pats, _) = &arms[0];
+ let first_pat = first_arm_pats.get(0);
+ let span = first_pat.span;
+ span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern");
+ printed_if_let_err = true;
+ }
+ },
+
+ MatchWhileLetDesugar => {
// find the first arm pattern so we can use its span
let &(ref first_arm_pats, _) = &arms[0];
let first_pat = first_arm_pats.get(0);
let span = first_pat.span;
- span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern");
- printed_if_let_err = true;
- }
- } else {
- span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern");
+ span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
+ },
+
+ MatchNormal => {
+ span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
+ },
}
}
Useful => (),
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 6cfdac93efc8a..6f179e0624fe2 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -429,6 +429,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
self.walk_block(&**blk);
}
+ ast::ExprWhileLet(..) => {
+ self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
+
ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
// The pattern lives as long as the block.
debug!("walk_expr for loop case: blk id={}", blk.id);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 2176cd5658943..90973dfaa0028 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -484,6 +484,9 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
ExprIfLet(..) => {
ir.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
}
+ ExprWhileLet(..) => {
+ ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
ExprForLoop(ref pat, _, _, _) => {
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
debug!("adding local variable {} from for loop with bm {:?}",
@@ -1022,6 +1025,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_loop(expr, WhileLoop(&**cond), &**blk, succ)
}
+ ExprWhileLet(..) => {
+ self.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
+
ExprForLoop(ref pat, ref head, ref blk, _) => {
let ln = self.propagate_through_loop(expr, ForLoop(&**pat), &**blk, succ);
self.propagate_through_expr(&**head, ln)
@@ -1480,6 +1487,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ExprIfLet(..) => {
this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
}
+ ExprWhileLet(..) => {
+ this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
}
}
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index fa494b357c19d..4a1c4aaa89514 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -530,6 +530,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
ast::ExprIfLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet");
}
+ ast::ExprWhileLet(..) => {
+ self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
}
}
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 43c989982996f..d81f78f23ffaf 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -3496,6 +3496,11 @@ fn populate_scope_map(cx: &CrateContext,
})
}
+ ast::ExprWhileLet(..) => {
+ cx.sess().span_bug(exp.span, "debuginfo::populate_scope_map() - \
+ Found unexpanded while-let.");
+ }
+
ast::ExprForLoop(ref pattern, ref head, ref body, _) => {
walk_expr(cx, &**head, scope_stack, scope_map);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index cea74c6573d54..9a51b258ae469 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3615,6 +3615,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprIfLet(..) => {
tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
}
+ ast::ExprWhileLet(..) => {
+ tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
RvalueDpsExpr
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 68bb3fcf94544..07a56ad46203c 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -4116,6 +4116,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.write_nil(id);
}
}
+ ast::ExprWhileLet(..) => {
+ tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
ast::ExprForLoop(ref pat, ref head, ref block, _) => {
check_expr(fcx, &**head);
let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 6898eb17e9170..459e7eb093e7c 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -93,6 +93,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
explain_span(cx, "method call", expr.span)
},
ast::ExprMatch(_, _, ast::MatchIfLetDesugar) => explain_span(cx, "if let", expr.span),
+ ast::ExprMatch(_, _, ast::MatchWhileLetDesugar) => {
+ explain_span(cx, "while let", expr.span)
+ },
ast::ExprMatch(..) => explain_span(cx, "match", expr.span),
_ => explain_span(cx, "expression", expr.span)
}
diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs
index 35e42e3c54b23..3c28cac6c6f7c 100644
--- a/src/librustc_back/svh.rs
+++ b/src/librustc_back/svh.rs
@@ -294,6 +294,7 @@ mod svh_visitor {
// just syntactic artifacts, expanded away by time of SVH.
ExprIfLet(..) => unreachable!(),
+ ExprWhileLet(..) => unreachable!(),
ExprMac(..) => unreachable!(),
}
}
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 274bb2e39e019..4ed3ee0159884 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -524,6 +524,8 @@ pub enum Expr_ {
// FIXME #6993: change to Option >) -> P >) -> P