Update stdlib, compiler, and tests to new kind system

This involved adding 'copy' to more generics than I hoped, but an
experiment with making it implicit showed that that way lies madness --
unless enforced, you will not remember to mark functions that don't
copy as not requiring copyable kind.

Issue #1177
This commit is contained in:
Marijn Haverbeke 2011-11-18 12:39:20 +01:00
parent 8f8ebb550c
commit f6491bb426
94 changed files with 327 additions and 489 deletions

View file

@ -199,7 +199,7 @@ fn require_unique_names(sess: session::session, metas: [@ast::meta_item]) {
} }
} }
fn span<T>(item: T) -> ast::spanned<T> { fn span<copy T>(item: T) -> ast::spanned<T> {
ret {node: item, span: ast_util::dummy_sp()}; ret {node: item, span: ast_util::dummy_sp()};
} }

View file

@ -196,7 +196,9 @@ fn mk_test_module(cx: test_ctxt) -> @ast::item {
ret @item; ret @item;
} }
fn nospan<T>(t: T) -> ast::spanned<T> { ret {node: t, span: dummy_sp()}; } fn nospan<copy T>(t: T) -> ast::spanned<T> {
ret {node: t, span: dummy_sp()};
}
fn mk_tests(cx: test_ctxt) -> @ast::item { fn mk_tests(cx: test_ctxt) -> @ast::item {
let ret_ty = mk_test_desc_vec_ty(cx); let ret_ty = mk_test_desc_vec_ty(cx);

View file

@ -389,7 +389,7 @@ fn encode_info_for_items(ecx: @encode_ctxt, ebml_w: ebml::writer) ->
// Path and definition ID indexing // Path and definition ID indexing
fn create_index<T>(index: [entry<T>], hash_fn: fn(T) -> uint) -> fn create_index<copy T>(index: [entry<T>], hash_fn: fn(T) -> uint) ->
[@[entry<T>]] { [@[entry<T>]] {
let buckets: [@mutable [entry<T>]] = []; let buckets: [@mutable [entry<T>]] = [];
uint::range(0u, 256u) {|_i| buckets += [@mutable []]; }; uint::range(0u, 256u) {|_i| buckets += [@mutable []]; };

View file

@ -150,7 +150,7 @@ fn parse_ty_constr_arg(st: @pstate, sd: str_def) ->
} }
} }
fn parse_constr<T>(st: @pstate, sd: str_def, pser: arg_parser<T>) -> fn parse_constr<copy T>(st: @pstate, sd: str_def, pser: arg_parser<T>) ->
@ty::constr_general<T> { @ty::constr_general<T> {
let sp = ast_util::dummy_sp(); // FIXME: use a real span let sp = ast_util::dummy_sp(); // FIXME: use a real span
let args: [@sp_constr_arg<T>] = []; let args: [@sp_constr_arg<T>] = [];

View file

@ -74,7 +74,7 @@ fn map_expr(cx: ctx, ex: @expr) {
cx.map.insert(ex.id, node_expr(ex)); cx.map.insert(ex.id, node_expr(ex));
} }
fn new_smallintmap_int_adapter<V>() -> std::map::hashmap<int, V> { fn new_smallintmap_int_adapter<copy V>() -> std::map::hashmap<int, V> {
let key_idx = fn (&&key: int) -> uint { key as uint }; let key_idx = fn (&&key: int) -> uint { key as uint };
let idx_key = fn (idx: uint) -> int { idx as int }; let idx_key = fn (idx: uint) -> int { idx as int };
ret new_smallintmap_adapter(key_idx, idx_key); ret new_smallintmap_adapter(key_idx, idx_key);
@ -85,11 +85,11 @@ fn new_smallintmap_int_adapter<V>() -> std::map::hashmap<int, V> {
// the entire codebase adapting all the callsites to the different // the entire codebase adapting all the callsites to the different
// interface. // interface.
// FIXME: hashmap and smallintmap should support the same interface. // FIXME: hashmap and smallintmap should support the same interface.
fn new_smallintmap_adapter<K, V>(key_idx: fn(K) -> uint, fn new_smallintmap_adapter<copy K, copy V>(key_idx: fn(K) -> uint,
idx_key: fn(uint) -> K) idx_key: fn(uint) -> K)
-> std::map::hashmap<K, V> { -> std::map::hashmap<K, V> {
obj adapter<shar K, shar V>(map: smallintmap::smallintmap<V>, obj adapter<copy K, copy V>(map: smallintmap::smallintmap<V>,
key_idx: fn(K) -> uint, key_idx: fn(K) -> uint,
idx_key: fn(uint) -> K) { idx_key: fn(uint) -> K) {

View file

@ -23,9 +23,7 @@ type def_id = {crate: crate_num, node: node_id};
const local_crate: crate_num = 0; const local_crate: crate_num = 0;
tag plicit<T> { explicit(T); implicit(T); } type ty_param = {ident: ident, kind: kind};
type ty_param = {ident: ident, kind: plicit<kind>};
tag def { tag def {
def_fn(def_id, purity); def_fn(def_id, purity);

View file

@ -2,7 +2,9 @@ import std::{str, option};
import codemap::span; import codemap::span;
import ast::*; import ast::*;
fn respan<T>(sp: span, t: T) -> spanned<T> { ret {node: t, span: sp}; } fn respan<copy T>(sp: span, t: T) -> spanned<T> {
ret {node: t, span: sp};
}
/* assuming that we're not in macro expansion */ /* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span { fn mk_sp(lo: uint, hi: uint) -> span {
@ -186,7 +188,7 @@ fn eq_def_id(&&a: def_id, &&b: def_id) -> bool {
a == b a == b
} }
fn new_def_id_hash<T>() -> std::map::hashmap<def_id, T> { fn new_def_id_hash<copy T>() -> std::map::hashmap<def_id, T> {
std::map::mk_hashmap(hash_def_id, eq_def_id) std::map::mk_hashmap(hash_def_id, eq_def_id)
} }
@ -228,9 +230,7 @@ fn ret_by_ref(style: ret_style) -> bool {
} }
} }
fn ty_param_kind(tp: ty_param) -> kind { fn ty_param_kind(tp: ty_param) -> kind { tp.kind }
alt tp.kind { ast::implicit(x) | ast::explicit(x) { x } }
}
// Local Variables: // Local Variables:
// mode: rust // mode: rust

View file

@ -103,7 +103,7 @@ fn elts_to_ell(cx: ext_ctxt, elts: [@expr]) ->
} }
} }
fn option_flatten_map<T, U>(f: fn@(T) -> option::t<U>, v: [T]) -> fn option_flatten_map<copy T, copy U>(f: fn@(T) -> option::t<U>, v: [T]) ->
option::t<[U]> { option::t<[U]> {
let res = []; let res = [];
for elem: T in v { for elem: T in v {

View file

@ -219,7 +219,7 @@ fn expect_gt(p: parser) {
} }
} }
fn spanned<T>(lo: uint, hi: uint, node: T) -> spanned<T> { fn spanned<copy T>(lo: uint, hi: uint, node: T) -> spanned<T> {
ret {node: node, span: ast_util::mk_sp(lo, hi)}; ret {node: node, span: ast_util::mk_sp(lo, hi)};
} }
@ -394,8 +394,8 @@ fn parse_constr_in_type(p: parser) -> @ast::ty_constr {
} }
fn parse_constrs<T>(pser: block(parser) -> @ast::constr_general<T>, fn parse_constrs<copy T>(pser: block(parser) -> @ast::constr_general<T>,
p: parser) -> p: parser) ->
[@ast::constr_general<T>] { [@ast::constr_general<T>] {
let constrs: [@ast::constr_general<T>] = []; let constrs: [@ast::constr_general<T>] = [];
while true { while true {
@ -595,9 +595,9 @@ fn parse_fn_block_arg(p: parser) -> ast::arg {
ret {mode: m, ty: t, ident: i, id: p.get_id()}; ret {mode: m, ty: t, ident: i, id: p.get_id()};
} }
fn parse_seq_to_before_gt<T>(sep: option::t<token::token>, fn parse_seq_to_before_gt<copy T>(sep: option::t<token::token>,
f: block(parser) -> T, f: block(parser) -> T,
p: parser) -> [T] { p: parser) -> [T] {
let first = true; let first = true;
let v = []; let v = [];
while p.peek() != token::GT && p.peek() != token::BINOP(token::LSR) && while p.peek() != token::GT && p.peek() != token::BINOP(token::LSR) &&
@ -612,16 +612,17 @@ fn parse_seq_to_before_gt<T>(sep: option::t<token::token>,
ret v; ret v;
} }
fn parse_seq_to_gt<T>(sep: option::t<token::token>, f: block(parser) -> T, fn parse_seq_to_gt<copy T>(sep: option::t<token::token>,
p: parser) -> [T] { f: block(parser) -> T, p: parser) -> [T] {
let v = parse_seq_to_before_gt(sep, f, p); let v = parse_seq_to_before_gt(sep, f, p);
expect_gt(p); expect_gt(p);
ret v; ret v;
} }
fn parse_seq_lt_gt<T>(sep: option::t<token::token>, f: block(parser) -> T, fn parse_seq_lt_gt<copy T>(sep: option::t<token::token>,
p: parser) -> spanned<[T]> { f: block(parser) -> T,
p: parser) -> spanned<[T]> {
let lo = p.get_lo_pos(); let lo = p.get_lo_pos();
expect(p, token::LT); expect(p, token::LT);
let result = parse_seq_to_before_gt::<T>(sep, f, p); let result = parse_seq_to_before_gt::<T>(sep, f, p);
@ -630,16 +631,16 @@ fn parse_seq_lt_gt<T>(sep: option::t<token::token>, f: block(parser) -> T,
ret spanned(lo, hi, result); ret spanned(lo, hi, result);
} }
fn parse_seq_to_end<T>(ket: token::token, sep: option::t<token::token>, fn parse_seq_to_end<copy T>(ket: token::token, sep: option::t<token::token>,
f: block(parser) -> T, p: parser) -> [T] { f: block(parser) -> T, p: parser) -> [T] {
let val = parse_seq_to_before_end(ket, sep, f, p); let val = parse_seq_to_before_end(ket, sep, f, p);
p.bump(); p.bump();
ret val; ret val;
} }
fn parse_seq_to_before_end<T>(ket: token::token, fn parse_seq_to_before_end<copy T>(ket: token::token,
sep: option::t<token::token>, sep: option::t<token::token>,
f: block(parser) -> T, p: parser) -> [T] { f: block(parser) -> T, p: parser) -> [T] {
let first: bool = true; let first: bool = true;
let v: [T] = []; let v: [T] = [];
while p.peek() != ket { while p.peek() != ket {
@ -653,9 +654,9 @@ fn parse_seq_to_before_end<T>(ket: token::token,
} }
fn parse_seq<T>(bra: token::token, ket: token::token, fn parse_seq<copy T>(bra: token::token, ket: token::token,
sep: option::t<token::token>, f: block(parser) -> T, sep: option::t<token::token>, f: block(parser) -> T,
p: parser) -> spanned<[T]> { p: parser) -> spanned<[T]> {
let lo = p.get_lo_pos(); let lo = p.get_lo_pos();
expect(p, bra); expect(p, bra);
let result = parse_seq_to_before_end::<T>(ket, sep, f, p); let result = parse_seq_to_before_end::<T>(ket, sep, f, p);
@ -1741,24 +1742,18 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
ret spanned(lo, hi, bloc); ret spanned(lo, hi, bloc);
} }
fn parse_ty_param(p: parser, def: ast::kind) -> ast::ty_param { fn parse_ty_param(p: parser) -> ast::ty_param {
// Accept both old and new kind names for now. FIXME remove this let k = if eat_word(p, "send") { ast::kind_sendable }
let k = if eat_word(p, "send") | eat_word(p, "uniq") else if eat_word(p, "copy") { ast::kind_copyable }
{ ast::explicit(ast::kind_sendable) } else { ast::kind_noncopyable };
else if eat_word(p, "copy") | eat_word(p, "shar")
{ ast::explicit(ast::kind_copyable) }
else if eat_word(p, "nocopy") | eat_word(p, "pin")
{ ast::explicit(ast::kind_noncopyable) }
else { ast::implicit(def) };
ret {ident: parse_ident(p), kind: k}; ret {ident: parse_ident(p), kind: k};
} }
fn parse_ty_params(p: parser, def: ast::kind) -> [ast::ty_param] { fn parse_ty_params(p: parser) -> [ast::ty_param] {
let ty_params: [ast::ty_param] = []; let ty_params: [ast::ty_param] = [];
if p.peek() == token::LT { if p.peek() == token::LT {
p.bump(); p.bump();
ty_params = parse_seq_to_gt(some(token::COMMA), ty_params = parse_seq_to_gt(some(token::COMMA), parse_ty_param, p);
{|p| parse_ty_param(p, def)}, p);
} }
ret ty_params; ret ty_params;
} }
@ -1811,7 +1806,7 @@ fn parse_fn(p: parser, proto: ast::proto, purity: ast::purity,
fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} { fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
let id = parse_value_ident(p); let id = parse_value_ident(p);
let ty_params = parse_ty_params(p, ast::kind_copyable); let ty_params = parse_ty_params(p);
ret {ident: id, tps: ty_params}; ret {ident: id, tps: ty_params};
} }
@ -1864,7 +1859,7 @@ fn parse_method(p: parser) -> @ast::method {
fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item { fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos(); let lo = p.get_last_lo_pos();
let ident = parse_value_ident(p); let ident = parse_value_ident(p);
let ty_params = parse_ty_params(p, ast::kind_copyable); let ty_params = parse_ty_params(p);
let fields: ast::spanned<[ast::obj_field]> = let fields: ast::spanned<[ast::obj_field]> =
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_obj_field, p); parse_obj_field, p);
@ -1881,7 +1876,7 @@ fn parse_item_obj(p: parser, attrs: [ast::attribute]) -> @ast::item {
fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos(); let lo = p.get_last_lo_pos();
let ident = parse_value_ident(p); let ident = parse_value_ident(p);
let ty_params = parse_ty_params(p, ast::kind_noncopyable); let ty_params = parse_ty_params(p);
expect(p, token::LPAREN); expect(p, token::LPAREN);
let arg_ident = parse_value_ident(p); let arg_ident = parse_value_ident(p);
expect(p, token::COLON); expect(p, token::COLON);
@ -2045,7 +2040,7 @@ fn parse_type_decl(p: parser) -> {lo: uint, ident: ast::ident} {
fn parse_item_type(p: parser, attrs: [ast::attribute]) -> @ast::item { fn parse_item_type(p: parser, attrs: [ast::attribute]) -> @ast::item {
let t = parse_type_decl(p); let t = parse_type_decl(p);
let tps = parse_ty_params(p, ast::kind_noncopyable); let tps = parse_ty_params(p);
expect(p, token::EQ); expect(p, token::EQ);
let ty = parse_ty(p, false); let ty = parse_ty(p, false);
let hi = p.get_hi_pos(); let hi = p.get_hi_pos();
@ -2056,7 +2051,7 @@ fn parse_item_type(p: parser, attrs: [ast::attribute]) -> @ast::item {
fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item { fn parse_item_tag(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos(); let lo = p.get_last_lo_pos();
let id = parse_ident(p); let id = parse_ident(p);
let ty_params = parse_ty_params(p, ast::kind_noncopyable); let ty_params = parse_ty_params(p);
let variants: [ast::variant] = []; let variants: [ast::variant] = [];
// Newtype syntax // Newtype syntax
if p.peek() == token::EQ { if p.peek() == token::EQ {

View file

@ -1167,12 +1167,11 @@ fn print_arg_mode(s: ps, m: ast::mode) {
} }
} }
fn print_kind(s: ps, kind: ast::plicit<ast::kind>) { fn print_kind(s: ps, kind: ast::kind) {
alt kind { alt kind {
ast::explicit(ast::kind_sendable.) { word_nbsp(s, "send"); } ast::kind_sendable. { word_nbsp(s, "send"); }
ast::explicit(ast::kind_copyable.) { word_nbsp(s, "copy"); } ast::kind_copyable. { word_nbsp(s, "copy"); }
ast::explicit(ast::kind_noncopyable.) { word_nbsp(s, "nocopy"); } ast::kind_noncopyable. {}
ast::implicit(_) {}
} }
} }

View file

@ -11,12 +11,12 @@ type interner<T> =
hasher: hashfn<T>, hasher: hashfn<T>,
eqer: eqfn<T>}; eqer: eqfn<T>};
fn mk<T>(hasher: hashfn<T>, eqer: eqfn<T>) -> interner<T> { fn mk<copy T>(hasher: hashfn<T>, eqer: eqfn<T>) -> interner<T> {
let m = map::mk_hashmap::<T, uint>(hasher, eqer); let m = map::mk_hashmap::<T, uint>(hasher, eqer);
ret {map: m, mutable vect: [], hasher: hasher, eqer: eqer}; ret {map: m, mutable vect: [], hasher: hasher, eqer: eqer};
} }
fn intern<T>(itr: interner<T>, val: T) -> uint { fn intern<copy T>(itr: interner<T>, val: T) -> uint {
alt itr.map.find(val) { alt itr.map.find(val) {
some(idx) { ret idx; } some(idx) { ret idx; }
none. { none. {
@ -31,7 +31,7 @@ fn intern<T>(itr: interner<T>, val: T) -> uint {
// |get| isn't "pure" in the traditional sense, because it can go from // |get| isn't "pure" in the traditional sense, because it can go from
// failing to returning a value as items are interned. But for typestate, // failing to returning a value as items are interned. But for typestate,
// where we first check a pred and then rely on it, ceasing to fail is ok. // where we first check a pred and then rely on it, ceasing to fail is ok.
pure fn get<T>(itr: interner<T>, idx: uint) -> T { pure fn get<copy T>(itr: interner<T>, idx: uint) -> T {
unchecked { unchecked {
itr.vect[idx] itr.vect[idx]
} }

View file

@ -21,7 +21,7 @@ fn hash_def(d: ast::def_id) -> uint {
ret h; ret h;
} }
fn new_def_hash<V>() -> std::map::hashmap<ast::def_id, V> { fn new_def_hash<copy V>() -> std::map::hashmap<ast::def_id, V> {
let hasher: std::map::hashfn<ast::def_id> = hash_def; let hasher: std::map::hashfn<ast::def_id> = hash_def;
let eqer: std::map::eqfn<ast::def_id> = def_eq; let eqer: std::map::eqfn<ast::def_id> = def_eq;
ret std::map::mk_hashmap::<ast::def_id, V>(hasher, eqer); ret std::map::mk_hashmap::<ast::def_id, V>(hasher, eqer);
@ -162,7 +162,7 @@ fn lit_in_range(l: @ast::lit, m1: @ast::lit, m2: @ast::lit) -> bool {
} }
} }
fn ranges_overlap<T>(a1: T, a2: T, b1: T, b2: T) -> bool { fn ranges_overlap<copy T>(a1: T, a2: T, b1: T, b2: T) -> bool {
let min1 = min(a1, a2); let min1 = min(a1, a2);
let max1 = max(a1, a2); let max1 = max(a1, a2);
let min2 = min(b1, b2); let min2 = min(b1, b2);

View file

@ -55,7 +55,7 @@ fn mk_filesearch(maybe_sysroot: option::t<fs::path>,
} }
// FIXME #1001: This can't be an obj method // FIXME #1001: This can't be an obj method
fn search<T>(filesearch: filesearch, pick: pick<T>) -> option::t<T> { fn search<copy T>(filesearch: filesearch, pick: pick<T>) -> option::t<T> {
for lib_search_path in filesearch.lib_search_paths() { for lib_search_path in filesearch.lib_search_paths() {
log #fmt["searching %s", lib_search_path]; log #fmt["searching %s", lib_search_path];
for path in fs::list_dir(lib_search_path) { for path in fs::list_dir(lib_search_path) {

View file

@ -224,7 +224,7 @@ fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
check_variants_T(crate, codemap, filename, "ty", stolen.tys, pprust::ty_to_str, replace_ty_in_crate, cx); check_variants_T(crate, codemap, filename, "ty", stolen.tys, pprust::ty_to_str, replace_ty_in_crate, cx);
} }
fn check_variants_T<T>( fn check_variants_T<copy T>(
crate: ast::crate, crate: ast::crate,
codemap: codemap::codemap, codemap: codemap::codemap,
filename: str, filename: str,

View file

@ -39,7 +39,7 @@ native mod rustrt {
type void; type void;
type rust_port; type rust_port;
fn chan_id_send<uniq T>(t: *sys::type_desc, fn chan_id_send<send T>(t: *sys::type_desc,
target_task: task::task, target_port: port_id, target_task: task::task, target_port: port_id,
data: T) -> ctypes::uintptr_t; data: T) -> ctypes::uintptr_t;
@ -52,7 +52,7 @@ native mod rustrt {
#[abi = "rust-intrinsic"] #[abi = "rust-intrinsic"]
native mod rusti { native mod rusti {
fn recv<uniq T>(port: *rustrt::rust_port) -> T; fn recv<send T>(port: *rustrt::rust_port) -> T;
} }
type port_id = int; type port_id = int;
@ -75,11 +75,11 @@ dropped.
Channels may be duplicated and themselves transmitted over other channels. Channels may be duplicated and themselves transmitted over other channels.
*/ */
tag chan<uniq T> { tag chan<send T> {
chan_t(task::task, port_id); chan_t(task::task, port_id);
} }
resource port_ptr<uniq T>(po: *rustrt::rust_port) { resource port_ptr<send T>(po: *rustrt::rust_port) {
// Once the port is detached it's guaranteed not to receive further // Once the port is detached it's guaranteed not to receive further
// messages // messages
rustrt::rust_port_detach(po); rustrt::rust_port_detach(po);
@ -103,7 +103,7 @@ transmitted. If a port value is copied, both copies refer to the same port.
Ports may be associated with multiple <chan>s. Ports may be associated with multiple <chan>s.
*/ */
tag port<uniq T> { port_t(@port_ptr<T>); } tag port<send T> { port_t(@port_ptr<T>); }
/* /*
Function: send Function: send
@ -113,7 +113,7 @@ Sends data over a channel.
The sent data is moved into the channel, whereupon the caller loses access The sent data is moved into the channel, whereupon the caller loses access
to it. to it.
*/ */
fn send<uniq T>(ch: chan<T>, -data: T) { fn send<send T>(ch: chan<T>, -data: T) {
let chan_t(t, p) = ch; let chan_t(t, p) = ch;
let res = rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data); let res = rustrt::chan_id_send(sys::get_type_desc::<T>(), t, p, data);
if res != 0u unsafe { if res != 0u unsafe {
@ -128,7 +128,7 @@ Function: port
Constructs a port. Constructs a port.
*/ */
fn port<uniq T>() -> port<T> { fn port<send T>() -> port<T> {
port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>()))) port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
} }
@ -140,7 +140,7 @@ Receive from a port.
If no data is available on the port then the task will block until data If no data is available on the port then the task will block until data
becomes available. becomes available.
*/ */
fn recv<uniq T>(p: port<T>) -> T { ret rusti::recv(***p) } fn recv<send T>(p: port<T>) -> T { ret rusti::recv(***p) }
/* /*
Function: chan Function: chan
@ -149,6 +149,6 @@ Constructs a channel.
The channel is bound to the port used to construct it. The channel is bound to the port used to construct it.
*/ */
fn chan<uniq T>(p: port<T>) -> chan<T> { fn chan<send T>(p: port<T>) -> chan<T> {
chan_t(task::get_task(), rustrt::get_port_id(***p)) chan_t(task::get_task(), rustrt::get_port_id(***p))
} }

View file

@ -33,7 +33,7 @@ Section: Functions
/* /*
Function: create Function: create
*/ */
fn create<T>() -> t<T> { fn create<copy T>() -> t<T> {
type cell<T> = option::t<T>; type cell<T> = option::t<T>;
let initial_capacity: uint = 32u; // 2^5 let initial_capacity: uint = 32u; // 2^5
@ -41,7 +41,7 @@ fn create<T>() -> t<T> {
* Grow is only called on full elts, so nelts is also len(elts), unlike * Grow is only called on full elts, so nelts is also len(elts), unlike
* elsewhere. * elsewhere.
*/ */
fn grow<T>(nelts: uint, lo: uint, elts: [mutable cell<T>]) -> fn grow<copy T>(nelts: uint, lo: uint, elts: [mutable cell<T>]) ->
[mutable cell<T>] { [mutable cell<T>] {
assert (nelts == vec::len(elts)); assert (nelts == vec::len(elts));
let rv = [mutable]; let rv = [mutable];
@ -60,7 +60,7 @@ fn create<T>() -> t<T> {
fn get<T>(elts: [mutable cell<T>], i: uint) -> T { fn get<T>(elts: [mutable cell<T>], i: uint) -> T {
ret alt elts[i] { option::some(t) { t } _ { fail } }; ret alt elts[i] { option::some(t) { t } _ { fail } };
} }
obj deque<shar T>(mutable nelts: uint, obj deque<copy T>(mutable nelts: uint,
mutable lo: uint, mutable lo: uint,
mutable hi: uint, mutable hi: uint,
mutable elts: [mutable cell<T>]) { mutable elts: [mutable cell<T>]) {

View file

@ -39,7 +39,7 @@ Function: lefts
Extracts from a vector of either all the left values. Extracts from a vector of either all the left values.
*/ */
fn lefts<T, U>(eithers: [t<T, U>]) -> [T] { fn lefts<copy T, U>(eithers: [t<T, U>]) -> [T] {
let result: [T] = []; let result: [T] = [];
for elt: t<T, U> in eithers { for elt: t<T, U> in eithers {
alt elt { left(l) { result += [l]; } _ {/* fallthrough */ } } alt elt { left(l) { result += [l]; } _ {/* fallthrough */ } }
@ -52,7 +52,7 @@ Function: rights
Extracts from a vector of either all the right values Extracts from a vector of either all the right values
*/ */
fn rights<T, U>(eithers: [t<T, U>]) -> [U] { fn rights<T, copy U>(eithers: [t<T, U>]) -> [U] {
let result: [U] = []; let result: [U] = [];
for elt: t<T, U> in eithers { for elt: t<T, U> in eithers {
alt elt { right(r) { result += [r]; } _ {/* fallthrough */ } } alt elt { right(r) { result += [r]; } _ {/* fallthrough */ } }
@ -68,7 +68,8 @@ Extracts from a vector of either all the left values and right values
Returns a structure containing a vector of left values and a vector of Returns a structure containing a vector of left values and a vector of
right values. right values.
*/ */
fn partition<T, U>(eithers: [t<T, U>]) -> {lefts: [T], rights: [U]} { fn partition<copy T, copy U>(eithers: [t<T, U>])
-> {lefts: [T], rights: [U]} {
let lefts: [T] = []; let lefts: [T] = [];
let rights: [U] = []; let rights: [U] = [];
for elt: t<T, U> in eithers { for elt: t<T, U> in eithers {

View file

@ -50,7 +50,7 @@ Function: insert
Insert a value into the map Insert a value into the map
*/ */
fn insert<K, V>(m: treemap<K, V>, k: K, v: V) -> treemap<K, V> { fn insert<copy K, copy V>(m: treemap<K, V>, k: K, v: V) -> treemap<K, V> {
@alt m { @alt m {
@empty. { node(@k, @v, @empty, @empty) } @empty. { node(@k, @v, @empty, @empty) }
@node(@kk, vv, left, right) { @node(@kk, vv, left, right) {
@ -68,7 +68,7 @@ Function: find
Find a value based on the key Find a value based on the key
*/ */
fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> { fn find<K, copy V>(m: treemap<K, V>, k: K) -> option<V> {
alt *m { alt *m {
empty. { none } empty. { none }
node(@kk, @v, left, right) { node(@kk, @v, left, right) {
@ -84,7 +84,7 @@ Function: traverse
Visit all pairs in the map in order. Visit all pairs in the map in order.
*/ */
fn traverse<K, V>(m: treemap<K, V>, f: block(K, V)) { fn traverse<K, copy V>(m: treemap<K, V>, f: block(K, V)) {
alt *m { alt *m {
empty. { } empty. { }
node(@k, @v, _, _) { node(@k, @v, _, _) {

View file

@ -25,7 +25,7 @@ Function: from_vec
Create a list from a vector Create a list from a vector
*/ */
fn from_vec<T>(v: [const T]) -> list<T> { fn from_vec<copy T>(v: [const T]) -> list<T> {
*vec::foldr({ |h, t| @cons(h, t) }, @nil::<T>, v) *vec::foldr({ |h, t| @cons(h, t) }, @nil::<T>, v)
} }
@ -44,7 +44,7 @@ ls - The list to fold
z - The initial value z - The initial value
f - The function to apply f - The function to apply
*/ */
fn foldl<T, U>(ls: list<U>, z: T, f: block(T, U) -> T) -> T { fn foldl<copy T, copy U>(ls: list<U>, z: T, f: block(T, U) -> T) -> T {
let accum: T = z; let accum: T = z;
let ls = ls; let ls = ls;
while true { while true {
@ -65,7 +65,8 @@ Apply function `f` to each element of `v`, starting from the first.
When function `f` returns true then an option containing the element When function `f` returns true then an option containing the element
is returned. If `f` matches no elements then none is returned. is returned. If `f` matches no elements then none is returned.
*/ */
fn find<T, U>(ls: list<T>, f: block(T) -> option::t<U>) -> option::t<U> { fn find<copy T, copy U>(ls: list<T>, f: block(T) -> option::t<U>)
-> option::t<U> {
let ls = ls; let ls = ls;
while true { while true {
alt ls { alt ls {
@ -83,7 +84,7 @@ Function: has
Returns true if a list contains an element with the given value Returns true if a list contains an element with the given value
*/ */
fn has<T>(ls: list<T>, elt: T) -> bool { fn has<copy T>(ls: list<T>, elt: T) -> bool {
let ls = ls; let ls = ls;
while true { while true {
alt ls { alt ls {
@ -99,7 +100,7 @@ Function: len
Returns the length of a list Returns the length of a list
*/ */
fn len<T>(ls: list<T>) -> uint { fn len<copy T>(ls: list<T>) -> uint {
fn count<T>(&&u: uint, _t: T) -> uint { ret u + 1u; } fn count<T>(&&u: uint, _t: T) -> uint { ret u + 1u; }
ret foldl(ls, 0u, bind count(_, _)); ret foldl(ls, 0u, bind count(_, _));
} }
@ -109,7 +110,7 @@ Function: tail
Returns all but the first element of a list Returns all but the first element of a list
*/ */
fn tail<T>(ls: list<T>) -> list<T> { fn tail<copy T>(ls: list<T>) -> list<T> {
alt ls { cons(_, tl) { ret *tl; } nil. { fail "list empty" } } alt ls { cons(_, tl) { ret *tl; } nil. { fail "list empty" } }
} }
@ -118,7 +119,7 @@ Function: head
Returns the first element of a list Returns the first element of a list
*/ */
fn head<T>(ls: list<T>) -> T { fn head<copy T>(ls: list<T>) -> T {
alt ls { cons(hd, _) { ret hd; } nil. { fail "list empty" } } alt ls { cons(hd, _) { ret hd; } nil. { fail "list empty" } }
} }
@ -127,7 +128,7 @@ Function: append
Appends one list to another Appends one list to another
*/ */
fn append<T>(l: list<T>, m: list<T>) -> list<T> { fn append<copy T>(l: list<T>, m: list<T>) -> list<T> {
alt l { alt l {
nil. { ret m; } nil. { ret m; }
cons(x, xs) { let rest = append(*xs, m); ret cons(x, @rest); } cons(x, xs) { let rest = append(*xs, m); ret cons(x, @rest); }

View file

@ -114,12 +114,13 @@ Parameters:
hasher - The hash function for key type K hasher - The hash function for key type K
eqer - The equality function for key type K eqer - The equality function for key type K
*/ */
fn mk_hashmap<K, V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K, V> { fn mk_hashmap<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>)
-> hashmap<K, V> {
let initial_capacity: uint = 32u; // 2^5 let initial_capacity: uint = 32u; // 2^5
let load_factor: util::rational = {num: 3, den: 4}; let load_factor: util::rational = {num: 3, den: 4};
tag bucket<K, V> { nil; deleted; some(K, V); } tag bucket<copy K, copy V> { nil; deleted; some(K, V); }
fn make_buckets<K, V>(nbkts: uint) -> [mutable bucket<K, V>] { fn make_buckets<copy K, copy V>(nbkts: uint) -> [mutable bucket<K, V>] {
ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts); ret vec::init_elt_mut::<bucket<K, V>>(nil::<K, V>, nbkts);
} }
// Derive two hash functions from the one given by taking the upper // Derive two hash functions from the one given by taking the upper
@ -146,9 +147,9 @@ fn mk_hashmap<K, V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K, V> {
* will fail. * will fail.
*/ */
fn insert_common<K, V>(hasher: hashfn<K>, eqer: eqfn<K>, fn insert_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
bkts: [mutable bucket<K, V>], nbkts: uint, key: K, bkts: [mutable bucket<K, V>],
val: V) -> bool { nbkts: uint, key: K, val: V) -> bool {
let i: uint = 0u; let i: uint = 0u;
let h: uint = hasher(key); let h: uint = hasher(key);
while i < nbkts { while i < nbkts {
@ -166,9 +167,9 @@ fn mk_hashmap<K, V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K, V> {
} }
fail; // full table fail; // full table
} }
fn find_common<K, V>(hasher: hashfn<K>, eqer: eqfn<K>, fn find_common<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
bkts: [mutable bucket<K, V>], nbkts: uint, key: K) -> bkts: [mutable bucket<K, V>],
option::t<V> { nbkts: uint, key: K) -> option::t<V> {
let i: uint = 0u; let i: uint = 0u;
let h: uint = hasher(key); let h: uint = hasher(key);
while i < nbkts { while i < nbkts {
@ -187,9 +188,11 @@ fn mk_hashmap<K, V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K, V> {
} }
ret option::none; ret option::none;
} }
fn rehash<K, V>(hasher: hashfn<K>, eqer: eqfn<K>, fn rehash<copy K, copy V>(hasher: hashfn<K>, eqer: eqfn<K>,
oldbkts: [mutable bucket<K, V>], _noldbkts: uint, oldbkts: [mutable bucket<K, V>],
newbkts: [mutable bucket<K, V>], nnewbkts: uint) { _noldbkts: uint,
newbkts: [mutable bucket<K, V>],
nnewbkts: uint) {
for b: bucket<K, V> in oldbkts { for b: bucket<K, V> in oldbkts {
alt b { alt b {
some(k_, v_) { some(k_, v_) {
@ -201,7 +204,7 @@ fn mk_hashmap<K, V>(hasher: hashfn<K>, eqer: eqfn<K>) -> hashmap<K, V> {
} }
} }
} }
obj hashmap<shar K, shar V>(hasher: hashfn<K>, obj hashmap<copy K, copy V>(hasher: hashfn<K>,
eqer: eqfn<K>, eqer: eqfn<K>,
mutable bkts: [mutable bucket<K, V>], mutable bkts: [mutable bucket<K, V>],
mutable nbkts: uint, mutable nbkts: uint,
@ -291,7 +294,7 @@ Function: new_str_hash
Construct a hashmap for string keys Construct a hashmap for string keys
*/ */
fn new_str_hash<V>() -> hashmap<str, V> { fn new_str_hash<copy V>() -> hashmap<str, V> {
ret mk_hashmap(str::hash, str::eq); ret mk_hashmap(str::hash, str::eq);
} }
@ -300,7 +303,7 @@ Function: new_int_hash
Construct a hashmap for int keys Construct a hashmap for int keys
*/ */
fn new_int_hash<V>() -> hashmap<int, V> { fn new_int_hash<copy V>() -> hashmap<int, V> {
fn hash_int(&&x: int) -> uint { ret x as uint; } fn hash_int(&&x: int) -> uint { ret x as uint; }
fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; } fn eq_int(&&a: int, &&b: int) -> bool { ret a == b; }
ret mk_hashmap(hash_int, eq_int); ret mk_hashmap(hash_int, eq_int);
@ -311,7 +314,7 @@ Function: new_uint_hash
Construct a hashmap for uint keys Construct a hashmap for uint keys
*/ */
fn new_uint_hash<V>() -> hashmap<uint, V> { fn new_uint_hash<copy V>() -> hashmap<uint, V> {
fn hash_uint(&&x: uint) -> uint { ret x; } fn hash_uint(&&x: uint) -> uint { ret x; }
fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; } fn eq_uint(&&a: uint, &&b: uint) -> bool { ret a == b; }
ret mk_hashmap(hash_uint, eq_uint); ret mk_hashmap(hash_uint, eq_uint);

View file

@ -73,11 +73,11 @@ Function: min
Returns the minimum of two values Returns the minimum of two values
*/ */
fn min<T>(x: T, y: T) -> T { x < y ? x : y } fn min<copy T>(x: T, y: T) -> T { x < y ? x : y }
/* /*
Function: max Function: max
Returns the maximum of two values Returns the maximum of two values
*/ */
fn max<T>(x: T, y: T) -> T { x < y ? y : x } fn max<copy T>(x: T, y: T) -> T { x < y ? y : x }

View file

@ -103,7 +103,8 @@ Example:
> }) > })
*/ */
fn chain<T, U, V>(res: t<T, V>, op: block(T) -> t<U, V>) -> t<U, V> { fn chain<T, copy U, copy V>(res: t<T, V>, op: block(T) -> t<U, V>)
-> t<U, V> {
alt res { alt res {
ok(t) { op(t) } ok(t) { op(t) }
err(e) { err(e) } err(e) { err(e) }

View file

@ -29,7 +29,7 @@ Function: insert
Add a value to the map. If the map already contains a value for Add a value to the map. If the map already contains a value for
the specified key then the original value is replaced. the specified key then the original value is replaced.
*/ */
fn insert<T>(m: smallintmap<T>, key: uint, val: T) { fn insert<copy T>(m: smallintmap<T>, key: uint, val: T) {
vec::grow_set::<option::t<T>>(m.v, key, none::<T>, some::<T>(val)); vec::grow_set::<option::t<T>>(m.v, key, none::<T>, some::<T>(val));
} }
@ -39,7 +39,7 @@ Function: find
Get the value for the specified key. If the key does not exist Get the value for the specified key. If the key does not exist
in the map then returns none. in the map then returns none.
*/ */
fn find<T>(m: smallintmap<T>, key: uint) -> option::t<T> { fn find<copy T>(m: smallintmap<T>, key: uint) -> option::t<T> {
if key < vec::len::<option::t<T>>(m.v) { ret m.v[key]; } if key < vec::len::<option::t<T>>(m.v) { ret m.v[key]; }
ret none::<T>; ret none::<T>;
} }
@ -53,10 +53,10 @@ Failure:
If the key does not exist in the map If the key does not exist in the map
*/ */
fn get<T>(m: smallintmap<T>, key: uint) -> T { fn get<copy T>(m: smallintmap<T>, key: uint) -> T {
alt find::<T>(m, key) { alt find(m, key) {
none::<T>. { log_err "smallintmap::get(): key not present"; fail; } none. { log_err "smallintmap::get(): key not present"; fail; }
some::<T>(v) { ret v; } some(v) { ret v; }
} }
} }
@ -65,13 +65,13 @@ Method: contains_key
Returns true if the map contains a value for the specified key Returns true if the map contains a value for the specified key
*/ */
fn contains_key<T>(m: smallintmap<T>, key: uint) -> bool { fn contains_key<copy T>(m: smallintmap<T>, key: uint) -> bool {
ret !option::is_none(find::<T>(m, key)); ret !option::is_none(find::<T>(m, key));
} }
// FIXME: Are these really useful? // FIXME: Are these really useful?
fn truncate<T>(m: smallintmap<T>, len: uint) { fn truncate<copy T>(m: smallintmap<T>, len: uint) {
m.v = vec::slice_mut::<option::t<T>>(m.v, 0u, len); m.v = vec::slice_mut::<option::t<T>>(m.v, 0u, len);
} }

View file

@ -20,8 +20,8 @@ Merge sort. Returns a new vector containing the sorted list.
Has worst case O(n log n) performance, best case O(n), but Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort. is not space efficient. This is a stable sort.
*/ */
fn merge_sort<T>(le: lteq<T>, v: [const T]) -> [T] { fn merge_sort<copy T>(le: lteq<T>, v: [const T]) -> [T] {
fn merge<T>(le: lteq<T>, a: [T], b: [T]) -> [T] { fn merge<copy T>(le: lteq<T>, a: [T], b: [T]) -> [T] {
let rs: [T] = []; let rs: [T] = [];
let a_len: uint = len::<T>(a); let a_len: uint = len::<T>(a);
let a_ix: uint = 0u; let a_ix: uint = 0u;
@ -46,30 +46,24 @@ fn merge_sort<T>(le: lteq<T>, v: [const T]) -> [T] {
ret merge::<T>(le, merge_sort::<T>(le, a), merge_sort::<T>(le, b)); ret merge::<T>(le, merge_sort::<T>(le, a), merge_sort::<T>(le, b));
} }
fn swap<T>(arr: [mutable T], x: uint, y: uint) { fn part<copy T>(compare_func: lteq<T>, arr: [mutable T], left: uint,
let a = arr[x]; right: uint, pivot: uint) -> uint {
arr[x] = arr[y];
arr[y] = a;
}
fn part<T>(compare_func: lteq<T>, arr: [mutable T], left: uint, right: uint,
pivot: uint) -> uint {
let pivot_value = arr[pivot]; let pivot_value = arr[pivot];
swap::<T>(arr, pivot, right); arr[pivot] <-> arr[right];
let storage_index: uint = left; let storage_index: uint = left;
let i: uint = left; let i: uint = left;
while i < right { while i < right {
if compare_func({ arr[i] }, pivot_value) { if compare_func(copy arr[i], pivot_value) {
swap::<T>(arr, i, storage_index); arr[i] <-> arr[storage_index];
storage_index += 1u; storage_index += 1u;
} }
i += 1u; i += 1u;
} }
swap::<T>(arr, storage_index, right); arr[storage_index] <-> arr[right];
ret storage_index; ret storage_index;
} }
fn qsort<T>(compare_func: lteq<T>, arr: [mutable T], left: uint, fn qsort<copy T>(compare_func: lteq<T>, arr: [mutable T], left: uint,
right: uint) { right: uint) {
if right > left { if right > left {
let pivot = (left + right) / 2u; let pivot = (left + right) / 2u;
@ -90,13 +84,13 @@ Quicksort. Sorts a mutable vector in place.
Has worst case O(n^2) performance, average case O(n log n). Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort. This is an unstable sort.
*/ */
fn quick_sort<T>(compare_func: lteq<T>, arr: [mutable T]) { fn quick_sort<copy T>(compare_func: lteq<T>, arr: [mutable T]) {
if len::<T>(arr) == 0u { ret; } if len::<T>(arr) == 0u { ret; }
qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u); qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
} }
fn qsort3<T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>, fn qsort3<copy T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
arr: [mutable T], left: int, right: int) { arr: [mutable T], left: int, right: int) {
if right <= left { ret; } if right <= left { ret; }
let v: T = arr[right]; let v: T = arr[right];
let i: int = left - 1; let i: int = left - 1;
@ -105,36 +99,36 @@ fn qsort3<T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
let q: int = j; let q: int = j;
while true { while true {
i += 1; i += 1;
while compare_func_lt({ arr[i] }, v) { i += 1; } while compare_func_lt(copy arr[i], v) { i += 1; }
j -= 1; j -= 1;
while compare_func_lt(v, { arr[j] }) { while compare_func_lt(v, copy arr[j]) {
if j == left { break; } if j == left { break; }
j -= 1; j -= 1;
} }
if i >= j { break; } if i >= j { break; }
swap::<T>(arr, i as uint, j as uint); arr[i] <-> arr[j];
if compare_func_eq({ arr[i] }, v) { if compare_func_eq(copy arr[i], v) {
p += 1; p += 1;
swap::<T>(arr, p as uint, i as uint); arr[p] <-> arr[i];
} }
if compare_func_eq(v, { arr[j] }) { if compare_func_eq(v, copy arr[j]) {
q -= 1; q -= 1;
swap::<T>(arr, j as uint, q as uint); arr[j] <-> arr[q];
} }
} }
swap::<T>(arr, i as uint, right as uint); arr[i] <-> arr[right];
j = i - 1; j = i - 1;
i += 1; i += 1;
let k: int = left; let k: int = left;
while k < p { while k < p {
swap::<T>(arr, k as uint, j as uint); arr[k] <-> arr[j];
k += 1; k += 1;
j -= 1; j -= 1;
if k == len::<T>(arr) as int { break; } if k == len::<T>(arr) as int { break; }
} }
k = right - 1; k = right - 1;
while k > q { while k > q {
swap::<T>(arr, i as uint, k as uint); arr[i] <-> arr[k];
k -= 1; k -= 1;
i += 1; i += 1;
if k == 0 { break; } if k == 0 { break; }
@ -156,8 +150,8 @@ According to these slides this is the algorithm of choice for
This is an unstable sort. This is an unstable sort.
*/ */
fn quick_sort3<T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>, fn quick_sort3<copy T>(compare_func_lt: lteq<T>, compare_func_eq: lteq<T>,
arr: [mutable T]) { arr: [mutable T]) {
if len::<T>(arr) == 0u { ret; } if len::<T>(arr) == 0u { ret; }
qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0, qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
(len::<T>(arr) as int) - 1); (len::<T>(arr) as int) - 1);

View file

@ -232,7 +232,7 @@ Returns:
A handle to the new task A handle to the new task
*/ */
fn spawn<uniq T>(-data: T, f: fn(T)) -> task { fn spawn<send T>(-data: T, f: fn(T)) -> task {
spawn_inner(data, f, none) spawn_inner(data, f, none)
} }
@ -245,7 +245,7 @@ termination
Immediately before termination, either on success or failure, the spawned Immediately before termination, either on success or failure, the spawned
task will send a <task_notification> message on the provided channel. task will send a <task_notification> message on the provided channel.
*/ */
fn spawn_notify<uniq T>(-data: T, f: fn(T), fn spawn_notify<send T>(-data: T, f: fn(T),
notify: comm::chan<task_notification>) -> task { notify: comm::chan<task_notification>) -> task {
spawn_inner(data, f, some(notify)) spawn_inner(data, f, some(notify))
} }
@ -259,7 +259,7 @@ This is a convenience wrapper around spawn_notify which, when paired
with <join> can be easily used to spawn a task then wait for it to with <join> can be easily used to spawn a task then wait for it to
complete. complete.
*/ */
fn spawn_joinable<uniq T>(-data: T, f: fn(T)) -> joinable_task { fn spawn_joinable<send T>(-data: T, f: fn(T)) -> joinable_task {
let p = comm::port::<task_notification>(); let p = comm::port::<task_notification>();
let id = spawn_notify(data, f, comm::chan::<task_notification>(p)); let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
ret (id, p); ret (id, p);
@ -275,11 +275,11 @@ fn spawn_joinable<uniq T>(-data: T, f: fn(T)) -> joinable_task {
// //
// After the transition this should all be rewritten. // After the transition this should all be rewritten.
fn spawn_inner<uniq T>(-data: T, f: fn(T), fn spawn_inner<send T>(-data: T, f: fn(T),
notify: option<comm::chan<task_notification>>) notify: option<comm::chan<task_notification>>)
-> task unsafe { -> task unsafe {
fn wrapper<uniq T>(-data: *u8, f: fn(T)) unsafe { fn wrapper<send T>(-data: *u8, f: fn(T)) unsafe {
let data: ~T = unsafe::reinterpret_cast(data); let data: ~T = unsafe::reinterpret_cast(data);
f(*data); f(*data);
} }

View file

@ -109,8 +109,8 @@ fn run_tests_console(opts: test_opts,
run_tests_console_(opts, tests, default_test_to_task) run_tests_console_(opts, tests, default_test_to_task)
} }
fn run_tests_console_<T>(opts: test_opts, tests: [test_desc<T>], fn run_tests_console_<copy T>(opts: test_opts, tests: [test_desc<T>],
to_task: test_to_task<T>) -> bool { to_task: test_to_task<T>) -> bool {
type test_state = type test_state =
@{out: io::writer, @{out: io::writer,
@ -121,7 +121,7 @@ fn run_tests_console_<T>(opts: test_opts, tests: [test_desc<T>],
mutable ignored: uint, mutable ignored: uint,
mutable failures: [test_desc<T>]}; mutable failures: [test_desc<T>]};
fn callback<T>(event: testevent<T>, st: test_state) { fn callback<copy T>(event: testevent<T>, st: test_state) {
alt event { alt event {
te_filtered(filtered_tests) { te_filtered(filtered_tests) {
st.total = vec::len(filtered_tests); st.total = vec::len(filtered_tests);
@ -214,9 +214,9 @@ tag testevent<T> {
te_result(test_desc<T>, test_result); te_result(test_desc<T>, test_result);
} }
fn run_tests<T>(opts: test_opts, tests: [test_desc<T>], fn run_tests<copy T>(opts: test_opts, tests: [test_desc<T>],
to_task: test_to_task<T>, to_task: test_to_task<T>,
callback: fn@(testevent<T>)) { callback: fn@(testevent<T>)) {
let filtered_tests = filter_tests(opts, tests); let filtered_tests = filter_tests(opts, tests);
callback(te_filtered(filtered_tests)); callback(te_filtered(filtered_tests));
@ -248,8 +248,8 @@ fn run_tests<T>(opts: test_opts, tests: [test_desc<T>],
fn get_concurrency() -> uint { rustrt::sched_threads() } fn get_concurrency() -> uint { rustrt::sched_threads() }
fn filter_tests<T>(opts: test_opts, fn filter_tests<copy T>(opts: test_opts,
tests: [test_desc<T>]) -> [test_desc<T>] { tests: [test_desc<T>]) -> [test_desc<T>] {
let filtered = tests; let filtered = tests;
// Remove tests that don't match the test filter // Remove tests that don't match the test filter
@ -262,7 +262,7 @@ fn filter_tests<T>(opts: test_opts,
option::none. { "" } option::none. { "" }
}; };
fn filter_fn<T>(test: test_desc<T>, filter_str: str) -> fn filter_fn<copy T>(test: test_desc<T>, filter_str: str) ->
option::t<test_desc<T>> { option::t<test_desc<T>> {
if str::find(test.name, filter_str) >= 0 { if str::find(test.name, filter_str) >= 0 {
ret option::some(test); ret option::some(test);
@ -278,7 +278,7 @@ fn filter_tests<T>(opts: test_opts,
filtered = if !opts.run_ignored { filtered = if !opts.run_ignored {
filtered filtered
} else { } else {
fn filter<T>(test: test_desc<T>) -> option::t<test_desc<T>> { fn filter<copy T>(test: test_desc<T>) -> option::t<test_desc<T>> {
if test.ignore { if test.ignore {
ret option::some({name: test.name, ret option::some({name: test.name,
fn: test.fn, fn: test.fn,
@ -304,8 +304,8 @@ fn filter_tests<T>(opts: test_opts,
type test_future<T> = {test: test_desc<T>, wait: fn@() -> test_result}; type test_future<T> = {test: test_desc<T>, wait: fn@() -> test_result};
fn run_test<T>(test: test_desc<T>, fn run_test<copy T>(test: test_desc<T>,
to_task: test_to_task<T>) -> test_future<T> { to_task: test_to_task<T>) -> test_future<T> {
if test.ignore { if test.ignore {
ret {test: test, wait: fn () -> test_result { tr_ignored }}; ret {test: test, wait: fn () -> test_result { tr_ignored }};
} }

View file

@ -44,7 +44,7 @@ Function: insert
Insert a value into the map Insert a value into the map
*/ */
fn insert<K, V>(m: treemap<K, V>, k: K, v: V) { fn insert<copy K, copy V>(m: treemap<K, V>, k: K, v: V) {
alt m { alt m {
@empty. { *m = node(@k, @v, @mutable empty, @mutable empty); } @empty. { *m = node(@k, @v, @mutable empty, @mutable empty); }
@node(@kk, _, _, _) { @node(@kk, _, _, _) {
@ -63,7 +63,7 @@ Function: find
Find a value based on the key Find a value based on the key
*/ */
fn find<K, V>(m: treemap<K, V>, k: K) -> option<V> { fn find<copy K, copy V>(m: treemap<K, V>, k: K) -> option<V> {
alt *m { alt *m {
empty. { none } empty. { none }
node(@kk, @v, _, _) { node(@kk, @v, _, _) {

View file

@ -121,7 +121,7 @@ Creates and initializes an immutable vector.
Creates an immutable vector of size `n_elts` and initializes the elements Creates an immutable vector of size `n_elts` and initializes the elements
to the value `t`. to the value `t`.
*/ */
fn init_elt<T>(t: T, n_elts: uint) -> [T] { fn init_elt<copy T>(t: T, n_elts: uint) -> [T] {
let v = []; let v = [];
reserve(v, n_elts); reserve(v, n_elts);
let i: uint = 0u; let i: uint = 0u;
@ -138,7 +138,7 @@ Creates and initializes a mutable vector.
Creates a mutable vector of size `n_elts` and initializes the elements Creates a mutable vector of size `n_elts` and initializes the elements
to the value `t`. to the value `t`.
*/ */
fn init_elt_mut<T>(t: T, n_elts: uint) -> [mutable T] { fn init_elt_mut<copy T>(t: T, n_elts: uint) -> [mutable T] {
let v = [mutable]; let v = [mutable];
reserve(v, n_elts); reserve(v, n_elts);
let i: uint = 0u; let i: uint = 0u;
@ -153,7 +153,7 @@ Function: to_mut
Produces a mutable vector from an immutable vector. Produces a mutable vector from an immutable vector.
*/ */
fn to_mut<T>(v: [T]) -> [mutable T] { fn to_mut<copy T>(v: [T]) -> [mutable T] {
let vres = [mutable]; let vres = [mutable];
for t: T in v { vres += [mutable t]; } for t: T in v { vres += [mutable t]; }
ret vres; ret vres;
@ -165,7 +165,7 @@ Function: from_mut
Produces an immutable vector from a mutable vector. Produces an immutable vector from a mutable vector.
*/ */
fn from_mut<T>(v: [mutable T]) -> [T] { fn from_mut<copy T>(v: [mutable T]) -> [T] {
let vres = []; let vres = [];
for t: T in v { vres += [t]; } for t: T in v { vres += [t]; }
ret vres; ret vres;
@ -181,7 +181,7 @@ Returns the first element of a vector
Predicates: Predicates:
<is_not_empty> (v) <is_not_empty> (v)
*/ */
fn head<T>(v: [const T]) : is_not_empty(v) -> T { ret v[0]; } fn head<copy T>(v: [const T]) : is_not_empty(v) -> T { ret v[0]; }
/* /*
Function: tail Function: tail
@ -191,7 +191,7 @@ Returns all but the first element of a vector
Predicates: Predicates:
<is_not_empty> (v) <is_not_empty> (v)
*/ */
fn tail<T>(v: [const T]) : is_not_empty(v) -> [T] { fn tail<copy T>(v: [const T]) : is_not_empty(v) -> [T] {
ret slice(v, 1u, len(v)); ret slice(v, 1u, len(v));
} }
@ -206,7 +206,7 @@ Returns all but the last elemnt of a vector
Preconditions: Preconditions:
`v` is not empty `v` is not empty
*/ */
fn init<T>(v: [const T]) -> [T] { fn init<copy T>(v: [const T]) -> [T] {
assert len(v) != 0u; assert len(v) != 0u;
slice(v, 0u, len(v) - 1u) slice(v, 0u, len(v) - 1u)
} }
@ -221,7 +221,7 @@ Returns:
An option containing the last element of `v` if `v` is not empty, or An option containing the last element of `v` if `v` is not empty, or
none if `v` is empty. none if `v` is empty.
*/ */
fn last<T>(v: [const T]) -> option::t<T> { fn last<copy T>(v: [const T]) -> option::t<T> {
if len(v) == 0u { ret none; } if len(v) == 0u { ret none; }
ret some(v[len(v) - 1u]); ret some(v[len(v) - 1u]);
} }
@ -234,7 +234,7 @@ Returns the last element of a non-empty vector `v`
Predicates: Predicates:
<is_not_empty> (v) <is_not_empty> (v)
*/ */
fn last_total<T>(v: [const T]) : is_not_empty(v) -> T { fn last_total<copy T>(v: [const T]) : is_not_empty(v) -> T {
ret v[len(v) - 1u]; ret v[len(v) - 1u];
} }
@ -243,7 +243,7 @@ Function: slice
Returns a copy of the elements from [`start`..`end`) from `v`. Returns a copy of the elements from [`start`..`end`) from `v`.
*/ */
fn slice<T>(v: [const T], start: uint, end: uint) -> [T] { fn slice<copy T>(v: [const T], start: uint, end: uint) -> [T] {
assert (start <= end); assert (start <= end);
assert (end <= len(v)); assert (end <= len(v));
let result = []; let result = [];
@ -259,7 +259,7 @@ Function: slice_mut
Returns a copy of the elements from [`start`..`end`) from `v`. Returns a copy of the elements from [`start`..`end`) from `v`.
*/ */
fn slice_mut<T>(v: [const T], start: uint, end: uint) -> [mutable T] { fn slice_mut<copy T>(v: [const T], start: uint, end: uint) -> [mutable T] {
assert (start <= end); assert (start <= end);
assert (end <= len(v)); assert (end <= len(v));
let result = [mutable]; let result = [mutable];
@ -277,7 +277,7 @@ Function: shift
Removes the first element from a vector and return it Removes the first element from a vector and return it
*/ */
fn shift<T>(&v: [const T]) -> T { fn shift<copy T>(&v: [const T]) -> T {
let ln = len::<T>(v); let ln = len::<T>(v);
assert (ln > 0u); assert (ln > 0u);
let e = v[0]; let e = v[0];
@ -291,7 +291,7 @@ Function: pop
Remove the last element from a vector and return it Remove the last element from a vector and return it
*/ */
fn pop<T>(&v: [const T]) -> T { fn pop<copy T>(&v: [const T]) -> T {
let ln = len(v); let ln = len(v);
assert (ln > 0u); assert (ln > 0u);
ln -= 1u; ln -= 1u;
@ -316,7 +316,7 @@ v - The vector to grow
n - The number of elements to add n - The number of elements to add
initval - The value for the new elements initval - The value for the new elements
*/ */
fn grow<T>(&v: [T], n: uint, initval: T) { fn grow<copy T>(&v: [T], n: uint, initval: T) {
reserve(v, next_power_of_two(len(v) + n)); reserve(v, next_power_of_two(len(v) + n));
let i: uint = 0u; let i: uint = 0u;
while i < n { v += [initval]; i += 1u; } while i < n { v += [initval]; i += 1u; }
@ -335,7 +335,7 @@ v - The vector to grow
n - The number of elements to add n - The number of elements to add
initval - The value for the new elements initval - The value for the new elements
*/ */
fn grow_mut<T>(&v: [mutable T], n: uint, initval: T) { fn grow_mut<copy T>(&v: [mutable T], n: uint, initval: T) {
reserve(v, next_power_of_two(len(v) + n)); reserve(v, next_power_of_two(len(v) + n));
let i: uint = 0u; let i: uint = 0u;
while i < n { v += [mutable initval]; i += 1u; } while i < n { v += [mutable initval]; i += 1u; }
@ -371,7 +371,7 @@ Sets the element at position `index` to `val`. If `index` is past the end
of the vector, expands the vector by replicating `initval` to fill the of the vector, expands the vector by replicating `initval` to fill the
intervening space. intervening space.
*/ */
fn grow_set<T>(&v: [mutable T], index: uint, initval: T, val: T) { fn grow_set<copy T>(&v: [mutable T], index: uint, initval: T, val: T) {
if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); } if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
v[index] = val; v[index] = val;
} }
@ -384,12 +384,12 @@ Function: map
Apply a function to each element of a vector and return the results Apply a function to each element of a vector and return the results
*/ */
fn map<T, U>(f: block(T) -> U, v: [const T]) -> [U] { fn map<copy T, U>(f: block(T) -> U, v: [const T]) -> [U] {
let result = []; let result = [];
reserve(result, len(v)); reserve(result, len(v));
for elem: T in v { for elem: T in v {
let elem2 = elem; // satisfies alias checker // copy satisfies alias checker
result += [f(elem2)]; result += [f(copy elem)];
} }
ret result; ret result;
} }
@ -399,12 +399,12 @@ Function: map2
Apply a function to each pair of elements and return the results Apply a function to each pair of elements and return the results
*/ */
fn map2<T, U, V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] { fn map2<copy T, copy U, V>(f: block(T, U) -> V, v0: [T], v1: [U]) -> [V] {
let v0_len = len::<T>(v0); let v0_len = len(v0);
if v0_len != len::<U>(v1) { fail; } if v0_len != len(v1) { fail; }
let u: [V] = []; let u: [V] = [];
let i = 0u; let i = 0u;
while i < v0_len { u += [f({ v0[i] }, { v1[i] })]; i += 1u; } while i < v0_len { u += [f(copy v0[i], copy v1[i])]; i += 1u; }
ret u; ret u;
} }
@ -416,11 +416,11 @@ Apply a function to each element of a vector and return the results
If function `f` returns `none` then that element is excluded from If function `f` returns `none` then that element is excluded from
the resulting vector. the resulting vector.
*/ */
fn filter_map<T, U>(f: block(T) -> option::t<U>, v: [const T]) -> [U] { fn filter_map<copy T, copy U>(f: block(T) -> option::t<U>, v: [const T])
-> [U] {
let result = []; let result = [];
for elem: T in v { for elem: T in v {
let elem2 = elem; // satisfies alias checker alt f(copy elem) {
alt f(elem2) {
none. {/* no-op */ } none. {/* no-op */ }
some(result_elem) { result += [result_elem]; } some(result_elem) { result += [result_elem]; }
} }
@ -437,13 +437,10 @@ holds.
Apply function `f` to each element of `v` and return a vector containing Apply function `f` to each element of `v` and return a vector containing
only those elements for which `f` returned true. only those elements for which `f` returned true.
*/ */
fn filter<T>(f: block(T) -> bool, v: [const T]) -> [T] { fn filter<copy T>(f: block(T) -> bool, v: [T]) -> [T] {
let result = []; let result = [];
for elem: T in v { for elem: T in v {
let elem2 = elem; // satisfies alias checker if f(elem) { result += [elem]; }
if f(elem2) {
result += [elem2];
}
} }
ret result; ret result;
} }
@ -454,8 +451,7 @@ Function: concat
Concatenate a vector of vectors. Flattens a vector of vectors of T into Concatenate a vector of vectors. Flattens a vector of vectors of T into
a single vector of T. a single vector of T.
*/ */
fn concat<T>(v: [const [const T]]) -> [T] { fn concat<copy T>(v: [const [const T]]) -> [T] {
// FIXME: So much copying
let new: [T] = []; let new: [T] = [];
for inner: [T] in v { new += inner; } for inner: [T] in v { new += inner; }
ret new; ret new;
@ -466,7 +462,7 @@ Function: foldl
Reduce a vector from left to right Reduce a vector from left to right
*/ */
fn foldl<T, U>(p: block(T, U) -> T, z: T, v: [const U]) -> T { fn foldl<copy T, U>(p: block(T, U) -> T, z: T, v: [const U]) -> T {
let accum = z; let accum = z;
iter(v) { |elt| iter(v) { |elt|
accum = p(accum, elt); accum = p(accum, elt);
@ -479,7 +475,7 @@ Function: foldr
Reduce a vector from right to left Reduce a vector from right to left
*/ */
fn foldr<T, U>(p: block(T, U) -> U, z: U, v: [const T]) -> U { fn foldr<T, copy U>(p: block(T, U) -> U, z: U, v: [const T]) -> U {
let accum = z; let accum = z;
riter(v) { |elt| riter(v) { |elt|
accum = p(elt, accum); accum = p(elt, accum);
@ -541,7 +537,7 @@ Apply function `f` to each element of `v`, starting from the first.
When function `f` returns true then an option containing the element When function `f` returns true then an option containing the element
is returned. If `f` matches no elements then none is returned. is returned. If `f` matches no elements then none is returned.
*/ */
fn find<T>(f: block(T) -> bool, v: [T]) -> option::t<T> { fn find<copy T>(f: block(T) -> bool, v: [T]) -> option::t<T> {
for elt: T in v { if f(elt) { ret some(elt); } } for elt: T in v { if f(elt) { ret some(elt); } }
ret none; ret none;
} }
@ -587,7 +583,7 @@ vector contains the first element of the i-th tuple of the input vector,
and the i-th element of the second vector contains the second element and the i-th element of the second vector contains the second element
of the i-th tuple of the input vector. of the i-th tuple of the input vector.
*/ */
fn unzip<T, U>(v: [(T, U)]) -> ([T], [U]) { fn unzip<copy T, copy U>(v: [(T, U)]) -> ([T], [U]) {
let as = [], bs = []; let as = [], bs = [];
for (a, b) in v { as += [a]; bs += [b]; } for (a, b) in v { as += [a]; bs += [b]; }
ret (as, bs); ret (as, bs);
@ -605,7 +601,7 @@ Preconditions:
<same_length> (v, u) <same_length> (v, u)
*/ */
fn zip<T, U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] { fn zip<copy T, copy U>(v: [T], u: [U]) : same_length(v, u) -> [(T, U)] {
let zipped = []; let zipped = [];
let sz = len(v), i = 0u; let sz = len(v), i = 0u;
assert (sz == len(u)); assert (sz == len(u));
@ -624,9 +620,7 @@ a - The index of the first element
b - The index of the second element b - The index of the second element
*/ */
fn swap<T>(v: [mutable T], a: uint, b: uint) { fn swap<T>(v: [mutable T], a: uint, b: uint) {
let t: T = v[a]; v[a] <-> v[b];
v[a] = v[b];
v[b] = t;
} }
/* /*
@ -637,7 +631,7 @@ Reverse the order of elements in a vector, in place
fn reverse<T>(v: [mutable T]) { fn reverse<T>(v: [mutable T]) {
let i: uint = 0u; let i: uint = 0u;
let ln = len::<T>(v); let ln = len::<T>(v);
while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; } while i < ln / 2u { v[i] <-> v[ln - i - 1u]; i += 1u; }
} }
@ -646,7 +640,7 @@ Function: reversed
Returns a vector with the order of elements reversed Returns a vector with the order of elements reversed
*/ */
fn reversed<T>(v: [const T]) -> [T] { fn reversed<copy T>(v: [const T]) -> [T] {
let rs: [T] = []; let rs: [T] = [];
let i = len::<T>(v); let i = len::<T>(v);
if i == 0u { ret rs; } else { i -= 1u; } if i == 0u { ret rs; } else { i -= 1u; }
@ -746,7 +740,7 @@ is sorted then the permutations are lexicographically sorted).
The total number of permutations produced is `len(v)!`. If `v` contains The total number of permutations produced is `len(v)!`. If `v` contains
repeated elements, then some permutations are repeated. repeated elements, then some permutations are repeated.
*/ */
fn permute<T>(v: [const T], put: block([T])) { fn permute<copy T>(v: [const T], put: block([T])) {
let ln = len(v); let ln = len(v);
if ln == 0u { if ln == 0u {
put([]); put([]);

View file

@ -55,25 +55,25 @@ mod map_reduce {
export reducer; export reducer;
export map_reduce; export map_reduce;
type putter<uniq K, uniq V> = fn(K, V); type putter<send K, send V> = fn(K, V);
// FIXME: the first K1 parameter should probably be a -, but that // FIXME: the first K1 parameter should probably be a -, but that
// doesn't parse at the moment. // doesn't parse at the moment.
type mapper<uniq K1, uniq K2, uniq V> = fn(K1, putter<K2, V>); type mapper<send K1, send K2, send V> = fn(K1, putter<K2, V>);
type getter<uniq V> = fn() -> option<V>; type getter<send V> = fn() -> option<V>;
type reducer<uniq K, uniq V> = fn(K, getter<V>); type reducer<send K, send V> = fn(K, getter<V>);
tag ctrl_proto<uniq K, uniq V> { tag ctrl_proto<send K, send V> {
find_reducer(K, chan<chan<reduce_proto<V>>>); find_reducer(K, chan<chan<reduce_proto<V>>>);
mapper_done; mapper_done;
} }
tag reduce_proto<uniq V> { emit_val(V); done; ref; release; } tag reduce_proto<send V> { emit_val(V); done; ref; release; }
fn start_mappers<uniq K1, uniq K2, fn start_mappers<send K1, send K2,
uniq V>(map: mapper<K1, K2, V>, send V>(map: mapper<K1, K2, V>,
ctrl: chan<ctrl_proto<K2, V>>, inputs: [K1]) -> ctrl: chan<ctrl_proto<K2, V>>, inputs: [K1]) ->
[joinable_task] { [joinable_task] {
let tasks = []; let tasks = [];
@ -84,15 +84,15 @@ mod map_reduce {
ret tasks; ret tasks;
} }
fn map_task<uniq K1, uniq K2, fn map_task<send K1, send K2,
uniq V>(-map: mapper<K1, K2, V>, send V>(-map: mapper<K1, K2, V>,
-ctrl: chan<ctrl_proto<K2, V>>, -ctrl: chan<ctrl_proto<K2, V>>,
-input: K1) { -input: K1) {
// log_err "map_task " + input; // log_err "map_task " + input;
let intermediates = treemap::init(); let intermediates = treemap::init();
fn emit<uniq K2, fn emit<send K2,
uniq V>(im: treemap::treemap<K2, chan<reduce_proto<V>>>, send V>(im: treemap::treemap<K2, chan<reduce_proto<V>>>,
ctrl: chan<ctrl_proto<K2, V>>, key: K2, val: V) { ctrl: chan<ctrl_proto<K2, V>>, key: K2, val: V) {
let c; let c;
alt treemap::find(im, key) { alt treemap::find(im, key) {
@ -110,15 +110,15 @@ mod map_reduce {
map(input, bind emit(intermediates, ctrl, _, _)); map(input, bind emit(intermediates, ctrl, _, _));
fn finish<uniq K, uniq V>(_k: K, v: chan<reduce_proto<V>>) { fn finish<send K, send V>(_k: K, v: chan<reduce_proto<V>>) {
send(v, release); send(v, release);
} }
treemap::traverse(intermediates, finish); treemap::traverse(intermediates, finish);
send(ctrl, mapper_done); send(ctrl, mapper_done);
} }
fn reduce_task<uniq K, fn reduce_task<send K,
uniq V>(-reduce: reducer<K, V>, -key: K, send V>(-reduce: reducer<K, V>, -key: K,
-out: chan<chan<reduce_proto<V>>>) { -out: chan<chan<reduce_proto<V>>>) {
let p = port(); let p = port();
@ -127,7 +127,7 @@ mod map_reduce {
let ref_count = 0; let ref_count = 0;
let is_done = false; let is_done = false;
fn get<uniq V>(p: port<reduce_proto<V>>, fn get<send V>(p: port<reduce_proto<V>>,
&ref_count: int, &is_done: bool) &ref_count: int, &is_done: bool)
-> option<V> { -> option<V> {
while !is_done || ref_count > 0 { while !is_done || ref_count > 0 {
@ -150,8 +150,8 @@ mod map_reduce {
reduce(key, bind get(p, ref_count, is_done)); reduce(key, bind get(p, ref_count, is_done));
} }
fn map_reduce<uniq K1, uniq K2, fn map_reduce<send K1, send K2,
uniq V>(map: mapper<K1, K2, V>, reduce: reducer<K2, V>, send V>(map: mapper<K1, K2, V>, reduce: reducer<K2, V>,
inputs: [K1]) { inputs: [K1]) {
let ctrl = port(); let ctrl = port();
@ -194,7 +194,7 @@ mod map_reduce {
} }
} }
fn finish<uniq K, uniq V>(_k: K, v: chan<reduce_proto<V>>) { fn finish<send K, send V>(_k: K, v: chan<reduce_proto<V>>) {
send(v, done); send(v, done);
} }
treemap::traverse(reducers, finish); treemap::traverse(reducers, finish);

View file

@ -1,5 +1,4 @@
// error-pattern: needed shared type, got pinned type block // error-pattern: copying a noncopyable value
// xfail-test
fn lol(f: block()) -> block() { ret f; } fn lol(f: block()) -> block() { ret f; }
fn main() { let i = 8; let f = lol(block () { log_err i; }); f(); } fn main() { let i = 8; let f = lol(block () { log_err i; }); f(); }

View file

@ -1,6 +1,5 @@
// error-pattern:cannot copy pinned type foo // error-pattern: copying a noncopyable value
// xfail-test
resource foo(i: int) { } resource foo(i: int) { }
fn main() { let x <- foo(10); let y = x; } fn main() { let x <- foo(10); let y = x; log_err x; }

View file

@ -1,16 +0,0 @@
// error-pattern:mismatched kinds for '@' operand
// xfail-test
resource r(i: @mutable int) {
*i = *i + 1;
}
fn main() {
let i = @mutable 0;
{
let j <- r(i);
// No no no no no
let k <- @j;
}
log_err *i;
assert *i == 2;
}

View file

@ -1,16 +0,0 @@
// error-pattern:mismatched kinds for record field
// xfail-test
resource r(i: @mutable int) {
*i = *i + 1;
}
fn main() {
let i = @mutable 0;
{
let j <- r(i);
// No no no no no
let k <- {x: j};
}
log_err *i;
assert *i == 2;
}

View file

@ -1,16 +0,0 @@
// error-pattern:mismatched kinds for tuple parameter
// xfail-test
resource r(i: @mutable int) {
*i = *i + 1;
}
fn main() {
let i = @mutable 0;
{
let j <- r(i);
// No no no no no
let k <- (j, 0);
}
log_err *i;
assert *i == 2;
}

View file

@ -1,16 +0,0 @@
// error-pattern:mismatched kinds for '~' operand
// xfail-test
resource r(i: @mutable int) {
*i = *i + 1;
}
fn main() {
let i = @mutable 0;
{
let j <- r(i);
// No no no no no
let k <- ~j;
}
log_err *i;
assert *i == 2;
}

View file

@ -1,4 +1,4 @@
// error-pattern:expected fn() but found fn(+int) // error-pattern:expected fn() but found fn(++int)
fn main() { fn main() {
fn f() { } fn f() { }

View file

@ -1,4 +1,4 @@
// error-pattern:can not pass a dynamically-sized type by value // error-pattern:can not pass a dynamically-sized type by value
fn f<T>(+_x: T) {} fn f<T>(++_x: T) {}
fn main() {} fn main() {}

View file

@ -1,5 +1,4 @@
// error-pattern: cannot copy pinned type ~~~{y: r} // error-pattern: copying a noncopyable value
// xfail-test
resource r(i: @mutable int) { resource r(i: @mutable int) {
*i = *i + 1; *i = *i + 1;
@ -11,6 +10,7 @@ fn main() {
// Can't do this copy // Can't do this copy
let x = ~~~{y: r(i)}; let x = ~~~{y: r(i)};
let z = x; let z = x;
log x;
} }
log_err *i; log_err *i;
} }

View file

@ -1,10 +0,0 @@
// error-pattern: mismatched kind
// xfail-test
resource r(b: bool) {
}
fn main() {
let i <- r(true);
let j = i;
}

View file

@ -1,11 +1,10 @@
// error-pattern: mismatched kind // error-pattern: copying a noncopyable value
// xfail-test
resource r(b: bool) { resource r(b: bool) {
} }
fn main() { fn main() {
let i <- ~r(true); let i <- ~r(true);
let j; let j = i;
j = i; log i;
} }

View file

@ -1,37 +0,0 @@
// error-pattern:needed shared type, got pinned type ~r
// xfail-test
resource r(i: @mutable int) {
*i += 1;
}
fn test1() {
let i = @mutable 100;
let j = @mutable 200;
{
let x <- ~r(i);
let y <- ~r(j);
// This is currently not allowed because ~resource is pinned.
// Note that ~resource is supposed to be shared.
x <-> y;
assert ***x == 200;
assert ***y == 100;
}
assert *i == 101;
assert *j == 201;
}
fn test2() {
let i = @mutable 0;
{
let x <- ~r(i);
let y <- ~r(i);
x <-> y;
}
assert *i == 2;
}
fn main() {
test1();
test2();
}

View file

@ -1,7 +1,6 @@
// error-pattern: needed unique type // error-pattern: instantiating a sendable type parameter with a copyable type
// xfail-test
fn f<uniq T>(i: T) { fn f<send T>(i: T) {
} }
fn main() { fn main() {

View file

@ -1,12 +1,10 @@
// error-pattern: needed shared type, got pinned type ~r // error-pattern: copying a noncopyable value
// xfail-test
resource r(i: @mutable int) { resource r(i: @mutable int) {
*i = *i + 1; *i = *i + 1;
} }
fn f<T>(i: [T], j: [T]) { fn f<T>(+i: [T], +j: [T]) {
// Shouldn't be able to do this copy of j
let k = i + j; let k = i + j;
} }
@ -16,6 +14,6 @@ fn main() {
let r1 <- [~r(i1)]; let r1 <- [~r(i1)];
let r2 <- [~r(i2)]; let r2 <- [~r(i2)];
f(r1, r2); f(r1, r2);
log_err *i1; log (r2, *i1);
log_err *i2; log (r1, *i2);
} }

View file

@ -1,5 +1,5 @@
// error-pattern: Unsatisfied precondition constraint // error-pattern: Unsatisfied precondition constraint
fn send<uniq T>(ch: _chan<T>, -data: T) { log ch; log data; fail; } fn send<send T>(ch: _chan<T>, -data: T) { log ch; log data; fail; }
type _chan<T> = int; type _chan<T> = int;
// Tests that "log message;" is flagged as using // Tests that "log message;" is flagged as using

View file

@ -1,10 +0,0 @@
// error-pattern: mismatched kind
// xfail-test
resource r(b: bool) {
}
fn main() {
let i <- [r(true)];
i += [r(true)];
}

View file

@ -1,11 +0,0 @@
// error-pattern: mismatched kind
// xfail-test
resource r(b: bool) {
}
fn main() {
let i <- [r(true)];
let j;
j <- copy [r(true)];
}

View file

@ -1,11 +0,0 @@
// error-pattern: mismatched kind
// xfail-test
resource r(b: bool) {
}
fn main() {
let i <- [r(true)];
let j;
j = i;
}

View file

@ -1,12 +1,11 @@
// error-pattern:mismatched kinds // error-pattern: copying a noncopyable value
// xfail-test
resource r(i: int) { resource r(_i: int) { }
}
fn main() { fn main() {
// This can't make sense as it would copy the resources // This can't make sense as it would copy the resources
let i <- [r(0)]; let i <- [r(0)];
let j <- [r(1)]; let j <- [r(1)];
let k = i + j; let k = i + j;
} log j;
}

View file

@ -4,8 +4,8 @@ fn test00_start(ch: chan_t<int>, message: int) { send(ch, copy message); }
type task_id = int; type task_id = int;
type port_id = int; type port_id = int;
type chan_t<uniq T> = {task: task_id, port: port_id}; type chan_t<send T> = {task: task_id, port: port_id};
fn send<uniq T>(ch: chan_t<T>, -data: T) { fail; } fn send<send T>(ch: chan_t<T>, -data: T) { fail; }
fn main() { fail "quux"; } fn main() { fail "quux"; }

View file

@ -5,7 +5,7 @@ import std::comm::port;
import std::comm::send; import std::comm::send;
import std::comm::recv; import std::comm::recv;
fn echo<uniq T>(c: chan<T>, oc: chan<chan<T>>) { fn echo<send T>(c: chan<T>, oc: chan<chan<T>>) {
// Tests that the type argument in port gets // Tests that the type argument in port gets
// visited // visited
let p = port::<T>(); let p = port::<T>();

View file

@ -2,6 +2,6 @@
// -*- rust -*- // -*- rust -*-
fn f<T, U>(x: T, y: U) -> {a: T, b: U} { ret {a: x, b: y}; } fn f<copy T, copy U>(x: T, y: U) -> {a: T, b: U} { ret {a: x, b: y}; }
fn main() { log f({x: 3, y: 4, z: 5}, 4).a.x; log f(5, 6).a; } fn main() { log f({x: 3, y: 4, z: 5}, 4).a.x; log f(5, 6).a; }

View file

@ -1,4 +1,4 @@
fn wrapper3<T>(i: T, j: int) { fn wrapper3<copy T>(i: T, j: int) {
log i; log i;
log j; log j;
// This is a regression test that the spawn3 thunk to wrapper3 // This is a regression test that the spawn3 thunk to wrapper3
@ -6,7 +6,7 @@ fn wrapper3<T>(i: T, j: int) {
assert j == 123456789; assert j == 123456789;
} }
fn spawn3<T>(i: T, j: int) { fn spawn3<copy T>(i: T, j: int) {
let wrapped = bind wrapper3(i, j); let wrapped = bind wrapper3(i, j);
wrapped(); wrapped();
} }

View file

@ -1,8 +1,8 @@
type box<T> = {c: @T}; type box<copy T> = {c: @T};
fn unbox<T>(b: box<T>) -> T { ret *b.c; } fn unbox<copy T>(b: box<T>) -> T { ret *b.c; }
fn main() { fn main() {
let foo: int = 17; let foo: int = 17;

View file

@ -4,7 +4,7 @@
// -*- rust -*- // -*- rust -*-
type compare<T> = fn@(T, T) -> bool; type compare<T> = fn@(T, T) -> bool;
fn test_generic<T>(expected: T, eq: compare<T>) { fn test_generic<copy T>(expected: T, eq: compare<T>) {
let actual: T = { expected }; let actual: T = { expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -3,7 +3,7 @@
// -*- rust -*- // -*- rust -*-
type compare<T> = fn@(~T, ~T) -> bool; type compare<T> = fn@(~T, ~T) -> bool;
fn test_generic<T>(expected: ~T, eq: compare<T>) { fn test_generic<copy T>(expected: ~T, eq: compare<T>) {
let actual: ~T = { expected }; let actual: ~T = { expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -4,7 +4,7 @@
// -*- rust -*- // -*- rust -*-
type compare<T> = fn@(T, T) -> bool; type compare<T> = fn@(T, T) -> bool;
fn test_generic<T>(expected: T, eq: compare<T>) { fn test_generic<copy T>(expected: T, eq: compare<T>) {
let actual: T = { expected }; let actual: T = { expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -6,7 +6,7 @@
// Tests for standalone blocks as expressions with dynamic type sizes // Tests for standalone blocks as expressions with dynamic type sizes
type compare<T> = fn@(T, T) -> bool; type compare<T> = fn@(T, T) -> bool;
fn test_generic<T>(expected: T, eq: compare<T>) { fn test_generic<copy T>(expected: T, eq: compare<T>) {
let actual: T = { expected }; let actual: T = { expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -4,7 +4,7 @@
// -*- rust -*- // -*- rust -*-
type compare<T> = fn@(T, T) -> bool; type compare<T> = fn@(T, T) -> bool;
fn test_generic<T>(expected: T, not_expected: T, eq: compare<T>) { fn test_generic<copy T>(expected: T, not_expected: T, eq: compare<T>) {
let actual: T = if true { expected } else { not_expected }; let actual: T = if true { expected } else { not_expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -6,7 +6,7 @@
// Tests for if as expressions with dynamic type sizes // Tests for if as expressions with dynamic type sizes
type compare<T> = fn@(T, T) -> bool; type compare<T> = fn@(T, T) -> bool;
fn test_generic<T>(expected: T, not_expected: T, eq: compare<T>) { fn test_generic<copy T>(expected: T, not_expected: T, eq: compare<T>) {
let actual: T = if true { expected } else { not_expected }; let actual: T = if true { expected } else { not_expected };
assert (eq(expected, actual)); assert (eq(expected, actual));
} }

View file

@ -1,8 +1,8 @@
fn fix_help<A, uniq B>(f: fn(fn@(A) -> B, A) -> B, x: A) -> B { fn fix_help<A, send B>(f: fn(fn@(A) -> B, A) -> B, x: A) -> B {
ret f(bind fix_help(f, _), x); ret f(bind fix_help(f, _), x);
} }
fn fix<A, uniq B>(f: fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B { fn fix<A, send B>(f: fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B {
ret bind fix_help(f, _); ret bind fix_help(f, _);
} }

View file

@ -1,6 +1,6 @@
// This is what the signature to spawn should look like with bare functions // This is what the signature to spawn should look like with bare functions
fn spawn<uniq T>(val: T, f: fn(T)) { fn spawn<send T>(val: T, f: fn(T)) {
f(val); f(val);
} }

View file

@ -1,5 +1,5 @@
obj ob<shar K>(k: K) { obj ob<copy K>(k: K) {
fn foo(it: block(~{a: K})) { it(~{a: k}); } fn foo(it: block(~{a: K})) { it(~{a: k}); }
} }

View file

@ -1,6 +1,6 @@
fn id<T>(t: T) -> T { ret t; } fn id<copy T>(t: T) -> T { ret t; }
fn main() { fn main() {
let expected = @100; let expected = @100;

View file

@ -1,6 +1,6 @@
fn id<uniq T>(t: T) -> T { ret t; } fn id<send T>(t: T) -> T { ret t; }
fn main() { fn main() {
let expected = ~100; let expected = ~100;

View file

@ -1,6 +1,6 @@
fn id<T>(t: T) -> T { ret t; } fn id<copy T>(t: T) -> T { ret t; }
fn main() { fn main() {
let t = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7}; let t = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7};

View file

@ -1,6 +1,6 @@
fn id<T>(t: T) -> T { ret t; } fn id<copy T>(t: T) -> T { ret t; }
fn main() { fn main() {
let t = {_0: 1, _1: 2, _2: 3, _3: 4, _4: 5, _5: 6, _6: 7}; let t = {_0: 1, _1: 2, _2: 3, _3: 4, _4: 5, _5: 6, _6: 7};

View file

@ -1,6 +1,6 @@
fn box<T>(x: {x: T, y: T, z: T}) -> @{x: T, y: T, z: T} { ret @x; } fn box<copy T>(x: {x: T, y: T, z: T}) -> @{x: T, y: T, z: T} { ret @x; }
fn main() { fn main() {
let x: @{x: int, y: int, z: int} = box::<int>({x: 1, y: 2, z: 3}); let x: @{x: int, y: int, z: int} = box::<int>({x: 1, y: 2, z: 3});

View file

@ -1,8 +1,8 @@
fn g<X>(x: X) -> X { ret x; } fn g<copy X>(x: X) -> X { ret x; }
fn f<T>(t: T) -> {a: T, b: T} { fn f<copy T>(t: T) -> {a: T, b: T} {
type pair = {a: T, b: T}; type pair = {a: T, b: T};
let x: pair = {a: t, b: t}; let x: pair = {a: t, b: t};

View file

@ -1,5 +1,5 @@
fn f<T>(t: T) { let t1: T = t; } fn f<copy T>(t: T) { let t1: T = t; }
fn main() { let x = {x: @10, y: @12}; f(x); } fn main() { let x = {x: @10, y: @12}; f(x); }

View file

@ -1,8 +1,8 @@
type recbox<T> = {x: @T}; type recbox<copy T> = {x: @T};
fn reclift<T>(t: T) -> recbox<T> { ret {x: @t}; } fn reclift<copy T>(t: T) -> recbox<T> { ret {x: @t}; }
fn main() { fn main() {
let foo: int = 17; let foo: int = 17;

View file

@ -1,6 +1,6 @@
type recbox<T> = {x: ~T}; type recbox<copy T> = {x: ~T};
fn reclift<T>(t: T) -> recbox<T> { ret {x: ~t}; } fn reclift<copy T>(t: T) -> recbox<T> { ret {x: ~t}; }
fn main() { fn main() {
let foo: int = 17; let foo: int = 17;

View file

@ -4,6 +4,6 @@
// -*- rust -*- // -*- rust -*-
// Issue #45: infer type parameters in function applications // Issue #45: infer type parameters in function applications
fn id<T>(x: T) -> T { ret x; } fn id<copy T>(x: T) -> T { ret x; }
fn main() { let x: int = 42; let y: int = id(x); assert (x == y); } fn main() { let x: int = 42; let y: int = id(x); assert (x == y); }

View file

@ -1,4 +1,4 @@
fn f<T>(x: ~T) -> ~T { ret x; } fn f<copy T>(x: ~T) -> ~T { ret x; }
fn main() { let x = f(~3); log *x; } fn main() { let x = f(~3); log *x; }

View file

@ -2,7 +2,7 @@
// -*- rust -*- // -*- rust -*-
fn id<T>(x: T) -> T { ret x; } fn id<copy T>(x: T) -> T { ret x; }
type triple = {x: int, y: int, z: int}; type triple = {x: int, y: int, z: int};

View file

@ -1,6 +1,6 @@
obj handle<shar T>(data: T) { obj handle<copy T>(data: T) {
fn get() -> T { ret data; } fn get() -> T { ret data; }
} }

View file

@ -1,6 +1,6 @@
obj buf<shar T>(data: {_0: T, _1: T, _2: T}) { obj buf<copy T>(data: {_0: T, _1: T, _2: T}) {
fn get(i: int) -> T { fn get(i: int) -> T {
if i == 0 { if i == 0 {
ret data._0; ret data._0;

View file

@ -1,4 +1,4 @@
fn get_third<T>(t: (T, T, T)) -> T { let (_, _, x) = t; ret x; } fn get_third<copy T>(t: (T, T, T)) -> T { let (_, _, x) = t; ret x; }
fn main() { fn main() {
log get_third((1, 2, 3)); log get_third((1, 2, 3));

View file

@ -1,5 +1,5 @@
fn box<T>(x: {x: T, y: T, z: T}) -> ~{x: T, y: T, z: T} { ret ~x; } fn box<copy T>(x: {x: T, y: T, z: T}) -> ~{x: T, y: T, z: T} { ret ~x; }
fn main() { fn main() {
let x: ~{x: int, y: int, z: int} = box::<int>({x: 1, y: 2, z: 3}); let x: ~{x: int, y: int, z: int} = box::<int>({x: 1, y: 2, z: 3});

View file

@ -1,5 +1,5 @@
fn quux<T>(x: T) -> T { let f = bind id::<T>(_); ret f(x); } fn quux<copy T>(x: T) -> T { let f = bind id::<T>(_); ret f(x); }
fn id<T>(x: T) -> T { ret x; } fn id<copy T>(x: T) -> T { ret x; }
fn main() { assert (quux(10) == 10); } fn main() { assert (quux(10) == 10); }

View file

@ -1,4 +1,4 @@
fn double<T>(a: T) -> [T] { ret [a] + [a]; } fn double<copy T>(a: T) -> [T] { ret [a] + [a]; }
fn double_int(a: int) -> [int] { ret [a] + [a]; } fn double_int(a: int) -> [int] { ret [a] + [a]; }

View file

@ -1,8 +1,8 @@
tag myvec<X> = [X]; tag myvec<X> = [X];
fn myvec_deref<X>(mv: myvec<X>) -> [X] { ret *mv; } fn myvec_deref<copy X>(mv: myvec<X>) -> [X] { ret *mv; }
fn myvec_elt<X>(mv: myvec<X>) -> X { ret mv[0]; } fn myvec_elt<copy X>(mv: myvec<X>) -> X { ret mv[0]; }
fn main() { fn main() {
let mv = myvec([1, 2, 3]); let mv = myvec([1, 2, 3]);

View file

@ -2,19 +2,19 @@ use std;
import std::list::*; import std::list::*;
pure fn pure_length_go<T>(ls: list<T>, acc: uint) -> uint { pure fn pure_length_go<copy T>(ls: list<T>, acc: uint) -> uint {
alt ls { nil. { acc } cons(_, tl) { pure_length_go(*tl, acc + 1u) } } alt ls { nil. { acc } cons(_, tl) { pure_length_go(*tl, acc + 1u) } }
} }
pure fn pure_length<T>(ls: list<T>) -> uint { pure_length_go(ls, 0u) } pure fn pure_length<copy T>(ls: list<T>) -> uint { pure_length_go(ls, 0u) }
pure fn nonempty_list<T>(ls: list<T>) -> bool { pure_length(ls) > 0u } pure fn nonempty_list<copy T>(ls: list<T>) -> bool { pure_length(ls) > 0u }
// Of course, the compiler can't take advantage of the // Of course, the compiler can't take advantage of the
// knowledge that ls is a cons node. Future work. // knowledge that ls is a cons node. Future work.
// Also, this is pretty contrived since nonempty_list // Also, this is pretty contrived since nonempty_list
// could be a "tag refinement", if we implement those. // could be a "tag refinement", if we implement those.
fn safe_head<T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) } fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) }
fn main() { fn main() {
let mylist = cons(@1u, @nil); let mylist = cons(@1u, @nil);

View file

@ -6,7 +6,7 @@ tag clam<T> { signed(int); unsigned(uint); }
fn getclam<T>() -> clam<T> { ret signed::<T>(42); } fn getclam<T>() -> clam<T> { ret signed::<T>(42); }
obj impatience<shar T>() { obj impatience<copy T>() {
fn moreclam() -> clam<T> { be getclam::<T>(); } fn moreclam() -> clam<T> { be getclam::<T>(); }
} }

View file

@ -5,7 +5,7 @@ type closable = @mutable bool;
resource close_res(i: closable) { *i = false; } resource close_res(i: closable) { *i = false; }
tag option<pin T> { none; some(T); } tag option<T> { none; some(T); }
fn sink(res: option<close_res>) { } fn sink(res: option<close_res>) { }

View file

@ -2,6 +2,6 @@
tag option<T> { none; some(T); } tag option<T> { none; some(T); }
fn f<T>() -> option<T> { ret none; } fn f<copy T>() -> option<T> { ret none; }
fn main() { f::<int>(); } fn main() { f::<int>(); }

View file

@ -4,9 +4,9 @@ import std::comm::send;
import std::comm::port; import std::comm::port;
// tests that ctrl's type gets inferred properly // tests that ctrl's type gets inferred properly
type command<uniq K, uniq V> = {key: K, val: V}; type command<send K, send V> = {key: K, val: V};
fn cache_server<uniq K, uniq V>(c: chan<chan<command<K, V>>>) { fn cache_server<send K, send V>(c: chan<chan<command<K, V>>>) {
let ctrl = port(); let ctrl = port();
send(c, chan(ctrl)); send(c, chan(ctrl));
} }

View file

@ -1,6 +1,6 @@
fn p_foo<pin T>(pinned: T) { } fn p_foo<T>(pinned: T) { }
fn s_foo<T>(shared: T) { } fn s_foo<copy T>(shared: T) { }
fn u_foo<uniq T>(unique: T) { } fn u_foo<send T>(unique: T) { }
resource r(i: int) { } resource r(i: int) { }

View file

@ -5,24 +5,24 @@ import std::list::*;
// Can't easily be written as a "pure fn" because there's // Can't easily be written as a "pure fn" because there's
// no syntax for specifying that f is pure. // no syntax for specifying that f is pure.
fn pure_foldl<T, U>(ls: list<T>, u: U, f: block(T, U) -> U) -> U { fn pure_foldl<copy T, copy U>(ls: list<T>, u: U, f: block(T, U) -> U) -> U {
alt ls { nil. { u } cons(hd, tl) { f(hd, pure_foldl(*tl, f(hd, u), f)) } } alt ls { nil. { u } cons(hd, tl) { f(hd, pure_foldl(*tl, f(hd, u), f)) } }
} }
// Shows how to use an "unchecked" block to call a general // Shows how to use an "unchecked" block to call a general
// fn from a pure fn // fn from a pure fn
pure fn pure_length<T>(ls: list<T>) -> uint { pure fn pure_length<copy T>(ls: list<T>) -> uint {
fn count<T>(_t: T, &&u: uint) -> uint { u + 1u } fn count<T>(_t: T, &&u: uint) -> uint { u + 1u }
unchecked{ pure_foldl(ls, 0u, bind count(_, _)) } unchecked{ pure_foldl(ls, 0u, bind count(_, _)) }
} }
pure fn nonempty_list<T>(ls: list<T>) -> bool { pure_length(ls) > 0u } pure fn nonempty_list<copy T>(ls: list<T>) -> bool { pure_length(ls) > 0u }
// Of course, the compiler can't take advantage of the // Of course, the compiler can't take advantage of the
// knowledge that ls is a cons node. Future work. // knowledge that ls is a cons node. Future work.
// Also, this is pretty contrived since nonempty_list // Also, this is pretty contrived since nonempty_list
// could be a "tag refinement", if we implement those. // could be a "tag refinement", if we implement those.
fn safe_head<T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) } fn safe_head<copy T>(ls: list<T>) : nonempty_list(ls) -> T { head(ls) }
fn main() { fn main() {
let mylist = cons(@1u, @nil); let mylist = cons(@1u, @nil);

View file

@ -1,4 +1,4 @@
fn f<T>(t: T) -> T { fn f<copy T>(t: T) -> T {
let t1 = t; let t1 = t;
t1 t1
} }

View file

@ -1,6 +1,6 @@
// Issue #976 // Issue #976
fn f<T>(x: ~T) { fn f<copy T>(x: ~T) {
let _x2 = x; let _x2 = x;
} }
fn main() { } fn main() { }

View file

@ -1,10 +1,10 @@
fn unique() { fn sendable() {
fn f<uniq T>(i: T, j: T) { fn f<send T>(i: T, j: T) {
assert i == j; assert i == j;
} }
fn g<uniq T>(i: T, j: T) { fn g<send T>(i: T, j: T) {
assert i != j; assert i != j;
} }
@ -16,7 +16,25 @@ fn unique() {
g(i, j); g(i, j);
} }
fn shared() { fn copyable() {
fn f<copy T>(i: T, j: T) {
assert i == j;
}
fn g<copy T>(i: T, j: T) {
assert i != j;
}
let i = ~100;
let j = ~100;
f(i, j);
let i = ~100;
let j = ~101;
g(i, j);
}
fn noncopyable() {
fn f<T>(i: T, j: T) { fn f<T>(i: T, j: T) {
assert i == j; assert i == j;
@ -34,26 +52,8 @@ fn shared() {
g(i, j); g(i, j);
} }
fn pinned() {
fn f<pin T>(i: T, j: T) {
assert i == j;
}
fn g<pin T>(i: T, j: T) {
assert i != j;
}
let i = ~100;
let j = ~100;
f(i, j);
let i = ~100;
let j = ~101;
g(i, j);
}
fn main() { fn main() {
unique(); sendable();
shared(); copyable();
pinned(); noncopyable();
} }

View file

@ -1,5 +1,5 @@
fn push<T>(&v: [const T], t: T) { v += [t]; } fn push<copy T>(&v: [const T], t: T) { v += [t]; }
fn main() { let v = [1, 2, 3]; push(v, 1); } fn main() { let v = [1, 2, 3]; push(v, 1); }

View file

@ -81,7 +81,7 @@ fn test_boxes(a: @int, b: @int, c: @int, d: @int) {
type eqfn<T> = fn@(T, T) -> bool; type eqfn<T> = fn@(T, T) -> bool;
fn test_parameterized<T>(e: eqfn<T>, a: T, b: T, c: T, d: T) { fn test_parameterized<copy T>(e: eqfn<T>, a: T, b: T, c: T, d: T) {
let deq: deque::t<T> = deque::create::<T>(); let deq: deque::t<T> = deque::create::<T>();
assert (deq.size() == 0u); assert (deq.size() == 0u);
deq.add_front(a); deq.add_front(a);

View file

@ -68,7 +68,7 @@ fn test_join_convenient() {
#[ignore] #[ignore]
fn spawn_polymorphic() { fn spawn_polymorphic() {
// FIXME #1038: Can't spawn palymorphic functions // FIXME #1038: Can't spawn palymorphic functions
/*fn foo<uniq T>(x: T) { log_err x; } /*fn foo<send T>(x: T) { log_err x; }
task::spawn(true, foo); task::spawn(true, foo);
task::spawn(42, foo);*/ task::spawn(42, foo);*/