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

View file

@ -1,6 +1,5 @@
import cast = unsafe::reinterpret_cast;
import comm;
import comm::_chan;
import option::some;
import option::none;
import option = option::t;
@ -33,7 +32,7 @@ native "rust" mod rustrt {
type rust_task = {
id : task,
mutable notify_enabled : u8,
mutable notify_chan : _chan<task_notification>,
mutable notify_chan : comm::chan_handle<task_notification>,
ctx : task_context,
stack_ptr : *u8
};
@ -76,14 +75,12 @@ tag task_notification {
fn join(task_port : (task_id, comm::port<task_notification>))
-> task_result {
let (id, port) = task_port;
while true {
alt comm::recv::<task_notification>(port) {
exit(_id, res) {
if _id == id { ret res }
}
}
alt comm::recv::<task_notification>(port) {
exit(_id, 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 {
@ -108,7 +105,7 @@ fn spawn(thunk : -fn() -> ()) -> task {
spawn_inner(thunk, none)
}
fn spawn_notify(thunk : -fn() -> (), notify : _chan<task_notification>)
fn spawn_notify(thunk : -fn() -> (), notify : comm::chan<task_notification>)
-> task {
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.
fn spawn_inner(thunk : -fn() -> (),
notify : option<_chan<task_notification>>)
notify : option<comm::chan<task_notification>>)
-> task_id {
let id = rustrt::new_task();
@ -144,7 +141,7 @@ fn spawn_inner(thunk : -fn() -> (),
alt notify {
some(c) {
(**task_ptr).notify_enabled = 1u8;
(**task_ptr).notify_chan = c;
(**task_ptr).notify_chan = *c;
}
none {}
};

View file

@ -14,10 +14,10 @@ import std::os;
import std::run;
import std::io;
import std::str;
import std::comm::_chan;
import std::comm::mk_port;
import std::comm::_port;
import std::comm::chan;
import std::comm::port;
import std::comm::send;
import std::comm::recv;
export handle;
export mk;
@ -26,27 +26,27 @@ export run;
export close;
export reqchan;
type reqchan = _chan<request>;
type reqchan = chan<request>;
type handle = {task: option::t<task_id>, chan: reqchan};
tag request {
exec([u8], [u8], [[u8]], _chan<response>);
exec([u8], [u8], [[u8]], chan<response>);
stop;
}
type response = {pid: int, infd: int, outfd: int, errfd: int};
fn mk() -> handle {
let setupport = mk_port();
let task = task::_spawn(bind fn(setupchan: _chan<_chan<request>>) {
let reqport = mk_port();
let reqchan = reqport.mk_chan();
let setupport = port();
let task = task::spawn(bind fn(setupchan: chan<chan<request>>) {
let reqport = port();
let reqchan = chan(reqport);
send(setupchan, reqchan);
worker(reqport);
} (setupport.mk_chan()));
} (chan(setupport)));
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,
prog: &str, args: &[str], input: &option::t<str>) ->
{status: int, out: str, err: str} {
let p = mk_port::<response>();
let ch = p.mk_chan();
let p = port();
let ch = chan(p);
send(handle.chan, exec(str::bytes(lib_path),
str::bytes(prog),
clone_ivecstr(args),
ch));
let resp = p.recv();
let resp = recv(p);
writeclose(resp.infd, input);
let output = readclose(resp.outfd);
@ -99,18 +99,12 @@ fn readclose(fd: int) -> str {
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
// 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
// here with defaults.
let execparms = {
lib_path: "",
prog: "",
args: ~[],
respchan: p.mk_chan()
};
// any tests), then the cleanups will puke.
let execparms;
while true {
// 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
// message goes out of scope. Seems like the scoping rules for
// the alt discriminant are wrong.
alt p.recv() {
alt recv(p) {
exec(lib_path, prog, args, respchan) {
{
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::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
// visited
let p = mk_port::<T>();

View file

@ -1,13 +1,13 @@
use std;
import std::comm::_chan;
import std::comm::chan;
import std::comm::send;
import std::comm::mk_port;
import std::comm::port;
// 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>>>) {
let ctrl = mk_port::<_chan<command<K, V>>>();
send(c, ctrl.mk_chan());
fn cache_server<~K, ~V>(c: &chan<chan<command<K, V>>>) {
let ctrl = port();
send(c, chan(ctrl));
}
fn main() { }

View file

@ -25,3 +25,19 @@ fn send_recv_fn() {
comm::send(c, 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);
}