1
Fork 0

auto merge of #17733 : jgallagher/rust/while-let, r=alexcrichton

This is *heavily* based on `if let` (#17634) by @jakub- and @kballard

This should close #17687
This commit is contained in:
bors 2014-10-13 19:37:40 +00:00
commit c7e0724274
25 changed files with 266 additions and 15 deletions

View file

@ -2488,6 +2488,8 @@ The currently implemented features of the reference compiler are:
* `if_let` - Allows use of the `if let` syntax. * `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 * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics
are inherently unstable and no promise about them is made. are inherently unstable and no promise about them is made.
@ -3494,6 +3496,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 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. 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 ### Return expressions
```{.ebnf .gram} ```{.ebnf .gram}

View file

@ -145,5 +145,6 @@ register_diagnostics!(
E0161, E0161,
E0162, E0162,
E0163, E0163,
E0164 E0164,
E0165
) )

View file

@ -1082,7 +1082,8 @@ impl LintPass for UnnecessaryParens {
ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true), ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true),
ast::ExprMatch(ref head, _, source) => match source { ast::ExprMatch(ref head, _, source) => match source {
ast::MatchNormal => (head, "`match` head expression", true), 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::ExprRet(Some(ref value)) => (value, "`return` value", false),
ast::ExprAssign(_, ref value) => (value, "assigned value", false), ast::ExprAssign(_, ref value) => (value, "assigned value", false),

View file

@ -259,6 +259,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
expr_exit expr_exit
} }
ast::ExprWhileLet(..) => {
self.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(ref pat, ref head, ref body, _) => { ast::ExprForLoop(ref pat, ref head, ref body, _) => {
// //
// [pred] // [pred]

View file

@ -261,20 +261,32 @@ fn check_arms(cx: &MatchCheckCtxt, arms: &[(Vec<P<Pat>>, Option<&Expr>)], source
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) { match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => { NotUseful => {
if source == MatchIfLetDesugar { match source {
if printed_if_let_err { MatchIfLetDesugar => {
// we already printed an irrefutable if-let pattern error. if printed_if_let_err {
// We don't want two, that's just confusing. // we already printed an irrefutable if-let pattern error.
} else { // 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 // find the first arm pattern so we can use its span
let &(ref first_arm_pats, _) = &arms[0]; let &(ref first_arm_pats, _) = &arms[0];
let first_pat = first_arm_pats.get(0); let first_pat = first_arm_pats.get(0);
let span = first_pat.span; let span = first_pat.span;
span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern"); span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
printed_if_let_err = true; },
}
} else { MatchNormal => {
span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"); span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern")
},
} }
} }
Useful => (), Useful => (),

View file

@ -429,6 +429,10 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> {
self.walk_block(&**blk); self.walk_block(&**blk);
} }
ast::ExprWhileLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(ref pat, ref head, ref blk, _) => { ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
// The pattern lives as long as the block. // The pattern lives as long as the block.
debug!("walk_expr for loop case: blk id={}", blk.id); debug!("walk_expr for loop case: blk id={}", blk.id);

View file

@ -484,6 +484,9 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
ExprIfLet(..) => { ExprIfLet(..) => {
ir.tcx.sess.span_bug(expr.span, "non-desugared 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, _, _, _) => { ExprForLoop(ref pat, _, _, _) => {
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| { pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
debug!("adding local variable {} from for loop with bm {:?}", 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) 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, _) => { ExprForLoop(ref pat, ref head, ref blk, _) => {
let ln = self.propagate_through_loop(expr, ForLoop(&**pat), &**blk, succ); let ln = self.propagate_through_loop(expr, ForLoop(&**pat), &**blk, succ);
self.propagate_through_expr(&**head, ln) self.propagate_through_expr(&**head, ln)
@ -1480,6 +1487,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
ExprIfLet(..) => { ExprIfLet(..) => {
this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet"); this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
} }
ExprWhileLet(..) => {
this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
} }
} }

View file

@ -530,6 +530,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
ast::ExprIfLet(..) => { ast::ExprIfLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet"); self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet");
} }
ast::ExprWhileLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
} }
} }

View file

@ -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, _) => { ast::ExprForLoop(ref pattern, ref head, ref body, _) => {
walk_expr(cx, &**head, scope_stack, scope_map); walk_expr(cx, &**head, scope_stack, scope_map);

View file

@ -3605,6 +3605,9 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
ast::ExprIfLet(..) => { ast::ExprIfLet(..) => {
tcx.sess.span_bug(expr.span, "non-desugared 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) => { ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
RvalueDpsExpr RvalueDpsExpr

View file

@ -4058,6 +4058,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
fcx.write_nil(id); fcx.write_nil(id);
} }
} }
ast::ExprWhileLet(..) => {
tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(ref pat, ref head, ref block, _) => { ast::ExprForLoop(ref pat, ref head, ref block, _) => {
check_expr(fcx, &**head); check_expr(fcx, &**head);
let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);

View file

@ -93,6 +93,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
explain_span(cx, "method call", expr.span) explain_span(cx, "method call", expr.span)
}, },
ast::ExprMatch(_, _, ast::MatchIfLetDesugar) => explain_span(cx, "if let", 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), ast::ExprMatch(..) => explain_span(cx, "match", expr.span),
_ => explain_span(cx, "expression", expr.span) _ => explain_span(cx, "expression", expr.span)
} }

View file

@ -294,6 +294,7 @@ mod svh_visitor {
// just syntactic artifacts, expanded away by time of SVH. // just syntactic artifacts, expanded away by time of SVH.
ExprIfLet(..) => unreachable!(), ExprIfLet(..) => unreachable!(),
ExprWhileLet(..) => unreachable!(),
ExprMac(..) => unreachable!(), ExprMac(..) => unreachable!(),
} }
} }

View file

@ -524,6 +524,8 @@ pub enum Expr_ {
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic. // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprWhile(P<Expr>, P<Block>, Option<Ident>), ExprWhile(P<Expr>, P<Block>, Option<Ident>),
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic. // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprWhileLet(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>), ExprForLoop(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
// Conditionless loop (can be exited with break, cont, or ret) // Conditionless loop (can be exited with break, cont, or ret)
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic. // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
@ -579,7 +581,8 @@ pub struct QPath {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum MatchSource { pub enum MatchSource {
MatchNormal, MatchNormal,
MatchIfLetDesugar MatchIfLetDesugar,
MatchWhileLetDesugar,
} }
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]

View file

@ -147,6 +147,8 @@ pub trait AstBuilder {
fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr>; fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr>;
fn expr_none(&self, sp: Span) -> P<ast::Expr>; fn expr_none(&self, sp: Span) -> P<ast::Expr>;
fn expr_break(&self, sp: Span) -> P<ast::Expr>;
fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr>; fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr>;
fn expr_fail(&self, span: Span, msg: InternedString) -> P<ast::Expr>; fn expr_fail(&self, span: Span, msg: InternedString) -> P<ast::Expr>;
@ -688,6 +690,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.expr_path(none) self.expr_path(none)
} }
fn expr_break(&self, sp: Span) -> P<ast::Expr> {
self.expr(sp, ast::ExprBreak(None))
}
fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> { fn expr_tuple(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr(sp, ast::ExprTup(exprs)) self.expr(sp, ast::ExprTup(exprs))
} }

View file

@ -67,6 +67,42 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident)) fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
} }
// Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <expr> <body>`
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
// to:
//
// [opt_ident]: loop {
// match <expr> {
// <pat> => <body>,
// _ => break
// }
// }
// `<pat> => <body>`
let pat_arm = {
let body_expr = fld.cx.expr_block(body);
fld.cx.arm(pat.span, vec![pat], body_expr)
};
// `_ => break`
let break_arm = {
let pat_under = fld.cx.pat_wild(span);
let break_expr = fld.cx.expr_break(span);
fld.cx.arm(span, vec![pat_under], break_expr)
};
// `match <expr> { ... }`
let arms = vec![pat_arm, break_arm];
let match_expr = fld.cx.expr(span,
ast::ExprMatch(expr, arms, ast::MatchWhileLetDesugar));
// `[opt_ident]: loop { ... }`
let loop_block = fld.cx.block_expr(match_expr);
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
}
// Desugar ExprIfLet // Desugar ExprIfLet
// From: `if let <pat> = <expr> <body> [<elseopt>]` // From: `if let <pat> = <expr> <body> [<elseopt>]`
ast::ExprIfLet(pat, expr, body, mut elseopt) => { ast::ExprIfLet(pat, expr, body, mut elseopt) => {

View file

@ -73,6 +73,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("slicing_syntax", Active), ("slicing_syntax", Active),
("if_let", Active), ("if_let", Active),
("while_let", Active),
// if you change this list without updating src/doc/reference.md, cmr will be sad // if you change this list without updating src/doc/reference.md, cmr will be sad
@ -345,6 +346,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
e.span, e.span,
"slicing syntax is experimental"); "slicing syntax is experimental");
} }
ast::ExprWhileLet(..) => {
self.gate_feature("while_let", e.span,
"`while let` syntax is experimental");
}
_ => {} _ => {}
} }
visit::walk_expr(self, e); visit::walk_expr(self, e);

