diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 435f52b4bf8..4b945494293 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -118,7 +118,9 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]}; #[auto_deserialize] enum def { def_fn(def_id, purity), - def_static_method(def_id, purity), + def_static_method(/* method */ def_id, + /* trait */ def_id, + purity), def_self(node_id), def_mod(def_id), def_foreign_mod(def_id), @@ -150,9 +152,10 @@ impl def : cmp::Eq { _ => false } } - def_static_method(e0a, e1a) => { + def_static_method(e0a, e1a, e2a) => { match (*other) { - def_static_method(e0b, e1b) => e0a == e0b && e1a == e1b, + def_static_method(e0b, e1b, e2b) => + e0a == e0b && e1a == e1b && e2a == e2b, _ => false } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 31ddcfafa2d..35b9e8d40c0 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -54,7 +54,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} { pure fn def_id_of_def(d: def) -> def_id { match d { - def_fn(id, _) | def_static_method(id, _) | def_mod(id) | + def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | def_use(id) | def_class(id, _) => { diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 4c647d41880..38838120a10 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -178,6 +178,12 @@ fn item_parent_item(d: ebml::Doc) -> Option { None } +fn item_reqd_and_translated_parent_item(cnum: ast::crate_num, + d: ebml::Doc) -> ast::def_id { + let trait_did = item_parent_item(d).expect(~"item without parent"); + {crate: cnum, node: trait_did.node} +} + fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id { let tagdoc = ebml::get_doc(d, tag_def_id); return translate_def_id(cdata, ebml::with_doc_data(tagdoc, @@ -297,35 +303,39 @@ fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident { } fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) - -> def_like { + -> def_like +{ let fam = item_family(item); match fam { - Const => dl_def(ast::def_const(did)), - Class => dl_def(ast::def_class(did, true)), - Struct => dl_def(ast::def_class(did, false)), - UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)), - Fn => dl_def(ast::def_fn(did, ast::impure_fn)), - PureFn => dl_def(ast::def_fn(did, ast::pure_fn)), - ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)), - UnsafeStaticMethod => dl_def(ast::def_static_method(did, - ast::unsafe_fn)), - StaticMethod => dl_def(ast::def_static_method(did, ast::impure_fn)), - PureStaticMethod => dl_def(ast::def_static_method(did, ast::pure_fn)), - Type | ForeignType => dl_def(ast::def_ty(did)), - Mod => dl_def(ast::def_mod(did)), - ForeignMod => dl_def(ast::def_foreign_mod(did)), - Variant => { - match item_parent_item(item) { - Some(t) => { - let tid = {crate: cnum, node: t.node}; - dl_def(ast::def_variant(tid, did)) - } - None => fail ~"item_to_def_like: enum item has no parent" - } - } - Trait | Enum => dl_def(ast::def_ty(did)), - Impl => dl_impl(did), - PublicField | PrivateField | InheritedField => dl_field, + Const => dl_def(ast::def_const(did)), + Class => dl_def(ast::def_class(did, true)), + Struct => dl_def(ast::def_class(did, false)), + UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)), + Fn => dl_def(ast::def_fn(did, ast::impure_fn)), + PureFn => dl_def(ast::def_fn(did, ast::pure_fn)), + ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)), + UnsafeStaticMethod => { + let trait_did = item_reqd_and_translated_parent_item(cnum, item); + dl_def(ast::def_static_method(did, trait_did, ast::unsafe_fn)) + } + StaticMethod => { + let trait_did = item_reqd_and_translated_parent_item(cnum, item); + dl_def(ast::def_static_method(did, trait_did, ast::impure_fn)) + } + PureStaticMethod => { + let trait_did = item_reqd_and_translated_parent_item(cnum, item); + dl_def(ast::def_static_method(did, trait_did, ast::pure_fn)) + } + Type | ForeignType => dl_def(ast::def_ty(did)), + Mod => dl_def(ast::def_mod(did)), + ForeignMod => dl_def(ast::def_foreign_mod(did)), + Variant => { + let enum_did = item_reqd_and_translated_parent_item(cnum, item); + dl_def(ast::def_variant(enum_did, did)) + } + Trait | Enum => dl_def(ast::def_ty(did)), + Impl => dl_impl(did), + PublicField | PrivateField | InheritedField => dl_field, } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index f188d8ee5d8..63a7ce1ac74 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -794,6 +794,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer, ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(ty_m.id)); + encode_parent_item(ebml_w, local_def(item.id)); encode_name(ecx, ebml_w, ty_m.ident); encode_family(ebml_w, purity_static_method_family(ty_m.purity)); diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 103f1eecf87..15b20c41b67 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -345,8 +345,8 @@ impl ast::def: tr { fn tr(xcx: extended_decode_ctxt) -> ast::def { match self { ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) } - ast::def_static_method(did, p) => { - ast::def_static_method(did.tr(xcx), p) + ast::def_static_method(did, did2, p) => { + ast::def_static_method(did.tr(xcx), did2.tr(xcx), p) } ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) } ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 18880fe917b..314dea1b576 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -1126,6 +1126,7 @@ impl Resolver { self.add_child(ident, new_parent, ~[ValueNS], ty_m.span); let def = def_static_method(local_def(ty_m.id), + local_def(item.id), ty_m.purity); (*method_name_bindings).define_value (Public, def, ty_m.span); diff --git a/src/rustc/middle/trans/callee.rs b/src/rustc/middle/trans/callee.rs index c851c5bc725..aa998fb7b92 100644 --- a/src/rustc/middle/trans/callee.rs +++ b/src/rustc/middle/trans/callee.rs @@ -78,8 +78,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_fn(did, _) => { fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id)) } - ast::def_static_method(did, _) => { - fn_callee(bcx, meth::trans_static_method_callee(bcx, did, + ast::def_static_method(impl_did, trait_did, _) => { + fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did, + trait_did, ref_expr.id)) } ast::def_variant(tid, vid) => { diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index 4e50f7a848e..c841d9bd913 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -641,10 +641,11 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id); return fn_data_to_datum(bcx, did, fn_data, lldest); } - ast::def_static_method(did, _) => { - let fn_data = meth::trans_static_method_callee(bcx, did, + ast::def_static_method(impl_did, trait_did, _) => { + let fn_data = meth::trans_static_method_callee(bcx, impl_did, + trait_did, ref_expr.id); - return fn_data_to_datum(bcx, did, fn_data, lldest); + return fn_data_to_datum(bcx, impl_did, fn_data, lldest); } ast::def_variant(tid, vid) => { if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u { diff --git a/src/rustc/middle/trans/meth.rs b/src/rustc/middle/trans/meth.rs index d8a2fda4d14..96cf7fabd1f 100644 --- a/src/rustc/middle/trans/meth.rs +++ b/src/rustc/middle/trans/meth.rs @@ -162,11 +162,50 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id, fn trans_static_method_callee(bcx: block, method_id: ast::def_id, + trait_id: ast::def_id, callee_id: ast::node_id) -> FnData { let _icx = bcx.insn_ctxt("impl::trans_static_method_callee"); let ccx = bcx.ccx(); + debug!("trans_static_method_callee(method_id=%?, trait_id=%s, \ + callee_id=%?)", + method_id, + ty::item_path_str(bcx.tcx(), trait_id), + callee_id); + let _indenter = indenter(); + + // When we translate a static fn defined in a trait like: + // + // trait Trait { + // static fn foo(...) {...} + // } + // + // this winds up being translated as something like: + // + // fn foo,M1...Mn>(...) {...} + // + // So when we see a call to this function foo, we have to figure + // out which impl the `Trait` bound on the type `self` was + // bound to. Due to the fact that we use a flattened list of + // impls, one per bound, this means we have to total up the bounds + // found on the type parametesr T1...Tn to find the index of the + // one we are interested in. + let bound_index = { + let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id); + let mut index = 0; + for trait_polyty.bounds.each |param_bounds| { + for param_bounds.each |param_bound| { + match *param_bound { + ty::bound_trait(_) => { index += 1; } + ty::bound_copy | ty::bound_owned | + ty::bound_send | ty::bound_const => {} + } + } + } + index + }; + let mname = if method_id.crate == ast::local_crate { match bcx.tcx().items.get(method_id.node) { ast_map::node_trait_method(trait_method, _, _) => { @@ -187,9 +226,7 @@ fn trans_static_method_callee(bcx: block, let vtbls = resolve_vtables_in_fn_ctxt( bcx.fcx, ccx.maps.vtable_map.get(callee_id)); - // FIXME(#3446) -- I am pretty sure index 0 is not the right one, - // if the static method is implemented on a generic type. (NDM) - match vtbls[0] { + match vtbls[bound_index] { typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => { let mth_id = method_with_name(bcx.ccx(), impl_did, mname); diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index c1ab29758f2..bf0ca36dddf 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -2403,13 +2403,13 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) -> } ast::def_fn(id, ast::unsafe_fn) | - ast::def_static_method(id, ast::unsafe_fn) => { + ast::def_static_method(id, _, ast::unsafe_fn) => { // Unsafe functions can only be touched in an unsafe context fcx.require_unsafe(sp, ~"access to unsafe function"); return ty::lookup_item_type(fcx.ccx.tcx, id); } - ast::def_fn(id, _) | ast::def_static_method(id, _) | + ast::def_fn(id, _) | ast::def_static_method(id, _, _) | ast::def_const(id) | ast::def_variant(_, id) | ast::def_class(id, _) => { return ty::lookup_item_type(fcx.ccx.tcx, id); diff --git a/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs new file mode 100644 index 00000000000..ac00f6a645b --- /dev/null +++ b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs @@ -0,0 +1,25 @@ +trait Deserializer { + fn read_int() -> int; +} + +trait Deserializable { + static fn deserialize(d: &D) -> self; +} + +impl int: Deserializable { + static fn deserialize(d: &D) -> int { + return d.read_int(); + } +} + +struct FromThinAir { dummy: () } + +impl FromThinAir: Deserializer { + fn read_int() -> int { 22 } +} + +fn main() { + let d = FromThinAir { dummy: () }; + let i: int = deserialize(&d); + assert i == 22; +} \ No newline at end of file