Skip to content

Commit 513a263

Browse files
committed
Merge pull request #1392 from Lenny222/list
list: add "is_not_empty" requirement to "head" and "tail" (analogous to "vec")
2 parents 4e88d5a + ab2a643 commit 513a263

File tree

6 files changed

+87
-16
lines changed

6 files changed

+87
-16
lines changed

src/comp/middle/last_use.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import syntax::{visit, ast_util};
22
import syntax::ast::*;
33
import syntax::codemap::span;
4-
import std::list::{list, nil, cons, tail};
4+
import std::list::{is_not_empty, list, nil, cons, tail};
55
import core::{vec, option};
66
import std::list;
77

@@ -192,7 +192,9 @@ fn visit_block(tp: block_type, cx: ctx, visit: block()) {
192192
visit();
193193
local.second = true;
194194
visit();
195-
cx.blocks = tail(cx.blocks);
195+
let cx_blocks = cx.blocks;
196+
check is_not_empty(cx_blocks);
197+
cx.blocks = tail(cx_blocks);
196198
cx.current = join_branches(local.exits);
197199
}
198200

src/comp/middle/resolve.rs

+2
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ fn map_crate(e: @env, c: @ast::crate) {
266266
let imp = follow_import(*e, sc, *path, vi.span);
267267
if option::is_some(imp) {
268268
let glob = {def: option::get(imp), item: vi};
269+
check list::is_not_empty(sc);
269270
alt list::head(sc) {
270271
scope_item(i) {
271272
e.mod_map.get(i.id).glob_imports += [glob];
@@ -461,6 +462,7 @@ fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
461462
}
462463

463464
fn visit_decl_with_scope(d: @decl, sc: scopes, v: vt<scopes>) {
465+
check list::is_not_empty(sc);
464466
let loc_pos = alt list::head(sc) {
465467
scope_block(_, _, pos) { pos }
466468
_ { @mutable 0u }

src/libstd/list.rs

+31-4
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,27 @@ fn has<copy T>(ls: list<T>, elt: T) -> bool {
9797
ret false;
9898
}
9999

100+
/*
101+
Function: is_empty
102+
103+
Returns true if the list is empty.
104+
*/
105+
pure fn is_empty<copy T>(ls: list<T>) -> bool {
106+
alt ls {
107+
nil. { true }
108+
_ { false }
109+
}
110+
}
111+
112+
/*
113+
Function: is_not_empty
114+
115+
Returns true if the list is not empty.
116+
*/
117+
pure fn is_not_empty<copy T>(ls: list<T>) -> bool {
118+
ret !is_empty(ls);
119+
}
120+
100121
/*
101122
Function: len
102123
@@ -112,17 +133,23 @@ Function: tail
112133
113134
Returns all but the first element of a list
114135
*/
115-
pure fn tail<copy T>(ls: list<T>) -> list<T> {
116-
alt ls { cons(_, tl) { ret *tl; } nil. { fail "list empty" } }
136+
pure fn tail<copy T>(ls: list<T>) : is_not_empty(ls) -> list<T> {
137+
alt ls {
138+
cons(_, tl) { ret *tl; }
139+
nil. { fail "list empty" }
140+
}
117141
}
118142

119143
/*
120144
Function: head
121145
122146
Returns the first element of a list
123147
*/
124-
pure fn head<copy T>(ls: list<T>) -> T {
125-
alt ls { cons(hd, _) { ret hd; } nil. { fail "list empty" } }
148+
pure fn head<copy T>(ls: list<T>) : is_not_empty(ls) -> T {
149+
alt ls {
150+
cons(hd, _) { ret hd; }
151+
nil. { fail "list empty" }
152+
}
126153
}
127154

128155
/*

src/test/run-pass/non-boolean-pure-fns.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ pure fn nonempty_list<copy T>(ls: list<T>) -> bool { pure_length(ls) > 0u }
1414
// knowledge that ls is a cons node. Future work.
1515
// Also, this is pretty contrived since nonempty_list
1616
// could be a "tag refinement", if we implement those.
17-
fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) }
17+
fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T {
18+
check is_not_empty(ls);
19+
ret head(ls);
20+
}
1821

1922
fn main() {
2023
let mylist = cons(@1u, @nil);

src/test/run-pass/unchecked-predicates.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
// Uses foldl to exhibit the unchecked block syntax.
2+
// TODO: since list's head/tail require the predicate "is_not_empty" now and
3+
// we have unit tests for list, this test might me not necessary anymore?
24
use std;
35

46
import std::list::*;
57

68
// Can't easily be written as a "pure fn" because there's
79
// no syntax for specifying that f is pure.
810
fn pure_foldl<copy T, copy U>(ls: list<T>, u: U, f: block(T, U) -> U) -> U {
9-
alt ls { nil. { u } cons(hd, tl) { f(hd, pure_foldl(*tl, f(hd, u), f)) } }
11+
alt ls {
12+
nil. { u }
13+
cons(hd, tl) { f(hd, pure_foldl(*tl, f(hd, u), f)) }
14+
}
1015
}
1116

1217
// Shows how to use an "unchecked" block to call a general
@@ -22,7 +27,10 @@ pure fn nonempty_list<copy T>(ls: list<T>) -> bool { pure_length(ls) > 0u }
2227
// knowledge that ls is a cons node. Future work.
2328
// Also, this is pretty contrived since nonempty_list
2429
// could be a "tag refinement", if we implement those.
25-
fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) }
30+
fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T {
31+
check is_not_empty(ls);
32+
ret head(ls)
33+
}
2634

2735
fn main() {
2836
let mylist = cons(@1u, @nil);

src/test/stdtest/list.rs

+36-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,38 @@ import core::*;
22

33
use std;
44
import std::list;
5-
import std::list::head;
6-
import std::list::tail;
7-
import std::list::from_vec;
5+
import std::list::{from_vec, head, is_empty, is_not_empty, tail};
86
import option;
97

8+
#[test]
9+
fn test_is_empty() {
10+
let empty : list::list<int> = from_vec([]);
11+
let full1 = from_vec([1]);
12+
let full2 = from_vec(['r', 'u']);
13+
14+
assert is_empty(empty);
15+
assert !is_empty(full1);
16+
assert !is_empty(full2);
17+
18+
assert !is_not_empty(empty);
19+
assert is_not_empty(full1);
20+
assert is_not_empty(full2);
21+
}
22+
1023
#[test]
1124
fn test_from_vec() {
1225
let l = from_vec([0, 1, 2]);
26+
27+
check is_not_empty(l);
1328
assert (head(l) == 0);
14-
assert (head(tail(l)) == 1);
15-
assert (head(tail(tail(l))) == 2);
29+
30+
let tail_l = tail(l);
31+
check is_not_empty(tail_l);
32+
assert (head(tail_l) == 1);
33+
34+
let tail_tail_l = tail(tail_l);
35+
check is_not_empty(tail_tail_l);
36+
assert (head(tail_tail_l) == 2);
1637
}
1738

1839
#[test]
@@ -24,9 +45,17 @@ fn test_from_vec_empty() {
2445
#[test]
2546
fn test_from_vec_mut() {
2647
let l = from_vec([mutable 0, 1, 2]);
48+
49+
check is_not_empty(l);
2750
assert (head(l) == 0);
28-
assert (head(tail(l)) == 1);
29-
assert (head(tail(tail(l))) == 2);
51+
52+
let tail_l = tail(l);
53+
check is_not_empty(tail_l);
54+
assert (head(tail_l) == 1);
55+
56+
let tail_tail_l = tail(tail_l);
57+
check is_not_empty(tail_tail_l);
58+
assert (head(tail_tail_l) == 2);
3059
}
3160

3261
#[test]

0 commit comments

Comments
 (0)