Skip to content

Commit d07c6e8

Browse files
author
Lenny222
committed
list: use predicate to enforce non-empty requirement
1 parent 816b0ac commit d07c6e8

File tree

6 files changed

+72
-16
lines changed

6 files changed

+72
-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

@@ -177,7 +177,9 @@ fn visit_block(tp: block_type, cx: ctx, visit: block()) {
177177
visit();
178178
local.second = true;
179179
visit();
180-
cx.blocks = tail(cx.blocks);
180+
let cx_blocks = cx.blocks;
181+
check is_not_empty(cx_blocks);
182+
cx.blocks = tail(cx_blocks);
181183
cx.current = join_branches(local.exits);
182184
}
183185

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];
@@ -455,6 +456,7 @@ fn visit_block_with_scope(b: ast::blk, sc: scopes, v: vt<scopes>) {
455456
}
456457

457458
fn visit_decl_with_scope(d: @decl, sc: scopes, v: vt<scopes>) {
459+
check list::is_not_empty(sc);
458460
let loc_pos = alt list::head(sc) {
459461
scope_block(_, _, pos) { pos }
460462
_ { @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

+21-7
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@ 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_not_empty, tail};
86
import option;
97

108
#[test]
119
fn test_from_vec() {
1210
let l = from_vec([0, 1, 2]);
11+
12+
check is_not_empty(l);
1313
assert (head(l) == 0);
14-
assert (head(tail(l)) == 1);
15-
assert (head(tail(tail(l))) == 2);
14+
15+
let tail_l = tail(l);
16+
check is_not_empty(tail_l);
17+
assert (head(tail_l) == 1);
18+
19+
let tail_tail_l = tail(tail_l);
20+
check is_not_empty(tail_tail_l);
21+
assert (head(tail_tail_l) == 2);
1622
}
1723

1824
#[test]
@@ -24,9 +30,17 @@ fn test_from_vec_empty() {
2430
#[test]
2531
fn test_from_vec_mut() {
2632
let l = from_vec([mutable 0, 1, 2]);
33+
34+
check is_not_empty(l);
2735
assert (head(l) == 0);
28-
assert (head(tail(l)) == 1);
29-
assert (head(tail(tail(l))) == 2);
36+
37+
let tail_l = tail(l);
38+
check is_not_empty(tail_l);
39+
assert (head(tail_l) == 1);
40+
41+
let tail_tail_l = tail(tail_l);
42+
check is_not_empty(tail_tail_l);
43+
assert (head(tail_tail_l) == 2);
3044
}
3145

3246
#[test]

0 commit comments

Comments
 (0)