Better type inference for chans and ports.

This commit is contained in:
Eric Holk 2011-08-17 17:13:11 -07:00
parent f023f82090
commit 3ab21e5ee0
6 changed files with 65 additions and 59 deletions

View file

@ -6,7 +6,7 @@ import task::task_id;
export _chan; export _chan;
export _port; export _port;
export chan_handle;
export mk_port; export mk_port;
export send; export send;
export recv; export recv;
@ -32,10 +32,9 @@ native "rust-intrinsic" mod rusti {
type port_id = int; type port_id = int;
type chan<~T> = { type chan_handle<~T> = { task : task_id, port : port_id};
task : task_id,
port : port_id tag chan<~T> { chan_t(chan_handle<T>); }
};
type _chan<~T> = chan<T>; type _chan<~T> = chan<T>;
resource port_ptr(po: *rustrt::rust_port) { resource port_ptr(po: *rustrt::rust_port) {
@ -43,11 +42,11 @@ resource port_ptr(po: *rustrt::rust_port) {
rustrt::del_port(po); rustrt::del_port(po);
} }
type port<~T> = @port_ptr; tag port<~T> { port_t(@port_ptr); }
obj port_obj<~T>(raw_port : port<T>) { obj port_obj<~T>(raw_port : port<T>) {
fn mk_chan() -> _chan<T> { fn mk_chan() -> chan<T> {
chan::<T>(raw_port) chan(raw_port)
} }
fn recv() -> T { fn recv() -> T {
@ -60,21 +59,21 @@ fn mk_port<~T>() -> _port<T> {
ret port_obj::<T>(port::<T>()); ret port_obj::<T>(port::<T>());
} }
fn send<~T>(ch : chan<T>, data : -T) { fn send<~T>(ch : &chan<T>, data : -T) {
rustrt::chan_id_send(ch.task, ch.port, data); rustrt::chan_id_send(ch.task, ch.port, data);
} }
fn port<~T>() -> port<T> { fn port<~T>() -> port<T> {
@port_ptr(rustrt::new_port(sys::size_of::<T>())) port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
} }
fn recv<~T>(p : port<T>) -> T { fn recv<~T>(p : &port<T>) -> T {
ret rusti::recv(**p) ret rusti::recv(***p)
} }
fn chan<~T>(p : port<T>) -> chan<T> { fn chan<~T>(p : &port<T>) -> chan<T> {
{ chan_t({
task: task::get_task_id(), task: task::get_task_id(),
port: rustrt::get_port_id(**p) port: rustrt::get_port_id(***p)
} })
} }

View file

@ -1,6 +1,5 @@
import cast = unsafe::reinterpret_cast; import cast = unsafe::reinterpret_cast;
import comm; import comm;
import comm::_chan;
import option::some; import option::some;
import option::none; import option::none;
import option = option::t; import option = option::t;
@ -33,7 +32,7 @@ native "rust" mod rustrt {
type rust_task = { type rust_task = {
id : task, id : task,
mutable notify_enabled : u8, mutable notify_enabled : u8,
mutable notify_chan : _chan<task_notification>, mutable notify_chan : comm::chan_handle<task_notification>,
ctx : task_context, ctx : task_context,
stack_ptr : *u8 stack_ptr : *u8
}; };
@ -76,14 +75,12 @@ tag task_notification {
fn join(task_port : (task_id, comm::port<task_notification>)) fn join(task_port : (task_id, comm::port<task_notification>))
-> task_result { -> task_result {
let (id, port) = task_port; let (id, port) = task_port;
while true {
alt comm::recv::<task_notification>(port) { alt comm::recv::<task_notification>(port) {
exit(_id, res) { exit(_id, res) {
if _id == id { ret res } if _id == id { ret res }
else { fail #fmt("join received id %d, expected %d", _id, id) }
} }
} }
}
fail
} }
fn join_id(t : task_id) -> task_result { fn join_id(t : task_id) -> task_result {
@ -108,7 +105,7 @@ fn spawn(thunk : -fn() -> ()) -> task {
spawn_inner(thunk, none) spawn_inner(thunk, none)
} }
fn spawn_notify(thunk : -fn() -> (), notify : _chan<task_notification>) fn spawn_notify(thunk : -fn() -> (), notify : comm::chan<task_notification>)
-> task { -> task {
spawn_inner(thunk, some(notify)) spawn_inner(thunk, some(notify))
} }
@ -121,7 +118,7 @@ fn spawn_joinable(thunk : -fn()) -> (task_id, comm::port<task_notification>) {
// FIXME: make this a fn~ once those are supported. // FIXME: make this a fn~ once those are supported.
fn spawn_inner(thunk : -fn() -> (), fn spawn_inner(thunk : -fn() -> (),
notify : option<_chan<task_notification>>) notify : option<comm::chan<task_notification>>)
-> task_id { -> task_id {
let id = rustrt::new_task(); let id = rustrt::new_task();
@ -144,7 +141,7 @@ fn spawn_inner(thunk : -fn() -> (),
alt notify { alt notify {
some(c) { some(c) {
(**task_ptr).notify_enabled = 1u8; (**task_ptr).notify_enabled = 1u8;
(**task_ptr).notify_chan = c; (**task_ptr).notify_chan = *c;
} }
none {} none {}
}; };

View file

@ -14,10 +14,10 @@ import std::os;
import std::run; import std::run;
import std::io; import std::io;
import std::str; import std::str;
import std::comm::_chan; import std::comm::chan;
import std::comm::mk_port; import std::comm::port;
import std::comm::_port;
import std::comm::send; import std::comm::send;
import std::comm::recv;
export handle; export handle;
export mk; export mk;
@ -26,27 +26,27 @@ export run;
export close; export close;
export reqchan; export reqchan;
type reqchan = _chan<request>; type reqchan = chan<request>;
type handle = {task: option::t<task_id>, chan: reqchan}; type handle = {task: option::t<task_id>, chan: reqchan};
tag request { tag request {
exec([u8], [u8], [[u8]], _chan<response>); exec([u8], [u8], [[u8]], chan<response>);
stop; stop;
} }
type response = {pid: int, infd: int, outfd: int, errfd: int}; type response = {pid: int, infd: int, outfd: int, errfd: int};
fn mk() -> handle { fn mk() -> handle {
let setupport = mk_port(); let setupport = port();
let task = task::_spawn(bind fn(setupchan: _chan<_chan<request>>) { let task = task::spawn(bind fn(setupchan: chan<chan<request>>) {
let reqport = mk_port(); let reqport = port();
let reqchan = reqport.mk_chan(); let reqchan = chan(reqport);
send(setupchan, reqchan); send(setupchan, reqchan);
worker(reqport); worker(reqport);
} (setupport.mk_chan())); } (chan(setupport)));
ret {task: option::some(task), ret {task: option::some(task),
chan: setupport.recv() chan: recv(setupport)
}; };
} }
@ -60,13 +60,13 @@ fn close(handle: &handle) {
fn run(handle: &handle, lib_path: &str, fn run(handle: &handle, lib_path: &str,
prog: &str, args: &[str], input: &option::t<str>) -> prog: &str, args: &[str], input: &option::t<str>) ->
{status: int, out: str, err: str} { {status: int, out: str, err: str} {
let p = mk_port::<response>(); let p = port();
let ch = p.mk_chan(); let ch = chan(p);
send(handle.chan, exec(str::bytes(lib_path), send(handle.chan, exec(str::bytes(lib_path),
str::bytes(prog), str::bytes(prog),
clone_ivecstr(args), clone_ivecstr(args),
ch)); ch));
let resp = p.recv(); let resp = recv(p);
writeclose(resp.infd, input); writeclose(resp.infd, input);
let output = readclose(resp.outfd); let output = readclose(resp.outfd);
@ -99,18 +99,12 @@ fn readclose(fd: int) -> str {
ret buf; ret buf;
} }
fn worker(p: _port<request>) { fn worker(p: port<request>) {
// FIXME (787): If we declare this inside of the while loop and then // FIXME (787): If we declare this inside of the while loop and then
// break out of it before it's ever initialized (i.e. we don't run // break out of it before it's ever initialized (i.e. we don't run
// any tests), then the cleanups will puke, so we're initializing it // any tests), then the cleanups will puke.
// here with defaults. let execparms;
let execparms = {
lib_path: "",
prog: "",
args: ~[],
respchan: p.mk_chan()
};
while true { while true {
// FIXME: Sending strings across channels seems to still // FIXME: Sending strings across channels seems to still
@ -124,7 +118,7 @@ fn worker(p: _port<request>) {
// put the entire alt in another block to make sure the exec // put the entire alt in another block to make sure the exec
// message goes out of scope. Seems like the scoping rules for // message goes out of scope. Seems like the scoping rules for
// the alt discriminant are wrong. // the alt discriminant are wrong.
alt p.recv() { alt recv(p) {
exec(lib_path, prog, args, respchan) { exec(lib_path, prog, args, respchan) {
{ {
lib_path: str::unsafe_from_bytes(lib_path), lib_path: str::unsafe_from_bytes(lib_path),

View file

@ -4,7 +4,7 @@ import std::comm::_chan;
import std::comm::mk_port; import std::comm::mk_port;
import std::comm::send; import std::comm::send;
fn echo<~T>(c: _chan<T>, oc: _chan<_chan<T>>) { fn echo<~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 = mk_port::<T>(); let p = mk_port::<T>();

View file

@ -1,13 +1,13 @@
use std; use std;
import std::comm::_chan; import std::comm::chan;
import std::comm::send; import std::comm::send;
import std::comm::mk_port; import std::comm::port;
// tests that ctrl's type gets inferred properly // tests that ctrl's type gets inferred properly
type command<K, V> = {key: K, val: V}; type command<~K, ~V> = {key: K, val: V};
fn cache_server<K, V>(c: _chan<_chan<command<K, V>>>) { fn cache_server<~K, ~V>(c: &chan<chan<command<K, V>>>) {
let ctrl = mk_port::<_chan<command<K, V>>>(); let ctrl = port();
send(c, ctrl.mk_chan()); send(c, chan(ctrl));
} }
fn main() { } fn main() { }

View file

@ -25,3 +25,19 @@ fn send_recv_fn() {
comm::send(c, 42); comm::send(c, 42);
assert(comm::recv(p) == 42); assert(comm::recv(p) == 42);
} }
#[test]
fn send_recv_fn_infer() {
let p = comm::port();
let c = comm::chan(p);
comm::send(c, 42);
assert(comm::recv(p) == 42);
}
#[test]
fn chan_chan() {
let p = comm::port(), p2 = comm::port::<int>();
let c = comm::chan(p);
comm::send(c, comm::chan(p2));
let c2 = comm::recv(p);
}