rustc: Mostly implement region-bounded stack closures

This commit is contained in:
Patrick Walton
2012-08-10 18:15:08 -07:00
parent 395d1ac185
commit 5bd4110170
30 changed files with 364 additions and 149 deletions

View File

@@ -163,14 +163,12 @@ mod global_env {
fn get_global_env_chan() -> comm::chan<msg> {
let global_ptr = rustrt::rust_global_env_chan_ptr();
let task_build_fn = || {
// FIXME (#2621): This would be a good place to use a very small
// foreign stack
task::task().sched_mode(task::single_threaded).unlinked()
};
unsafe {
priv::chan_from_global_ptr(
global_ptr, task_build_fn, global_env_task)
priv::chan_from_global_ptr(global_ptr, || {
// FIXME (#2621): This would be a good place to use a very
// small foreign stack
task::task().sched_mode(task::single_threaded).unlinked()
}, global_env_task)
}
}

View File

@@ -109,7 +109,7 @@ extern mod rusti {
}
/// A function used to initialize the elements of a vector
type init_op<T> = fn(uint) -> T;
type init_op/&<T> = fn(uint) -> T;
/// Returns true if a vector contains no elements
pure fn is_empty<T>(v: &[const T]) -> bool {

View File

@@ -81,7 +81,7 @@ fn map_slices<A: copy send, B: copy send>(
fn map<A: copy send, B: copy send>(xs: ~[A], f: fn~(A) -> B) -> ~[B] {
vec::concat(map_slices(xs, || {
fn~(_base: uint, slice : &[A], copy f) -> ~[B] {
vec::map(slice, f)
vec::map(slice, |x| f(x))
}
}))
}
@@ -139,7 +139,7 @@ fn alli<A: copy send>(xs: ~[A], f: fn~(uint, A) -> bool) -> bool {
fn any<A: copy send>(xs: ~[A], f: fn~(A) -> bool) -> bool {
do vec::any(map_slices(xs, || {
fn~(_base : uint, slice: &[A], copy f) -> bool {
vec::any(slice, f)
vec::any(slice, |x| f(x))
}
})) |x| { x }
}

View File

@@ -347,9 +347,7 @@ fn filter_tests(opts: test_opts,
} else { return option::none; }
}
let filter = |x| filter_fn(x, filter_str);
vec::filter_map(filtered, filter)
vec::filter_map(filtered, |x| filter_fn(x, filter_str))
};
// Maybe pull out the ignored test and unignore them

View File

@@ -39,15 +39,16 @@ fn get_monitor_task_gl() -> iotask unsafe {
debug!{"ENTERING global_loop::get() loop chan: %?",
monitor_loop_chan_ptr};
let builder_fn = || {
task::task().sched_mode(task::single_threaded).unlinked()
};
debug!{"before priv::chan_from_global_ptr"};
type monchan = chan<iotask>;
let monitor_ch = do chan_from_global_ptr::<monchan>(monitor_loop_chan_ptr,
builder_fn) |msg_po| {
let monitor_ch =
do chan_from_global_ptr::<monchan>(monitor_loop_chan_ptr,
|| {
task::task().sched_mode
(task::single_threaded)
.unlinked()
}) |msg_po| {
debug!{"global monitor task starting"};
// As a weak task the runtime will notify us when to exit

View File

@@ -85,13 +85,11 @@ fn parse_ty_rust_fn(st: @pstate, conv: conv_did) -> ty::t {
return ty::mk_fn(st.tcx, parse_ty_fn(st, conv));
}
fn parse_proto(c: char) -> ast::proto {
match c {
'~' => ast::proto_uniq,
'@' => ast::proto_box,
'&' => ast::proto_block,
'n' => ast::proto_bare,
_ => fail ~"illegal fn type kind " + str::from_char(c)
fn parse_proto(st: @pstate) -> ty::fn_proto {
match next(st) {
'n' => ty::proto_bare,
'v' => ty::proto_vstore(parse_vstore(st)),
c => fail ~"illegal proto type kind " + str::from_char(c)
}
}
@@ -360,7 +358,7 @@ fn parse_purity(c: char) -> purity {
}
fn parse_ty_fn(st: @pstate, conv: conv_did) -> ty::fn_ty {
let proto = parse_proto(next(st));
let proto = parse_proto(st);
let purity = parse_purity(next(st));
let bounds = parse_bounds(st, conv);
assert (next(st) == '[');

View File

@@ -306,12 +306,15 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
}
}
}
fn enc_proto(w: io::writer, proto: proto) {
fn enc_proto(w: io::writer, cx: @ctxt, proto: ty::fn_proto) {
w.write_str(&"f");
match proto {
proto_uniq => w.write_str(&"f~"),
proto_box => w.write_str(&"f@"),
proto_block => w.write_str(~"f&"),
proto_bare => w.write_str(&"fn")
ty::proto_bare => w.write_str(&"n"),
ty::proto_vstore(vstore) => {
w.write_str(&"v");
enc_vstore(w, cx, vstore);
}
}
}
@@ -335,7 +338,7 @@ fn enc_purity(w: io::writer, p: purity) {
}
fn enc_ty_fn(w: io::writer, cx: @ctxt, ft: ty::fn_ty) {
enc_proto(w, ft.proto);
enc_proto(w, cx, ft.proto);
enc_purity(w, ft.purity);
enc_bounds(w, cx, ft.bounds);
w.write_char('[');

View File

@@ -14,7 +14,7 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
if !cx.allow_block {
match ty::get(ty::expr_ty(cx.tcx, ex)).struct {
ty::ty_fn({proto: p, _}) if is_blockish(p) => {
ty::ty_fn({proto: p, _}) if ty::is_blockish(p) => {
cx.tcx.sess.span_err(ex.span,
~"expressions with stack closure type \
can only appear in callee or (by-ref) argument position");

View File

@@ -218,10 +218,7 @@ impl check_loan_ctxt {
fn is_stack_closure(id: ast::node_id) -> bool {
let fn_ty = ty::node_id_to_type(self.tcx(), id);
let proto = ty::ty_fn_proto(fn_ty);
match proto {
ast::proto_block => true,
ast::proto_bare | ast::proto_uniq | ast::proto_box => false
}
return ty::is_blockish(proto);
}
fn is_allowed_pure_arg(expr: @ast::expr) -> bool {

View File

@@ -59,7 +59,7 @@ fn check_capture_clause(tcx: ty::ctxt,
fn compute_capture_vars(tcx: ty::ctxt,
fn_expr_id: ast::node_id,
fn_proto: ast::proto,
fn_proto: ty::fn_proto,
cap_clause: ast::capture_clause) -> ~[capture_var] {
let freevars = freevars::get_freevars(tcx, fn_expr_id);
let cap_map = map::int_hash();
@@ -101,10 +101,12 @@ fn compute_capture_vars(tcx: ty::ctxt,
// now go through anything that is referenced but was not explicitly
// named and add that
let implicit_mode = match fn_proto {
ast::proto_block => cap_ref,
ast::proto_bare | ast::proto_box | ast::proto_uniq => cap_copy
};
let implicit_mode;
if ty::is_blockish(fn_proto) {
implicit_mode = cap_ref;
} else {
implicit_mode = cap_copy;
}
do vec::iter(*freevars) |fvar| {
let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;

View File

@@ -25,7 +25,8 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
v.visit_block(b, {in_loop: false, can_ret: false}, v);
}
expr_loop_body(@{node: expr_fn_block(_, b, _), _}) => {
let blk = is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx, e)));
let blk = ty::is_blockish(ty::ty_fn_proto(ty::expr_ty(tcx,
e)));
v.visit_block(b, {in_loop: true, can_ret: blk}, v);
}
expr_break => {

View File

@@ -144,10 +144,12 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
let fty = ty::node_id_to_type(cx.tcx, id);
match ty::ty_fn_proto(fty) {
proto_uniq => b(check_for_uniq),
proto_box => b(check_for_box),
proto_bare => b(check_for_bare),
proto_block => b(check_for_block)
ty::proto_vstore(ty::vstore_uniq) => b(check_for_uniq),
ty::proto_vstore(ty::vstore_box) => b(check_for_box),
ty::proto_bare => b(check_for_bare),
ty::proto_vstore(ty::vstore_slice(_)) => b(check_for_block),
ty::proto_vstore(ty::vstore_fixed(_)) =>
fail ~"fixed vstore not allowed here"
}
}

View File

@@ -383,18 +383,22 @@ impl &mem_categorization_ctxt {
let ty = ty::node_id_to_type(self.tcx, fn_node_id);
let proto = ty::ty_fn_proto(ty);
match proto {
ast::proto_block => {
ty::proto_vstore(ty::vstore_slice(_)) => {
let upcmt = self.cat_def(id, span, expr_ty, *inner);
@{id:id, span:span,
cat:cat_stack_upvar(upcmt), lp:upcmt.lp,
mutbl:upcmt.mutbl, ty:upcmt.ty}
}
ast::proto_bare | ast::proto_uniq | ast::proto_box => {
ty::proto_bare |
ty::proto_vstore(ty::vstore_uniq) |
ty::proto_vstore(ty::vstore_box) => {
// FIXME #2152 allow mutation of moved upvars
@{id:id, span:span,
cat:cat_special(sk_heap_upvar), lp:none,
mutbl:m_imm, ty:expr_ty}
}
ty::proto_vstore(ty::vstore_fixed(_)) =>
fail ~"fixed vstore not allowed here"
}
}

View File

@@ -496,6 +496,13 @@ fn determine_rp_in_ty(ty: @ast::ty,
}
}
ast::ty_fn(ast::proto_bare, _, _) |
ast::ty_fn(ast::proto_block, _, _) if cx.anon_implies_rp => {
debug!("referenced bare fn type with regions %s",
pprust::ty_to_str(ty));
cx.add_rp(cx.item_id);
}
_ => {}
}

View File

@@ -2043,7 +2043,7 @@ fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
}
ty::ty_trait(_, _) => {
some(ty::mk_fn(tcx, {purity: ast::impure_fn,
proto: ast::proto_box,
proto: ty::proto_vstore(ty::vstore_box),
bounds: @~[],
inputs: ~[],
output: ty::mk_nil(tcx),
@@ -3774,8 +3774,28 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
}
ast::expr_addr_of(_, x) => { return trans_addr_of(bcx, x, dest); }
ast::expr_fn(proto, decl, body, cap_clause) => {
return closure::trans_expr_fn(bcx, proto, decl, body, e.id,
cap_clause, none, dest);
// Don't use this function for anything real. Use the one in
// astconv instead.
fn ast_proto_to_proto_simple(ast_proto: ast::proto)
-> ty::fn_proto {
match ast_proto {
ast::proto_bare =>
ty::proto_bare,
ast::proto_uniq =>
ty::proto_vstore(ty::vstore_uniq),
ast::proto_box =>
ty::proto_vstore(ty::vstore_box),
ast::proto_block =>
ty::proto_vstore(ty::vstore_slice(ty::re_static))
}
}
// XXX: This syntax should be reworked a bit (in the parser I
// guess?); @fn() { ... } won't work.
return closure::trans_expr_fn(bcx,
ast_proto_to_proto_simple(proto),
decl, body, e.id, cap_clause, none,
dest);
}
ast::expr_fn_block(decl, body, cap_clause) => {
match check ty::get(expr_ty(bcx, e)).struct {

View File

@@ -347,7 +347,7 @@ fn load_environment(fcx: fn_ctxt,
}
fn trans_expr_fn(bcx: block,
proto: ast::proto,
proto: ty::fn_proto,
decl: ast::fn_decl,
body: ast::blk,
id: ast::node_id,
@@ -364,8 +364,8 @@ fn trans_expr_fn(bcx: block,
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
let trans_closure_env = fn@(ck: ty::closure_kind) -> result {
let cap_vars = capture::compute_capture_vars(
ccx.tcx, id, proto, cap_clause);
let cap_vars = capture::compute_capture_vars(ccx.tcx, id, proto,
cap_clause);
let ret_handle = match is_loop_body { some(x) => x, none => none };
let {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, ck, id,
ret_handle);
@@ -382,14 +382,19 @@ fn trans_expr_fn(bcx: block,
};
let {bcx: bcx, val: closure} = match proto {
ast::proto_block => trans_closure_env(ty::ck_block),
ast::proto_box => trans_closure_env(ty::ck_box),
ast::proto_uniq => trans_closure_env(ty::ck_uniq),
ast::proto_bare => {
ty::proto_vstore(ty::vstore_slice(_)) =>
trans_closure_env(ty::ck_block),
ty::proto_vstore(ty::vstore_box) =>
trans_closure_env(ty::ck_box),
ty::proto_vstore(ty::vstore_uniq) =>
trans_closure_env(ty::ck_uniq),
ty::proto_bare => {
trans_closure(ccx, sub_path, decl, body, llfn, no_self, none,
id, |_fcx| { }, |_bcx| { });
{bcx: bcx, val: C_null(T_opaque_box_ptr(ccx))}
}
ty::proto_vstore(ty::vstore_fixed(_)) =>
fail ~"vstore_fixed unexpected"
};
fill_fn_pair(bcx, get_dest_addr(dest), llfn, closure);
@@ -416,11 +421,15 @@ fn make_fn_glue(
};
return match ty::get(t).struct {
ty::ty_fn({proto: ast::proto_bare, _}) |
ty::ty_fn({proto: ast::proto_block, _}) => bcx,
ty::ty_fn({proto: ast::proto_uniq, _}) => fn_env(ty::ck_uniq),
ty::ty_fn({proto: ast::proto_box, _}) => fn_env(ty::ck_box),
_ => fail ~"make_fn_glue invoked on non-function type"
ty::ty_fn({proto: ty::proto_bare, _}) |
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_slice(_)), _}) =>
bcx,
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_uniq), _}) =>
fn_env(ty::ck_uniq),
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_box), _}) =>
fn_env(ty::ck_box),
_ =>
fail ~"make_fn_glue invoked on non-function type"
};
}

View File

@@ -960,7 +960,8 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let frameaddress_val = Call(bcx, frameaddress, ~[C_i32(0i32)]);
let fty = ty::mk_fn(bcx.tcx(), {
purity: ast::impure_fn,
proto: ast::proto_block,
proto:
ty::proto_vstore(ty::vstore_slice(ty::re_bound(ty::br_anon))),
bounds: @~[],
inputs: ~[{
mode: ast::expl(ast::by_val),

View File

@@ -185,10 +185,12 @@ impl reflector {
ast::extern_fn => 3u
};
let protoval = match fty.proto {
ast::proto_bare => 0u,
ast::proto_uniq => 2u,
ast::proto_box => 3u,
ast::proto_block => 4u
ty::proto_bare => 0u,
ty::proto_vstore(ty::vstore_uniq) => 2u,
ty::proto_vstore(ty::vstore_box) => 3u,
ty::proto_vstore(ty::vstore_slice(_)) => 4u,
ty::proto_vstore(ty::vstore_fixed(_)) =>
fail ~"fixed unexpected"
};
let retval = match fty.ret_style {
ast::noreturn => 0u,

View File

@@ -351,14 +351,20 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t) -> ~[u8] {
ty::ty_param(*) => {
ccx.tcx.sess.bug(~"non-monomorphized type parameter");
}
ty::ty_fn({proto: ast::proto_box, _}) => ~[shape_box_fn],
ty::ty_fn({proto: ast::proto_uniq, _}) => ~[shape_uniq_fn],
ty::ty_fn({proto: ast::proto_block, _}) => ~[shape_stack_fn],
ty::ty_fn({proto: ast::proto_bare, _}) => ~[shape_bare_fn],
ty::ty_opaque_closure_ptr(_) => ~[shape_opaque_closure_ptr],
ty::ty_var(_) | ty::ty_var_integral(_) | ty::ty_self => {
ccx.sess.bug(~"shape_of: unexpected type struct found");
}
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_box), _}) =>
~[shape_box_fn],
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_uniq), _}) =>
~[shape_uniq_fn],
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_slice(_)), _}) =>
~[shape_stack_fn],
ty::ty_fn({proto: ty::proto_vstore(ty::vstore_fixed(_)), _}) =>
fail ~"fixed vstore is impossible",
ty::ty_fn({proto: ty::proto_bare, _}) =>
~[shape_bare_fn],
ty::ty_opaque_closure_ptr(_) =>
~[shape_opaque_closure_ptr],
ty::ty_var(_) | ty::ty_var_integral(_) | ty::ty_self =>
ccx.sess.bug(~"shape_of: unexpected type struct found")
}
}

View File

@@ -202,13 +202,16 @@ fn mark_for_expr(cx: ctx, e: @expr) {
}
expr_fn(*) | expr_fn_block(*) => {
match ty::ty_fn_proto(ty::expr_ty(cx.ccx.tcx, e)) {
proto_bare | proto_uniq => {}
proto_box | proto_block => {
ty::proto_bare | ty::proto_vstore(ty::vstore_uniq) => {}
ty::proto_vstore(ty::vstore_box) |
ty::proto_vstore(ty::vstore_slice(_)) => {
for vec::each(*freevars::get_freevars(cx.ccx.tcx, e.id)) |fv| {
let node_id = ast_util::def_id_of_def(fv.def).node;
node_type_needs(cx, use_repr, node_id);
}
}
ty::proto_vstore(ty::vstore_fixed(_)) =>
fail ~"vstore_fixed not allowed here"
}
}
expr_assign(val, _) | expr_swap(val, _) | expr_assign_op(_, val, _) |

View File

@@ -172,9 +172,13 @@ export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch;
export terr_regions_not_same, terr_regions_no_overlap;
export terr_proto_mismatch;
export terr_ret_style_mismatch;
export terr_fn;
export purity_to_str;
export param_tys_in_type;
export eval_repeat_count;
export fn_proto, proto_bare, proto_vstore;
export ast_proto_to_proto;
export is_blockish;
// Data types
@@ -317,6 +321,11 @@ enum closure_kind {
ck_uniq,
}
enum fn_proto {
proto_bare, // supertype of all other protocols
proto_vstore(vstore)
}
/// Innards of a function type:
///
/// - `purity` is the function's effect (pure, impure, unsafe).
@@ -326,7 +335,7 @@ enum closure_kind {
/// - `output` is the return type.
/// - `ret_style` indicates whether the function returns a value or fails.
type fn_ty = {purity: ast::purity,
proto: ast::proto,
proto: fn_proto,
bounds: @~[param_bound],
inputs: ~[arg],
output: t,
@@ -443,7 +452,7 @@ enum sty {
}
enum terr_vstore_kind {
terr_vec, terr_str
terr_vec, terr_str, terr_fn
}
// Data structures used in type unification
@@ -452,7 +461,7 @@ enum type_err {
terr_ret_style_mismatch(ast::ret_style, ast::ret_style),
terr_purity_mismatch(purity, purity),
terr_mutability,
terr_proto_mismatch(ast::proto, ast::proto),
terr_proto_mismatch(ty::fn_proto, ty::fn_proto),
terr_box_mutability,
terr_ptr_mutability,
terr_ref_mutability,
@@ -675,6 +684,10 @@ fn mk_t_with_id(cx: ctxt, +st: sty, o_def_id: option<ast::def_id>) -> t {
ty_rec(flds) => for flds.each |f| { flags |= get(f.mt.ty).flags; },
ty_tup(ts) => for ts.each |tt| { flags |= get(tt).flags; },
ty_fn(ref f) => {
match f.proto {
ty::proto_vstore(vstore_slice(r)) => flags |= rflags(r),
ty::proto_bare | ty::proto_vstore(_) => {}
}
for f.inputs.each |a| { flags |= get(a.ty).flags; }
flags |= get(f.output).flags;
}
@@ -995,8 +1008,27 @@ fn fold_regions_and_ty(
ty_trait(def_id, ref substs) => {
ty::mk_trait(cx, def_id, fold_substs(substs, fldr, fldt))
}
ref sty @ ty_fn(_) => {
fold_sty_to_ty(cx, sty, |t| fldfnt(t))
ref sty @ ty_fn(f) => {
let new_proto;
match f.proto {
proto_bare =>
new_proto = proto_bare,
proto_vstore(vstore_slice(r)) =>
new_proto = proto_vstore(vstore_slice(fldr(r))),
proto_vstore(old_vstore) =>
new_proto = proto_vstore(old_vstore)
}
let new_args = vec::map(f.inputs, |a| {
let new_ty = fldfnt(a.ty);
{mode: a.mode, ty: new_ty}
});
let new_output = fldfnt(f.output);
ty::mk_fn(cx, {
inputs: new_args,
output: new_output,
proto: new_proto with f
})
}
ref sty => {
fold_sty_to_ty(cx, sty, |t| fldt(t))
@@ -1311,7 +1343,7 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
}
ty_fn(ref fty) => {
match fty.proto {
proto_bare | proto_block => false,
proto_bare | proto_vstore(vstore_slice(_)) => false,
_ => true
}
}
@@ -1551,13 +1583,18 @@ pure fn kind_is_owned(k: kind) -> bool {
*k & KIND_MASK_OWNED == KIND_MASK_OWNED
}
fn proto_kind(p: proto) -> kind {
fn proto_kind(p: fn_proto) -> kind {
match p {
ast::proto_block => kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE),
ast::proto_box => kind_safe_for_default_mode() | kind_owned(),
ast::proto_uniq => kind_send_copy() | kind_owned(),
ast::proto_bare => kind_safe_for_default_mode_send() | kind_const() |
kind_owned()
proto_vstore(vstore_slice(_)) =>
kind_noncopyable() | kind_(KIND_MASK_DEFAULT_MODE),
proto_vstore(vstore_box) =>
kind_safe_for_default_mode() | kind_owned(),
proto_vstore(vstore_uniq) =>
kind_send_copy() | kind_owned(),
proto_vstore(vstore_fixed(_)) =>
fail ~"fixed vstore protos are not allowed",
proto_bare =>
kind_safe_for_default_mode_send() | kind_const() | kind_owned()
}
}
@@ -2296,7 +2333,7 @@ fn ty_fn_args(fty: t) -> ~[arg] {
}
}
fn ty_fn_proto(fty: t) -> ast::proto {
fn ty_fn_proto(fty: t) -> fn_proto {
match get(fty).struct {
ty_fn(ref f) => f.proto,
_ => fail ~"ty_fn_proto() called on non-fn type"
@@ -2579,7 +2616,11 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str {
fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
fn terr_vstore_kind_to_str(k: terr_vstore_kind) -> ~str {
match k { terr_vec => ~"[]", terr_str => ~"str" }
match k {
terr_vec => ~"[]",
terr_str => ~"str",
terr_fn => ~"fn"
}
}
match *err {
@@ -2600,7 +2641,8 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str {
}
terr_proto_mismatch(e, a) => {
return fmt!{"closure protocol mismatch (%s vs %s)",
proto_to_str(e), proto_to_str(a)};
util::ppaux::proto_ty_to_str(cx, e),
util::ppaux::proto_ty_to_str(cx, a)};
}
terr_mutability => return ~"values differ in mutability",
terr_box_mutability => return ~"boxed values differ in mutability",
@@ -3214,6 +3256,21 @@ fn normalize_ty(cx: ctxt, t: t) -> t {
// This type has a region. Get rid of it
mk_rptr(cx, re_static, normalize_mt(cx, mt)),
ty_fn({purity: purity,
proto: proto_vstore(vstore),
bounds: bounds,
inputs: inputs,
output: output,
ret_style: ret_style}) =>
mk_fn(cx, {
purity: purity,
proto: proto_vstore(normalize_vstore(vstore)),
bounds: bounds,
inputs: inputs,
output: output,
ret_style: ret_style
}),
ty_enum(did, r) =>
match r.self_r {
some(_) =>
@@ -3267,6 +3324,17 @@ fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint {
}
}
pure fn is_blockish(proto: fn_proto) -> bool {
match proto {
proto_vstore(vstore_slice(_)) =>
true,
proto_vstore(vstore_box) | proto_vstore(vstore_uniq) | proto_bare =>
false,
proto_vstore(vstore_fixed(_)) =>
fail ~"fixed vstore not allowed here"
}
}
// Local Variables:
// mode: rust
// fill-column: 78;

View File

@@ -251,7 +251,7 @@ fn check_main_fn_ty(ccx: @crate_ctxt,
let tcx = ccx.tcx;
let main_t = ty::node_id_to_type(tcx, main_id);
match ty::get(main_t).struct {
ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare, bounds,
ty::ty_fn({purity: ast::impure_fn, proto: ty::proto_bare, bounds,
inputs, output, ret_style: ast::return_val}) => {
match tcx.items.find(main_id) {
some(ast_map::node_item(it,_)) => {

View File

@@ -200,7 +200,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
// Run through the normal function type conversion process.
let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
let fn_decl = ty_of_fn_decl(self, rscope, new_proto, bounds,
ast_fn_decl, none);
ast_fn_decl, none, span);
return ty::mk_fn(tcx, fn_decl);
}
_ => ()
@@ -286,7 +286,8 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
}
ast::ty_fn(proto, ast_bounds, decl) => {
let bounds = collect::compute_bounds(self.ccx(), ast_bounds);
let fn_decl = ty_of_fn_decl(self, rscope, proto, bounds, decl, none);
let fn_decl = ty_of_fn_decl(self, rscope, proto, bounds, decl, none,
ast_ty.span);
ty::mk_fn(tcx, fn_decl)
}
ast::ty_path(path, id) => {
@@ -418,15 +419,33 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy owned>(
{mode: mode, ty: ty}
}
fn ast_proto_to_proto<AC: ast_conv, RS: region_scope copy owned>(
self: AC, rscope: RS, span: span, ast_proto: ast::proto) -> ty::fn_proto {
match ast_proto {
ast::proto_bare =>
ty::proto_bare,
ast::proto_uniq =>
ty::proto_vstore(ty::vstore_uniq),
ast::proto_box =>
ty::proto_vstore(ty::vstore_box),
ast::proto_block => {
let result = rscope.anon_region();
let region = get_region_reporting_err(self.tcx(), span, result);
ty::proto_vstore(ty::vstore_slice(region))
}
}
}
type expected_tys = option<{inputs: ~[ty::arg],
output: ty::t}>;
fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
self: AC, rscope: RS,
proto: ast::proto,
ast_proto: ast::proto,
bounds: @~[ty::param_bound],
decl: ast::fn_decl,
expected_tys: expected_tys) -> ty::fn_ty {
expected_tys: expected_tys,
span: span) -> ty::fn_ty {
debug!{"ty_of_fn_decl"};
do indent {
@@ -450,6 +469,8 @@ fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy owned>(
_ => ast_ty_to_ty(self, rb, decl.output)
};
let proto = ast_proto_to_proto(self, rscope, span, ast_proto);
{purity: decl.purity, proto: proto, bounds: bounds, inputs: input_tys,
output: output_ty, ret_style: decl.cf}
}

View File

@@ -1116,9 +1116,14 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
}
enum fn_or_ast_proto {
foap_fn_proto(ty::fn_proto),
foap_ast_proto(ast::proto)
}
fn check_expr_fn(fcx: @fn_ctxt,
expr: @ast::expr,
proto: ast::proto,
fn_or_ast_proto: fn_or_ast_proto,
decl: ast::fn_decl,
body: ast::blk,
is_loop_body: bool,
@@ -1143,9 +1148,29 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
};
let ast_proto;
match fn_or_ast_proto {
foap_fn_proto(fn_proto) => {
// Generate a fake AST prototype. We'll fill in the type with
// the real one later.
// XXX: This is a hack.
ast_proto = ast::proto_box;
}
foap_ast_proto(existing_ast_proto) => {
ast_proto = existing_ast_proto;
}
}
// construct the function type
let fn_ty = astconv::ty_of_fn_decl(fcx, fcx, proto, @~[],
decl, expected_tys);
let mut fn_ty = astconv::ty_of_fn_decl(fcx, fcx, ast_proto, @~[],
decl, expected_tys, expr.span);
// Patch up the function declaration, if necessary.
match fn_or_ast_proto {
foap_fn_proto(fn_proto) => fn_ty.proto = fn_proto,
foap_ast_proto(_) => {}
}
let fty = ty::mk_fn(tcx, fn_ty);
debug!{"check_expr_fn_with_unifier %s fty=%s",
@@ -1485,15 +1510,17 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
bot = alt::check_alt(fcx, expr, discrim, arms);
}
ast::expr_fn(proto, decl, body, cap_clause) => {
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
check_expr_fn(fcx, expr, foap_ast_proto(proto), decl, body, false,
expected);
capture::check_capture_clause(tcx, expr.id, cap_clause);
}
ast::expr_fn_block(decl, body, cap_clause) => {
// Take the prototype from the expected type, but default to block:
let proto = unpack_expected(fcx, expected, |sty|
match sty { ty::ty_fn({proto, _}) => some(proto), _ => none }
).get_default(ast::proto_box);
check_expr_fn(fcx, expr, proto, decl, body, false, expected);
).get_default(ty::proto_vstore(ty::vstore_box));
check_expr_fn(fcx, expr, foap_fn_proto(proto), decl, body, false,
expected);
capture::check_capture_clause(tcx, expr.id, cap_clause);
}
ast::expr_loop_body(b) => {
@@ -1525,7 +1552,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
};
match check b.node {
ast::expr_fn_block(decl, body, cap_clause) => {
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
check_expr_fn(fcx, b, foap_fn_proto(proto), decl, body, true,
some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
capture::check_capture_clause(tcx, b.id, cap_clause);
}
@@ -1553,7 +1581,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
};
match check b.node {
ast::expr_fn_block(decl, body, cap_clause) => {
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
check_expr_fn(fcx, b, foap_fn_proto(proto), decl, body, true,
some(inner_ty));
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
capture::check_capture_clause(tcx, b.id, cap_clause);
}
@@ -2438,7 +2467,8 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
~"frame_address" => {
let fty = ty::mk_fn(ccx.tcx, {
purity: ast::impure_fn,
proto: ast::proto_block,
proto:
ty::proto_vstore(ty::vstore_slice(ty::re_bound(ty::br_anon))),
bounds: @~[],
inputs: ~[{
mode: ast::expl(ast::by_val),
@@ -2458,7 +2488,7 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
}
};
let fty = ty::mk_fn(tcx, {purity: ast::impure_fn,
proto: ast::proto_bare,
proto: ty::proto_bare,
bounds: @~[],
inputs: inputs, output: output,
ret_style: ast::return_val});

View File

@@ -334,7 +334,8 @@ class lookup {
fn ty_from_did(did: ast::def_id) -> ty::t {
match check ty::get(ty::lookup_item_type(self.tcx(), did).ty).struct {
ty::ty_fn(fty) => {
ty::mk_fn(self.tcx(), {proto: ast::proto_box with fty})
ty::mk_fn(self.tcx(),
{proto: ty::proto_vstore(ty::vstore_box) with fty})
}
}
/*
@@ -416,7 +417,8 @@ class lookup {
// a bit hokey, but the method unbound has a bare protocol, whereas
// a.b has a protocol like fn@() (perhaps eventually fn&()):
let fty = ty::mk_fn(tcx, {proto: ast::proto_box with m.fty});
let fty = ty::mk_fn(tcx, {proto: ty::proto_vstore(ty::vstore_box)
with m.fty});
self.candidates.push(
{self_ty: self.self_ty,

View File

@@ -230,6 +230,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
let cx = fcx.ccx;
match ex.node {
ast::expr_path(*) => {
debug!("(vtable - resolving expr) resolving path expr");
match fcx.opt_node_ty_substs(ex.id) {
some(ref substs) => {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
@@ -249,6 +250,8 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
ast::expr_field(*) | ast::expr_binary(*) |
ast::expr_unary(*) | ast::expr_assign_op(*) |
ast::expr_index(*) => {
debug!("(vtable - resolving expr) resolving field/binary/unary/\
assign/index expr");
match cx.method_map.find(ex.id) {
some({origin: method_static(did), _}) => {
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
@@ -269,6 +272,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
}
}
ast::expr_cast(src, _) => {
debug!("(vtable - resolving expr) resolving cast expr");
let target_ty = fcx.expr_ty(ex);
match ty::get(target_ty).struct {
ty::ty_trait(*) => {

View File

@@ -126,7 +126,8 @@ fn get_enum_variant_types(ccx: @crate_ctxt,
});
result_ty = some(ty::mk_fn(tcx,
{purity: ast::pure_fn,
proto: ast::proto_box,
proto: ty::proto_vstore
(ty::vstore_box),
bounds: @~[],
inputs: args,
output: enum_ty,
@@ -474,7 +475,7 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
tps: ty::ty_params_to_tys(tcx, tps)});
let t_ctor = ty::mk_fn(
tcx, {purity: ast::impure_fn,
proto: ast::proto_block,
proto: ty::proto_vstore(ty::vstore_slice(ty::re_static)),
bounds: @~[],
inputs: t_args,
output: t_res,
@@ -490,8 +491,8 @@ fn convert_struct(ccx: @crate_ctxt, rp: bool, struct_def: @ast::struct_def,
// Write the dtor type
let t_dtor = ty::mk_fn(
tcx,
ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_block, @~[],
ast_util::dtor_dec(), none));
ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, @~[],
ast_util::dtor_dec(), none, dtor.span));
write_ty_to_tcx(tcx, dtor.node.id, t_dtor);
tcx.tcache.insert(local_def(dtor.node.id),
{bounds: tpt.bounds,
@@ -536,7 +537,7 @@ fn ty_of_method(ccx: @crate_ctxt,
{ident: m.ident,
tps: ty_param_bounds(ccx, m.tps),
fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, @~[],
m.decl, none),
m.decl, none, m.span),
self_ty: m.self_ty.node,
purity: m.decl.purity,
vis: m.vis}
@@ -548,7 +549,7 @@ fn ty_of_ty_method(self: @crate_ctxt,
{ident: m.ident,
tps: ty_param_bounds(self, m.tps),
fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, @~[], m.decl,
none),
none, m.span),
// assume public, because this is only invoked on trait methods
self_ty: m.self_ty.node,
purity: m.decl.purity, vis: ast::public}
@@ -602,7 +603,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
ast::item_fn(decl, tps, _) => {
let bounds = ty_param_bounds(ccx, tps);
let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, @~[],
decl, none);
decl, none, it.span);
let tpt = {bounds: bounds,
rp: false, // functions do not have a self
ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -726,7 +727,7 @@ fn ty_of_foreign_fn_decl(ccx: @crate_ctxt,
let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
let t_fn = ty::mk_fn(ccx.tcx, {purity: decl.purity,
proto: ast::proto_bare,
proto: ty::proto_bare,
bounds: @~[],
inputs: input_tys,
output: output_ty,

View File

@@ -251,7 +251,7 @@ import std::smallintmap::smallintmap;
import std::map::hashmap;
import middle::ty;
import middle::ty::{tv_vid, tvi_vid, region_vid, vid,
ty_int, ty_uint, get};
ty_int, ty_uint, get, terr_fn};
import syntax::{ast, ast_util};
import syntax::ast::{ret_style, purity};
import util::ppaux::{ty_to_str, mt_to_str};
@@ -1654,7 +1654,7 @@ trait combine {
fn flds(a: ty::field, b: ty::field) -> cres<ty::field>;
fn modes(a: ast::mode, b: ast::mode) -> cres<ast::mode>;
fn args(a: ty::arg, b: ty::arg) -> cres<ty::arg>;
fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto>;
fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto>;
fn ret_styles(r1: ret_style, r2: ret_style) -> cres<ret_style>;
fn purities(f1: purity, f2: purity) -> cres<purity>;
fn contraregions(a: ty::region, b: ty::region) -> cres<ty::region>;
@@ -2053,10 +2053,25 @@ impl sub: combine {
}
}
fn protos(a: ast::proto, b: ast::proto) -> cres<ast::proto> {
(&self.lub()).protos(a, b).compare(b, || {
ty::terr_proto_mismatch(b, a)
})
fn protos(a: ty::fn_proto, b: ty::fn_proto) -> cres<ty::fn_proto> {
match (a, b) {
(ty::proto_bare, _) => ok(ty::proto_bare),
(ty::proto_vstore(ty::vstore_box),
ty::proto_vstore(ty::vstore_slice(_))) =>
ok(ty::proto_vstore(ty::vstore_box)),
(ty::proto_vstore(ty::vstore_uniq),
ty::proto_vstore(ty::vstore_slice(_))) =>
ok(ty::proto_vstore(ty::vstore_uniq)),
(_, ty::proto_bare) => err(ty::terr_proto_mismatch(b, a)),
(ty::proto_vstore(vs_a), ty::proto_vstore(vs_b)) => {
do self.vstores(ty::terr_fn, vs_a, vs_b).chain |vs_c| {
ok(ty::proto_vstore(vs_c))
}
}
}
}
fn purities(f1: purity, f2: purity) -> cres<purity> {
@@ -2214,15 +2229,21 @@ impl lub: combine {
glb(self.infcx()).tys(a, b)
}
fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto> {
if p1 == ast::proto_bare {
ok(p2)
} else if p2 == ast::proto_bare {
ok(p1)
} else if p1 == p2 {
ok(p1)
} else {
ok(ast::proto_block)
// XXX: Wrong.
fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto> {
match (p1, p2) {
(ty::proto_bare, _) => ok(p2),
(_, ty::proto_bare) => ok(p1),
(ty::proto_vstore(v1), ty::proto_vstore(v2)) => {
self.infcx().try(|| {
do self.vstores(terr_fn, v1, v2).chain |vs| {
ok(ty::proto_vstore(vs))
}
}).chain_err(|_err| {
// XXX: Totally unsound, but fixed up later.
ok(ty::proto_vstore(ty::vstore_slice(ty::re_static)))
})
}
}
}
@@ -2411,15 +2432,21 @@ impl glb: combine {
lub(self.infcx()).tys(a, b)
}
fn protos(p1: ast::proto, p2: ast::proto) -> cres<ast::proto> {
if p1 == ast::proto_block {
ok(p2)
} else if p2 == ast::proto_block {
ok(p1)
} else if p1 == p2 {
ok(p1)
} else {
ok(ast::proto_bare)
fn protos(p1: ty::fn_proto, p2: ty::fn_proto) -> cres<ty::fn_proto> {
match (p1, p2) {
(ty::proto_vstore(ty::vstore_slice(_)), _) => ok(p2),
(_, ty::proto_vstore(ty::vstore_slice(_))) => ok(p1),
(ty::proto_vstore(v1), ty::proto_vstore(v2)) => {
self.infcx().try(|| {
do self.vstores(terr_fn, v1, v2).chain |vs| {
ok(ty::proto_vstore(vs))
}
}).chain_err(|_err| {
// XXX: Totally unsound, but fixed up later.
ok(ty::proto_bare)
})
}
_ => ok(ty::proto_bare)
}
}

View File

@@ -188,6 +188,13 @@ fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str {
}
}
fn proto_ty_to_str(cx: ctxt, proto: ty::fn_proto) -> ~str {
match proto {
ty::proto_bare => ~"",
ty::proto_vstore(vstore) => vstore_to_str(cx, vstore)
}
}
fn tys_to_str(cx: ctxt, ts: ~[t]) -> ~str {
let mut rs = ~"";
for ts.each |t| { rs += ty_to_str(cx, t); }
@@ -211,7 +218,7 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
};
modestr + ty_to_str(cx, ty)
}
fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ast::proto,
fn fn_to_str(cx: ctxt, purity: ast::purity, proto: ty::fn_proto,
ident: option<ast::ident>,
inputs: ~[arg], output: t, cf: ast::ret_style) -> ~str {
let mut s;
@@ -220,7 +227,10 @@ fn ty_to_str(cx: ctxt, typ: t) -> ~str {
ast::impure_fn => ~"",
_ => purity_to_str(purity) + ~" "
};
s += proto_to_str(proto);
s += ~"fn";
s += proto_ty_to_str(cx, proto);
match ident {
some(i) => { s += ~" "; s += *i; }
_ => { }

View File

@@ -37,8 +37,8 @@ fn range(lo: uint, hi: uint, it: fn(uint)) {
}
fn main() {
let range = |a| range(0u, 1000u, a);
let filt = |a| filter(
let range: fn@(fn&(uint)) = |a| range(0u, 1000u, a);
let filt: fn@(fn&(&&uint)) = |a| filter(
range,
|&&n: uint| n % 3u != 0u && n % 5u != 0u,
a);