View file

@ -1216,6 +1216,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
folder.fold_block(body), folder.fold_block(body),
opt_ident.map(|i| folder.fold_ident(i))) opt_ident.map(|i| folder.fold_ident(i)))
} }
ExprWhileLet(pat, expr, body, opt_ident) => {
ExprWhileLet(folder.fold_pat(pat),
folder.fold_expr(expr),
folder.fold_block(body),
opt_ident.map(|i| folder.fold_ident(i)))
}
ExprForLoop(pat, iter, body, opt_ident) => { ExprForLoop(pat, iter, body, opt_ident) => {
ExprForLoop(folder.fold_pat(pat), ExprForLoop(folder.fold_pat(pat),
folder.fold_expr(iter), folder.fold_expr(iter),

View file

@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
| ast::ExprMatch(..) | ast::ExprMatch(..)
| ast::ExprBlock(_) | ast::ExprBlock(_)
| ast::ExprWhile(..) | ast::ExprWhile(..)
| ast::ExprWhileLet(..)
| ast::ExprLoop(..) | ast::ExprLoop(..)
| ast::ExprForLoop(..) => false, | ast::ExprForLoop(..) => false,
_ => true _ => true

View file

@ -26,7 +26,7 @@ use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, Ex
use ast::{ExprLit, ExprLoop, ExprMac}; use ast::{ExprLit, ExprLoop, ExprMac};
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc}; use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
use ast::{Once, Many}; use ast::{Once, Many};
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
use ast::{FnOnceUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind};
@ -2935,7 +2935,11 @@ impl<'a> Parser<'a> {
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)) self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
} }
/// Parse a 'while' or 'while let' expression ('while' token already eaten)
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> { pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
if self.is_keyword(keywords::Let) {
return self.parse_while_let_expr(opt_ident);
}
let lo = self.last_span.lo; let lo = self.last_span.lo;
let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
let body = self.parse_block(); let body = self.parse_block();
@ -2943,6 +2947,18 @@ impl<'a> Parser<'a> {
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)); return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
} }
/// Parse a 'while let' expression ('while' token already eaten)
pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
let lo = self.last_span.lo;
self.expect_keyword(keywords::Let);
let pat = self.parse_pat();
self.expect(&token::EQ);
let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
let body = self.parse_block();
let hi = body.span.hi;
return self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident));
}
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> { pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
let lo = self.last_span.lo; let lo = self.last_span.lo;
let body = self.parse_block(); let body = self.parse_block();

View file

@ -1515,6 +1515,19 @@ impl<'a> State<'a> {
try!(space(&mut self.s)); try!(space(&mut self.s));
try!(self.print_block(&**blk)); try!(self.print_block(&**blk));
} }
ast::ExprWhileLet(ref pat, ref expr, ref blk, opt_ident) => {
for ident in opt_ident.iter() {
try!(self.print_ident(*ident));
try!(self.word_space(":"));
}
try!(self.head("while let"));
try!(self.print_pat(&**pat));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_expr(&**expr));
try!(space(&mut self.s));
try!(self.print_block(&**blk));
}
ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => { ast::ExprForLoop(ref pat, ref iter, ref blk, opt_ident) => {
for ident in opt_ident.iter() { for ident in opt_ident.iter() {
try!(self.print_ident(*ident)); try!(self.print_ident(*ident));

View file

@ -733,6 +733,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
visitor.visit_block(&**if_block); visitor.visit_block(&**if_block);
walk_expr_opt(visitor, optional_else); walk_expr_opt(visitor, optional_else);
} }
ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
visitor.visit_pat(&**pattern);
visitor.visit_expr(&**subexpression);
visitor.visit_block(&**block);
}
ExprForLoop(ref pattern, ref subexpression, ref block, _) => { ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
visitor.visit_pat(&**pattern); visitor.visit_pat(&**pattern);
visitor.visit_expr(&**subexpression); visitor.visit_expr(&**subexpression);

View file

@ -9,7 +9,7 @@
// except according to those terms. // except according to those terms.
#![deny(unnecessary_parens)] #![deny(unnecessary_parens)]
#![feature(if_let)] #![feature(if_let,while_let)]
#[deriving(Eq, PartialEq)] #[deriving(Eq, PartialEq)]
struct X { y: bool } struct X { y: bool }
@ -34,6 +34,7 @@ fn main() {
_ => {} _ => {}
} }
if let 1i = (1i) {} //~ ERROR unnecessary parentheses around `if let` head expression if let 1i = (1i) {} //~ ERROR unnecessary parentheses around `if let` head expression
while let 1i = (2i) {} //~ ERROR unnecessary parentheses around `while let` head expression
let v = X { y: false }; let v = X { y: false };
// struct lits needs parens, so these shouldn't warn. // struct lits needs parens, so these shouldn't warn.
if (v == X { y: true }) {} if (v == X { y: true }) {}

View file

@ -0,0 +1,37 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(macro_rules,while_let)]
fn macros() {
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
while let $p = $e $b
}}
}
macro_rules! bar{
($p:pat, $e:expr, $b:block) => {{
foo!($p, $e, $b)
}}
}
foo!(a, 1i, { //~ ERROR irrefutable while-let
println!("irrefutable pattern");
});
bar!(a, 1i, { //~ ERROR irrefutable while-let
println!("irrefutable pattern");
});
}
pub fn main() {
while let a = 1i { //~ ERROR irrefutable while-let
println!("irrefutable pattern");
}
}

View file

@ -0,0 +1,56 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(while_let)]
use std::collections::PriorityQueue;
fn make_pq() -> PriorityQueue<int> {
PriorityQueue::from_vec(vec![1i,2,3])
}
pub fn main() {
let mut pq = make_pq();
let mut sum = 0i;
while let Some(x) = pq.pop() {
sum += x;
}
assert_eq!(sum, 6i);
pq = make_pq();
sum = 0;
'a: while let Some(x) = pq.pop() {
sum += x;
if x == 2 {
break 'a;
}
}
assert_eq!(sum, 5i);
pq = make_pq();
sum = 0;
'a: while let Some(x) = pq.pop() {
if x == 3 {
continue 'a;
}
sum += x;
}
assert_eq!(sum, 3i);
let mut pq1 = make_pq();
sum = 0;
while let Some(x) = pq1.pop() {
let mut pq2 = make_pq();
while let Some(y) = pq2.pop() {
sum += x * y;
}
}
assert_eq!(sum, 6i + 12 + 18);
}