new liveness pass to supercede last_use / initedness

This commit is contained in:
Niko Matsakis 2012-05-19 05:52:01 -07:00
parent a3be0b1054
commit 30b47649ea
89 changed files with 2104 additions and 162 deletions

View File

@ -351,7 +351,7 @@ enum expr_ {
}
#[auto_serialize]
type capture_item = {
type capture_item = @{
id: int,
is_move: bool,
name: ident, // Currently, can only capture a local var.

View File

@ -434,7 +434,7 @@ class parser {
fn parse_capture_item(p:parser, is_move: bool) -> capture_item {
let sp = mk_sp(p.span.lo, p.span.hi);
let ident = parse_ident(p);
{id: p.get_id(), is_move: is_move, name: ident, span: sp}
@{id: p.get_id(), is_move: is_move, name: ident, span: sp}
}
if eat_keyword(self, "move") {
@ -1710,7 +1710,7 @@ class parser {
let id = p.get_id();
let sp = mk_sp(p.span.lo, p.span.hi);
let ident = parse_ident(p);
res += [{id:id, is_move: is_move, name:ident, span:sp}];
res += [@{id:id, is_move: is_move, name:ident, span:sp}];
if !eat(p, token::COMMA) {
ret res;
}

View File

@ -192,6 +192,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
bind middle::check_loop::check_crate(ty_cx, crate));
time(time_passes, "alt checking",
bind middle::check_alt::check_crate(ty_cx, crate));
let _last_use_map =
time(time_passes, "liveness checking",
bind middle::liveness::check_crate(ty_cx, method_map, crate));
time(time_passes, "typestate checking",
bind middle::tstate::ck::check_crate(ty_cx, crate));
let (root_map, mutbl_map) = time(

View File

@ -541,6 +541,15 @@ enum assignment_type {
}
impl methods for assignment_type {
fn checked_by_liveness() -> bool {
// the liveness pass guarantees that immutable local variables
// are only assigned once; but it doesn't consider &mut
alt self {
at_straight_up {true}
at_swap {true}
at_mutbl_ref {false}
}
}
fn ing_form(desc: str) -> str {
alt self {
at_straight_up { "assigning to " + desc }
@ -717,6 +726,13 @@ impl methods for check_loan_ctxt {
}
}
fn is_local_variable(cmt: cmt) -> bool {
alt cmt.cat {
cat_local(_) {true}
_ {false}
}
}
fn is_self_field(cmt: cmt) -> bool {
alt cmt.cat {
cat_comp(cmt_base, comp_field(_)) {
@ -735,9 +751,13 @@ impl methods for check_loan_ctxt {
#debug["check_assignment(cmt=%s)",
self.bccx.cmt_to_repr(cmt)];
// check that the lvalue `ex` is assignable, but be careful
// because assigning to self.foo in a ctor is always allowed.
if !self.in_ctor || !self.is_self_field(cmt) {
if self.in_ctor && self.is_self_field(cmt)
&& at.checked_by_liveness() {
// assigning to self.foo in a ctor is always allowed.
} else if self.is_local_variable(cmt) && at.checked_by_liveness() {
// liveness guarantees that immutable local variables
// are only assigned once
} else {
alt cmt.mutbl {
m_mutbl { /*ok*/ }
m_const | m_imm {

View File

@ -1,5 +1,6 @@
import syntax::{ast, ast_util};
import driver::session::session;
import syntax::codemap::span;
import std::map;
import std::map::hashmap;
@ -14,15 +15,17 @@ export cap_drop;
export cap_ref;
enum capture_mode {
cap_copy, //< Copy the value into the closure.
cap_move, //< Move the value into the closure.
cap_drop, //< Drop value after creating closure.
cap_ref, //< Reference directly from parent stack frame (block fn).
cap_copy, // Copy the value into the closure.
cap_move, // Move the value into the closure.
cap_drop, // Drop value after creating closure.
cap_ref, // Reference directly from parent stack frame (block fn).
}
type capture_var = {
def: ast::def, //< The variable being accessed free.
mode: capture_mode //< How is the variable being accessed.
def: ast::def, // Variable being accessed free
span: span, // Location of access or cap item
cap_item: option<ast::capture_item>, // Capture item, if any
mode: capture_mode // How variable is being accessed
};
type capture_map = map::hashmap<ast::def_id, capture_var>;
@ -70,15 +73,24 @@ fn compute_capture_vars(tcx: ty::ctxt,
// if we are moving the value in, but it's not actually used,
// must drop it.
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_move });
cap_map.insert(cap_def_id, {def:cap_def,
span: cap_item.span,
cap_item: some(cap_item),
mode:cap_move});
} else {
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_drop });
cap_map.insert(cap_def_id, {def:cap_def,
span: cap_item.span,
cap_item: some(cap_item),
mode:cap_drop});
}
} else {
// if we are copying the value in, but it's not actually used,
// just ignore it.
if vec::any(*freevars, {|fv| fv.def == cap_def}) {
cap_map.insert(cap_def_id, { def:cap_def, mode:cap_copy });
cap_map.insert(cap_def_id, {def:cap_def,
span: cap_item.span,
cap_item: some(cap_item),
mode:cap_copy});
}
}
}
@ -96,7 +108,10 @@ fn compute_capture_vars(tcx: ty::ctxt,
alt cap_map.find(fvar_def_id) {
option::some(_) { /* was explicitly named, do nothing */ }
option::none {
cap_map.insert(fvar_def_id, {def:fvar.def, mode:implicit_mode});
cap_map.insert(fvar_def_id, {def:fvar.def,
span: fvar.span,
cap_item: none,
mode:implicit_mode});
}
}
}

1502
src/rustc/middle/liveness.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -72,6 +72,7 @@ mod middle {
mod borrowck;
mod alias;
mod last_use;
mod liveness;
mod block_use;
mod kind;
mod freevars;

View File

@ -1,8 +0,0 @@
// error-pattern:unsatisfied precondition constraint (for example, init(i
fn main() {
let i: int;
log(debug, false && { i = 5; true });
log(debug, i);
}

View File

@ -0,0 +1,9 @@
fn test(cond: bool) {
let v: int;
v = 1; //! NOTE prior assignment occurs here
v = 2; //! ERROR re-assignment of immutable variable
}
fn main() {
test(true);
}

View File

@ -1,4 +0,0 @@
// error-pattern:unsatisfied precondition constraint
fn force(f: fn()) { f(); }
fn main() { let x: int; force(fn&() { log(error, x); }); }

View File

@ -1,14 +0,0 @@
// error-pattern:unsatisfied precondition
fn foo() -> int {
let x: int;
let i: int;
loop { i = 0; break; x = 0; }
log(debug, x);
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -1,14 +0,0 @@
// error-pattern:unsatisfied precondition
fn foo() -> int {
let x: int;
let i: int;
while 1 != 2 { i = 0; break; x = 0; }
log(debug, x);
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -1,7 +0,0 @@
// error-pattern:unsatisfied precondition
fn main() {
// Typestate should work even in a fn@. we should reject this program.
let f = fn@() -> int { let i: int; ret i; };
log(error, f());
}

View File

@ -1,6 +0,0 @@
// error-pattern:unsatisfied precondition
fn main() {
let j = fn@() -> int { let i: int; ret i; }();
log(error, j);
}

View File

@ -1,12 +0,0 @@
// -*- rust -*-
// error-pattern: precondition
type point = {x: int, y: int};
fn main() {
let origin: point;
let right: point = {x: 10 with origin};
origin = {x: 0, y: 0};
}

View File

@ -1,5 +0,0 @@
fn main(s: [str]) {
let a: [int] = [];
vec::each(a) { |x| //! ERROR in function `anon`, not all control paths
} //! ERROR see function return type of `bool`
}

View File

@ -0,0 +1,6 @@
fn main() {
let i: int;
log(debug, false && { i = 5; true });
log(debug, i); //! ERROR use of possibly uninitialized variable: `i`
}

View File

@ -0,0 +1,11 @@
fn test(cond: bool) {
let v: int;
loop {
v = 1; //! ERROR re-assignment of immutable variable
//!^ NOTE prior assignment occurs here
}
}
fn main() {
test(true);
}

View File

@ -0,0 +1,9 @@
fn test(cond: bool) {
let v: int;
v = 2; //! NOTE prior assignment occurs here
v += 1; //! ERROR re-assignment of immutable variable
}
fn main() {
test(true);
}

View File

@ -0,0 +1,18 @@
fn test1() {
let v: int;
let mut w: int;
v = 1; //! NOTE prior assignment occurs here
w = 2;
v <-> w; //! ERROR re-assignment of immutable variable
}
fn test2() {
let v: int;
let mut w: int;
v = 1; //! NOTE prior assignment occurs here
w = 2;
w <-> v; //! ERROR re-assignment of immutable variable
}
fn main() {
}

View File

@ -0,0 +1,7 @@
fn force(f: fn()) { f(); }
fn main() {
let x: int;
force(fn&() {
log(debug, x); //! ERROR capture of possibly uninitialized variable: `x`
});
}

View File

@ -0,0 +1,16 @@
fn foo() -> int {
let x: int;
let i: int;
while 1 != 2 {
i = 0;
break;
x = 0; //! WARNING unreachable statement
}
log(debug, x); //! ERROR use of possibly uninitialized variable: `x`
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -0,0 +1,16 @@
fn foo() -> int {
let x: int;
let i: int;
loop {
i = 0;
break;
x = 0; //! WARNING unreachable statement
}
log(debug, x); //! ERROR use of possibly uninitialized variable: `x`
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -0,0 +1,11 @@
class cat {
let how_hungry : int;
fn meow() {}
new() {
self.meow();
//!^ ERROR use of possibly uninitialized field: `self.how_hungry`
}
}
fn main() {
}

View File

@ -0,0 +1,7 @@
class cat {
let how_hungry : int;
new() {} //! ERROR field `self.how_hungry` is never initialized
}
fn main() {
}

View File

@ -0,0 +1,14 @@
class cat {
let mut a: int;
let mut b: int;
let mut c: int;
new() {
self.a = 3;
self.b = self.a;
self.a += self.c; //! ERROR use of possibly uninitialized field: `self.c`
}
}
fn main() {
}

View File

@ -1,4 +1,3 @@
// error-pattern:unsatisfied precondition
class cat {
priv {
let mut meows : uint;
@ -13,7 +12,7 @@ class cat {
new(in_x : uint, in_y : int) {
let foo;
self.meows = in_x + (in_y as uint);
self.how_hungry = foo;
self.how_hungry = foo; //! ERROR use of possibly uninitialized variable: `foo`
}
}

View File

@ -0,0 +1,6 @@
fn foo(x: int) { log(debug, x); }
fn main() {
let x: int; if 1 > 2 { x = 10; }
foo(x); //! ERROR use of possibly uninitialized variable: `x`
}

View File

@ -1,5 +1,3 @@
// error-pattern:unsatisfied precondition
fn foo(x: int) { log(debug, x); }
fn main() {
@ -9,5 +7,5 @@ fn main() {
} else {
x = 10;
}
foo(x);
foo(x); //! ERROR use of possibly uninitialized variable: `x`
}

View File

@ -0,0 +1,7 @@
fn main() {
let j = fn@() -> int {
let i: int;
ret i; //! ERROR use of possibly uninitialized variable: `i`
};
j();
}

View File

@ -0,0 +1,7 @@
fn main() {
let f = fn@() -> int {
let i: int;
ret i; //! ERROR use of possibly uninitialized variable: `i`
};
log(error, f());
}

View File

@ -0,0 +1,8 @@
// -*- rust -*-
type point = {x: int, y: int};
fn main() {
let mut origin: point;
origin = {x: 10 with origin}; //! ERROR use of possibly uninitialized variable: `origin`
}

View File

@ -0,0 +1,8 @@
fn test(cond: bool) {
let v: int;
v += 1; //! ERROR use of possibly uninitialized variable: `v`
}
fn main() {
test(true);
}

View File

@ -0,0 +1,8 @@
fn test(cond: bool) {
let mut v: int;
v = v + 1; //! ERROR use of possibly uninitialized variable: `v`
}
fn main() {
test(true);
}

View File

@ -0,0 +1,5 @@
fn main(s: [str]) {
let a: [int] = [];
vec::each(a) { |x| //! ERROR not all control paths return a value
}
}

View File

@ -0,0 +1,10 @@
fn take(-x: int) {}
fn main() {
let x: int = 25;
loop {
take(x); //! ERROR use of moved variable: `x`
//!^ NOTE move of variable occurred here
}
}

View File

@ -0,0 +1,16 @@
fn main() {
let y: int = 42;
let mut x: int;
loop {
log(debug, y);
loop {
loop {
loop {
x <- y; //! ERROR use of moved variable
//!^ NOTE move of variable occurred here
}
}
}
}
}

View File

@ -1,10 +1,11 @@
// error-pattern:unsatisfied precondition constraint (for example, init(y
fn main() {
let y: int = 42;
let x: int;
let mut x: int;
loop {
log(debug, y);
while true { while true { while true { x <- y; } } }
//!^ ERROR use of moved variable: `y`
//!^^ NOTE move of variable occurred here
}
}

View File

@ -0,0 +1,6 @@
fn main() {
let i: int;
log(debug, false || { i = 5; true });
log(debug, i); //! ERROR use of possibly uninitialized variable: `i`
}

View File

@ -0,0 +1,6 @@
fn f() -> int {
let x: int;
ret x; //! ERROR use of possibly uninitialized variable: `x`
}
fn main() { f(); }

View File

@ -0,0 +1,5 @@
fn main() {
let x = 3;
let y;
x <-> y; //! ERROR use of possibly uninitialized variable: `y`
}

View File

@ -0,0 +1,6 @@
fn main() {
let bar;
fn baz(x: int) { }
bind baz(bar); //! ERROR use of possibly uninitialized variable: `bar`
}

View File

@ -0,0 +1,6 @@
fn foo(x: int) { log(debug, x); }
fn main() {
let x: int;
foo(x); //! ERROR use of possibly uninitialized variable: `x`
}

View File

@ -0,0 +1,5 @@
fn main() {
let x = @5;
let y <- x; //! NOTE move of variable occurred here
log(debug, *x); //! ERROR use of moved variable: `x`
}

View File

@ -1,4 +1,3 @@
// error-pattern:unsatisfied precondition constraint
fn send<T: send>(ch: _chan<T>, -data: T) {
log(debug, ch);
log(debug, data);
@ -10,8 +9,8 @@ enum _chan<T> = int;
// Tests that "log(debug, message);" is flagged as using
// message after the send deinitializes it
fn test00_start(ch: _chan<int>, message: int, count: int) {
send(ch, message);
log(debug, message);
send(ch, message); //! NOTE move of variable occurred here
log(debug, message); //! ERROR use of moved variable: `message`
}
fn main() { fail; }

View File

@ -0,0 +1,6 @@
fn test() {
let w: [int];
w[5] = 0; //! ERROR use of possibly uninitialized variable: `w`
}
fn main() { test(); }

View File

@ -0,0 +1,12 @@
fn test(cond: bool) {
let v;
while cond {
v = 3;
break;
}
#debug["%d", v]; //! ERROR use of possibly uninitialized variable: `v`
}
fn main() {
test(true);
}

View File

@ -0,0 +1,4 @@
fn main() {
let x: bool;
while x { } //! ERROR use of possibly uninitialized variable: `x`
}

View File

@ -0,0 +1,7 @@
fn f() -> int {
let mut x: int;
while 1 == 1 { x = 10; }
ret x; //! ERROR use of possibly uninitialized variable: `x`
}
fn main() { f(); }

View File

@ -1,4 +0,0 @@
// error-pattern:unsatisfied precondition constraint
fn test(-foo: int) { assert (foo == 10); }
fn main() { let x = 10; test(x); log(debug, x); }

View File

@ -1,8 +0,0 @@
// error-pattern:unsatisfied precondition constraint (for example, init(i
fn main() {
let i: int;
log(debug, false || { i = 5; true });
log(debug, i);
}

View File

@ -1,5 +0,0 @@
// error-pattern: precondition constraint
fn f() -> int { let x: int; ret x; }
fn main() { f(); }

View File

@ -1,3 +0,0 @@
// error-pattern:unsatisfied precondition
fn main() { let x = 3; let y; x <-> y; }

View File

@ -0,0 +1,7 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let i: int = 4;
log(debug, false && { check is_even(i); true });
even(i); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,11 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn force(f: fn()) { f(); }
fn main() {
let x: int = 4;
force(fn&() {
even(x); //! ERROR unsatisfied precondition
});
}

View File

@ -0,0 +1,16 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn foo() -> int {
let x: int = 4;
while 1 != 2 {
break;
check is_even(x); //! WARNING unreachable statement
}
even(x); //! ERROR unsatisfied precondition
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -0,0 +1,16 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn foo() -> int {
let x: int = 4;
loop {
break;
check is_even(x); //! WARNING unreachable statement
}
even(x); //! ERROR unsatisfied precondition
ret 17;
}
fn main() { log(debug, foo()); }

View File

@ -0,0 +1,25 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
class cat {
priv {
let mut meows : uint;
}
let how_hungry : int;
fn eat() {
self.how_hungry -= 5;
}
new(in_x : uint, in_y : int) {
let foo = 3;
self.meows = in_x + (in_y as uint);
self.how_hungry = even(foo); //! ERROR unsatisfied precondition
}
}
fn main() {
let nyan : cat = cat(52u, 99);
nyan.eat();
}

View File

@ -0,0 +1,13 @@
// -*- rust -*-
type point = {x: int, y: int};
pure fn test(_p: point) -> bool { true }
fn tested(p: point) : test(p) -> point { p }
fn main() {
let origin: point;
origin = {x: 0, y: 0};
let right: point = {x: 10 with tested(origin)};
//!^ ERROR precondition
}

View File

@ -0,0 +1,10 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn foo(x: int) { log(debug, x); }
fn main() {
let x: int = 10;
if 1 > 2 { check is_even(x); }
even(x); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,14 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn foo(x: int) { log(debug, x); }
fn main() {
let x: int = 10;
if 1 > 2 {
#debug("whoops");
} else {
check is_even(x);
}
even(x); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,19 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let mut x: int = 42;
loop {
loop {
loop {
check is_even(x);
even(x); // OK
loop {
even(x); //! ERROR unsatisfied precondition
x = 11;
}
}
}
}
}

View File

@ -0,0 +1,7 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let i: int = 4;
log(debug, false || { check is_even(i); true });
even(i); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,9 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn f() -> int {
let x: int = 4;
ret even(x); //! ERROR unsatisfied precondition
}
fn main() { f(); }

View File

@ -0,0 +1,9 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let x = 4;
fn baz(_x: int) { }
bind baz(even(x)); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,9 @@
fn foo(v: [int]) : vec::is_empty(v) { #debug("%d", v[0]); }
fn main() {
let f = fn@() {
let v = [1];
foo(v); //! ERROR unsatisfied precondition constraint
}();
log(error, f);
}

View File

@ -0,0 +1,9 @@
fn foo(v: [int]) : vec::is_empty(v) { #debug("%d", v[0]); }
fn main() {
let f = fn@() {
let v = [1];
foo(v); //! ERROR unsatisfied precondition constraint
};
log(error, f());
}

View File

@ -0,0 +1,7 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let x: int = 4;
even(x); //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,15 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn test(cond: bool) {
let v = 4;
while cond {
check is_even(v);
break;
}
even(v); //! ERROR unsatisfied precondition
}
fn main() {
test(true);
}

View File

@ -0,0 +1,7 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn main() {
let x: int = 4;
while even(x) != 0 { } //! ERROR unsatisfied precondition
}

View File

@ -0,0 +1,10 @@
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn f() {
let mut x: int = 10;
while 1 == 1 { x = 10; }
even(x); //! ERROR unsatisfied precondition
}
fn main() { f(); }

View File

@ -1,7 +0,0 @@
// error-pattern:unsatisfied precondition constraint (for example, init(bar
fn main() {
let bar;
fn baz(x: int) { }
bind baz(bar);
}

View File

@ -1,2 +0,0 @@
// error-pattern:unsatisfied precondition constraint (for example, init(x
fn main() { let x = @5; let y <- x; log(debug, *x); }

View File

@ -1,5 +0,0 @@
// error-pattern:unsatisfied precondition
fn foo(x: int) { log(debug, x); }
fn main() { let x: int; if 1 > 2 { x = 10; } foo(x); }

View File

@ -1,5 +0,0 @@
// error-pattern:unsatisfied precondition
fn foo(x: int) { log(debug, x); }
fn main() { let x: int; foo(x); }

View File

@ -1,5 +0,0 @@
// error-pattern: precondition constraint
fn f() -> int { let x: int; while 1 == 1 { x = 10; } ret x; }
fn main() { f(); }

View File

@ -1,3 +0,0 @@
// error-pattern: precondition constraint
fn main() { let x: bool; while x { } }

View File

@ -1,14 +0,0 @@
// error-pattern:unsatisfied precondition constraint (for example, init(y
fn main() {
let y: int = 42;
let x: int;
loop {
log(debug, y);
loop {
loop {
loop { x <- y; }
}
}
}
}

View File

@ -1,5 +0,0 @@
// error-pattern:unsatisfied precondition constraint
fn test() { let w: [int]; w[5] = 0; }
fn main() { test(); }

View File

@ -0,0 +1,10 @@
fn test(cond: bool) {
let v: int;
v = 1;
loop { } // loop never terminates, so no error is reported
v = 2;
}
fn main() {
// note: don't call test()... :)
}

View File

@ -0,0 +1,9 @@
fn test() {
let _v: int;
_v = 1;
ret;
_v = 2; //! WARNING: unreachable statement
}
fn main() {
}

View File

@ -0,0 +1,14 @@
// xfail-test --- tstate incorrectly fails this
fn test() {
let v;
loop {
v = 3;
break;
}
#debug["%d", v];
}
fn main() {
test();
}

View File

@ -0,0 +1,15 @@
fn take(-x: int) -> int {x}
fn the_loop() {
let mut list = [];
loop {
let x = 5;
if x > 3 {
list += [take(x)];
} else {
break;
}
}
}
fn main() {}

View File

@ -0,0 +1,17 @@
// xfail-test
pure fn is_even(i: int) -> bool { (i%2) == 0 }
fn even(i: int) : is_even(i) -> int { i }
fn test() {
let v = 4;
loop {
check is_even(v);
break;
}
even(v);
}
fn main() {
test();
}