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:
commit
c7e0724274
@ -2488,6 +2488,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.
|
||||
|
||||
@ -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
|
||||
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}
|
||||
|
@ -145,5 +145,6 @@ register_diagnostics!(
|
||||
E0161,
|
||||
E0162,
|
||||
E0163,
|
||||
E0164
|
||||
E0164,
|
||||
E0165
|
||||
)
|
||||
|
@ -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),
|
||||
|
@ -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]
|
||||
|
@ -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) {
|
||||
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 => (),
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -3605,6 +3605,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
|
||||
|
@ -4058,6 +4058,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);
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -294,6 +294,7 @@ mod svh_visitor {
|
||||
|
||||
// just syntactic artifacts, expanded away by time of SVH.
|
||||
ExprIfLet(..) => unreachable!(),
|
||||
ExprWhileLet(..) => unreachable!(),
|
||||
ExprMac(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -524,6 +524,8 @@ pub enum Expr_ {
|
||||
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
|
||||
ExprWhile(P<Expr>, P<Block>, Option<Ident>),
|
||||
// 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>),
|
||||
// Conditionless loop (can be exited with break, cont, or ret)
|
||||
// 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)]
|
||||
pub enum MatchSource {
|
||||
MatchNormal,
|
||||
MatchIfLetDesugar
|
||||
MatchIfLetDesugar,
|
||||
MatchWhileLetDesugar,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
|
@ -147,6 +147,8 @@ pub trait AstBuilder {
|
||||
fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> 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_fail(&self, span: Span, msg: InternedString) -> P<ast::Expr>;
|
||||
@ -688,6 +690,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
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> {
|
||||
self.expr(sp, ast::ExprTup(exprs))
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
// 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
|
||||
// From: `if let <pat> = <expr> <body> [<elseopt>]`
|
||||
ast::ExprIfLet(pat, expr, body, mut elseopt) => {
|
||||
|
@ -73,6 +73,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
("slicing_syntax", Active),
|
||||
|
||||
("if_let", Active),
|
||||
("while_let", Active),
|
||||
|
||||
// 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,
|
||||
"slicing syntax is experimental");
|
||||
}
|
||||
ast::ExprWhileLet(..) => {
|
||||
self.gate_feature("while_let", e.span,
|
||||
"`while let` syntax is experimental");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_expr(self, e);
|
||||
|
@ -1216,6 +1216,12 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
|
||||
folder.fold_block(body),
|
||||
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(folder.fold_pat(pat),
|
||||
folder.fold_expr(iter),
|
||||
|
@ -28,6 +28,7 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
||||
| ast::ExprMatch(..)
|
||||
| ast::ExprBlock(_)
|
||||
| ast::ExprWhile(..)
|
||||
| ast::ExprWhileLet(..)
|
||||
| ast::ExprLoop(..)
|
||||
| ast::ExprForLoop(..) => false,
|
||||
_ => true
|
||||
|
@ -26,7 +26,7 @@ use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIfLet, ExprIndex, Ex
|
||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||
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::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
|
||||
use ast::{FnOnceUnboxedClosureKind};
|
||||
@ -2935,7 +2935,11 @@ impl<'a> Parser<'a> {
|
||||
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> {
|
||||
if self.is_keyword(keywords::Let) {
|
||||
return self.parse_while_let_expr(opt_ident);
|
||||
}
|
||||
let lo = self.last_span.lo;
|
||||
let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL);
|
||||
let body = self.parse_block();
|
||||
@ -2943,6 +2947,18 @@ impl<'a> Parser<'a> {
|
||||
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> {
|
||||
let lo = self.last_span.lo;
|
||||
let body = self.parse_block();
|
||||
|
@ -1515,6 +1515,19 @@ impl<'a> State<'a> {
|
||||
try!(space(&mut self.s));
|
||||
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) => {
|
||||
for ident in opt_ident.iter() {
|
||||
try!(self.print_ident(*ident));
|
||||
|
@ -733,6 +733,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_block(&**if_block);
|
||||
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, _) => {
|
||||
visitor.visit_pat(&**pattern);
|
||||
visitor.visit_expr(&**subexpression);
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(unnecessary_parens)]
|
||||
#![feature(if_let)]
|
||||
#![feature(if_let,while_let)]
|
||||
|
||||
#[deriving(Eq, PartialEq)]
|
||||
struct X { y: bool }
|
||||
@ -34,6 +34,7 @@ fn main() {
|
||||
_ => {}
|
||||
}
|
||||
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 };
|
||||
// struct lits needs parens, so these shouldn't warn.
|
||||
if (v == X { y: true }) {}
|
||||
|
37
src/test/compile-fail/while-let.rs
Normal file
37
src/test/compile-fail/while-let.rs
Normal 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");
|
||||
}
|
||||
}
|
56
src/test/run-pass/while-let.rs
Normal file
56
src/test/run-pass/while-let.rs
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user