rejigger impl to have an opaque closure ptr rather than

opaque closure
This commit is contained in:
Niko Matsakis 2012-01-05 16:19:12 -08:00
parent 7db640e63d
commit 8e89df69de
9 changed files with 403 additions and 303 deletions

View File

@ -26,8 +26,8 @@ const frame_glue_fns_field_drop: int = 1;
const frame_glue_fns_field_reloc: int = 2;
// n.b. must be same as cbox_elt_refcnt
const box_rc_field_refcnt: int = 0;
const box_rc_field_body: int = 1;
const general_code_alignment: int = 16;
@ -72,9 +72,13 @@ const obj_body_elt_inner_obj: int = 3;
const fn_field_code: int = 0;
const fn_field_box: int = 1;
const closure_elt_tydesc: int = 0;
const closure_elt_ty_params: int = 1;
const closure_elt_bindings: int = 2;
// closure_box, see trans_closure.rs
//
// n.b. the refcnt must be compatible with a normal box
const cbox_elt_refcnt: int = 0;
const cbox_elt_tydesc: int = 1;
const cbox_elt_ty_params: int = 2;
const cbox_elt_bindings: int = 3;
const vec_elt_fill: int = 0;

View File

@ -277,7 +277,14 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
'E' { let def = parse_def(st, conv); ret ty::mk_native(st.tcx, def); }
'Y' { ret ty::mk_type(st.tcx); }
'y' { ret ty::mk_send_type(st.tcx); }
'C' { ret ty::mk_opaque_closure(st.tcx); }
'C' {
let ck = alt next(st) as char {
'&' { ty::closure_block }
'@' { ty::closure_shared }
'~' { ty::closure_send }
};
ret ty::mk_opaque_closure_ptr(st.tcx, ck);
}
'#' {
let pos = parse_hex(st);
assert (next(st) as char == ':');

View File

@ -189,7 +189,9 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
}
ty::ty_type. { w.write_char('Y'); }
ty::ty_send_type. { w.write_char('y'); }
ty::ty_opaque_closure. { w.write_char('C'); }
ty::ty_opaque_closure_ptr(ty::closure_block.) { w.write_str("C&"); }
ty::ty_opaque_closure_ptr(ty::closure_shared.) { w.write_str("C@"); }
ty::ty_opaque_closure_ptr(ty::closure_send.) { w.write_str("C~"); }
ty::ty_constr(ty, cs) {
w.write_str("A[");
enc_ty(w, cx, ty);

View File

@ -51,7 +51,7 @@ const shape_obj: u8 = 19u8;
const shape_res: u8 = 20u8;
const shape_var: u8 = 21u8;
const shape_uniq: u8 = 22u8;
const shape_opaque_closure: u8 = 23u8; // the closure itself.
const shape_opaque_closure_ptr: u8 = 23u8; // the closure itself.
// FIXME: This is a bad API in trans_common.
fn C_u8(n: u8) -> ValueRef { ret trans_common::C_u8(n as uint); }
@ -419,8 +419,8 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint],
ty::ty_fn(_) {
s += [shape_fn];
}
ty::ty_opaque_closure. {
s += [shape_opaque_closure];
ty::ty_opaque_closure_ptr(_) {
s += [shape_opaque_closure_ptr];
}
}

View File

