Merge branch 'master' of github.com:graydon/rust
This commit is contained in:
commit
bdb84e76c5
9 changed files with 163 additions and 71 deletions
|
@ -47,30 +47,21 @@ const vec_elt_pad: int = 3;
|
||||||
const vec_elt_data: int = 4;
|
const vec_elt_data: int = 4;
|
||||||
|
|
||||||
const tydesc_field_first_param: int = 0;
|
const tydesc_field_first_param: int = 0;
|
||||||
|
|
||||||
const tydesc_field_size: int = 1;
|
const tydesc_field_size: int = 1;
|
||||||
|
|
||||||
const tydesc_field_align: int = 2;
|
const tydesc_field_align: int = 2;
|
||||||
|
|
||||||
const tydesc_field_copy_glue: int = 3;
|
const tydesc_field_copy_glue: int = 3;
|
||||||
|
|
||||||
const tydesc_field_drop_glue: int = 4;
|
const tydesc_field_drop_glue: int = 4;
|
||||||
|
|
||||||
const tydesc_field_free_glue: int = 5;
|
const tydesc_field_free_glue: int = 5;
|
||||||
|
|
||||||
const tydesc_field_sever_glue: int = 6;
|
const tydesc_field_sever_glue: int = 6;
|
||||||
|
|
||||||
const tydesc_field_mark_glue: int = 7;
|
const tydesc_field_mark_glue: int = 7;
|
||||||
|
|
||||||
|
|
||||||
// FIXME no longer used in rustc, drop when rustboot is gone
|
// FIXME no longer used in rustc, drop when rustboot is gone
|
||||||
const tydesc_field_obj_drop_glue: int = 8;
|
const tydesc_field_obj_drop_glue: int = 8;
|
||||||
|
|
||||||
const tydesc_field_is_stateful: int = 9;
|
const tydesc_field_is_stateful: int = 9;
|
||||||
|
|
||||||
const tydesc_field_cmp_glue: int = 10;
|
const tydesc_field_cmp_glue: int = 10;
|
||||||
|
const tydesc_field_shape: int = 11;
|
||||||
const n_tydesc_fields: int = 11;
|
const tydesc_field_shape_tables: int = 12;
|
||||||
|
const tydesc_field_n_params: int = 13;
|
||||||
|
const n_tydesc_fields: int = 14;
|
||||||
|
|
||||||
const cmp_glue_op_eq: uint = 0u;
|
const cmp_glue_op_eq: uint = 0u;
|
||||||
|
|
||||||
|
|
|
@ -895,7 +895,8 @@ fn linearize_ty_params(cx: &@block_ctxt, t: &ty::t) ->
|
||||||
|
|
||||||
fn trans_stack_local_derived_tydesc(cx: &@block_ctxt, llsz: ValueRef,
|
fn trans_stack_local_derived_tydesc(cx: &@block_ctxt, llsz: ValueRef,
|
||||||
llalign: ValueRef, llroottydesc: ValueRef,
|
llalign: ValueRef, llroottydesc: ValueRef,
|
||||||
llparamtydescs: ValueRef) -> ValueRef {
|
llparamtydescs: ValueRef,
|
||||||
|
n_params: uint) -> ValueRef {
|
||||||
let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
|
let llmyroottydesc = alloca(cx, bcx_ccx(cx).tydesc_type);
|
||||||
// By convention, desc 0 is the root descriptor.
|
// By convention, desc 0 is the root descriptor.
|
||||||
|
|
||||||
|
@ -904,11 +905,14 @@ fn trans_stack_local_derived_tydesc(cx: &@block_ctxt, llsz: ValueRef,
|
||||||
// Store a pointer to the rest of the descriptors.
|
// Store a pointer to the rest of the descriptors.
|
||||||
|
|
||||||
let llfirstparam = cx.build.GEP(llparamtydescs, ~[C_int(0), C_int(0)]);
|
let llfirstparam = cx.build.GEP(llparamtydescs, ~[C_int(0), C_int(0)]);
|
||||||
cx.build.Store(llfirstparam,
|
store_inbounds(cx, llfirstparam, llmyroottydesc,
|
||||||
cx.build.GEP(llmyroottydesc, ~[C_int(0), C_int(0)]));
|
~[C_int(0), C_int(abi::tydesc_field_first_param)]);
|
||||||
cx.build.Store(llsz, cx.build.GEP(llmyroottydesc, ~[C_int(0), C_int(1)]));
|
store_inbounds(cx, C_uint(n_params), llmyroottydesc,
|
||||||
cx.build.Store(llalign,
|
~[C_int(0), C_int(abi::tydesc_field_n_params)]);
|
||||||
cx.build.GEP(llmyroottydesc, ~[C_int(0), C_int(2)]));
|
store_inbounds(cx, llsz, llmyroottydesc,
|
||||||
|
~[C_int(0), C_int(abi::tydesc_field_size)]);
|
||||||
|
store_inbounds(cx, llalign, llmyroottydesc,
|
||||||
|
~[C_int(0), C_int(abi::tydesc_field_align)]);
|
||||||
ret llmyroottydesc;
|
ret llmyroottydesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,7 +968,8 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: &ty::t, escapes: bool,
|
||||||
v = td_val;
|
v = td_val;
|
||||||
} else {
|
} else {
|
||||||
let llparamtydescs =
|
let llparamtydescs =
|
||||||
alloca(bcx, T_array(T_ptr(bcx_ccx(bcx).tydesc_type), n_params));
|
alloca(bcx, T_array(T_ptr(bcx_ccx(bcx).tydesc_type),
|
||||||
|
n_params + 1u));
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for td: ValueRef in tys.descs {
|
for td: ValueRef in tys.descs {
|
||||||
let tdp = bcx.build.GEP(llparamtydescs, ~[C_int(0), C_int(i)]);
|
let tdp = bcx.build.GEP(llparamtydescs, ~[C_int(0), C_int(i)]);
|
||||||
|
@ -973,7 +978,7 @@ fn get_derived_tydesc(cx: &@block_ctxt, t: &ty::t, escapes: bool,
|
||||||
}
|
}
|
||||||
v =
|
v =
|
||||||
trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
trans_stack_local_derived_tydesc(bcx, sz.val, align.val, root,
|
||||||
llparamtydescs);
|
llparamtydescs, n_params);
|
||||||
}
|
}
|
||||||
bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
|
bcx.fcx.derived_tydescs.insert(t, {lltydesc: v, escapes: escapes});
|
||||||
ret rslt(cx, v);
|
ret rslt(cx, v);
|
||||||
|
@ -1191,20 +1196,28 @@ fn emit_tydescs(ccx: &@crate_ctxt) {
|
||||||
none. { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) }
|
none. { ccx.stats.n_null_glues += 1u; C_null(cmp_fn_ty) }
|
||||||
some(v) { ccx.stats.n_real_glues += 1u; v }
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
||||||
};
|
};
|
||||||
let // copy_glue
|
|
||||||
// drop_glue
|
let shape = shape::shape_of(ccx, pair.key);
|
||||||
// free_glue
|
let shape_tables =
|
||||||
// sever_glue
|
llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables,
|
||||||
// mark_glue
|
T_ptr(T_i8()));
|
||||||
// obj_drop_glue
|
|
||||||
// is_stateful
|
let tydesc =
|
||||||
tydesc =
|
|
||||||
C_named_struct(ccx.tydesc_type,
|
C_named_struct(ccx.tydesc_type,
|
||||||
~[C_null(T_ptr(T_ptr(ccx.tydesc_type))), ti.size,
|
~[C_null(T_ptr(T_ptr(ccx.tydesc_type))),
|
||||||
ti.align, copy_glue, drop_glue, free_glue,
|
ti.size, // size
|
||||||
C_null(glue_fn_ty), C_null(glue_fn_ty),
|
ti.align, // align
|
||||||
C_null(glue_fn_ty), C_null(glue_fn_ty),
|
copy_glue, // copy_glue
|
||||||
cmp_glue]); // cmp_glue
|
drop_glue, // drop_glue
|
||||||
|
free_glue, // free_glue
|
||||||
|
C_null(glue_fn_ty), // sever_glue
|
||||||
|
C_null(glue_fn_ty), // mark_glue
|
||||||
|
C_null(glue_fn_ty), // obj_drop_glue
|
||||||
|
C_null(glue_fn_ty), // is_stateful
|
||||||
|
cmp_glue, // cmp_glue
|
||||||
|
C_shape(ccx, shape), // shape
|
||||||
|
shape_tables, // shape_tables
|
||||||
|
C_int(0)]); // n_params
|
||||||
|
|
||||||
let gvar = ti.tydesc;
|
let gvar = ti.tydesc;
|
||||||
llvm::LLVMSetInitializer(gvar, tydesc);
|
llvm::LLVMSetInitializer(gvar, tydesc);
|
||||||
|
@ -2288,8 +2301,9 @@ fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: &ty::t,
|
||||||
let ti = none[@tydesc_info];
|
let ti = none[@tydesc_info];
|
||||||
let r = get_tydesc(cx, t, false, ti);
|
let r = get_tydesc(cx, t, false, ti);
|
||||||
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
|
lazily_emit_tydesc_glue(cx, abi::tydesc_field_cmp_glue, ti);
|
||||||
|
let lltydesc = r.val;
|
||||||
let lltydescs =
|
let lltydescs =
|
||||||
r.bcx.build.GEP(r.val,
|
r.bcx.build.GEP(lltydesc,
|
||||||
~[C_int(0), C_int(abi::tydesc_field_first_param)]);
|
~[C_int(0), C_int(abi::tydesc_field_first_param)]);
|
||||||
lltydescs = r.bcx.build.Load(lltydescs);
|
lltydescs = r.bcx.build.Load(lltydescs);
|
||||||
|
|
||||||
|
@ -2297,7 +2311,7 @@ fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: &ty::t,
|
||||||
alt ti {
|
alt ti {
|
||||||
none. {
|
none. {
|
||||||
let llfnptr =
|
let llfnptr =
|
||||||
r.bcx.build.GEP(r.val,
|
r.bcx.build.GEP(lltydesc,
|
||||||
~[C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
|
~[C_int(0), C_int(abi::tydesc_field_cmp_glue)]);
|
||||||
llfn = r.bcx.build.Load(llfnptr);
|
llfn = r.bcx.build.Load(llfnptr);
|
||||||
}
|
}
|
||||||
|
@ -2306,7 +2320,7 @@ fn call_cmp_glue(cx: &@block_ctxt, lhs: ValueRef, rhs: ValueRef, t: &ty::t,
|
||||||
|
|
||||||
let llcmpresultptr = alloca(r.bcx, T_i1());
|
let llcmpresultptr = alloca(r.bcx, T_i1());
|
||||||
let llargs: ValueRef[] =
|
let llargs: ValueRef[] =
|
||||||
~[llcmpresultptr, r.bcx.fcx.lltaskptr, C_null(T_ptr(T_nil())),
|
~[llcmpresultptr, r.bcx.fcx.lltaskptr, lltydesc,
|
||||||
lltydescs, llrawlhsptr, llrawrhsptr, llop];
|
lltydescs, llrawlhsptr, llrawrhsptr, llop];
|
||||||
r.bcx.build.Call(llfn, llargs);
|
r.bcx.build.Call(llfn, llargs);
|
||||||
ret rslt(r.bcx, r.bcx.build.Load(llcmpresultptr));
|
ret rslt(r.bcx, r.bcx.build.Load(llcmpresultptr));
|
||||||
|
@ -2366,7 +2380,7 @@ fn call_memmove(cx: &@block_ctxt, dst: ValueRef, src: ValueRef,
|
||||||
let src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
|
let src_ptr = cx.build.PointerCast(src, T_ptr(T_i8()));
|
||||||
let dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
let dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
|
||||||
let size = cx.build.IntCast(n_bytes, T_i32());
|
let size = cx.build.IntCast(n_bytes, T_i32());
|
||||||
let align = C_int(0);
|
let align = C_int(1);
|
||||||
let volatile = C_bool(false);
|
let volatile = C_bool(false);
|
||||||
ret rslt(cx,
|
ret rslt(cx,
|
||||||
cx.build.Call(memmove,
|
cx.build.Call(memmove,
|
||||||
|
@ -2397,7 +2411,12 @@ fn memmove_ty(cx: &@block_ctxt, dst: ValueRef, src: ValueRef, t: &ty::t) ->
|
||||||
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
|
if ty::type_has_dynamic_size(bcx_tcx(cx), t) {
|
||||||
let llsz = size_of(cx, t);
|
let llsz = size_of(cx, t);
|
||||||
ret call_memmove(llsz.bcx, dst, src, llsz.val);
|
ret call_memmove(llsz.bcx, dst, src, llsz.val);
|
||||||
} else { ret rslt(cx, cx.build.Store(cx.build.Load(src), dst)); }
|
} else if ty::type_is_structural(bcx_tcx(cx), t) {
|
||||||
|
let llsz = llsize_of(type_of(bcx_ccx(cx), cx.sp, t));
|
||||||
|
ret call_memmove(cx, dst, src, llsz);
|
||||||
|
} else {
|
||||||
|
ret rslt(cx, cx.build.Store(cx.build.Load(src), dst));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicates any heap-owned memory owned by a value of the given type.
|
// Duplicates any heap-owned memory owned by a value of the given type.
|
||||||
|
@ -4696,7 +4715,7 @@ fn trans_arg_expr(cx: &@block_ctxt, arg: &ty::arg, lldestty0: TypeRef,
|
||||||
// - create_llargs_for_fn_args.
|
// - create_llargs_for_fn_args.
|
||||||
// - new_fn_ctxt
|
// - new_fn_ctxt
|
||||||
// - trans_args
|
// - trans_args
|
||||||
fn trans_args(cx: &@block_ctxt, llenv: ValueRef, llobj: &option::t[ValueRef],
|
fn trans_args(cx: &@block_ctxt, llenv: ValueRef,
|
||||||
gen: &option::t[generic_info], lliterbody: &option::t[ValueRef],
|
gen: &option::t[generic_info], lliterbody: &option::t[ValueRef],
|
||||||
es: &(@ast::expr)[], fn_ty: &ty::t) ->
|
es: &(@ast::expr)[], fn_ty: &ty::t) ->
|
||||||
{bcx: @block_ctxt, args: ValueRef[], retslot: ValueRef} {
|
{bcx: @block_ctxt, args: ValueRef[], retslot: ValueRef} {
|
||||||
|
@ -4815,8 +4834,7 @@ fn trans_call(cx: &@block_ctxt, f: &@ast::expr,
|
||||||
|
|
||||||
let ret_ty = ty::node_id_to_type(bcx_tcx(cx), id);
|
let ret_ty = ty::node_id_to_type(bcx_tcx(cx), id);
|
||||||
let args_res =
|
let args_res =
|
||||||
trans_args(bcx, llenv, f_res.llobj, f_res.generic, lliterbody, args,
|
trans_args(bcx, llenv, f_res.generic, lliterbody, args, fn_ty);
|
||||||
fn_ty);
|
|
||||||
bcx = args_res.bcx;
|
bcx = args_res.bcx;
|
||||||
let llargs = args_res.args;
|
let llargs = args_res.args;
|
||||||
let llretslot = args_res.retslot;
|
let llretslot = args_res.retslot;
|
||||||
|
@ -8000,8 +8018,9 @@ fn trans_crate(sess: &session::session, crate: &@ast::crate, tcx: &ty::ctxt,
|
||||||
trans_mod(cx, crate.node.module);
|
trans_mod(cx, crate.node.module);
|
||||||
create_crate_map(ccx);
|
create_crate_map(ccx);
|
||||||
emit_tydescs(ccx);
|
emit_tydescs(ccx);
|
||||||
// Translate the metadata:
|
shape::gen_shape_tables(ccx);
|
||||||
|
|
||||||
|
// Translate the metadata.
|
||||||
write_metadata(cx.ccx, crate);
|
write_metadata(cx.ccx, crate);
|
||||||
if ccx.sess.get_opts().stats {
|
if ccx.sess.get_opts().stats {
|
||||||
log_err "--- trans stats ---";
|
log_err "--- trans stats ---";
|
||||||
|
|
|
@ -433,7 +433,7 @@ fn trans_alt(cx: &@block_ctxt, expr: &@ast::expr, arms: &ast::arm[],
|
||||||
ret rslt(cx, cx.build.Unreachable());
|
ret rslt(cx, cx.build.Unreachable());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret rslt(cx, C_nil());
|
ret er;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -597,22 +597,13 @@ fn T_tydesc(taskptr_type: TypeRef) -> TypeRef {
|
||||||
T_ptr(T_fn(~[T_ptr(T_nil()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
T_ptr(T_fn(~[T_ptr(T_nil()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
||||||
pvoid], T_void()));
|
pvoid], T_void()));
|
||||||
let cmp_glue_fn_ty =
|
let cmp_glue_fn_ty =
|
||||||
T_ptr(T_fn(~[T_ptr(T_i1()), taskptr_type, T_ptr(T_nil()), tydescpp,
|
T_ptr(T_fn(~[T_ptr(T_i1()), taskptr_type, T_ptr(tydesc), tydescpp,
|
||||||
pvoid, pvoid, T_i8()], T_void()));
|
pvoid, pvoid, T_i8()], T_void()));
|
||||||
|
|
||||||
let // first_param
|
let elems =
|
||||||
// size
|
|
||||||
// align
|
|
||||||
// copy_glue
|
|
||||||
// drop_glue
|
|
||||||
// free_glue
|
|
||||||
// sever_glue
|
|
||||||
// mark_glue
|
|
||||||
// obj_drop_glue
|
|
||||||
// is_stateful
|
|
||||||
elems =
|
|
||||||
~[tydescpp, T_int(), T_int(), glue_fn_ty, glue_fn_ty, glue_fn_ty,
|
~[tydescpp, T_int(), T_int(), glue_fn_ty, glue_fn_ty, glue_fn_ty,
|
||||||
glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, cmp_glue_fn_ty];
|
glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, cmp_glue_fn_ty,
|
||||||
|
T_ptr(T_i8()), T_ptr(T_i8()), T_int()];
|
||||||
set_struct_body(tydesc, elems);
|
set_struct_body(tydesc, elems);
|
||||||
ret tydesc;
|
ret tydesc;
|
||||||
}
|
}
|
||||||
|
@ -874,3 +865,14 @@ fn C_bytes(bytes : &u8[]) -> ValueRef {
|
||||||
ivec::len(bytes), False);
|
ivec::len(bytes), False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn C_shape(ccx : &@crate_ctxt, bytes : &u8[]) -> ValueRef {
|
||||||
|
let llshape = C_bytes(bytes);
|
||||||
|
let llglobal = llvm::LLVMAddGlobal(ccx.llmod, val_ty(llshape),
|
||||||
|
str::buf(ccx.names.next("shape")));
|
||||||
|
llvm::LLVMSetInitializer(llglobal, llshape);
|
||||||
|
llvm::LLVMSetGlobalConstant(llglobal, True);
|
||||||
|
llvm::LLVMSetLinkage(llglobal,
|
||||||
|
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||||
|
ret llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,7 @@ export type_param;
|
||||||
export unify;
|
export unify;
|
||||||
export variant_info;
|
export variant_info;
|
||||||
export walk_ty;
|
export walk_ty;
|
||||||
|
export occurs_check_fails;
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
tag mode { mo_val; mo_alias(bool); }
|
tag mode { mo_val; mo_alias(bool); }
|
||||||
|
@ -655,6 +656,7 @@ fn walk_ty(cx: &ctxt, walker: ty_walk, ty: t) {
|
||||||
ty_str. {/* no-op */ }
|
ty_str. {/* no-op */ }
|
||||||
ty_istr. {/* no-op */ }
|
ty_istr. {/* no-op */ }
|
||||||
ty_type. {/* no-op */ }
|
ty_type. {/* no-op */ }
|
||||||
|
ty_task. {/* no-op */ }
|
||||||
ty_native(_) {/* no-op */ }
|
ty_native(_) {/* no-op */ }
|
||||||
ty_box(tm) { walk_ty(cx, walker, tm.ty); }
|
ty_box(tm) { walk_ty(cx, walker, tm.ty); }
|
||||||
ty_vec(tm) { walk_ty(cx, walker, tm.ty); }
|
ty_vec(tm) { walk_ty(cx, walker, tm.ty); }
|
||||||
|
@ -686,6 +688,9 @@ fn walk_ty(cx: &ctxt, walker: ty_walk, ty: t) {
|
||||||
walk_ty(cx, walker, sub);
|
walk_ty(cx, walker, sub);
|
||||||
for tp: t in tps { walk_ty(cx, walker, tp); }
|
for tp: t in tps { walk_ty(cx, walker, tp); }
|
||||||
}
|
}
|
||||||
|
ty_constr(sub, _) {
|
||||||
|
walk_ty(cx, walker, sub);
|
||||||
|
}
|
||||||
ty_var(_) {/* no-op */ }
|
ty_var(_) {/* no-op */ }
|
||||||
ty_param(_,_) {/* no-op */ }
|
ty_param(_,_) {/* no-op */ }
|
||||||
}
|
}
|
||||||
|
@ -1393,6 +1398,24 @@ fn type_param(cx: &ctxt, ty: &t) -> option::t[uint] {
|
||||||
ret none;
|
ret none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns an ivec of all the type variables
|
||||||
|
// occurring in t. It may contain duplicates.
|
||||||
|
fn vars_in_type(cx:&ctxt, ty: &t) -> int[] {
|
||||||
|
fn collect_var(cx:&ctxt, vars: &@mutable int[], ty: t) {
|
||||||
|
alt struct(cx, ty) {
|
||||||
|
ty_var(v) {
|
||||||
|
*vars += ~[v];
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let rslt: @mutable int[] = @mutable (~[]);
|
||||||
|
walk_ty(cx, bind collect_var(cx, rslt, _), ty);
|
||||||
|
// Works because of a "convenient" bug that lets us
|
||||||
|
// return a mutable ivec as if it's immutable
|
||||||
|
ret *rslt;
|
||||||
|
}
|
||||||
|
|
||||||
fn type_autoderef(cx: &ctxt, t: &ty::t) -> ty::t {
|
fn type_autoderef(cx: &ctxt, t: &ty::t) -> ty::t {
|
||||||
let t1: ty::t = t;
|
let t1: ty::t = t;
|
||||||
while true {
|
while true {
|
||||||
|
@ -1990,6 +2013,32 @@ fn is_lval(expr: &@ast::expr) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn occurs_check_fails(tcx: &ctxt, sp: &option::t[span], vid: int, rt: &t)
|
||||||
|
-> bool {
|
||||||
|
if (!type_contains_vars(tcx, rt)) {
|
||||||
|
// Fast path
|
||||||
|
ret false;
|
||||||
|
}
|
||||||
|
// Occurs check!
|
||||||
|
if ivec::member(vid, vars_in_type(tcx, rt)) {
|
||||||
|
alt sp {
|
||||||
|
some (s) {
|
||||||
|
// Maybe this should be span_err -- however, there's an
|
||||||
|
// assertion later on that the type doesn't contain
|
||||||
|
// variables, so in this case we have to be sure to die.
|
||||||
|
tcx.sess.span_fatal(s,
|
||||||
|
"Type inference failed because I \
|
||||||
|
could not find a type\n that's both of the form " +
|
||||||
|
ty_to_str(tcx, ty::mk_var(tcx, (vid)))
|
||||||
|
+ " and of the form " + ty_to_str(tcx, rt)
|
||||||
|
+ ". Such a type would have to be infinitely \
|
||||||
|
large.");
|
||||||
|
}
|
||||||
|
_ { ret true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { ret false; }
|
||||||
|
}
|
||||||
|
|
||||||
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as
|
// Type unification via Robinson's algorithm (Robinson 1965). Implemented as
|
||||||
// described in Hoder and Voronkov:
|
// described in Hoder and Voronkov:
|
||||||
|
@ -2318,9 +2367,6 @@ mod unify {
|
||||||
// TODO: rewrite this using tuple pattern matching when available, to
|
// TODO: rewrite this using tuple pattern matching when available, to
|
||||||
// avoid all this rightward drift and spikiness.
|
// avoid all this rightward drift and spikiness.
|
||||||
|
|
||||||
// TODO: occurs check, to make sure we don't loop forever when
|
|
||||||
// unifying e.g. 'a and option['a]
|
|
||||||
|
|
||||||
// Fast path.
|
// Fast path.
|
||||||
|
|
||||||
if eq_ty(expected, actual) { ret ures_ok(expected); }
|
if eq_ty(expected, actual) { ret ures_ok(expected); }
|
||||||
|
@ -2694,9 +2740,15 @@ mod unify {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixups and substitutions
|
// Fixups and substitutions
|
||||||
fn fixup_vars(tcx: ty_ctxt, vb: @var_bindings, typ: t) -> fixup_result {
|
// Takes an optional span - complain about occurs check violations
|
||||||
fn subst_vars(tcx: ty_ctxt, vb: @var_bindings,
|
// iff the span is present (so that if we already know we're going
|
||||||
|
// to error anyway, we don't complain)
|
||||||
|
fn fixup_vars(tcx: ty_ctxt, sp: &option::t[span],
|
||||||
|
vb: @var_bindings, typ: t) -> fixup_result {
|
||||||
|
fn subst_vars(tcx: ty_ctxt, sp: &option::t[span], vb: @var_bindings,
|
||||||
unresolved: @mutable option::t[int], vid: int) -> t {
|
unresolved: @mutable option::t[int], vid: int) -> t {
|
||||||
|
// Should really return a fixup_result instead of a t, but fold_ty
|
||||||
|
// doesn't allow returning anything but a t.
|
||||||
if vid as uint >= ufindivec::set_count(vb.sets) {
|
if vid as uint >= ufindivec::set_count(vb.sets) {
|
||||||
*unresolved = some(vid);
|
*unresolved = some(vid);
|
||||||
ret ty::mk_var(tcx, vid);
|
ret ty::mk_var(tcx, vid);
|
||||||
|
@ -2705,15 +2757,18 @@ mod unify {
|
||||||
alt smallintmap::find[t](vb.types, root_id) {
|
alt smallintmap::find[t](vb.types, root_id) {
|
||||||
none. { *unresolved = some(vid); ret ty::mk_var(tcx, vid); }
|
none. { *unresolved = some(vid); ret ty::mk_var(tcx, vid); }
|
||||||
some(rt) {
|
some(rt) {
|
||||||
|
if occurs_check_fails(tcx, sp, vid, rt) {
|
||||||
|
// Return the type unchanged, so we can error out downstream
|
||||||
|
ret rt;
|
||||||
|
}
|
||||||
ret fold_ty(tcx,
|
ret fold_ty(tcx,
|
||||||
fm_var(bind subst_vars(tcx, vb, unresolved, _)),
|
fm_var(bind subst_vars(tcx, sp, vb, unresolved, _)), rt);
|
||||||
rt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let unresolved = @mutable none[int];
|
let unresolved = @mutable none[int];
|
||||||
let rty =
|
let rty =
|
||||||
fold_ty(tcx, fm_var(bind subst_vars(tcx, vb, unresolved, _)),
|
fold_ty(tcx, fm_var(bind subst_vars(tcx, sp, vb, unresolved, _)),
|
||||||
typ);
|
typ);
|
||||||
let ur = *unresolved;
|
let ur = *unresolved;
|
||||||
alt ur {
|
alt ur {
|
||||||
|
@ -2721,13 +2776,14 @@ mod unify {
|
||||||
some(var_id) { ret fix_err(var_id); }
|
some(var_id) { ret fix_err(var_id); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn resolve_type_var(tcx: &ty_ctxt, vb: &@var_bindings, vid: int) ->
|
fn resolve_type_var(tcx: &ty_ctxt, sp: &option::t[span],
|
||||||
|
vb: &@var_bindings, vid: int) ->
|
||||||
fixup_result {
|
fixup_result {
|
||||||
if vid as uint >= ufindivec::set_count(vb.sets) { ret fix_err(vid); }
|
if vid as uint >= ufindivec::set_count(vb.sets) { ret fix_err(vid); }
|
||||||
let root_id = ufindivec::find(vb.sets, vid as uint);
|
let root_id = ufindivec::find(vb.sets, vid as uint);
|
||||||
alt smallintmap::find[t](vb.types, root_id) {
|
alt smallintmap::find[t](vb.types, root_id) {
|
||||||
none. { ret fix_err(vid); }
|
none. { ret fix_err(vid); }
|
||||||
some(rt) { ret fixup_vars(tcx, vb, rt); }
|
some(rt) { ret fixup_vars(tcx, sp, vb, rt); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -879,7 +879,18 @@ fn do_autoderef(fcx: &@fn_ctxt, sp: &span, t: &ty::t) -> ty::t {
|
||||||
let t1 = t;
|
let t1 = t;
|
||||||
while true {
|
while true {
|
||||||
alt structure_of(fcx, sp, t1) {
|
alt structure_of(fcx, sp, t1) {
|
||||||
ty::ty_box(inner) { t1 = inner.ty; }
|
ty::ty_box(inner) {
|
||||||
|
alt ty::struct(fcx.ccx.tcx, t1) {
|
||||||
|
ty::ty_var(v1) {
|
||||||
|
if ty::occurs_check_fails(fcx.ccx.tcx, some(sp), v1,
|
||||||
|
ty::mk_box(fcx.ccx.tcx, inner)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
|
t1 = inner.ty;
|
||||||
|
}
|
||||||
ty::ty_res(_, inner, tps) {
|
ty::ty_res(_, inner, tps) {
|
||||||
t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner);
|
t1 = ty::substitute_type_params(fcx.ccx.tcx, tps, inner);
|
||||||
}
|
}
|
||||||
|
@ -942,7 +953,7 @@ fn do_fn_block_coerce(fcx: &@fn_ctxt, sp: &span, actual: &ty::t,
|
||||||
|
|
||||||
|
|
||||||
fn resolve_type_vars_if_possible(fcx: &@fn_ctxt, typ: ty::t) -> ty::t {
|
fn resolve_type_vars_if_possible(fcx: &@fn_ctxt, typ: ty::t) -> ty::t {
|
||||||
alt ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ) {
|
alt ty::unify::fixup_vars(fcx.ccx.tcx, none, fcx.var_bindings, typ) {
|
||||||
fix_ok(new_type) { ret new_type; }
|
fix_ok(new_type) { ret new_type; }
|
||||||
fix_err(_) { ret typ; }
|
fix_err(_) { ret typ; }
|
||||||
}
|
}
|
||||||
|
@ -1073,7 +1084,8 @@ mod writeback {
|
||||||
fn resolve_type_vars_in_type(fcx: &@fn_ctxt, sp: &span, typ: ty::t) ->
|
fn resolve_type_vars_in_type(fcx: &@fn_ctxt, sp: &span, typ: ty::t) ->
|
||||||
option::t[ty::t] {
|
option::t[ty::t] {
|
||||||
if !ty::type_contains_vars(fcx.ccx.tcx, typ) { ret some(typ); }
|
if !ty::type_contains_vars(fcx.ccx.tcx, typ) { ret some(typ); }
|
||||||
alt ty::unify::fixup_vars(fcx.ccx.tcx, fcx.var_bindings, typ) {
|
alt ty::unify::fixup_vars(fcx.ccx.tcx, some(sp),
|
||||||
|
fcx.var_bindings, typ) {
|
||||||
fix_ok(new_type) { ret some(new_type); }
|
fix_ok(new_type) { ret some(new_type); }
|
||||||
fix_err(vid) {
|
fix_err(vid) {
|
||||||
fcx.ccx.tcx.sess.span_err(sp,
|
fcx.ccx.tcx.sess.span_err(sp,
|
||||||
|
@ -1139,7 +1151,7 @@ mod writeback {
|
||||||
if !wbcx.success { ret; }
|
if !wbcx.success { ret; }
|
||||||
let var_id = lookup_local(wbcx.fcx, l.span, l.node.id);
|
let var_id = lookup_local(wbcx.fcx, l.span, l.node.id);
|
||||||
let fix_rslt =
|
let fix_rslt =
|
||||||
ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx,
|
ty::unify::resolve_type_var(wbcx.fcx.ccx.tcx, some(l.span),
|
||||||
wbcx.fcx.var_bindings, var_id);
|
wbcx.fcx.var_bindings, var_id);
|
||||||
alt fix_rslt {
|
alt fix_rslt {
|
||||||
fix_ok(lty) { write::ty_only(wbcx.fcx.ccx.tcx, l.node.id, lty); }
|
fix_ok(lty) { write::ty_only(wbcx.fcx.ccx.tcx, l.node.id, lty); }
|
||||||
|
|
5
src/test/compile-fail/occurs-check-2.rs
Normal file
5
src/test/compile-fail/occurs-check-2.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// error-pattern: Type inference failed because I could not find
|
||||||
|
fn main() {
|
||||||
|
let f = @f;
|
||||||
|
f();
|
||||||
|
}
|
4
src/test/compile-fail/occurs-check.rs
Normal file
4
src/test/compile-fail/occurs-check.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// error-pattern: Type inference failed because I could not find
|
||||||
|
fn main() {
|
||||||
|
let f = @f;
|
||||||
|
}
|
3
src/test/run-pass/alt-bot-2.rs
Normal file
3
src/test/run-pass/alt-bot-2.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// n.b. This was only ever failing with optimization disabled.
|
||||||
|
fn a() -> int { alt ret 1 { 2 { 3 } } }
|
||||||
|
fn main() { a(); }
|
Loading…
Reference in a new issue