Self types for ifaces
This allows a 'Name:' to appear in front of an iface declaration's name, which will cause 'Name' to refer to the self type (with the same number of type parameters as the iface has) in the method signatures of the iface. For example: iface F: functor<A> { fn fmap<B>(f: fn(A) -> B) -> F<B>; } Issue #1718
This commit is contained in:
parent
5c42e3df9c
commit
e0fa5cd2ed
@ -216,6 +216,13 @@ fn parse_ty(st: @pstate, conv: conv_did) -> ty::t {
|
||||
let did = parse_def(st, conv);
|
||||
ret ty::mk_param(st.tcx, parse_int(st) as uint, did);
|
||||
}
|
||||
's' {
|
||||
assert next(st) as char == '[';
|
||||
let params = [];
|
||||
while peek(st) as char != ']' { params += [parse_ty(st, conv)]; }
|
||||
st.pos += 1u;
|
||||
ret ty::mk_self(st.tcx, params);
|
||||
}
|
||||
'@' { ret ty::mk_box(st.tcx, parse_mt(st, conv)); }
|
||||
'~' { ret ty::mk_uniq(st.tcx, parse_mt(st, conv)); }
|
||||
'*' { ret ty::mk_ptr(st.tcx, parse_mt(st, conv)); }
|
||||
|
@ -169,6 +169,11 @@ fn enc_sty(w: io::writer, cx: @ctxt, st: ty::sty) {
|
||||
w.write_char('|');
|
||||
w.write_str(uint::str(id));
|
||||
}
|
||||
ty::ty_self(tps) {
|
||||
w.write_str("s[");
|
||||
for t in tps { enc_ty(w, cx, t); }
|
||||
w.write_char(']');
|
||||
}
|
||||
ty::ty_type { w.write_char('Y'); }
|
||||
ty::ty_send_type { w.write_char('y'); }
|
||||
ty::ty_opaque_closure_ptr(ty::ck_block) { w.write_str("C&"); }
|
||||
|
@ -888,10 +888,17 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
|
||||
ast::item_impl(tps, _, _, _) {
|
||||
if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
|
||||
}
|
||||
ast::item_iface(tps, _) | ast::item_enum(_, tps) |
|
||||
ast::item_ty(_, tps) {
|
||||
ast::item_enum(_, tps) | ast::item_ty(_, tps) {
|
||||
if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
|
||||
}
|
||||
ast::item_iface(tps, _) {
|
||||
if ns == ns_type {
|
||||
if name == "self" {
|
||||
ret some(def_self(local_def(it.id)));
|
||||
}
|
||||
ret lookup_in_ty_params(e, name, tps);
|
||||
}
|
||||
}
|
||||
ast::item_mod(_) {
|
||||
ret lookup_in_local_mod(e, it.id, sp, name, ns, inside);
|
||||
}
|
||||
|
@ -421,9 +421,6 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
add_substr(s, shape_of(ccx, subt, ty_param_map));
|
||||
|
||||
}
|
||||
ty::ty_var(n) {
|
||||
fail "shape_of ty_var";
|
||||
}
|
||||
ty::ty_param(n, _) {
|
||||
// Find the type parameter in the parameter list.
|
||||
alt vec::position_elt(ty_param_map, n) {
|
||||
@ -450,8 +447,8 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
|
||||
ty::ty_constr(inner_t, _) {
|
||||
s += shape_of(ccx, inner_t, ty_param_map);
|
||||
}
|
||||
ty::ty_named(_, _) {
|
||||
ccx.tcx.sess.bug("shape_of: shouldn't see a ty_named");
|
||||
ty::ty_var(_) | ty::ty_named(_, _) | ty::ty_self(_) {
|
||||
ccx.tcx.sess.bug("shape_of: unexpected type struct found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5315,7 +5315,10 @@ fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
|
||||
impl::trans_impl_vtable(ccx, item_path(ccx, it), i_did, ms, tps, it);
|
||||
}
|
||||
ast::item_iface(_, _) {
|
||||
impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
|
||||
if !vec::any(*ty::iface_methods(ccx.tcx, local_def(it.id)), {|m|
|
||||
ty::type_contains_vars(ccx.tcx, ty::mk_fn(ccx.tcx, m.fty))}) {
|
||||
impl::trans_iface_vtable(ccx, item_path(ccx, it), it);
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
|
@ -94,10 +94,9 @@ fn trans_static_callee(bcx: @block_ctxt, callee_id: ast::node_id,
|
||||
{env: self_env(val) with lval_static_fn(bcx, did, callee_id)}
|
||||
}
|
||||
|
||||
fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, m: ty::method)
|
||||
-> {ty: ty::t, llty: TypeRef} {
|
||||
let fty = ty::mk_fn(ccx.tcx, m.fty);
|
||||
let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *m.tps);
|
||||
fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
|
||||
tps: @[ty::param_bounds]) -> {ty: ty::t, llty: TypeRef} {
|
||||
let bare_fn_ty = type_of_fn_from_ty(ccx, fty, *tps);
|
||||
let {inputs, output} = llfn_arg_tys(bare_fn_ty);
|
||||
{ty: fty, llty: T_fn([dict_ty] + inputs, output)}
|
||||
}
|
||||
@ -107,7 +106,9 @@ fn trans_vtable_callee(bcx: @block_ctxt, self: ValueRef, dict: ValueRef,
|
||||
n_method: uint) -> lval_maybe_callee {
|
||||
let bcx = bcx, ccx = bcx_ccx(bcx), tcx = ccx.tcx;
|
||||
let method = ty::iface_methods(tcx, iface_id)[n_method];
|
||||
let {ty: fty, llty: llfty} = wrapper_fn_ty(ccx, val_ty(dict), method);
|
||||
let {ty: fty, llty: llfty} =
|
||||
wrapper_fn_ty(ccx, val_ty(dict), ty::node_id_to_type(tcx, callee_id),
|
||||
method.tps);
|
||||
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
|
||||
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
||||
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
|
||||
@ -266,7 +267,8 @@ fn trans_impl_vtable(ccx: @crate_ctxt, pt: path,
|
||||
|
||||
fn trans_iface_wrapper(ccx: @crate_ctxt, pt: path, m: ty::method,
|
||||
n: uint) -> ValueRef {
|
||||
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()), m);
|
||||
let {llty: llfty, _} = wrapper_fn_ty(ccx, T_ptr(T_i8()),
|
||||
ty::mk_fn(ccx.tcx, m.fty), m.tps);
|
||||
trans_wrapper(ccx, pt, llfty, {|llfn, bcx|
|
||||
let self = Load(bcx, PointerCast(bcx,
|
||||
LLVMGetParam(llfn, 2u as c_uint),
|
||||
@ -358,10 +360,7 @@ fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
|
||||
d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
|
||||
orig += 1u;
|
||||
}
|
||||
_ {
|
||||
tcx.sess.bug("Someone forgot to document an invariant in \
|
||||
dict_id");
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ export mk_send_type;
|
||||
export mk_uint;
|
||||
export mk_uniq;
|
||||
export mk_var;
|
||||
export mk_self;
|
||||
export mk_opaque_closure_ptr;
|
||||
export mk_named;
|
||||
export gen_ty;
|
||||
@ -126,6 +127,7 @@ export ty_send_type;
|
||||
export ty_uint;
|
||||
export ty_uniq;
|
||||
export ty_var;
|
||||
export ty_self;
|
||||
export ty_named;
|
||||
export same_type;
|
||||
export ty_var_id;
|
||||
@ -266,9 +268,10 @@ enum sty {
|
||||
ty_iface(def_id, [t]),
|
||||
ty_res(def_id, t, [t]),
|
||||
ty_tup([t]),
|
||||
ty_var(int), // type variable
|
||||
|
||||
ty_param(uint, def_id), // fn/enum type param
|
||||
ty_var(int), // type variable during typechecking
|
||||
ty_param(uint, def_id), // type parameter
|
||||
ty_self([t]), // interface method self type
|
||||
|
||||
ty_type, // type_desc*
|
||||
ty_send_type, // type_desc* that has been cloned into exchange heap
|
||||
@ -324,45 +327,25 @@ type ty_param_bounds_and_ty = {bounds: @[param_bounds], ty: t};
|
||||
type type_cache = hashmap<ast::def_id, ty_param_bounds_and_ty>;
|
||||
|
||||
const idx_nil: uint = 0u;
|
||||
|
||||
const idx_bool: uint = 1u;
|
||||
|
||||
const idx_int: uint = 2u;
|
||||
|
||||
const idx_float: uint = 3u;
|
||||
|
||||
const idx_uint: uint = 4u;
|
||||
|
||||
const idx_i8: uint = 5u;
|
||||
|
||||
const idx_i16: uint = 6u;
|
||||
|
||||
const idx_i32: uint = 7u;
|
||||
|
||||
const idx_i64: uint = 8u;
|
||||
|
||||
const idx_u8: uint = 9u;
|
||||
|
||||
const idx_u16: uint = 10u;
|
||||
|
||||
const idx_u32: uint = 11u;
|
||||
|
||||
const idx_u64: uint = 12u;
|
||||
|
||||
const idx_f32: uint = 13u;
|
||||
|
||||
const idx_f64: uint = 14u;
|
||||
|
||||
const idx_char: uint = 15u;
|
||||
|
||||
const idx_str: uint = 16u;
|
||||
|
||||
const idx_type: uint = 17u;
|
||||
|
||||
const idx_send_type: uint = 18u;
|
||||
|
||||
const idx_bot: uint = 19u;
|
||||
|
||||
const idx_first_others: uint = 20u;
|
||||
|
||||
type type_store = interner::interner<@raw_t>;
|
||||
@ -462,7 +445,7 @@ fn mk_raw_ty(cx: ctxt, st: sty) -> @raw_t {
|
||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) |
|
||||
ty_str | ty_type | ty_send_type | ty_opaque_closure_ptr(_) {}
|
||||
ty_param(_, _) { has_params = true; }
|
||||
ty_var(_) { has_vars = true; }
|
||||
ty_var(_) | ty_self(_) { has_vars = true; }
|
||||
ty_enum(_, tys) | ty_iface(_, tys) {
|
||||
for tt: t in tys { derive_flags_t(cx, has_params, has_vars, tt); }
|
||||
}
|
||||
@ -598,6 +581,8 @@ fn mk_res(cx: ctxt, did: ast::def_id, inner: t, tps: [t]) -> t {
|
||||
|
||||
fn mk_var(cx: ctxt, v: int) -> t { ret gen_ty(cx, ty_var(v)); }
|
||||
|
||||
fn mk_self(cx: ctxt, tps: [t]) -> t { ret gen_ty(cx, ty_self(tps)); }
|
||||
|
||||
fn mk_param(cx: ctxt, n: uint, k: def_id) -> t {
|
||||
ret gen_ty(cx, ty_param(n, k));
|
||||
}
|
||||
@ -653,7 +638,6 @@ pure fn ty_name(cx: ctxt, typ: t) -> option<@str> {
|
||||
}
|
||||
|
||||
fn default_arg_mode_for_ty(tcx: ty::ctxt, ty: ty::t) -> ast::rmode {
|
||||
assert !ty::type_contains_vars(tcx, ty);
|
||||
if ty::type_is_immediate(tcx, ty) { ast::by_val }
|
||||
else { ast::by_ref }
|
||||
}
|
||||
@ -664,7 +648,7 @@ fn walk_ty(cx: ctxt, ty: t, f: fn(t)) {
|
||||
ty_str | ty_send_type | ty_type |
|
||||
ty_opaque_closure_ptr(_) | ty_var(_) | ty_param(_, _) {}
|
||||
ty_box(tm) | ty_vec(tm) | ty_ptr(tm) { walk_ty(cx, tm.ty, f); }
|
||||
ty_enum(_, subtys) | ty_iface(_, subtys) {
|
||||
ty_enum(_, subtys) | ty_iface(_, subtys) | ty_self(subtys) {
|
||||
for subty: t in subtys { walk_ty(cx, subty, f); }
|
||||
}
|
||||
ty_rec(fields) {
|
||||
@ -728,6 +712,9 @@ fn fold_ty(cx: ctxt, fld: fold_mode, ty_0: t) -> t {
|
||||
ty_iface(did, subtys) {
|
||||
ty = mk_iface(cx, did, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
|
||||
}
|
||||
ty_self(subtys) {
|
||||
ty = mk_self(cx, vec::map(subtys, {|t| fold_ty(cx, fld, t) }));
|
||||
}
|
||||
ty_rec(fields) {
|
||||
let new_fields: [field] = [];
|
||||
for fl: field in fields {
|
||||
@ -1189,15 +1176,9 @@ fn type_is_pod(cx: ctxt, ty: t) -> bool {
|
||||
result = type_is_pod(cx, substitute_type_params(cx, tps, inner));
|
||||
}
|
||||
ty_constr(subt, _) { result = type_is_pod(cx, subt); }
|
||||
ty_var(_) {
|
||||
cx.sess.bug("ty_var in type_is_pod");
|
||||
}
|
||||
ty_param(_, _) { result = false; }
|
||||
ty_opaque_closure_ptr(_) { result = true; }
|
||||
ty_named(_,_) {
|
||||
cx.sess.bug("ty_named in type_is_pod");
|
||||
}
|
||||
|
||||
_ { cx.sess.bug("unexpected type in type_is_pod"); }
|
||||
}
|
||||
|
||||
ret result;
|
||||
@ -1352,6 +1333,11 @@ fn hash_type_structure(st: sty) -> uint {
|
||||
ty_fn(f) { ret hash_fn(27u, f.inputs, f.output); }
|
||||
ty_var(v) { ret hash_uint(30u, v as uint); }
|
||||
ty_param(pid, _) { ret hash_uint(31u, pid); }
|
||||
ty_self(ts) {
|
||||
let h = 28u;
|
||||
for t in ts { h += (h << 5u) + t; }
|
||||
ret h;
|
||||
}
|
||||
ty_type { ret 32u; }
|
||||
ty_bot { ret 34u; }
|
||||
ty_ptr(mt) { ret hash_subty(35u, mt.ty); }
|
||||
@ -2548,19 +2534,8 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
||||
// Replaces type parameters in the given type using the given list of
|
||||
// substitions.
|
||||
fn substitute_type_params(cx: ctxt, substs: [ty::t], typ: t) -> t {
|
||||
if !type_contains_params(cx, typ) { ret typ; }
|
||||
// Precondition? idx < vec::len(substs)
|
||||
fn substituter(_cx: ctxt, substs: @[ty::t], idx: uint, _did: def_id)
|
||||
-> t {
|
||||
if idx < vec::len(*substs) {
|
||||
ret substs[idx];
|
||||
}
|
||||
else {
|
||||
fail #fmt("Internal error in substituter (substitute_type_params)\
|
||||
%u %u", vec::len(*substs), idx);
|
||||
}
|
||||
}
|
||||
ret fold_ty(cx, fm_param(bind substituter(cx, @substs, _, _)), typ);
|
||||
fold_ty(cx, fm_param({|idx, _id| substs[idx]}), typ)
|
||||
}
|
||||
|
||||
fn def_has_ty_params(def: ast::def) -> bool {
|
||||
|
@ -44,9 +44,7 @@ type dict_map = hashmap<ast::node_id, dict_res>;
|
||||
type ty_table = hashmap<ast::def_id, ty::t>;
|
||||
|
||||
// Used for typechecking the methods of an impl
|
||||
enum self_info {
|
||||
self_impl(ty::t),
|
||||
}
|
||||
enum self_info { self_impl(ty::t) }
|
||||
|
||||
type crate_ctxt = {mutable self_infos: [self_info],
|
||||
impl_map: resolve::impl_map,
|
||||
@ -118,11 +116,6 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, id.node));
|
||||
ret {bounds: @[], ty: typ};
|
||||
}
|
||||
ast::def_mod(_) {
|
||||
// Hopefully part of a path.
|
||||
// TODO: return a type that's more poisonous, perhaps?
|
||||
ret {bounds: @[], ty: ty::mk_nil(fcx.ccx.tcx)};
|
||||
}
|
||||
ast::def_ty(_) {
|
||||
fcx.ccx.tcx.sess.span_fatal(sp, "expected value but found type");
|
||||
}
|
||||
@ -317,19 +310,34 @@ fn ast_ty_to_ty(tcx: ty::ctxt, mode: mode, &&ast_ty: @ast::ty) -> ty::t {
|
||||
typ = ty::mk_fn(tcx, ty_of_fn_decl(tcx, mode, proto, decl));
|
||||
}
|
||||
ast::ty_path(path, id) {
|
||||
alt tcx.def_map.find(id) {
|
||||
some(ast::def_ty(id)) {
|
||||
alt tcx.def_map.get(id) {
|
||||
ast::def_ty(id) {
|
||||
typ = instantiate(tcx, ast_ty.span, mode, id, path.node.types);
|
||||
}
|
||||
some(ast::def_ty_param(id, n)) {
|
||||
ast::def_ty_param(id, n) {
|
||||
if vec::len(path.node.types) > 0u {
|
||||
tcx.sess.span_err(ast_ty.span, "provided type parameters to \
|
||||
a type parameter");
|
||||
}
|
||||
typ = ty::mk_param(tcx, n, id);
|
||||
}
|
||||
some(_) {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
"found type name used as a variable");
|
||||
ast::def_self(iface_id) {
|
||||
alt tcx.items.get(iface_id.node) {
|
||||
ast_map::node_item(@{node: ast::item_iface(tps, _), _}, _) {
|
||||
if vec::len(tps) != vec::len(path.node.types) {
|
||||
tcx.sess.span_err(ast_ty.span, "incorrect number of type \
|
||||
parameter to self type");
|
||||
}
|
||||
typ = ty::mk_self(tcx, vec::map(path.node.types, {|ast_ty|
|
||||
ast_ty_to_ty(tcx, mode, ast_ty)
|
||||
}));
|
||||
}
|
||||
_ { fail; }
|
||||
}
|
||||
}
|
||||
_ {
|
||||
tcx.sess.span_fatal(ast_ty.span, "internal error in instantiate");
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
"found type name used as a variable");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -588,14 +596,17 @@ fn mk_ty_params(tcx: ty::ctxt, atps: [ast::ty_param])
|
||||
}
|
||||
|
||||
fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
impl_tps: uint, if_m: ty::method, substs: [ty::t]) {
|
||||
impl_tps: uint, if_m: ty::method, substs: [ty::t],
|
||||
self_ty: ty::t) -> ty::t {
|
||||
if impl_m.tps != if_m.tps {
|
||||
tcx.sess.span_err(sp, "method `" + if_m.ident +
|
||||
"` has an incompatible set of type parameters");
|
||||
ty::mk_fn(tcx, impl_m.fty)
|
||||
} else {
|
||||
let auto_modes = vec::map2(impl_m.fty.inputs, if_m.fty.inputs, {|i, f|
|
||||
alt ty::struct(tcx, f.ty) {
|
||||
ty::ty_param(0u, _) {
|
||||
ty::ty_param(_, _) | ty::ty_self(_)
|
||||
if alt i.mode { ast::infer(_) { true } _ { false } } {
|
||||
{mode: ast::expl(ast::by_ref) with i}
|
||||
}
|
||||
_ { i }
|
||||
@ -606,19 +617,81 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span, impl_m: ty::method,
|
||||
let substs = substs + vec::init_fn(vec::len(*if_m.tps), {|i|
|
||||
ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
|
||||
});
|
||||
let if_fty = ty::substitute_type_params(tcx, substs,
|
||||
ty::mk_fn(tcx, if_m.fty));
|
||||
let if_fty = ty::mk_fn(tcx, if_m.fty);
|
||||
if_fty = ty::substitute_type_params(tcx, substs, if_fty);
|
||||
if ty::type_contains_vars(tcx, if_fty) {
|
||||
if_fty = fixup_self_in_method_ty(tcx, if_fty, substs,
|
||||
self_full(self_ty, impl_tps));
|
||||
}
|
||||
alt ty::unify::unify(impl_fty, if_fty, ty::unify::precise, tcx) {
|
||||
ty::unify::ures_err(err) {
|
||||
tcx.sess.span_err(sp, "method `" + if_m.ident +
|
||||
"` has an incompatible type: " +
|
||||
ty::type_err_to_str(err));
|
||||
impl_fty
|
||||
}
|
||||
_ {}
|
||||
ty::unify::ures_ok(tp) { tp }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum self_subst { self_param(ty::t, @fn_ctxt, span), self_full(ty::t, uint) }
|
||||
|
||||
// Mangles an iface method ty to make its self type conform to the self type
|
||||
// of a specific impl or bounded type parameter. This is rather involved
|
||||
// because the type parameters of ifaces and impls are not required to line up
|
||||
// (an impl can have less or more parameters than the iface it implements), so
|
||||
// some mangling of the substituted types is required.
|
||||
fn fixup_self_in_method_ty(cx: ty::ctxt, mty: ty::t, m_substs: [ty::t],
|
||||
self: self_subst) -> ty::t {
|
||||
if ty::type_contains_vars(cx, mty) {
|
||||
ty::fold_ty(cx, ty::fm_general(fn@(t: ty::t) -> ty::t {
|
||||
alt ty::struct(cx, t) {
|
||||
ty::ty_self(tps) {
|
||||
if vec::len(tps) > 0u {
|
||||
// Move the substs into the type param system of the
|
||||
// context.
|
||||
let substs = vec::map(tps, {|t|
|
||||
let f = fixup_self_in_method_ty(cx, t, m_substs,
|
||||
self);
|
||||
ty::substitute_type_params(cx, m_substs, f)
|
||||
});
|
||||
alt self {
|
||||
self_param(t, fcx, sp) {
|
||||
// Simply ensure that the type parameters for the self
|
||||
// type match the context.
|
||||
vec::iter2(substs, m_substs) {|s, ms|
|
||||
demand::simple(fcx, sp, s, ms);
|
||||
}
|
||||
t
|
||||
}
|
||||
self_full(selfty, impl_n_tps) {
|
||||
// Add extra substs for impl type parameters.
|
||||
while vec::len(substs) < impl_n_tps {
|
||||
substs += [ty::mk_param(cx, vec::len(substs),
|
||||
{crate: 0, node: 0})];
|
||||
}
|
||||
// And for method type parameters.
|
||||
let method_n_tps =
|
||||
(vec::len(m_substs) - vec::len(tps)) as int;
|
||||
if method_n_tps > 0 {
|
||||
substs += vec::tail_n(m_substs, vec::len(m_substs)
|
||||
- (method_n_tps as uint));
|
||||
}
|
||||
// And then instantiate the self type using all those.
|
||||
ty::substitute_type_params(cx, substs, selfty)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alt self { self_param(t, _, _) | self_full(t, _) { t } }
|
||||
}
|
||||
}
|
||||
_ { t }
|
||||
}
|
||||
}), mty)
|
||||
} else { mty }
|
||||
}
|
||||
|
||||
// Item collection - a pair of bootstrap passes:
|
||||
//
|
||||
// (1) Collect the IDs of all type items (typedefs) and store them in a table.
|
||||
@ -682,15 +755,15 @@ mod collect {
|
||||
for m in ms {
|
||||
let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
|
||||
let mty = ty_of_method(cx.tcx, m_collect, m);
|
||||
my_methods += [mty];
|
||||
my_methods += [{mty: mty, id: m.id, span: m.span}];
|
||||
let fty = ty::mk_fn(cx.tcx, mty.fty);
|
||||
cx.tcx.tcache.insert(local_def(m.id),
|
||||
{bounds: @(*i_bounds + *bounds),
|
||||
ty: fty});
|
||||
write_ty(cx.tcx, m.id, fty);
|
||||
}
|
||||
write_ty(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
|
||||
selfty));
|
||||
let selfty = ast_ty_to_ty(cx.tcx, m_collect, selfty);
|
||||
write_ty(cx.tcx, it.id, selfty);
|
||||
alt ifce {
|
||||
some(t) {
|
||||
let iface_ty = ast_ty_to_ty(cx.tcx, m_collect, t);
|
||||
@ -700,10 +773,18 @@ mod collect {
|
||||
ty::ty_iface(did, tys) {
|
||||
for if_m in *ty::iface_methods(cx.tcx, did) {
|
||||
alt vec::find(my_methods,
|
||||
{|m| if_m.ident == m.ident}) {
|
||||
some(m) {
|
||||
compare_impl_method(cx.tcx, t.span, m,
|
||||
vec::len(tps), if_m, tys);
|
||||
{|m| if_m.ident == m.mty.ident}) {
|
||||
some({mty: m, id, span}) {
|
||||
let mt = compare_impl_method(
|
||||
cx.tcx, span, m, vec::len(tps), if_m, tys,
|
||||
selfty);
|
||||
let old = cx.tcx.tcache.get(local_def(id));
|
||||
if old.ty != mt {
|
||||
cx.tcx.tcache.insert(local_def(id),
|
||||
{bounds: old.bounds,
|
||||
ty: mt});
|
||||
write_ty(cx.tcx, id, mt);
|
||||
}
|
||||
}
|
||||
none {
|
||||
cx.tcx.sess.span_err(t.span, "missing method `" +
|
||||
@ -1459,12 +1540,54 @@ fn impl_self_ty(tcx: ty::ctxt, did: ast::def_id) -> {n_tps: uint, ty: ty::t} {
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
name: ast::ident, ty: ty::t, sp: span)
|
||||
-> option<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
|
||||
origin: method_origin}> {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
fn lookup_method(fcx: @fn_ctxt, expr: @ast::expr, node_id: ast::node_id,
|
||||
name: ast::ident, ty: ty::t, tps: [ty::t])
|
||||
-> option::t<method_origin> {
|
||||
alt lookup_method_inner(fcx, expr, name, ty) {
|
||||
some({method_ty: fty, n_tps: method_n_tps, substs, origin, self_sub}) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
let substs = substs, n_tps = vec::len(substs), n_tys = vec::len(tps);
|
||||
let has_self = ty::type_contains_params(tcx, fty);
|
||||
if method_n_tps + n_tps > 0u {
|
||||
if n_tys > 0u {
|
||||
if n_tys != method_n_tps {
|
||||
tcx.sess.span_fatal
|
||||
(expr.span, "incorrect number of type \
|
||||
parameters given for this method");
|
||||
|
||||
}
|
||||
substs += tps;
|
||||
} else {
|
||||
substs += vec::init_fn(method_n_tps, {|_i|
|
||||
ty::mk_var(tcx, next_ty_var_id(fcx))
|
||||
});
|
||||
};
|
||||
write_ty_substs(tcx, node_id, fty, substs);
|
||||
} else if n_tys > 0u {
|
||||
tcx.sess.span_fatal(expr.span,
|
||||
"this method does not take type \
|
||||
parameters");
|
||||
} else {
|
||||
write_ty(tcx, node_id, fty);
|
||||
}
|
||||
if has_self && !option::is_none(self_sub) {
|
||||
let fty = ty::node_id_to_type(tcx, node_id);
|
||||
fty = fixup_self_in_method_ty(
|
||||
tcx, fty, substs, option::get(self_sub));
|
||||
write_ty(tcx, node_id, fty);
|
||||
}
|
||||
some(origin)
|
||||
}
|
||||
none { none }
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
|
||||
name: ast::ident, ty: ty::t)
|
||||
-> option::t<{method_ty: ty::t, n_tps: uint, substs: [ty::t],
|
||||
origin: method_origin,
|
||||
self_sub: option::t<self_subst>}> {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
// First, see whether this is an interface-bounded parameter
|
||||
alt ty::struct(tcx, ty) {
|
||||
ty::ty_param(n, did) {
|
||||
@ -1473,11 +1596,8 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
alt bound {
|
||||
ty::bound_iface(t) {
|
||||
let (iid, tps) = alt ty::struct(tcx, t) {
|
||||
ty::ty_iface(i, tps) { (i, tps) }
|
||||
_ {
|
||||
tcx.sess.span_bug(sp, "Undocument invariant in \
|
||||
lookup_method");
|
||||
}
|
||||
ty::ty_iface(i, tps) { (i, tps) }
|
||||
_ { fail; }
|
||||
};
|
||||
let ifce_methods = ty::iface_methods(tcx, iid);
|
||||
alt vec::position(*ifce_methods, {|m| m.ident == name}) {
|
||||
@ -1486,7 +1606,9 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
ret some({method_ty: ty::mk_fn(tcx, m.fty),
|
||||
n_tps: vec::len(*m.tps),
|
||||
substs: tps,
|
||||
origin: method_param(iid, pos, n, bound_n)});
|
||||
origin: method_param(iid, pos, n, bound_n),
|
||||
self_sub: some(self_param(ty, fcx, expr.span))
|
||||
});
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
@ -1501,10 +1623,17 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
let i = 0u;
|
||||
for m in *ty::iface_methods(tcx, did) {
|
||||
if m.ident == name {
|
||||
ret some({method_ty: ty::mk_fn(tcx, m.fty),
|
||||
let fty = ty::mk_fn(tcx, m.fty);
|
||||
if ty::type_contains_vars(tcx, fty) {
|
||||
tcx.sess.span_fatal(
|
||||
expr.span, "can not call a method that contains a \
|
||||
self type through a boxed iface");
|
||||
}
|
||||
ret some({method_ty: fty,
|
||||
n_tps: vec::len(*m.tps),
|
||||
substs: tps,
|
||||
origin: method_iface(i)});
|
||||
origin: method_iface(i),
|
||||
self_sub: none});
|
||||
}
|
||||
i += 1u;
|
||||
}
|
||||
@ -1527,7 +1656,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
}
|
||||
|
||||
let result = none;
|
||||
std::list::iter(isc) {|impls|
|
||||
std::list::iter(fcx.ccx.impl_map.get(expr.id)) {|impls|
|
||||
if option::is_some(result) { ret; }
|
||||
for @{did, methods, _} in *impls {
|
||||
alt vec::find(methods, {|m| m.ident == name}) {
|
||||
@ -1541,13 +1670,14 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
|
||||
if option::is_some(result) {
|
||||
// FIXME[impl] score specificity to resolve ambiguity?
|
||||
tcx.sess.span_err(
|
||||
sp, "multiple applicable methods in scope");
|
||||
expr.span, "multiple applicable methods in scope");
|
||||
} else {
|
||||
result = some({
|
||||
method_ty: ty_from_did(tcx, m.did),
|
||||
n_tps: m.n_tps,
|
||||
substs: vars,
|
||||
origin: method_static(m.did)
|
||||
origin: method_static(m.did),
|
||||
self_sub: none
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1763,13 +1893,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||
}
|
||||
}
|
||||
fn lookup_op_method(fcx: @fn_ctxt, op_ex: @ast::expr, self_t: ty::t,
|
||||
opname: str,
|
||||
args: [option<@ast::expr>]) -> option<ty::t> {
|
||||
let isc = fcx.ccx.impl_map.get(op_ex.id);
|
||||
alt lookup_method(fcx, isc, opname, self_t, op_ex.span) {
|
||||
some({method_ty, n_tps: 0u, substs, origin}) {
|
||||
let callee_id = ast_util::op_expr_callee_id(op_ex);
|
||||
write_ty_substs(fcx.ccx.tcx, callee_id, method_ty, substs);
|
||||
opname: str, args: [option::t<@ast::expr>])
|
||||
-> option::t<ty::t> {
|
||||
let callee_id = ast_util::op_expr_callee_id(op_ex);
|
||||
alt lookup_method(fcx, op_ex, callee_id, opname, self_t, []) {
|
||||
some(origin) {
|
||||
let method_ty = ty::node_id_to_type(fcx.ccx.tcx, callee_id);
|
||||
check_call_or_bind(fcx, op_ex.span, method_ty, args);
|
||||
fcx.ccx.method_map.insert(op_ex.id, origin);
|
||||
some(ty::ty_fn_ret(fcx.ccx.tcx, method_ty))
|
||||
@ -2235,36 +2364,9 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
|
||||
_ {}
|
||||
}
|
||||
if !handled {
|
||||
let iscope = fcx.ccx.impl_map.get(expr.id);
|
||||
alt lookup_method(fcx, iscope, field, expr_t, expr.span) {
|
||||
some({method_ty: fty, n_tps: method_n_tps, substs, origin}) {
|
||||
let substs = substs, n_tps = vec::len(substs);
|
||||
if method_n_tps + n_tps > 0u {
|
||||
if n_tys > 0u {
|
||||
if n_tys != method_n_tps {
|
||||
tcx.sess.span_fatal
|
||||
(expr.span, "incorrect number of type \
|
||||
parameters given for this method");
|
||||
|
||||
}
|
||||
for ty in tys {
|
||||
substs += [ast_ty_to_ty_crate(fcx.ccx, ty)];
|
||||
}
|
||||
} else {
|
||||
let i = 0u;
|
||||
while i < method_n_tps {
|
||||
substs += [ty::mk_var(tcx, next_ty_var_id(fcx))];
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
write_ty_substs(fcx.ccx.tcx, id, fty, substs);
|
||||
} else if n_tys > 0u {
|
||||
tcx.sess.span_fatal(expr.span,
|
||||
"this method does not take type \
|
||||
parameters");
|
||||
} else {
|
||||
write_ty(tcx, id, fty);
|
||||
}
|
||||
let tps = vec::map(tys, {|ty| ast_ty_to_ty_crate(fcx.ccx, ty)});
|
||||
alt lookup_method(fcx, expr, expr.id, field, expr_t, tps) {
|
||||
some(origin) {
|
||||
fcx.ccx.method_map.insert(id, origin);
|
||||
}
|
||||
none {
|
||||
|
@ -259,9 +259,7 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ {
|
||||
item_impl(tps, option::map(ifce, fld.fold_ty), fld.fold_ty(ty),
|
||||
vec::map(methods, fld.fold_method))
|
||||
}
|
||||
item_iface(tps, methods) {
|
||||
item_iface(tps, methods)
|
||||
}
|
||||
item_iface(tps, methods) { item_iface(tps, methods) }
|
||||
item_res(decl, typms, body, did, cid) {
|
||||
item_res(fold_fn_decl(decl, fld), typms, fld.fold_block(body),
|
||||
did, cid)
|
||||
|
@ -579,4 +579,4 @@ mod test {
|
||||
let doc = extract::from_srv(srv, "");
|
||||
run(srv, doc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user