@ -93,7 +93,7 @@ fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
if is_method {
atys += [T_ptr(cx.rust_object_type)];
} else {
atys += [T_opaque_boxed_closure_ptr(cx)];
atys += [T_opaque_cbox_ptr(cx)];
}
// Args >2: ty params, if not acquired via capture...
@ -202,8 +202,8 @@ fn type_of_inner(cx: @crate_ctxt, sp: span, t: ty::t)
}
T_struct(tys)
}
ty::ty_opaque_closure. {
T_opaque_closure(cx)
ty::ty_opaque_closure_ptr(_) {
T_opaque_cbox_ptr(cx)
}
ty::ty_constr(subt,_) {
// FIXME: could be a constraint on ty_fn
@ -415,25 +415,13 @@ fn llalign_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef {
}
fn size_of(bcx: @block_ctxt, t: ty::t) -> result {
assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
let {bcx, sz, align: _} = metrics(bcx, t, none);
rslt(bcx, sz)
}
fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
assert !ty::type_has_opaque_size(bcx_tcx(bcx), t);
alt ty::struct(ccx.tcx, t) {
ty::ty_opaque_closure. {
// Hack: the alignment of an opaque closure is always defined as the
// alignment of a pointer. This is not, however, strictly correct,
// depending on your point of view.
llalign_of(bcx, T_ptr(T_i8()));
}
_ {
let {bcx, sz: _, align} = metrics(bcx, t, none);
rslt(bcx, align)
}
}
let {bcx, sz: _, align} = metrics(bcx, t, none);
rslt(bcx, align)
}
// Computes the size/alignment of the type `t`. `opt_v`, if provided, should
@ -443,8 +431,6 @@ fn align_of(bcx: @block_ctxt, t: ty::t) -> result {
// instance is required.
fn metrics(bcx: @block_ctxt, t: ty::t, opt_v: option<ValueRef>)
-> metrics_result {
assert (option::is_some(opt_v) ||
!ty::type_has_opaque_size(bcx_tcx(bcx), t));
let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, t) {
let sp = bcx.sp;
@ -651,29 +637,6 @@ fn dynamic_metrics(bcx: @block_ctxt,
let total_align = C_int(bcx_ccx(bcx), 1); // FIXME: stub
ret {bcx: bcx, sz: total_size, align: total_align};
}
ty::ty_opaque_closure. {
// Unlike most other types, the type of an opaque closure does not
// fully specify its size. This is because the opaque closure type
// only says that this is a closure over some data, but doesn't say
// how much data there is (hence the word opaque). This is an
// unavoidable consequence of the way that closures encapsulate the
// closed over data. Therefore the only way to know the
// size/alignment of a particular opaque closure instance is to load
// the type descriptor from the instance and consult its
// size/alignment fields. Note that it is meaningless to say "what is
// the size of the type opaque closure?" One can only ask "what is the
// size of this particular opaque closure?"
let v = alt opt_v {
none. { fail "Require value to compute metrics of opaque closures"; }
some(v) { v }
};
let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(bcx_ccx(bcx))));
let tdptrptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
let tdptr = Load(bcx, tdptrptr);
let sz = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_size]));
let align = Load(bcx, GEPi(bcx, tdptr, [0, abi::tydesc_field_align]));
ret { bcx: bcx, sz: sz, align: align };
}
}
}
@ -1354,9 +1317,8 @@ fn make_take_glue(cx: @block_ctxt, v: ValueRef, t: ty::t) {
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
trans_closure::make_fn_glue(bcx, v, t, take_ty)
}
ty::ty_opaque_closure. {
trans_closure::call_opaque_closure_glue(
bcx, v, abi::tydesc_field_take_glue)
ty::ty_opaque_closure_ptr(ck) {
trans_closure::make_opaque_cbox_take_glue(bcx, ck, v)
}
_ when ty::type_is_structural(bcx_tcx(bcx), t) {
iter_structural_ty(bcx, v, t, take_ty)
@ -1429,9 +1391,8 @@ fn make_free_glue(bcx: @block_ctxt, v: ValueRef, t: ty::t) {
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
trans_closure::make_fn_glue(bcx, v, t, free_ty)
}
ty::ty_opaque_closure. {
trans_closure::call_opaque_closure_glue(
bcx, v, abi::tydesc_field_free_glue)
ty::ty_opaque_closure_ptr(ck) {
trans_closure::make_opaque_cbox_free_glue(bcx, ck, v)
}
_ { bcx }
};
@ -1458,9 +1419,8 @@ fn make_drop_glue(bcx: @block_ctxt, v0: ValueRef, t: ty::t) {
ty::ty_native_fn(_, _) | ty::ty_fn(_) {
trans_closure::make_fn_glue(bcx, v0, t, drop_ty)
}
ty::ty_opaque_closure. {
trans_closure::call_opaque_closure_glue(
bcx, v0, abi::tydesc_field_drop_glue)
ty::ty_opaque_closure_ptr(ck) {
trans_closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
}
_ {
if ty::type_needs_drop(ccx.tcx, t) &&
@ -2617,7 +2577,7 @@ type lval_maybe_callee = {bcx: @block_ctxt,
generic: option::t<generic_info>};
fn null_env_ptr(bcx: @block_ctxt) -> ValueRef {
C_null(T_opaque_boxed_closure_ptr(bcx_ccx(bcx)))
C_null(T_opaque_cbox_ptr(bcx_ccx(bcx)))
}
fn lval_from_local_var(bcx: @block_ctxt, r: local_var_result) -> lval_result {
@ -3274,7 +3234,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
let llenv, dict_param = none;
alt f_res.env {
null_env. {
llenv = llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(bcx_ccx(cx)));
llenv = llvm::LLVMGetUndef(T_opaque_cbox_ptr(bcx_ccx(cx)));
}
obj_env(e) { llenv = e; }
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
@ -5257,7 +5217,7 @@ fn fill_fn_pair(bcx: @block_ctxt, pair: ValueRef, llfn: ValueRef,
Store(bcx, llfn, code_cell);
let env_cell = GEPi(bcx, pair, [0, abi::fn_field_box]);
let llenvblobptr =
PointerCast(bcx, llenvptr, T_opaque_boxed_closure_ptr(ccx));
PointerCast(bcx, llenvptr, T_opaque_cbox_ptr(ccx));
Store(bcx, llenvblobptr, env_cell);
}

View File

@ -31,28 +31,22 @@ import trans::{
// roughly as follows:
//
// struct closure_box {
// unsigned ref_count; // only used for sharid environments
// struct closure {
// type_desc *tydesc; // descriptor for the "struct closure" type
// type_desc *bound_tdescs[]; // bound descriptors
// struct {
// upvar1_t upvar1;
// ...
// upvarN_t upvarN;
// } bound_data;
// };
// unsigned ref_count; // only used for shared environments
// type_desc *tydesc; // descriptor for the "struct closure_box" type
// type_desc *bound_tdescs[]; // bound descriptors
// struct {
// upvar1_t upvar1;
// ...
// upvarN_t upvarN;
// } bound_data;
// };
//
// NB: this struct is defined in the code in trans_common::T_closure()
// and mk_closure_ty() below. The former defines the LLVM version and
// the latter the Rust equivalent. It occurs to me that these could
// perhaps be unified, but currently they are not.
//
// Note that the closure carries a type descriptor that describes
// itself. Trippy. This is needed because the precise types of the
// closed over data are lost in the closure type (`fn(T)->U`), so if
// we need to take/drop, we must know what data is in the upvars and
// so forth.
// Note that the closure carries a type descriptor that describes the
// closure itself. Trippy. This is needed because the precise types
// of the closed over data are lost in the closure type (`fn(T)->U`),
// so if we need to take/drop, we must know what data is in the upvars
// and so forth. This struct is defined in the code in mk_closure_tys()
// below.
//
// The allocation strategy for this closure depends on the closure
// type. For a sendfn, the closure (and the referenced type
@ -63,6 +57,53 @@ import trans::{
// easier when upcasting to block(T)->U, in the shape code, and so
// forth.
//
// ## Opaque Closures ##
//
// One interesting part of closures is that they encapsulate the data
// that they close over. So when I have a ptr to a closure, I do not
// know how many type descriptors it contains nor what upvars are
// captured within. That means I do not know precisely how big it is
// nor where its fields are located. This is called an "opaque
// closure".
//
// Typically an opaque closure suffices because I only manipulate it
// by ptr. The routine trans_common::T_opaque_cbox_ptr() returns an
// appropriate type for such an opaque closure; it allows access to the
// first two fields, but not the others.
//
// But sometimes, such as when cloning or freeing a closure, we need
// to know the full information. That is where the type descriptor
// that defines the closure comes in handy. We can use its take and
// drop glue functions to allocate/free data as needed.
//
// ## Subtleties concerning alignment ##
//
// You'll note that the closure_box structure is a flat structure with
// four fields. In some ways, it would be more convenient to use a nested
// structure like so:
//
// struct {
// int;
// struct {
// type_desc*;
// type_desc*[];
// bound_data;
// } }
//
// This would be more convenient because it would allow us to use more
// of the existing infrastructure: we could treat the inner struct as
// a type and then hvae a boxed variant (which would add the int) etc.
// However, there is one subtle problem with this: grouping the latter
// 3 fields into an inner struct causes the alignment of the entire
// struct to be the max alignment of the bound_data. This will
// therefore vary from closure to closure. That would mean that we
// cannot reliably locate the initial type_desc* in an opaque closure!
// That's definitely a bad thing. Therefore, I have elected to create
// a flat structure, even though it means some mild amount of code
// duplication (however, we used to do it the other way, and we were
// jumping through about as many hoops just trying to wedge a ref
// count into a unique pointer, so it's kind of a wash in the end).
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tag environment_value {
@ -79,16 +120,24 @@ tag environment_value {
env_ref(ValueRef, ty::t, lval_kind);
}
// Given a closure ty, emits a corresponding tuple ty
fn mk_closure_ty(tcx: ty::ctxt,
ck: ty::closure_kind,
ty_params: [fn_ty_param],
bound_data_ty: ty::t)
-> ty::t {
let tydesc_ty = alt ck {
fn mk_tydesc_ty(tcx: ty::ctxt, ck: ty::closure_kind) -> ty::t {
ret alt ck {
ty::closure_block. | ty::closure_shared. { ty::mk_type(tcx) }
ty::closure_send. { ty::mk_send_type(tcx) }
};
}
// Given a closure ty, emits a corresponding tuple ty
fn mk_closure_tys(tcx: ty::ctxt,
ck: ty::closure_kind,
ty_params: [fn_ty_param],
bound_values: [environment_value]) -> (ty::t, [ty::t]) {
let bound_tys = [];
let tydesc_ty =
mk_tydesc_ty(tcx, ck);
// Compute the closed over tydescs
let param_ptrs = [];
for tp in ty_params {
param_ptrs += [tydesc_ty];
@ -96,26 +145,98 @@ fn mk_closure_ty(tcx: ty::ctxt,
for dict in dicts { param_ptrs += [tydesc_ty]; }
}
}
ty::mk_tup(tcx, [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty])
// Compute the closed over data
for bv in bound_values {
bound_tys += [alt bv {
env_copy(_, t, _) { t }
env_move(_, t, _) { t }
env_ref(_, t, _) { t }
env_expr(e) { ty::expr_ty(tcx, e) }
}];
}
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
// closure_ty == ref count, data tydesc, typarams, bound data
let closure_ty =
ty::mk_tup(tcx, [ty::mk_int(tcx), tydesc_ty,
ty::mk_tup(tcx, param_ptrs), bound_data_ty]);
ret (closure_ty, bound_tys);
}
fn shared_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
let opaque_closure_ty = ty::mk_opaque_closure(tcx);
ret ty::mk_imm_box(tcx, opaque_closure_ty);
}
fn allocate_cbox(bcx: @block_ctxt,
ck: ty::closure_kind,
cbox_ty: ty::t)
-> (@block_ctxt, ValueRef, [ValueRef]) {
fn send_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
let opaque_closure_ty = ty::mk_opaque_closure(tcx);
let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), opaque_closure_ty]);
ret ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
fn alloc_in_heap(bcx: @block_ctxt,
cbox_ty: ty::t,
shared: bool,
&temp_cleanups: [ValueRef])
-> (@block_ctxt, ValueRef) {
// n.b. If you are wondering why we don't use
// trans_malloc_boxed() or alloc_uniq(), see the section about
// "Subtleties concerning alignment" in the big comment at the
// top of the file.
let {bcx, val:llsz} = size_of(bcx, cbox_ty);
let ti = none;
let {bcx, val:lltydesc} =
get_tydesc(bcx, cbox_ty, true, tps_normal, ti).result;
let malloc =
if shared { bcx_ccx(bcx).upcalls.shared_malloc }
else { bcx_ccx(bcx).upcalls.malloc };
let box = Call(bcx, malloc, [llsz, lltydesc]);
add_clean_free(bcx, box, shared);
temp_cleanups += [box];
(bcx, box)
}
let ccx = bcx_ccx(bcx);
// Allocate the box:
let temp_cleanups = [];
let (bcx, box, rc) = alt ck {
ty::closure_shared. {
let (bcx, box) = alloc_in_heap(bcx, cbox_ty, false, temp_cleanups);
(bcx, box, 1)
}
ty::closure_send. {
let (bcx, box) = alloc_in_heap(bcx, cbox_ty, true, temp_cleanups);
(bcx, box, 0xdeadc0de) // use arbitrary value for debugging
}
ty::closure_block. {
let {bcx, val: box} = trans::alloc_ty(bcx, cbox_ty);
(bcx, box, 0xdeadc0df) // use arbitrary value for debugging
}
};
// Initialize ref count
let box = PointerCast(bcx, box, T_opaque_cbox_ptr(ccx));
let ref_cnt = GEPi(bcx, box, [0, abi::box_rc_field_refcnt]);
Store(bcx, C_int(ccx, rc), ref_cnt);
ret (bcx, box, temp_cleanups);
}
type closure_result = {
llbox: ValueRef, // llvalue of boxed environment
box_ty: ty::t, // type of boxed environment
bcx: @block_ctxt // final bcx
llbox: ValueRef, // llvalue of ptr to closure
cboxptr_ty: ty::t, // type of ptr to closure
bcx: @block_ctxt // final bcx
};
fn cast_if_we_can(bcx: @block_ctxt, llbox: ValueRef, t: ty::t) -> ValueRef {
let ccx = bcx_ccx(bcx);
if check type_has_static_size(ccx, t) {
let llty = type_of(ccx, bcx.sp, t);
ret PointerCast(bcx, llbox, llty);
} else {
ret llbox;
}
}
// Given a block context and a list of tydescs and values to bind
// construct a closure out of them. If copying is true, it is a
// heap allocated closure that copies the upvars into environment.
@ -126,16 +247,6 @@ fn store_environment(
ck: ty::closure_kind)
-> closure_result {
fn dummy_environment_box(bcx: @block_ctxt, r: result)
-> (@block_ctxt, ValueRef, ValueRef) {
// Prevent glue from trying to free this.
let ccx = bcx_ccx(bcx);
let ref_cnt = GEPi(bcx, r.val, [0, abi::box_rc_field_refcnt]);
Store(r.bcx, C_int(ccx, 2), ref_cnt);
let closure = GEPi(r.bcx, r.val, [0, abi::box_rc_field_body]);
(r.bcx, closure, r.val)
}
fn maybe_clone_tydesc(bcx: @block_ctxt,
ck: ty::closure_kind,
td: ValueRef) -> ValueRef {
@ -152,61 +263,17 @@ fn store_environment(
//let ccx = bcx_ccx(bcx);
let tcx = bcx_tcx(bcx);
// First, synthesize a tuple type containing the types of all the
// bound expressions.
// bindings_ty = [bound_ty1, bound_ty2, ...]
let bound_tys = [];
for bv in bound_values {
bound_tys += [alt bv {
env_copy(_, t, _) { t }
env_move(_, t, _) { t }
env_ref(_, t, _) { t }
env_expr(e) { ty::expr_ty(tcx, e) }
}];
}
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
let closure_ty =
mk_closure_ty(tcx, ck, lltyparams, bound_data_ty);
// compute the shape of the closure
let (cbox_ty, bound_tys) =
mk_closure_tys(tcx, ck, lltyparams, bound_values);
let temp_cleanups = [];
// allocate closure in the heap
let (bcx, llbox, temp_cleanups) = allocate_cbox(bcx, ck, cbox_ty);
// Allocate a box that can hold something closure-sized.
//
// For now, no matter what kind of closure we have, we always allocate
// space for a ref cnt in the closure. If the closure is a block or
// unique closure, this ref count isn't really used: we initialize it to 2
// so that it will never drop to zero. This is a hack and could go away
// but then we'd have to modify the code to do the right thing when
// casting from a shared closure to a block.
let (bcx, closure, box) = alt ck {
ty::closure_shared. {
let r = trans::trans_malloc_boxed(bcx, closure_ty);
add_clean_free(bcx, r.box, false);
temp_cleanups += [r.box];
(r.bcx, r.body, r.box)
}
ty::closure_send. {
// Dummy up a box in the exchange heap.
let tup_ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
let box_ty = ty::mk_uniq(tcx, {ty: tup_ty, mut: ast::imm});
check trans_uniq::type_is_unique_box(bcx, box_ty);
let r = trans_uniq::alloc_uniq(bcx, box_ty);
add_clean_free(bcx, r.val, true);
temp_cleanups += [r.val];
dummy_environment_box(bcx, r)
}
ty::closure_block. {
// Dummy up a box on the stack,
let ty = ty::mk_tup(tcx, [ty::mk_int(tcx), closure_ty]);
let r = trans::alloc_ty(bcx, ty);
dummy_environment_box(bcx, r)
}
};
// Store bindings tydesc.
// store data tydesc.
alt ck {
ty::closure_shared. | ty::closure_send. {
let bound_tydesc = GEPi(bcx, closure, [0, abi::closure_elt_tydesc]);
let bound_tydesc = GEPi(bcx, llbox, [0, abi::cbox_elt_tydesc]);
let ti = none;
// NDM I believe this is the correct value,
@ -218,7 +285,7 @@ fn store_environment(
let tps = tps_normal;
let {result:closure_td, _} =
trans::get_tydesc(bcx, closure_ty, true, tps, ti);
trans::get_tydesc(bcx, cbox_ty, true, tps, ti);
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_take_glue, ti);
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_drop_glue, ti);
trans::lazily_emit_tydesc_glue(bcx, abi::tydesc_field_free_glue, ti);
@ -229,16 +296,18 @@ fn store_environment(
ty::closure_block. { /* skip this for blocks, not really relevant */ }
}
check type_is_tup_like(bcx, closure_ty);
let box_ty = ty::mk_imm_box(bcx_tcx(bcx), closure_ty);
// cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
// tuple. This could be a ptr in uniq or a box or on stack,
// whatever.
let cboxptr_ty = ty::mk_ptr(tcx, {ty:cbox_ty, mut:ast::imm});
let llbox = cast_if_we_can(bcx, llbox, cboxptr_ty);
check type_is_tup_like(bcx, cboxptr_ty);
// If necessary, copy tydescs describing type parameters into the
// appropriate slot in the closure.
let {bcx:bcx, val:ty_params_slot} =
GEP_tup_like_1(bcx, closure_ty, closure,
[0, abi::closure_elt_ty_params]);
GEP_tup_like_1(bcx, cboxptr_ty, llbox, [0, abi::cbox_elt_ty_params]);
let off = 0;
for tp in lltyparams {
let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off]));
@ -254,38 +323,36 @@ fn store_environment(
// Copy expr values into boxed bindings.
// Silly check
let {bcx: bcx, val:bindings_slot} =
GEP_tup_like_1(bcx, cboxptr_ty, llbox, [0, abi::cbox_elt_bindings]);
vec::iteri(bound_values) { |i, bv|
let bound = trans::GEP_tup_like_1(bcx, box_ty, box,
[0, abi::box_rc_field_body,
abi::closure_elt_bindings,
i as int]);
bcx = bound.bcx;
let bound_data = GEPi(bcx, bindings_slot, [0, i as int]);
alt bv {
env_expr(e) {
bcx = trans::trans_expr_save_in(bcx, e, bound.val);
add_clean_temp_mem(bcx, bound.val, bound_tys[i]);
temp_cleanups += [bound.val];
bcx = trans::trans_expr_save_in(bcx, e, bound_data);
add_clean_temp_mem(bcx, bound_data, bound_tys[i]);
temp_cleanups += [bound_data];
}
env_copy(val, ty, owned.) {
let val1 = load_if_immediate(bcx, val, ty);
bcx = trans::copy_val(bcx, INIT, bound.val, val1, ty);
bcx = trans::copy_val(bcx, INIT, bound_data, val1, ty);
}
env_copy(val, ty, owned_imm.) {
bcx = trans::copy_val(bcx, INIT, bound.val, val, ty);
bcx = trans::copy_val(bcx, INIT, bound_data, val, ty);
}
env_copy(_, _, temporary.) {
fail "Cannot capture temporary upvar";
}
env_move(val, ty, kind) {
let src = {bcx:bcx, val:val, kind:kind};
bcx = move_val(bcx, INIT, bound.val, src, ty);
bcx = move_val(bcx, INIT, bound_data, src, ty);
}
env_ref(val, ty, owned.) {
Store(bcx, val, bound.val);
Store(bcx, val, bound_data);
}
env_ref(val, ty, owned_imm.) {
let addr = do_spill_noroot(bcx, val);
Store(bcx, addr, bound.val);
Store(bcx, addr, bound_data);
}
env_ref(_, _, temporary.) {
fail "Cannot capture temporary upvar";
@ -294,7 +361,7 @@ fn store_environment(
}
for cleanup in temp_cleanups { revoke_clean(bcx, cleanup); }
ret {llbox: box, box_ty: box_ty, bcx: bcx};
ret {llbox: llbox, cboxptr_ty: cboxptr_ty, bcx: bcx};
}
// Given a context and a list of upvars, build a closure. This just
@ -338,23 +405,21 @@ fn build_closure(bcx0: @block_ctxt,
// with the upvars and type descriptors.
fn load_environment(enclosing_cx: @block_ctxt,
fcx: @fn_ctxt,
boxed_closure_ty: ty::t,
cboxptr_ty: ty::t,
cap_vars: [capture::capture_var],
ck: ty::closure_kind) {
let bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
let ccx = bcx_ccx(bcx);
let sp = bcx.sp;
check (type_has_static_size(ccx, boxed_closure_ty));
let llty = type_of(ccx, sp, boxed_closure_ty);
check (type_has_static_size(ccx, cboxptr_ty));
let llty = type_of(ccx, sp, cboxptr_ty);
let llclosure = PointerCast(bcx, fcx.llenv, llty);
// Populate the type parameters from the environment. We need to
// do this first because the tydescs are needed to index into
// the bindings if they are dynamically sized.
let lltydescs = GEPi(bcx, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_ty_params]);
let lltydescs = GEPi(bcx, llclosure, [0, abi::cbox_elt_ty_params]);
let off = 0;
for tp in copy enclosing_cx.fcx.lltyparams {
let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
@ -372,15 +437,15 @@ fn load_environment(enclosing_cx: @block_ctxt,
}
// Populate the upvars from the environment.
let path = [0, abi::box_rc_field_body, abi::closure_elt_bindings];
let path = [0, abi::cbox_elt_bindings];
let i = 0u;
vec::iter(cap_vars) { |cap_var|
alt cap_var.mode {
capture::cap_drop. { /* ignore */ }
_ {
check type_is_tup_like(bcx, boxed_closure_ty);
check type_is_tup_like(bcx, cboxptr_ty);
let upvarptr = GEP_tup_like(
bcx, boxed_closure_ty, llclosure, path + [i as int]);
bcx, cboxptr_ty, llclosure, path + [i as int]);
bcx = upvarptr.bcx;
let llupvarptr = upvarptr.val;
alt ck {
@ -415,9 +480,9 @@ fn trans_expr_fn(bcx: @block_ctxt,
let trans_closure_env = lambda(ck: ty::closure_kind) -> ValueRef {
let cap_vars = capture::compute_capture_vars(
ccx.tcx, id, proto, cap_clause);
let {llbox, box_ty, bcx} = build_closure(bcx, cap_vars, ck);
let {llbox, cboxptr_ty, bcx} = build_closure(bcx, cap_vars, ck);
trans_closure(sub_cx, sp, decl, body, llfn, no_self, [], id, {|fcx|
load_environment(bcx, fcx, box_ty, cap_vars, ck);
load_environment(bcx, fcx, cboxptr_ty, cap_vars, ck);
});
llbox
};
@ -427,7 +492,7 @@ fn trans_expr_fn(bcx: @block_ctxt,
ast::proto_shared(_) { trans_closure_env(ty::closure_shared) }
ast::proto_send. { trans_closure_env(ty::closure_send) }
ast::proto_bare. {
let closure = C_null(T_opaque_boxed_closure_ptr(ccx));
let closure = C_null(T_opaque_cbox_ptr(ccx));
trans_closure(sub_cx, sp, decl, body, llfn, no_self, [],
id, {|_fcx|});
closure
@ -514,7 +579,7 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
};
// Actually construct the closure
let {llbox, box_ty, bcx} = store_environment(
let {llbox, cboxptr_ty, bcx} = store_environment(
bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
env_vals + vec::map(bound, {|x| env_expr(x)}),
ty::closure_shared);
@ -522,13 +587,27 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
// Make thunk
let llthunk =
trans_bind_thunk(cx.fcx.lcx, cx.sp, pair_ty, outgoing_fty_real, args,
box_ty, *param_bounds, target_res);
cboxptr_ty, *param_bounds, target_res);
// Fill the function pair
fill_fn_pair(bcx, get_dest_addr(dest), llthunk.val, llbox);
ret bcx;
}
fn make_null_test(
in_bcx: @block_ctxt,
ptr: ValueRef,
blk: block(@block_ctxt) -> @block_ctxt)
-> @block_ctxt {
let not_null_bcx = new_sub_block_ctxt(in_bcx, "not null");
let next_bcx = new_sub_block_ctxt(in_bcx, "next");
let null_test = IsNull(in_bcx, ptr);
CondBr(in_bcx, null_test, next_bcx.llbb, not_null_bcx.llbb);
let not_null_bcx = blk(not_null_bcx);
Br(not_null_bcx, next_bcx.llbb);
ret next_bcx;
}
fn make_fn_glue(
cx: @block_ctxt,
v: ValueRef,
@ -538,52 +617,128 @@ fn make_fn_glue(
let bcx = cx;
let tcx = bcx_tcx(cx);
let fn_env = lambda(blk: block(@block_ctxt, ValueRef) -> @block_ctxt)
-> @block_ctxt {
let fn_env = lambda(ck: ty::closure_kind) -> @block_ctxt {
let box_cell_v = GEPi(cx, v, [0, abi::fn_field_box]);
let box_ptr_v = Load(cx, box_cell_v);
let inner_cx = new_sub_block_ctxt(cx, "iter box");
let next_cx = new_sub_block_ctxt(cx, "next");
let null_test = IsNull(cx, box_ptr_v);
CondBr(cx, null_test, next_cx.llbb, inner_cx.llbb);
inner_cx = blk(inner_cx, box_cell_v);
Br(inner_cx, next_cx.llbb);
ret next_cx;
make_null_test(cx, box_ptr_v) {|bcx|
let closure_ty = ty::mk_opaque_closure_ptr(tcx, ck);
glue_fn(bcx, box_cell_v, closure_ty)
}
};
ret alt ty::struct(tcx, t) {
ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) {
bcx
}
ty::ty_fn({proto: ast::proto_block., _}) {
bcx
}
ty::ty_native_fn(_, _) | ty::ty_fn({proto: ast::proto_bare., _}) { bcx }
ty::ty_fn({proto: ast::proto_block., _}) { bcx }
ty::ty_fn({proto: ast::proto_send., _}) {
fn_env({ |bcx, box_cell_v|
let box_ty = trans_closure::send_opaque_closure_box_ty(tcx);
glue_fn(bcx, box_cell_v, box_ty)
})
fn_env(ty::closure_send)
}
ty::ty_fn({proto: ast::proto_shared(_), _}) {
fn_env({ |bcx, box_cell_v|
let box_ty = trans_closure::shared_opaque_closure_box_ty(tcx);
glue_fn(bcx, box_cell_v, box_ty)
})
fn_env(ty::closure_shared)
}
_ { fail "make_fn_glue invoked on non-function type" }
};
}
fn call_opaque_closure_glue(bcx: @block_ctxt,
v: ValueRef, // ptr to an opaque closure
field: int) -> @block_ctxt {
fn make_opaque_cbox_take_glue(
bcx: @block_ctxt,
ck: ty::closure_kind,
cboxptr: ValueRef) // ptr to ptr to the opaque closure
-> @block_ctxt {
// Easy cases:
alt ck {
ty::closure_block. { ret bcx; }
ty::closure_shared. { ret incr_refcnt_of_boxed(bcx, Load(bcx, cboxptr)); }
ty::closure_send. { /* hard case: */ }
}
// Hard case, a deep copy:
let ccx = bcx_ccx(bcx);
let v = PointerCast(bcx, v, T_ptr(T_opaque_closure(ccx)));
let tydescptr = GEPi(bcx, v, [0, abi::closure_elt_tydesc]);
let tydesc = Load(bcx, tydescptr);
let ti = none;
call_tydesc_glue_full(bcx, v, tydesc, field, ti);
ret bcx;
let llopaquecboxty = T_opaque_cbox_ptr(ccx);
let cbox_in = Load(bcx, cboxptr);
make_null_test(bcx, cbox_in) {|bcx|
// Load the size from the type descr found in the cbox
let cbox_in = PointerCast(bcx, cbox_in, llopaquecboxty);
let tydescptr = GEPi(bcx, cbox_in, [0, abi::cbox_elt_tydesc]);
let tydesc = Load(bcx, tydescptr);
let tydesc = PointerCast(bcx, tydesc, T_ptr(ccx.tydesc_type));
let sz = Load(bcx, GEPi(bcx, tydesc, [0, abi::tydesc_field_size]));
// Allocate memory, update original ptr, and copy existing data
let malloc = ccx.upcalls.shared_malloc;
let cbox_out = Call(bcx, malloc, [sz, tydesc]);
let cbox_out = PointerCast(bcx, cbox_out, llopaquecboxty);
let {bcx, val: _} = call_memmove(bcx, cbox_out, cbox_in, sz);
Store(bcx, cbox_out, cboxptr);
// Take the data in the tuple
let ti = none;
call_tydesc_glue_full(bcx, cbox_out, tydesc,
abi::tydesc_field_take_glue, ti);
bcx
}
}
fn make_opaque_cbox_drop_glue(
bcx: @block_ctxt,
ck: ty::closure_kind,
cboxptr: ValueRef) // ptr to the opaque closure
-> @block_ctxt {
alt ck {
ty::closure_block. { bcx }
ty::closure_shared. {
decr_refcnt_maybe_free(bcx, Load(bcx, cboxptr),
ty::mk_opaque_closure_ptr(bcx_tcx(bcx), ck))
}
ty::closure_send. {
free_ty(bcx, Load(bcx, cboxptr),
ty::mk_opaque_closure_ptr(bcx_tcx(bcx), ck))
}
}
}
fn make_opaque_cbox_free_glue(
bcx: @block_ctxt,
ck: ty::closure_kind,
cbox: ValueRef) // ptr to the opaque closure
-> @block_ctxt {
alt ck {
ty::closure_block. { ret bcx; }
ty::closure_shared. | ty::closure_send. { /* hard cases: */ }
}
let ccx = bcx_ccx(bcx);
make_null_test(bcx, cbox) {|bcx|
// Load the type descr found in the cbox
let lltydescty = T_ptr(ccx.tydesc_type);
let cbox = PointerCast(bcx, cbox, T_opaque_cbox_ptr(ccx));
let tydescptr = GEPi(bcx, cbox, [0, abi::cbox_elt_tydesc]);
let tydesc = Load(bcx, tydescptr);
let tydesc = PointerCast(bcx, tydesc, lltydescty);
// Null out the type descr in the cbox. This is subtle:
// we will be freeing the data in the cbox, and we may need the
// information in the type descr to guide the GEP_tup_like process
// etc if generic types are involved. So we null it out at first
// then free it manually below.
Store(bcx, C_null(lltydescty), tydescptr);
// Drop the tuple data then free the descriptor
let ti = none;
call_tydesc_glue_full(bcx, cbox, tydesc,
abi::tydesc_field_drop_glue, ti);
// Free the ty descr (if necc) and the box itself
alt ck {
ty::closure_block. { fail "Impossible."; }
ty::closure_shared. {
trans_free_if_not_gc(bcx, cbox)
}
ty::closure_send. {
let bcx = trans_shared_free(bcx, tydesc);
trans_shared_free(bcx, cbox)
}
}
}
}
// pth is cx.path
@ -592,7 +747,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
incoming_fty: ty::t,
outgoing_fty: ty::t,
args: [option::t<@ast::expr>],
boxed_closure_ty: ty::t,
cboxptr_ty: ty::t,
param_bounds: [ty::param_bounds],
target_fn: option::t<ValueRef>)
-> {val: ValueRef, ty: TypeRef} {
@ -648,9 +803,9 @@ fn trans_bind_thunk(cx: @local_ctxt,
// to the original function. So, let's create one of those:
// The llenv pointer needs to be the correct size. That size is
// 'boxed_closure_ty', which was determined by trans_bind.
check (type_has_static_size(ccx, boxed_closure_ty));
let llclosure_ptr_ty = type_of(ccx, sp, boxed_closure_ty);
// 'cboxptr_ty', which was determined by trans_bind.
check type_has_static_size(ccx, cboxptr_ty);
let llclosure_ptr_ty = type_of(ccx, sp, cboxptr_ty);
let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
// "target", in this context, means the function that's having some of its
@ -660,15 +815,14 @@ fn trans_bind_thunk(cx: @local_ctxt,
// target function lives in the first binding spot.
let (lltargetfn, lltargetenv, starting_idx) = alt target_fn {
some(fptr) {
(fptr, llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(ccx)), 0)
(fptr, llvm::LLVMGetUndef(T_opaque_cbox_ptr(ccx)), 0)
}
none. {
// Silly check
check type_is_tup_like(bcx, boxed_closure_ty);
check type_is_tup_like(bcx, cboxptr_ty);
let {bcx: cx, val: pair} =
GEP_tup_like(bcx, boxed_closure_ty, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_bindings, 0]);
GEP_tup_like(bcx, cboxptr_ty, llclosure,
[0, abi::cbox_elt_bindings, 0]);
let lltargetenv =
Load(cx, GEPi(cx, pair, [0, abi::fn_field_box]));
let lltargetfn = Load
@ -702,10 +856,9 @@ fn trans_bind_thunk(cx: @local_ctxt,
let llargs: [ValueRef] = [llretptr, lltargetenv];
// Copy in the type parameters.
check type_is_tup_like(l_bcx, boxed_closure_ty);
check type_is_tup_like(l_bcx, cboxptr_ty);
let {bcx: l_bcx, val: param_record} =
GEP_tup_like(l_bcx, boxed_closure_ty, llclosure,
[0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
GEP_tup_like(l_bcx, cboxptr_ty, llclosure, [0, abi::cbox_elt_ty_params]);
let off = 0;
for param in param_bounds {
let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
@ -743,11 +896,10 @@ fn trans_bind_thunk(cx: @local_ctxt,
// closure.
some(e) {
// Silly check
check type_is_tup_like(bcx, boxed_closure_ty);
check type_is_tup_like(bcx, cboxptr_ty);
let bound_arg =
GEP_tup_like(bcx, boxed_closure_ty, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_bindings, b]);
GEP_tup_like(bcx, cboxptr_ty, llclosure,
[0, abi::cbox_elt_bindings, b]);
bcx = bound_arg.bcx;
let val = bound_arg.val;
if out_arg.mode == ast::by_val { val = Load(bcx, val); }

View File

@ -542,7 +542,7 @@ fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef unsafe {
}
fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
ret T_struct([T_ptr(tfn), T_opaque_boxed_closure_ptr(cx)]);
ret T_struct([T_ptr(tfn), T_opaque_cbox_ptr(cx)]);
}
fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
@ -698,34 +698,14 @@ fn T_typaram(tn: type_names) -> TypeRef {
fn T_typaram_ptr(tn: type_names) -> TypeRef { ret T_ptr(T_typaram(tn)); }
fn T_closure(cx: @crate_ctxt,
llbindings_ty: TypeRef,
n_ty_params: uint) -> TypeRef {
ret T_struct([T_ptr(cx.tydesc_type),
T_captured_tydescs(cx, n_ty_params),
llbindings_ty])
}
fn T_opaque_closure(cx: @crate_ctxt) -> TypeRef {
let s = "closure";
fn T_opaque_cbox_ptr(cx: @crate_ctxt) -> TypeRef {
let s = "*cbox";
if cx.tn.name_has_type(s) { ret cx.tn.get_type(s); }
let t = T_closure(cx, T_nil(), 0u);
cx.tn.associate(s, t);
ret t;
}
fn T_boxed_closure_ptr(cx: @crate_ctxt, llbindings_ty: TypeRef,
n_ty_params: uint) -> TypeRef {
// NB: keep this in sync with code in trans_bind; we're making
// an LLVM typeref structure that has the same "shape" as the ty::t
// it constructs.
ret T_ptr(T_box(cx, T_closure(cx, llbindings_ty, n_ty_params)));
}
fn T_opaque_boxed_closure_ptr(cx: @crate_ctxt) -> TypeRef {
let s = "*closure";
if cx.tn.name_has_type(s) { ret cx.tn.get_type(s); }
let t = T_boxed_closure_ptr(cx, T_nil(), 0u);
let t = T_ptr(T_struct([cx.int_type,
T_ptr(cx.tydesc_type),
T_i8() /* represents closed over tydescs
and data go here; see trans_closure.rs*/
]));
cx.tn.associate(s, t);
ret t;
}

View File

@ -58,7 +58,7 @@ fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
T_ptr(type_of_or_i8(bcx, basety)), tz,
tr, base);
rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
rslt(bcx, PointerCast(bcx, val, T_opaque_cbox_ptr(bcx_ccx(bcx))))
}
fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,

View File

@ -84,7 +84,7 @@ export mk_send_type;
export mk_uint;
export mk_uniq;
export mk_var;
export mk_opaque_closure;
export mk_opaque_closure_ptr;
export mk_named;
export gen_ty;
export mode;
@ -111,7 +111,7 @@ export ty_bool;
export ty_bot;
export ty_box;
export ty_constr;
export ty_opaque_closure;
export ty_opaque_closure_ptr;
export ty_constr_arg;
export ty_float;
export ty_fn, fn_ty;
@ -149,7 +149,6 @@ export kind_can_be_copied, kind_can_be_sent, proto_kind, kind_lteq, type_kind;
export type_err;
export type_err_to_str;
export type_has_dynamic_size;
export type_has_opaque_size;
export type_needs_drop;
export type_is_bool;
export type_is_bot;
@ -276,7 +275,7 @@ tag sty {
ty_send_type; // type_desc* that has been cloned into exchange heap
ty_native(def_id);
ty_constr(t, [@type_constr]);
ty_opaque_closure; // type of a captured environment.
ty_opaque_closure_ptr(closure_kind); // ptr to env for fn, fn@, fn~
ty_named(t, @str);
}
@ -368,9 +367,7 @@ const idx_send_type: uint = 18u;
const idx_bot: uint = 19u;
const idx_opaque_closure: uint = 20u;
const idx_first_others: uint = 21u;
const idx_first_others: uint = 20u;
type type_store = interner::interner<@raw_t>;
@ -400,7 +397,6 @@ fn populate_type_store(cx: ctxt) {
intern(cx, ty_type);
intern(cx, ty_send_type);
intern(cx, ty_bot);
intern(cx, ty_opaque_closure);
assert (vec::len(cx.ts.vect) == idx_first_others);
}
@ -471,7 +467,8 @@ fn mk_raw_ty(cx: ctxt, st: sty) -> @raw_t {
}
alt st {
ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_float(_) | ty_uint(_) |
ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
ty_str. | ty_send_type. | ty_type. | ty_native(_) |
ty_opaque_closure_ptr(_) {
/* no-op */
}
ty_param(_, _) { has_params = true; }
@ -636,8 +633,8 @@ fn mk_send_type(_cx: ctxt) -> t { ret idx_send_type; }
fn mk_native(cx: ctxt, did: def_id) -> t { ret gen_ty(cx, ty_native(did)); }
fn mk_opaque_closure(_cx: ctxt) -> t {
ret idx_opaque_closure;
fn mk_opaque_closure_ptr(cx: ctxt, ck: closure_kind) -> t {
ret gen_ty(cx, ty_opaque_closure_ptr(ck));
}
fn mk_named(cx: ctxt, base: t, name: @str) -> t {
@ -685,7 +682,8 @@ type ty_walk = fn@(t);
fn walk_ty(cx: ctxt, walker: ty_walk, ty: t) {
alt struct(cx, ty) {
ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
ty_str. | ty_send_type. | ty_type. | ty_native(_) |
ty_opaque_closure_ptr(_) {
/* no-op */
}
ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, walker, tm.ty); }
@ -739,7 +737,8 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
}
alt interner::get(*cx.ts, ty).struct {
ty_nil. | ty_bot. | ty_bool. | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str. | ty_send_type. | ty_type. | ty_native(_) | ty_opaque_closure. {
ty_str. | ty_send_type. | ty_type. | ty_native(_) |
ty_opaque_closure_ptr(_) {
/* no-op */
}
ty_box(tm) {
@ -881,6 +880,7 @@ fn sequence_element_type(cx: ctxt, ty: t) -> t {
pure fn type_is_tup_like(cx: ctxt, ty: t) -> bool {
let sty = struct(cx, ty);
alt sty {
ty_ptr(_) | ty_uniq(_) |
ty_box(_) | ty_rec(_) | ty_tup(_) | ty_tag(_,_) { true }
_ { false }
}
@ -1058,7 +1058,9 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
// anything about its fields.
ty_obj(_) { kind_copyable }
ty_fn(f) { proto_kind(f.proto) }
ty_opaque_closure. { kind_noncopyable }
ty_opaque_closure_ptr(closure_block.) { kind_noncopyable }
ty_opaque_closure_ptr(closure_shared.) { kind_copyable }
ty_opaque_closure_ptr(closure_send.) { kind_sendable }
// Those with refcounts-to-inner raise pinned to shared,
// lower unique to shared. Therefore just set result to shared.
ty_box(_) | ty_iface(_, _) { kind_copyable }
@ -1141,15 +1143,6 @@ fn type_structurally_contains(cx: ctxt, ty: t, test: fn(sty) -> bool) ->
}
}
pure fn type_has_opaque_size(cx: ctxt, ty: t) -> bool unchecked {
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
alt sty {
ty_opaque_closure. { true}
_ { false }
}
})
}
pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
/* type_structurally_contains can't be declared pure
@ -1162,7 +1155,7 @@ pure fn type_has_dynamic_size(cx: ctxt, ty: t) -> bool unchecked {
*/
type_structurally_contains(cx, ty, fn (sty: sty) -> bool {
alt sty {
ty_opaque_closure. | ty_param(_, _) { true }
ty_param(_, _) { true }
_ { false }
}
})
@ -1424,13 +1417,15 @@ fn hash_type_structure(st: sty) -> uint {
}
ty_uniq(mt) { ret hash_subty(37u, mt.ty); }
ty_send_type. { ret 38u; }
ty_opaque_closure. { ret 39u; }
ty_named(t, name) { (str::hash(*name) << 5u) + hash_subty(40u, t) }
ty_named(t, name) { (str::hash(*name) << 5u) + hash_subty(39u, t) }
ty_iface(did, tys) {
let h = hash_def(41u, did);
for typ: t in tys { h += (h << 5u) + typ; }
let h = hash_def(40u, did);
for typ: t in tys { h = hash_subty(h, typ); }
ret h;
}
ty_opaque_closure_ptr(closure_block.) { ret 41u; }
ty_opaque_closure_ptr(closure_shared.) { ret 42u; }
ty_opaque_closure_ptr(closure_send.) { ret 43u; }
}
}