diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index dc7496dddb35..680129aa778e 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -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)); } diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index a9baa4f74702..9570669d2030 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -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&"); } diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs index 2ba68b927f0a..043e28b57c04 100644 --- a/src/comp/middle/resolve.rs +++ b/src/comp/middle/resolve.rs @@ -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); } diff --git a/src/comp/middle/shape.rs b/src/comp/middle/shape.rs index 500a8591516f..6d94552db7a5 100644 --- a/src/comp/middle/shape.rs +++ b/src/comp/middle/shape.rs @@ -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"); } } diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs index 37e410e9d5c9..6868c233cff3 100644 --- a/src/comp/middle/trans/base.rs +++ b/src/comp/middle/trans/base.rs @@ -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); + } } _ { } } diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs index 18ee215b2dcd..c2f0d655da0f 100644 --- a/src/comp/middle/trans/impl.rs +++ b/src/comp/middle/trans/impl.rs @@ -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"); - } + _ {} } } } diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index 0826eda4cf38..0f03d273b4c5 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; 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 { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 50f5dd210073..adc276ee3359 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -44,9 +44,7 @@ type dict_map = hashmap; type ty_table = hashmap; // 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 { + 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}> { + 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 { - 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 { + 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 { diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 24c0a7446d4a..6402571eda5d 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -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) diff --git a/src/rustdoc/tystr_pass.rs b/src/rustdoc/tystr_pass.rs index 58cbff8edb28..99137629db66 100644 --- a/src/rustdoc/tystr_pass.rs +++ b/src/rustdoc/tystr_pass.rs @@ -579,4 +579,4 @@ mod test { let doc = extract::from_srv(srv, ""); run(srv, doc) } -} \ No newline at end of file +}