diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index d940b6d6667f..46a744572749 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -732,6 +732,11 @@ impl Ord for Sign { } } +impl TotalEq for Sign { + fn equals(&self, other: &Sign) -> bool { + *self == *other + } +} impl TotalOrd for Sign { fn cmp(&self, other: &Sign) -> Ordering { diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs index 6733599d1ea2..ff14009e5561 100644 --- a/src/libextra/num/rational.rs +++ b/src/libextra/num/rational.rs @@ -110,6 +110,25 @@ cmp_impl!(impl TotalEq, equals) cmp_impl!(impl Ord, lt, gt, le, ge) cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) +impl Orderable for Ratio { + #[inline] + fn min(&self, other: &Ratio) -> Ratio { + if *self < *other { self.clone() } else { other.clone() } + } + + #[inline] + fn max(&self, other: &Ratio) -> Ratio { + if *self > *other { self.clone() } else { other.clone() } + } + + #[inline] + fn clamp(&self, mn: &Ratio, mx: &Ratio) -> Ratio { + if *self > *mx { mx.clone()} else + if *self < *mn { mn.clone() } else { self.clone() } + } +} + + /* Arithmetic */ // a/b * c/d = (a*c)/(b*d) impl diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 645188ce5a4d..1c5d202d4d95 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f; pub static tag_misc_info_crate_items: uint = 0x80; pub static tag_item_method_provided_source: uint = 0x81; +pub static tag_item_impl_vtables: uint = 0x82; pub struct LinkMeta { name: @str, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 97344ee91adb..6f7feae4479b 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -16,6 +16,7 @@ use metadata::cstore; use metadata::decoder; use metadata; use middle::ty; +use middle::typeck; use std::vec; use reader = extra::ebml::reader; @@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt, decoder::get_impl_trait(cdata, def.node, tcx) } +// Given a def_id for an impl, return information about its vtables +pub fn get_impl_vtables(tcx: ty::ctxt, + def: ast::def_id) -> typeck::impl_res { + let cstore = tcx.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_impl_vtables(cdata, def.node, tcx) +} + pub fn get_impl_method(cstore: @mut cstore::CStore, def: ast::def_id, mname: ast::ident) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 480661b263ab..01c5019154f5 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -21,6 +21,9 @@ use metadata::tydecode::{parse_ty_data, parse_def_id, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::ty; +use middle::typeck; +use middle::astencode::vtable_decoder_helpers; + use std::hash::HashUtil; use std::uint; @@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd, } } +pub fn get_impl_vtables(cdata: cmd, + id: ast::node_id, + tcx: ty::ctxt) -> typeck::impl_res +{ + let item_doc = lookup_item(id, cdata.data); + let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables); + let mut decoder = reader::Decoder(vtables_doc); + + typeck::impl_res { + trait_vtables: decoder.read_vtable_res(tcx, cdata), + self_vtables: decoder.read_vtable_param_res(tcx, cdata) + } +} + + pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, name: ast::ident) -> Option { let items = reader::get_doc(reader::Doc(cdata.data), tag_items); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 8d1f086b3a77..c216e8d23865 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -17,6 +17,8 @@ use metadata::decoder; use metadata::tyencode; use middle::ty::{node_id_to_type, lookup_item_type}; use middle::ty; +use middle::typeck; +use middle::astencode; use middle; use std::hash::HashUtil; @@ -161,6 +163,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, ebml_w.end_tag(); } +fn encode_impl_vtables(ebml_w: &mut writer::Encoder, + ecx: &EncodeContext, + vtables: &typeck::impl_res) { + ebml_w.start_tag(tag_item_impl_vtables); + astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables); + astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables); + ebml_w.end_tag(); +} + // Item info table encoding fn encode_family(ebml_w: &mut writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); @@ -1008,6 +1019,8 @@ fn encode_info_for_item(ecx: &EncodeContext, let trait_ref = ty::node_id_to_trait_ref( tcx, ast_trait_ref.ref_id); encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); + let impl_vtables = ty::lookup_impl_vtables(tcx, def_id); + encode_impl_vtables(ebml_w, ecx, &impl_vtables); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index f3e0779475cc..bf39be407c52 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -250,6 +250,8 @@ impl def_id_encoder_helpers for S { trait def_id_decoder_helpers { fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id; } impl def_id_decoder_helpers for D { @@ -257,6 +259,12 @@ impl def_id_decoder_helpers for D { let did: ast::def_id = Decodable::decode(self); did.tr(xcx) } + + fn read_def_id_noxcx(&mut self, + cdata: @cstore::crate_metadata) -> ast::def_id { + let did: ast::def_id = Decodable::decode(self); + decoder::translate_def_id(cdata, did) + } } // ______________________________________________________________________ @@ -582,12 +590,6 @@ impl tr for method_origin { typeck::method_trait(did, m, vstore) => { typeck::method_trait(did.tr(xcx), m, vstore) } - typeck::method_self(did, m) => { - typeck::method_self(did.tr(xcx), m) - } - typeck::method_super(trait_did, m) => { - typeck::method_super(trait_did.tr(xcx), m) - } } } } @@ -595,7 +597,7 @@ impl tr for method_origin { // ______________________________________________________________________ // Encoding and decoding vtable_res -fn encode_vtable_res(ecx: &e::EncodeContext, +pub fn encode_vtable_res(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, dr: typeck::vtable_res) { // can't autogenerate this code because automatic code of @@ -603,13 +605,20 @@ fn encode_vtable_res(ecx: &e::EncodeContext, // hand-written encoding routines combine with auto-generated // ones. perhaps we should fix this. do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| { - do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| { - encode_vtable_origin(ecx, ebml_w, vtable_origin) - } + encode_vtable_param_res(ecx, ebml_w, *param_tables); } } -fn encode_vtable_origin(ecx: &e::EncodeContext, +pub fn encode_vtable_param_res(ecx: &e::EncodeContext, + ebml_w: &mut writer::Encoder, + param_tables: typeck::vtable_param_res) { + do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } +} + + +pub fn encode_vtable_origin(ecx: &e::EncodeContext, ebml_w: &mut writer::Encoder, vtable_origin: &typeck::vtable_origin) { do ebml_w.emit_enum("vtable_origin") |ebml_w| { @@ -630,40 +639,46 @@ fn encode_vtable_origin(ecx: &e::EncodeContext, typeck::vtable_param(pn, bn) => { do ebml_w.emit_enum_variant("vtable_param", 1u, 2u) |ebml_w| { do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { - ebml_w.emit_uint(pn); + pn.encode(ebml_w); } do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { ebml_w.emit_uint(bn); } } } - typeck::vtable_self(def_id) => { - do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| { - do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { - ebml_w.emit_def_id(def_id) - } - } - } } } } -trait vtable_decoder_helpers { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) +pub trait vtable_decoder_helpers { + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res; - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res; + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { - fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_res { @self.read_to_vec(|this| - @this.read_to_vec(|this| - this.read_vtable_origin(xcx))) + this.read_vtable_param_res(tcx, cdata)) } - fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + fn read_vtable_param_res(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) + -> typeck::vtable_param_res { + @self.read_to_vec(|this| + this.read_vtable_origin(tcx, cdata)) + } + + fn read_vtable_origin(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { do this.read_enum_variant(["vtable_static", @@ -674,33 +689,26 @@ impl vtable_decoder_helpers for reader::Decoder { 0 => { typeck::vtable_static( do this.read_enum_variant_arg(0u) |this| { - this.read_def_id(xcx) + this.read_def_id_noxcx(cdata) }, do this.read_enum_variant_arg(1u) |this| { - this.read_tys(xcx) + this.read_tys_noxcx(tcx, cdata) }, do this.read_enum_variant_arg(2u) |this| { - this.read_vtable_res(xcx) + this.read_vtable_res(tcx, cdata) } ) } 1 => { typeck::vtable_param( do this.read_enum_variant_arg(0u) |this| { - this.read_uint() + Decodable::decode(this) }, do this.read_enum_variant_arg(1u) |this| { this.read_uint() } ) } - 2 => { - typeck::vtable_self( - do this.read_enum_variant_arg(0u) |this| { - this.read_def_id(xcx) - } - ) - } // hard to avoid - user input _ => fail!("bad enum variant") } @@ -995,9 +1003,35 @@ trait ebml_decoder_decoder_helpers { source: DefIdSource, did: ast::def_id) -> ast::def_id; + + // Versions of the type reading functions that don't need the full + // ExtendedDecodeContext. + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t; + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t]; } impl ebml_decoder_decoder_helpers for reader::Decoder { + fn read_ty_noxcx(&mut self, + tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t { + do self.read_opaque |_, doc| { + tydecode::parse_ty_data( + *doc.data, + cdata.cnum, + doc.start, + tcx, + |_, id| decoder::translate_def_id(cdata, id)) + } + } + + fn read_tys_noxcx(&mut self, + tcx: ty::ctxt, + cdata: @cstore::crate_metadata) -> ~[ty::t] { + self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) ) + } + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1160,8 +1194,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, val_dsr.read_method_map_entry(xcx)); } c::tag_table_vtable_map => { - dcx.maps.vtable_map.insert(id, - val_dsr.read_vtable_res(xcx)); + dcx.maps.vtable_map.insert( + id, + val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata)); } c::tag_table_adjustments => { let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 1ea32b3f4046..e768a6d687c2 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -15,8 +15,7 @@ use metadata::csearch; use middle::ty::{ty_struct, ty_enum}; use middle::ty; -use middle::typeck::{method_map, method_origin, method_param, method_self}; -use middle::typeck::{method_super}; +use middle::typeck::{method_map, method_origin, method_param}; use middle::typeck::{method_static, method_trait}; use std::util::ignore; @@ -291,9 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, method_num: method_num, _ }) | - method_trait(trait_id, method_num, _) | - method_self(trait_id, method_num) | - method_super(trait_id, method_num) => { + method_trait(trait_id, method_num, _) => { if trait_id.crate == local_crate { match tcx.items.find(&trait_id.node) { Some(&node_item(item, _)) => { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index d64615e5dc7b..057e2ae531c6 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -193,30 +193,15 @@ pub fn trans_fn_ref_with_vtables_to_callee( type_params, vtables))} } -fn get_impl_resolutions(bcx: @mut Block, - impl_id: ast::def_id) - -> typeck::vtable_res { - if impl_id.crate == ast::local_crate { - bcx.ccx().maps.vtable_map.get_copy(&impl_id.node) - } else { - // XXX: This is a temporary hack to work around not properly - // exporting information about resolutions for impls. - // This doesn't actually work if the trait has param bounds, - // but it does allow us to survive the case when it does not. - let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get(); - @vec::from_elem(trait_ref.substs.tps.len(), @~[]) - } -} - fn resolve_default_method_vtables(bcx: @mut Block, impl_id: ast::def_id, method: &ty::Method, substs: &ty::substs, impl_vtables: Option) - -> typeck::vtable_res { + -> (typeck::vtable_res, typeck::vtable_param_res) { // Get the vtables that the impl implements the trait at - let trait_vtables = get_impl_resolutions(bcx, impl_id); + let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id); // Build up a param_substs that we are going to resolve the // trait_vtables under. @@ -224,11 +209,11 @@ fn resolve_default_method_vtables(bcx: @mut Block, tys: substs.tps.clone(), self_ty: substs.self_ty, vtables: impl_vtables, - self_vtable: None + self_vtables: None }); let trait_vtables_fixed = resolve_vtables_under_param_substs( - bcx.tcx(), param_substs, trait_vtables); + bcx.tcx(), param_substs, impl_res.trait_vtables); // Now we pull any vtables for parameters on the actual method. let num_method_vtables = method.generics.type_param_defs.len(); @@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block, None => vec::from_elem(num_method_vtables, @~[]) }; - @(*trait_vtables_fixed + method_vtables) + let param_vtables = @(*trait_vtables_fixed + method_vtables); + + let self_vtables = resolve_param_vtables_under_param_substs( + bcx.tcx(), param_substs, impl_res.self_vtables); + + (param_vtables, self_vtables) } @@ -296,7 +286,7 @@ pub fn trans_fn_ref_with_vtables( // We need to do a bunch of special handling for default methods. // We need to modify the def_id and our substs in order to monomorphize // the function. - let (is_default, def_id, substs, self_vtable, vtables) = + let (is_default, def_id, substs, self_vtables, vtables) = match ty::provided_source(tcx, def_id) { None => (false, def_id, substs, None, vtables), Some(source_id) => { @@ -319,20 +309,6 @@ pub fn trans_fn_ref_with_vtables( .expect("could not find trait_ref for impl with \ default methods"); - // Get all of the type params for the receiver - let param_defs = method.generics.type_param_defs; - let receiver_substs = - type_params.initn(param_defs.len()).to_owned(); - let receiver_vtables = match vtables { - None => @~[], - Some(call_vtables) => { - @call_vtables.initn(param_defs.len()).to_owned() - } - }; - - let self_vtable = - typeck::vtable_static(impl_id, receiver_substs, - receiver_vtables); // Compute the first substitution let first_subst = make_substs_for_receiver_types( tcx, impl_id, trait_ref, method); @@ -341,20 +317,22 @@ pub fn trans_fn_ref_with_vtables( let new_substs = first_subst.subst(tcx, &substs); - let vtables = + let (param_vtables, self_vtables) = resolve_default_method_vtables(bcx, impl_id, - method, &new_substs, vtables); + method, &substs, vtables); debug!("trans_fn_with_vtables - default method: \ substs = %s, trait_subst = %s, \ first_subst = %s, new_subst = %s, \ - self_vtable = %s, vtables = %s", + vtables = %s, \ + self_vtable = %s, param_vtables = %s", substs.repr(tcx), trait_ref.substs.repr(tcx), first_subst.repr(tcx), new_substs.repr(tcx), - self_vtable.repr(tcx), vtables.repr(tcx)); + vtables.repr(tcx), + self_vtables.repr(tcx), param_vtables.repr(tcx)); (true, source_id, - new_substs, Some(self_vtable), Some(vtables)) + new_substs, Some(self_vtables), Some(param_vtables)) } }; @@ -400,7 +378,7 @@ pub fn trans_fn_ref_with_vtables( let (val, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, - vtables, self_vtable, + vtables, self_vtables, Some(ref_id)); let mut val = val; if must_cast && ref_id != 0 { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 713939a5d831..702ef71a573c 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -133,7 +133,7 @@ pub struct param_substs { tys: ~[ty::t], self_ty: Option, vtables: Option, - self_vtable: Option + self_vtables: Option } impl param_substs { @@ -1020,14 +1020,25 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt, vts: typeck::vtable_res) -> typeck::vtable_res { @vts.iter().transform(|ds| - @ds.iter().transform( - |d| resolve_vtable_under_param_substs(tcx, - param_substs, - d)) - .collect::<~[typeck::vtable_origin]>()) - .collect::<~[typeck::vtable_param_res]>() + resolve_param_vtables_under_param_substs(tcx, + param_substs, + *ds)) + .collect() } +pub fn resolve_param_vtables_under_param_substs( + tcx: ty::ctxt, + param_substs: Option<@param_substs>, + ds: typeck::vtable_param_res) + -> typeck::vtable_param_res { + @ds.iter().transform( + |d| resolve_vtable_under_param_substs(tcx, + param_substs, + d)) + .collect() +} + + // Apply the typaram substitutions in the FunctionContext to a vtable. This should // eliminate any vtable_params. @@ -1068,31 +1079,26 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt, } } } - typeck::vtable_self(_trait_id) => { - match param_substs { - Some(@param_substs - {self_vtable: Some(ref self_vtable), _}) => { - (*self_vtable).clone() - } - _ => { - tcx.sess.bug(fmt!( - "resolve_vtable_in_fn_ctxt: asked to lookup but \ - no self_vtable in the fn_ctxt!")) - } - } - } } } pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, - n_param: uint, + n_param: typeck::param_index, n_bound: uint) -> typeck::vtable_origin { - debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", + debug!("find_vtable(n_param=%?, n_bound=%u, ps=%s)", n_param, n_bound, ps.repr(tcx)); - ps.vtables.get()[n_param][n_bound].clone() + let param_bounds = match n_param { + typeck::param_self => ps.self_vtables.expect("self vtables missing"), + typeck::param_numbered(n) => { + let tables = ps.vtables + .expect("vtables missing where they are needed"); + tables[n] + } + }; + param_bounds[n_bound].clone() } pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a65999ff2aa1..9228f20513bb 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -147,46 +147,13 @@ pub fn trans_method_callee(bcx: @mut Block, mentry: typeck::method_map_entry) -> Callee { let _icx = push_ctxt("impl::trans_method_callee"); - let tcx = bcx.tcx(); debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)", callee_id, bcx.expr_to_str(this), mentry.repr(bcx.tcx())); - // Replace method_self with method_static here. - let mut origin = mentry.origin; - match origin { - typeck::method_super(trait_id, method_index) => { - // is the self type for this method call - let self_ty = node_id_type(bcx, this.id); - // is the ID of the implementation of - // trait for type - let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty); - // Get the supertrait's methods - let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id); - // Make sure to fail with a readable error message if - // there's some internal error here - if !(method_index < supertrait_method_def_ids.len()) { - tcx.sess.bug("trans_method_callee: supertrait method \ - index is out of bounds"); - } - // Get the method name using the method index in the origin - let method_name = - ty::method(tcx, supertrait_method_def_ids[method_index]).ident; - // Now that we know the impl ID, we can look up the method - // ID from its name - origin = typeck::method_static( - method_with_name(bcx.ccx(), impl_id, method_name)); - } - typeck::method_self(*) | - typeck::method_static(*) | typeck::method_param(*) | - typeck::method_trait(*) => {} - } - - debug!("origin=%?", origin); - - match origin { + match mentry.origin { typeck::method_static(did) => { let callee_fn = callee::trans_fn_ref(bcx, did, callee_id); let mut temp_cleanups = ~[]; @@ -210,7 +177,8 @@ pub fn trans_method_callee(bcx: @mut Block, }) => { match bcx.fcx.param_substs { Some(substs) => { - let vtbl = find_vtable(bcx.tcx(), substs, p, b); + let vtbl = find_vtable(bcx.tcx(), substs, + p, b); trans_monomorphized_callee(bcx, callee_id, this, mentry, trait_id, off, vtbl) } @@ -219,24 +187,6 @@ pub fn trans_method_callee(bcx: @mut Block, } } - typeck::method_self(trait_id, method_index) => { - match bcx.fcx.param_substs { - Some(@param_substs - {self_vtable: Some(ref vtbl), _}) => { - trans_monomorphized_callee(bcx, - callee_id, - this, - mentry, - trait_id, - method_index, - (*vtbl).clone()) - } - _ => { - fail!("trans_method_callee: missing self_vtable") - } - } - } - typeck::method_trait(_, off, store) => { trans_trait_callee(bcx, callee_id, @@ -245,9 +195,6 @@ pub fn trans_method_callee(bcx: @mut Block, store, mentry.explicit_self) } - typeck::method_super(*) => { - fail!("method_super should have been handled above") - } } } @@ -402,9 +349,6 @@ pub fn trans_monomorphized_callee(bcx: @mut Block, typeck::vtable_param(*) => { fail!("vtable_param left in monomorphized function's vtable substs"); } - typeck::vtable_self(*) => { - fail!("vtable_self left in monomorphized function's vtable substs"); - } }; } @@ -611,7 +555,7 @@ pub fn vtable_id(ccx: @mut CrateContext, tys: (*substs).clone(), vtables: Some(sub_vtables), self_ty: None, - self_vtable: None + self_vtables: None }; monomorphize::make_mono_id( diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 789532abc611..9852e6b09b76 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -41,7 +41,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id: ast::def_id, real_substs: &ty::substs, vtables: Option, - self_vtable: Option, + self_vtables: Option, ref_id: Option) -> (ValueRef, bool) { @@ -54,7 +54,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, fn_id.repr(ccx.tcx), real_substs.repr(ccx.tcx), vtables.repr(ccx.tcx), - self_vtable.repr(ccx.tcx), + self_vtables.repr(ccx.tcx), ref_id); assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t))); @@ -72,7 +72,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext, tys: real_substs.tps.map(|x| do_normalize(x)), vtables: vtables, self_ty: real_substs.self_ty.map(|x| do_normalize(x)), - self_vtable: self_vtable + self_vtables: self_vtables }; for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); } @@ -371,8 +371,7 @@ pub fn make_mono_id(ccx: @mut CrateContext, Some(vts) => { debug!("make_mono_id vtables=%s substs=%s", vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx)); - let self_vtables = substs.self_vtable.map(|vtbl| @~[(*vtbl).clone()]); - let vts_iter = self_vtables.iter().chain_(vts.iter()); + let vts_iter = substs.self_vtables.iter().chain_(vts.iter()); vts_iter.zip(substs_iter).transform(|(vtable, subst)| { let v = vtable.map(|vt| meth::vtable_id(ccx, vt)); (*subst, if !v.is_empty() { Some(@v) } else { None }) diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 4d5d597d382f..aa19af01893c 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -274,13 +274,12 @@ pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) { opt_static_did = Some(did); } typeck::method_param(typeck::method_param { - param_num: param, + param_num: typeck::param_numbered(param), _ }) => { cx.uses[param] |= use_tydesc; } - typeck::method_trait(*) | typeck::method_self(*) - | typeck::method_super(*) => (), + _ => (), } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 20c39cc84eff..e2a926875e89 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -317,6 +317,9 @@ struct ctxt_ { // some point. Local variable definitions not in this set can be warned // about. used_mut_nodes: @mut HashSet, + + // vtable resolution information for impl declarations + impl_vtables: typeck::impl_vtable_map } pub enum tbox_flag { @@ -911,6 +914,7 @@ pub fn mk_ctxt(s: session::Session, impls: @mut HashMap::new(), used_unsafe: @mut HashSet::new(), used_mut_nodes: @mut HashSet::new(), + impl_vtables: @mut HashMap::new(), } } @@ -3061,9 +3065,7 @@ pub fn method_call_type_param_defs(tcx: ctxt, typeck::method_param(typeck::method_param { trait_id: trt_id, method_num: n_mth, _}) | - typeck::method_trait(trt_id, n_mth, _) | - typeck::method_self(trt_id, n_mth) | - typeck::method_super(trt_id, n_mth) => { + typeck::method_trait(trt_id, n_mth, _) => { // ...trait methods bounds, in contrast, include only the // method bounds, so we must preprend the tps from the // trait itself. This ought to be harmonized. @@ -3956,6 +3958,14 @@ pub fn lookup_item_type(cx: ctxt, || csearch::get_type(cx, did)) } +pub fn lookup_impl_vtables(cx: ctxt, + did: ast::def_id) + -> typeck::impl_res { + lookup_locally_or_in_crate_store( + "impl_vtables", did, cx.impl_vtables, + || csearch::get_impl_vtables(cx, did) ) +} + /// Given the did of a trait, returns its canonical trait ref. pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { match cx.trait_defs.find(&did) { @@ -4339,9 +4349,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), // relation on the supertraits from each bounded trait's constraint // list. pub fn each_bound_trait_and_supertraits(tcx: ctxt, - bounds: &ParamBounds, + bounds: &[@TraitRef], f: &fn(@TraitRef) -> bool) -> bool { - for bounds.trait_bounds.iter().advance |&bound_trait_ref| { + for bounds.iter().advance |&bound_trait_ref| { let mut supertrait_set = HashMap::new(); let mut trait_refs = ~[]; let mut i = 0; @@ -4383,38 +4393,14 @@ pub fn count_traits_and_supertraits(tcx: ctxt, type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; for type_param_defs.iter().advance |type_param_def| { - for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { + for each_bound_trait_and_supertraits( + tcx, type_param_def.bounds.trait_bounds) |_| { total += 1; } } return total; } -// Given a trait and a type, returns the impl of that type. -// This is broken, of course, by parametric impls. This used to use -// a table specifically for this mapping, but I removed that table. -// This is only used when calling a supertrait method from a default method, -// and should go away once I fix how that works. -sully -pub fn bogus_get_impl_id_from_ty(tcx: ctxt, - trait_id: def_id, self_ty: t) -> def_id { - match tcx.trait_impls.find(&trait_id) { - Some(ty_to_impl) => { - for ty_to_impl.iter().advance |imp| { - let impl_ty = tcx.tcache.get_copy(&imp.did); - if impl_ty.ty == self_ty { return imp.did; } - } - // try autoderef! - match deref(tcx, self_ty, false) { - Some(some_ty) => - bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty), - None => tcx.sess.bug("get_impl_id: no impl of trait for \ - this type") - } - }, - None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls") - } -} - pub fn get_tydesc_ty(tcx: ctxt) -> Result { do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| { tcx.intrinsic_defs.find_copy(tydesc_lang_item) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 8d546366846b..fd2ef337261d 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -90,7 +90,8 @@ use middle::typeck::check::vtable; use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{method_map_entry, method_origin, method_param}; -use middle::typeck::{method_self, method_static, method_trait, method_super}; +use middle::typeck::{method_static, method_trait}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; @@ -328,64 +329,6 @@ impl<'self> LookupContext<'self> { } } - pub fn push_inherent_candidates_from_param(&self, - rcvr_ty: ty::t, - param_ty: param_ty) { - debug!("push_inherent_candidates_from_param(param_ty=%?)", - param_ty); - let _indenter = indenter(); - - let tcx = self.tcx(); - let mut next_bound_idx = 0; // count only trait bounds - let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { - Some(t) => t, - None => { - tcx.sess.span_bug( - self.expr.span, - fmt!("No param def for %?", param_ty)); - } - }; - - for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds) - |bound_trait_ref| - { - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - - let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); - let pos = { - match trait_methods.iter().position(|m| { - m.explicit_self != ast::sty_static && - m.ident == self.m_name }) - { - Some(pos) => pos, - None => { - debug!("trait doesn't contain method: %?", - bound_trait_ref.def_id); - loop; // check next trait or bound - } - } - }; - let method = trait_methods[pos]; - - let cand = Candidate { - rcvr_ty: rcvr_ty, - rcvr_substs: bound_trait_ref.substs.clone(), - method_ty: method, - origin: method_param( - method_param { - trait_id: bound_trait_ref.def_id, - method_num: pos, - param_num: param_ty.idx, - bound_num: this_bound_idx, - }) - }; - - debug!("pushing inherent candidate for param: %?", cand); - self.inherent_candidates.push(cand); - } - } - pub fn push_inherent_candidates_from_trait(&self, self_ty: ty::t, did: def_id, @@ -438,69 +381,87 @@ impl<'self> LookupContext<'self> { }); } + pub fn push_inherent_candidates_from_param(&self, + rcvr_ty: ty::t, + param_ty: param_ty) { + debug!("push_inherent_candidates_from_param(param_ty=%?)", + param_ty); + let _indenter = indenter(); + + let tcx = self.tcx(); + let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { + Some(t) => t, + None => { + tcx.sess.span_bug( + self.expr.span, + fmt!("No param def for %?", param_ty)); + } + }; + + self.push_inherent_candidates_from_bounds( + rcvr_ty, type_param_def.bounds.trait_bounds, + param_numbered(param_ty.idx)); + } + + pub fn push_inherent_candidates_from_self(&self, self_ty: ty::t, did: def_id) { - struct MethodInfo { - method_ty: @ty::Method, - trait_def_id: ast::def_id, - index: uint, - trait_ref: @ty::TraitRef - } - let tcx = self.tcx(); - // First, try self methods - let mut method_info: Option = None; - let methods = ty::trait_methods(tcx, did); - match methods.iter().position(|m| m.ident == self.m_name) { - Some(i) => { - method_info = Some(MethodInfo { - method_ty: methods[i], - index: i, - trait_def_id: did, - trait_ref: ty::lookup_trait_def(tcx, did).trait_ref - }); - } - None => () - } - // No method found yet? Check each supertrait - if method_info.is_none() { - for ty::trait_supertraits(tcx, did).iter().advance |trait_ref| { - let supertrait_methods = - ty::trait_methods(tcx, trait_ref.def_id); - match supertrait_methods.iter().position(|m| m.ident == self.m_name) { - Some(i) => { - method_info = Some(MethodInfo { - method_ty: supertrait_methods[i], - index: i, - trait_def_id: trait_ref.def_id, - trait_ref: *trait_ref - }); - break; + + let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref; + self.push_inherent_candidates_from_bounds( + self_ty, &[trait_ref], param_self); + } + + pub fn push_inherent_candidates_from_bounds(&self, + self_ty: ty::t, + bounds: &[@TraitRef], + param: param_index) { + let tcx = self.tcx(); + let mut next_bound_idx = 0; // count only trait bounds + + for ty::each_bound_trait_and_supertraits(tcx, bounds) + |bound_trait_ref| + { + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); + let pos = { + match trait_methods.iter().position(|m| { + m.explicit_self != ast::sty_static && + m.ident == self.m_name }) + { + Some(pos) => pos, + None => { + debug!("trait doesn't contain method: %?", + bound_trait_ref.def_id); + loop; // check next trait or bound } - None => () } - } - } - match method_info { - Some(ref info) => { - // We've found a method -- return it - let origin = if did == info.trait_def_id { - method_self(info.trait_def_id, info.index) - } else { - method_super(info.trait_def_id, info.index) - }; - self.inherent_candidates.push(Candidate { - rcvr_ty: self_ty, - rcvr_substs: info.trait_ref.substs.clone(), - method_ty: info.method_ty, - origin: origin - }); - } - _ => return + }; + let method = trait_methods[pos]; + + let cand = Candidate { + rcvr_ty: self_ty, + rcvr_substs: bound_trait_ref.substs.clone(), + method_ty: method, + origin: method_param( + method_param { + trait_id: bound_trait_ref.def_id, + method_num: pos, + param_num: param, + bound_num: this_bound_idx, + }) + }; + + debug!("pushing inherent candidate for param: %?", cand); + self.inherent_candidates.push(cand); } } + pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) { let opt_impl_infos = self.tcx().inherent_impls.find(&did); for opt_impl_infos.iter().advance |impl_infos| { @@ -1005,14 +966,13 @@ impl<'self> LookupContext<'self> { /*! * * There are some limitations to calling functions through a - * traint instance, because (a) the self type is not known + * trait instance, because (a) the self type is not known * (that's the whole point of a trait instance, after all, to * obscure the self type) and (b) the call must go through a * vtable and hence cannot be monomorphized. */ match candidate.origin { - method_static(*) | method_param(*) | - method_self(*) | method_super(*) => { + method_static(*) | method_param(*) => { return; // not a call to a trait instance } method_trait(*) => {} @@ -1036,10 +996,11 @@ impl<'self> LookupContext<'self> { // No code can call the finalize method explicitly. let bad; match candidate.origin { - method_static(method_id) | method_self(method_id, _) - | method_super(method_id, _) => { + method_static(method_id) => { bad = self.tcx().destructors.contains(&method_id); } + // XXX: does this properly enforce this on everything now + // that self has been merged in? -sully method_param(method_param { trait_id: trait_id, _ }) | method_trait(trait_id, _, _) => { bad = self.tcx().destructor_for_type.contains_key(&trait_id); @@ -1158,8 +1119,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num) } - method_trait(did, idx, _) | method_self(did, idx) | - method_super(did, idx) => { + method_trait(did, idx, _) => { type_of_trait_method(self.tcx(), did, idx) } }; @@ -1180,8 +1140,7 @@ impl<'self> LookupContext<'self> { method_param(ref mp) => { self.report_param_candidate(idx, (*mp).trait_id) } - method_trait(trait_did, _, _) | method_self(trait_did, _) - | method_super(trait_did, _) => { + method_trait(trait_did, _, _) => { self.report_trait_candidate(idx, trait_did) } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index da09f79d0312..50f7f18b0a6d 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -16,11 +16,11 @@ use middle::typeck::check::{structurally_resolved_type}; use middle::typeck::infer::fixup_err_to_str; use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; -use middle::typeck::{CrateCtxt, vtable_origin, vtable_res}; -use middle::typeck::{vtable_static, vtable_param, vtable_self}; +use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res}; +use middle::typeck::{vtable_static, vtable_param, impl_res}; +use middle::typeck::{param_numbered, param_self, param_index}; use middle::subst::Subst; use util::common::indenter; -use util::ppaux::tys_to_str; use util::ppaux; use std::hashmap::HashSet; @@ -46,6 +46,16 @@ use syntax::visit; // *fully* resolved. (We could be less restrictive than that, but it // would require much more care, and this seems to work decently in // practice.) +// +// While resolution on a single type requires the type to be fully +// resolved, when resolving a substitution against a list of bounds, +// we do not require all of the types to be resolved in advance. +// Furthermore, we process substitutions in reverse order, which +// allows resolution on later parameters to give information on +// earlier params referenced by the typeclass bounds. +// It may be better to do something more clever, like processing fully +// resolved types first. + /// Location info records the span and ID of the expression or item that is /// responsible for this vtable instantiation. (This may not be an expression @@ -84,42 +94,19 @@ fn lookup_vtables(vcx: &VtableContext, substs.repr(vcx.tcx())); let _i = indenter(); - let tcx = vcx.tcx(); - let mut result = ~[]; - let mut i = 0u; - for substs.tps.iter().advance |ty| { - // ty is the value supplied for the type parameter A... - let mut param_result = ~[]; - for ty::each_bound_trait_and_supertraits( - tcx, type_param_defs[i].bounds) |trait_ref| - { - // ...and here trait_ref is each bound that was declared on A, - // expressed in terms of the type parameters. + // We do this backwards for reasons discussed above. + assert_eq!(substs.tps.len(), type_param_defs.len()); + let mut result = + substs.tps.rev_iter() + .zip(type_param_defs.rev_iter()) + .transform(|(ty, def)| + lookup_vtables_for_param(vcx, location_info, Some(substs), + &*def.bounds, *ty, is_early)) + .to_owned_vec(); + result.reverse(); - debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx)); - - // Substitute the values of the type parameters that may - // appear in the bound. - let trait_ref = trait_ref.subst(tcx, substs); - - debug!("after subst: %s", trait_ref.repr(tcx)); - - match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) { - Some(vtable) => param_result.push(vtable), - None => { - vcx.tcx().sess.span_fatal( - location_info.span, - fmt!("failed to find an implementation of \ - trait %s for %s", - vcx.infcx.trait_ref_to_str(trait_ref), - vcx.infcx.ty_to_str(*ty))); - } - } - } - result.push(@param_result); - i += 1u; - } + assert_eq!(substs.tps.len(), result.len()); debug!("lookup_vtables result(\ location_info=%?, \ type_param_defs=%s, \ @@ -132,25 +119,58 @@ fn lookup_vtables(vcx: &VtableContext, @result } -fn fixup_substs(vcx: &VtableContext, - location_info: &LocationInfo, - id: ast::def_id, - substs: ty::substs, - is_early: bool) - -> Option { +fn lookup_vtables_for_param(vcx: &VtableContext, + location_info: &LocationInfo, + // None for substs means the identity + substs: Option<&ty::substs>, + type_param_bounds: &ty::ParamBounds, + ty: ty::t, + is_early: bool) -> vtable_param_res { let tcx = vcx.tcx(); - // use a dummy type just to package up the substs that need fixing up - let t = ty::mk_trait(tcx, - id, substs, - ty::RegionTraitStore(ty::re_static), - ast::m_imm, - ty::EmptyBuiltinBounds()); - do fixup_ty(vcx, location_info, t, is_early).map |t_f| { - match ty::get(*t_f).sty { - ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(), - _ => fail!("t_f should be a trait") + + // ty is the value supplied for the type parameter A... + let mut param_result = ~[]; + + for ty::each_bound_trait_and_supertraits( + tcx, type_param_bounds.trait_bounds) |trait_ref| + { + // ...and here trait_ref is each bound that was declared on A, + // expressed in terms of the type parameters. + + // Substitute the values of the type parameters that may + // appear in the bound. + let trait_ref = substs.map_default(trait_ref, |substs| { + debug!("about to subst: %s, %s", + trait_ref.repr(tcx), substs.repr(tcx)); + trait_ref.subst(tcx, *substs) + }); + + debug!("after subst: %s", trait_ref.repr(tcx)); + + match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) { + Some(vtable) => param_result.push(vtable), + None => { + vcx.tcx().sess.span_fatal( + location_info.span, + fmt!("failed to find an implementation of \ + trait %s for %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.ty_to_str(ty))); + } } } + + debug!("lookup_vtables_for_param result(\ + location_info=%?, \ + type_param_bounds=%s, \ + ty=%s, \ + result=%s)", + location_info, + type_param_bounds.repr(vcx.tcx()), + ty.repr(vcx.tcx()), + param_result.repr(vcx.tcx())); + + return @param_result; } fn relate_trait_refs(vcx: &VtableContext, @@ -173,10 +193,15 @@ fn relate_trait_refs(vcx: &VtableContext, { result::Ok(()) => {} // Ok. result::Err(ref err) => { + // There is an error, but we need to do some work to make + // the message good. + // Resolve any type vars in the trait refs let r_act_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref); let r_exp_trait_ref = vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref); + // Only print the message if there aren't any previous type errors + // inside the types. if !ty::trait_ref_contains_error(&r_act_trait_ref) && !ty::trait_ref_contains_error(&r_exp_trait_ref) { @@ -192,8 +217,7 @@ fn relate_trait_refs(vcx: &VtableContext, } } -// Look up the vtable to use when treating an item of type `t` as if it has -// type `trait_ty` +// Look up the vtable implementing the trait `trait_ref` at type `t` fn lookup_vtable(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, @@ -216,222 +240,249 @@ fn lookup_vtable(vcx: &VtableContext, // The type has unconstrained type variables in it, so we can't // do early resolution on it. Return some completely bogus vtable // information: we aren't storing it anyways. - return Some(vtable_param(0, 0)); + return Some(vtable_param(param_self, 0)); } }; - match ty::get(ty).sty { + // If the type is self or a param, we look at the trait/supertrait + // bounds to see if they include the trait we are looking for. + let vtable_opt = match ty::get(ty).sty { ty::ty_param(param_ty {idx: n, def_id: did}) => { - let mut n_bound = 0; let type_param_def = tcx.ty_param_defs.get(&did.node); - for ty::each_bound_trait_and_supertraits( - tcx, type_param_def.bounds) |bound_trait_ref| - { - debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); - - if bound_trait_ref.def_id == trait_ref.def_id { - relate_trait_refs(vcx, - location_info, - bound_trait_ref, - trait_ref); - let vtable = vtable_param(n, n_bound); - debug!("found param vtable: %?", - vtable); - return Some(vtable); - } - - n_bound += 1; - } + lookup_vtable_from_bounds(vcx, location_info, + type_param_def.bounds.trait_bounds, + param_numbered(n), + trait_ref) } ty::ty_self(trait_id) => { - debug!("trying to find %? vtable for type %?", - trait_ref.def_id, trait_id); - - if trait_id == trait_ref.def_id { - let vtable = vtable_self(trait_id); - debug!("found self vtable: %?", vtable); - return Some(vtable); - } + let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref; + lookup_vtable_from_bounds(vcx, location_info, + &[self_trait_ref], + param_self, + trait_ref) } - _ => { - let mut found = ~[]; + // Default case just falls through + _ => None + }; - let mut impls_seen = HashSet::new(); + if vtable_opt.is_some() { return vtable_opt; } - match tcx.trait_impls.find(&trait_ref.def_id) { - None => { - // Nothing found. Continue. - } - Some(implementations) => { - // implementations is the list of all impls in scope for - // trait_ref. (Usually, there's just one.) - for implementations.iter().advance |im| { - // im is one specific impl of trait_ref. + // If we aren't a self type or param, or it was, but we didn't find it, + // do a search. + return search_for_vtable(vcx, location_info, + ty, trait_ref, is_early) +} - // First, ensure we haven't processed this impl yet. - if impls_seen.contains(&im.did) { - loop; - } - impls_seen.insert(im.did); +// Given a list of bounds on a type, search those bounds to see if any +// of them are the vtable we are looking for. +fn lookup_vtable_from_bounds(vcx: &VtableContext, + location_info: &LocationInfo, + bounds: &[@ty::TraitRef], + param: param_index, + trait_ref: @ty::TraitRef) + -> Option { + let tcx = vcx.tcx(); - // ty::impl_traits gives us the trait im implements, - // if there is one (there's either zero or one). - // - // If foo implements a trait t, and if t is the - // same trait as trait_ref, we need to - // unify it with trait_ref in order to get all - // the ty vars sorted out. - let r = ty::impl_trait_ref(tcx, im.did); - for r.iter().advance |&of_trait_ref| { - if of_trait_ref.def_id != trait_ref.def_id { loop; } + let mut n_bound = 0; + for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| { + debug!("checking bounds trait %s", + bound_trait_ref.repr(vcx.tcx())); - // At this point, we know that of_trait_ref is - // the same trait as trait_ref, but - // possibly applied to different substs. - // - // Next, we check whether the "for" ty in - // the impl is compatible with the type - // that we're casting to a trait. That is, - // if im is: - // - // impl self_ty: some_trait { ... } - // - // we check whether self_ty is the type - // of the thing that we're trying to cast - // to some_trait. If not, then we try the next - // impl. - // - // FIXME(#5781) this should be mk_eqty not mk_subty - let ty::ty_param_substs_and_ty { - substs: substs, - ty: for_ty - } = impl_self_ty(vcx, location_info, im.did); - match infer::mk_subty(vcx.infcx, - false, - infer::RelateSelfType( - location_info.span), - ty, - for_ty) { - result::Err(_) => loop, - result::Ok(()) => () - } - - // Now, in the previous example, for_ty is - // bound to the type self_ty, and substs - // is bound to [T]. - debug!("The self ty is %s and its substs are %s", - vcx.infcx.ty_to_str(for_ty), - tys_to_str(vcx.tcx(), substs.tps)); - - // Next, we unify trait_ref -- the type - // that we want to cast to -- with of_trait_ref - // -- the trait that im implements. At - // this point, we require that they be - // unifiable with each other -- that's - // what relate_trait_refs does. - // - // For example, in the above example, - // of_trait_ref would be some_trait, so we - // would be unifying trait_ref (for some - // value of U) with some_trait. This - // would fail if T and U weren't - // compatible. - - debug!("(checking vtable) @2 relating trait \ - ty %s to of_trait_ref %s", - vcx.infcx.trait_ref_to_str(trait_ref), - vcx.infcx.trait_ref_to_str(of_trait_ref)); - - let of_trait_ref = of_trait_ref.subst(tcx, &substs); - relate_trait_refs( - vcx, location_info, - of_trait_ref, trait_ref); - - // Recall that trait_ref -- the trait type - // we're casting to -- is the trait with - // id trait_ref.def_id applied to the substs - // trait_ref.substs. Now we extract out the - // types themselves from trait_ref.substs. - - // Recall that substs is the impl self - // type's list of substitutions. That is, - // if this is an impl of some trait for - // foo, then substs is [T, - // U]. substs might contain type - // variables, so we call fixup_substs to - // resolve them. - - let substs_f = match fixup_substs(vcx, - location_info, - trait_ref.def_id, - substs, - is_early) { - Some(ref substs) => (*substs).clone(), - None => { - assert!(is_early); - // Bail out with a bogus answer - return Some(vtable_param(0, 0)); - } - }; - - debug!("The fixed-up substs are %s - \ - they will be unified with the bounds for \ - the target ty, %s", - tys_to_str(vcx.tcx(), substs_f.tps), - vcx.infcx.trait_ref_to_str(trait_ref)); - - // Next, we unify the fixed-up - // substitutions for the impl self ty with - // the substitutions from the trait type - // that we're trying to cast - // to. connect_trait_tps requires these - // lists of types to unify pairwise. - - let im_generics = - ty::lookup_item_type(tcx, im.did).generics; - connect_trait_tps(vcx, - location_info, - &substs_f, - trait_ref, - im.did); - let subres = lookup_vtables( - vcx, location_info, - *im_generics.type_param_defs, &substs_f, - is_early); - - // Finally, we register that we found a - // matching impl, and record the def ID of - // the impl as well as the resolved list - // of type substitutions for the target - // trait. - found.push(vtable_static(im.did, - substs_f.tps.clone(), - subres)); - } - } - } - } - - match found.len() { - 0 => { /* fallthrough */ } - 1 => return Some(found[0].clone()), - _ => { - if !is_early { - vcx.tcx().sess.span_err( - location_info.span, - "multiple applicable methods in scope"); - } - return Some(found[0].clone()); - } - } + if bound_trait_ref.def_id == trait_ref.def_id { + relate_trait_refs(vcx, + location_info, + bound_trait_ref, + trait_ref); + let vtable = vtable_param(param, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); } + + n_bound += 1; } return None; } +fn search_for_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ref: @ty::TraitRef, + is_early: bool) + -> Option +{ + let tcx = vcx.tcx(); + + let mut found = ~[]; + let mut impls_seen = HashSet::new(); + + // XXX: this is a bad way to do this, since we do + // pointless allocations. + let impls = tcx.trait_impls.find(&trait_ref.def_id) + .map_default(@mut ~[], |x| **x); + // impls is the list of all impls in scope for trait_ref. + for impls.iter().advance |im| { + // im is one specific impl of trait_ref. + + // First, ensure we haven't processed this impl yet. + if impls_seen.contains(&im.did) { + loop; + } + impls_seen.insert(im.did); + + // ty::impl_traits gives us the trait im implements. + // + // If foo implements a trait t, and if t is the same trait as + // trait_ref, we need to unify it with trait_ref in order to + // get all the ty vars sorted out. + let r = ty::impl_trait_ref(tcx, im.did); + let of_trait_ref = r.expect("trait_ref missing on trait impl"); + if of_trait_ref.def_id != trait_ref.def_id { loop; } + + // At this point, we know that of_trait_ref is the same trait + // as trait_ref, but possibly applied to different substs. + // + // Next, we check whether the "for" ty in the impl is + // compatible with the type that we're casting to a + // trait. That is, if im is: + // + // impl some_trait for self_ty { ... } + // + // we check whether self_ty is the type of the thing that + // we're trying to cast to some_trait. If not, then we try + // the next impl. + // + // XXX: document a bit more what this means + // + // FIXME(#5781) this should be mk_eqty not mk_subty + let ty::ty_param_substs_and_ty { + substs: substs, + ty: for_ty + } = impl_self_ty(vcx, location_info, im.did); + match infer::mk_subty(vcx.infcx, + false, + infer::RelateSelfType( + location_info.span), + ty, + for_ty) { + result::Err(_) => loop, + result::Ok(()) => () + } + + // Now, in the previous example, for_ty is bound to + // the type self_ty, and substs is bound to [T]. + debug!("The self ty is %s and its substs are %s", + vcx.infcx.ty_to_str(for_ty), + vcx.infcx.tys_to_str(substs.tps)); + + // Next, we unify trait_ref -- the type that we want to cast + // to -- with of_trait_ref -- the trait that im implements. At + // this point, we require that they be unifiable with each + // other -- that's what relate_trait_refs does. + // + // For example, in the above example, of_trait_ref would be + // some_trait, so we would be unifying trait_ref (for + // some value of U) with some_trait. This would fail if T + // and U weren't compatible. + + debug!("(checking vtable) @2 relating trait \ + ty %s to of_trait_ref %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.trait_ref_to_str(of_trait_ref)); + + let of_trait_ref = of_trait_ref.subst(tcx, &substs); + relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref); + + + // Recall that trait_ref -- the trait type we're casting to -- + // is the trait with id trait_ref.def_id applied to the substs + // trait_ref.substs. + + // Resolve any sub bounds. Note that there still may be free + // type variables in substs. This might still be OK: the + // process of looking up bounds might constrain some of them. + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; + let subres = lookup_vtables(vcx, location_info, + *im_generics.type_param_defs, &substs, + is_early); + + + // substs might contain type variables, so we call + // fixup_substs to resolve them. + let substs_f = match fixup_substs(vcx, + location_info, + trait_ref.def_id, + substs, + is_early) { + Some(ref substs) => (*substs).clone(), + None => { + assert!(is_early); + // Bail out with a bogus answer + return Some(vtable_param(param_self, 0)); + } + }; + + debug!("The fixed-up substs are %s - \ + they will be unified with the bounds for \ + the target ty, %s", + vcx.infcx.tys_to_str(substs_f.tps), + vcx.infcx.trait_ref_to_str(trait_ref)); + + // Next, we unify the fixed-up substitutions for the impl self + // ty with the substitutions from the trait type that we're + // trying to cast to. connect_trait_tps requires these lists + // of types to unify pairwise. + // I am a little confused about this, since it seems to be + // very similar to the relate_trait_refs we already do, + // but problems crop up if it is removed, so... -sully + connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did); + + // Finally, we register that we found a matching impl, and + // record the def ID of the impl as well as the resolved list + // of type substitutions for the target trait. + found.push(vtable_static(im.did, substs_f.tps.clone(), subres)); + } + + match found.len() { + 0 => { return None } + 1 => return Some(found[0].clone()), + _ => { + if !is_early { + vcx.tcx().sess.span_err( + location_info.span, + "multiple applicable methods in scope"); + } + return Some(found[0].clone()); + } + } +} + + +fn fixup_substs(vcx: &VtableContext, + location_info: &LocationInfo, + id: ast::def_id, + substs: ty::substs, + is_early: bool) + -> Option { + let tcx = vcx.tcx(); + // use a dummy type just to package up the substs that need fixing up + let t = ty::mk_trait(tcx, + id, substs, + ty::RegionTraitStore(ty::re_static), + ast::m_imm, + ty::EmptyBuiltinBounds()); + do fixup_ty(vcx, location_info, t, is_early).map |t_f| { + match ty::get(*t_f).sty { + ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(), + _ => fail!("t_f should be a trait") + } + } +} + fn fixup_ty(vcx: &VtableContext, location_info: &LocationInfo, ty: ty::t, @@ -682,16 +733,39 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) { Some(trait_ref) => { let infcx = infer::new_infer_ctxt(ccx.tcx); let vcx = VtableContext { ccx: ccx, infcx: infcx }; - let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); + let loc_info = location_info_for_item(impl_item); + // First, check that the impl implements any trait bounds + // on the trait. + let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id); let vtbls = lookup_vtables(&vcx, - &location_info_for_item(impl_item), + &loc_info, *trait_def.generics.type_param_defs, &trait_ref.substs, false); - // FIXME(#7450): Doesn't work cross crate - ccx.vtable_map.insert(impl_item.id, vtbls); + // Now, locate the vtable for the impl itself. The real + // purpose of this is to check for supertrait impls, + // but that falls out of doing this. + let param_bounds = ty::ParamBounds { + builtin_bounds: ty::EmptyBuiltinBounds(), + trait_bounds: ~[trait_ref] + }; + let t = ty::node_id_to_type(ccx.tcx, impl_item.id); + debug!("=== Doing a self lookup now."); + // Right now, we don't have any place to store this. + // We will need to make one so we can use this information + // for compiling default methods that refer to supertraits. + let self_vtable_res = + lookup_vtables_for_param(&vcx, &loc_info, None, + ¶m_bounds, t, false); + + + let res = impl_res { + trait_vtables: vtbls, + self_vtables: self_vtable_res + }; + ccx.tcx.impl_vtables.insert(def_id, res); } } } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 4d437d83f2ab..a7319d4b0081 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -20,7 +20,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::{vtable_res, vtable_origin}; -use middle::typeck::{vtable_static, vtable_param, vtable_self}; +use middle::typeck::{vtable_static, vtable_param}; use middle::typeck::method_map_entry; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; @@ -109,9 +109,6 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { &vtable_param(n, b) => { vtable_param(n, b) } - &vtable_self(def_id) => { - vtable_self(def_id) - } } } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 1f0fb1357628..eb32f4e59f00 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -653,6 +653,11 @@ impl InferCtxt { self.resolve_type_vars_if_possible(t)) } + pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str { + let tstrs = ts.map(|t| self.ty_to_str(*t)); + fmt!("(%s)", tstrs.connect(", ")) + } + pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str { let t = self.resolve_type_vars_in_trait_ref_if_possible(t); trait_ref_to_str(self.tcx, &t) diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 81b18e746b23..0ea00e15863d 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -75,14 +75,14 @@ pub mod infer; pub mod collect; pub mod coherence; +#[deriving(Clone, Encodable, Decodable, Eq, Ord)] +pub enum param_index { + param_numbered(uint), + param_self +} + #[deriving(Clone, Encodable, Decodable)] pub enum method_origin { - // supertrait method invoked on "self" inside a default method - // first field is supertrait ID; - // second field is method index (relative to the *supertrait* - // method list) - method_super(ast::def_id, uint), - // fully statically resolved method method_static(ast::def_id), @@ -92,9 +92,6 @@ pub enum method_origin { // method invoked on a trait instance method_trait(ast::def_id, uint, ty::TraitStore), - // method invoked on "self" inside a default method - method_self(ast::def_id, uint) - } // details for a method invoked with a receiver whose type is a type parameter @@ -109,7 +106,7 @@ pub struct method_param { // index of the type parameter (from those that are in scope) that is // the type of the receiver - param_num: uint, + param_num: param_index, // index of the bound for this type parameter which specifies the trait bound_num: uint, @@ -153,15 +150,10 @@ pub enum vtable_origin { fn foo(a: T) -- a's vtable would have a vtable_param origin - The first uint is the param number (identifying T in the example), + The first argument is the param index (identifying T in the example), and the second is the bound number (identifying baz) */ - vtable_param(uint, uint), - - /* - Dynamic vtable, comes from self. - */ - vtable_self(ast::def_id) + vtable_param(param_index, uint), } impl Repr for vtable_origin { @@ -178,15 +170,34 @@ impl Repr for vtable_origin { vtable_param(x, y) => { fmt!("vtable_param(%?, %?)", x, y) } - vtable_self(def_id) => { - fmt!("vtable_self(%?)", def_id) - } } } } pub type vtable_map = @mut HashMap; + +// Information about the vtable resolutions for for a trait impl. +// Mostly the information is important for implementing default +// methods. +#[deriving(Clone)] +pub struct impl_res { + // resolutions for any bounded params on the trait definition + trait_vtables: vtable_res, + // resolutions for the trait /itself/ (and for supertraits) + self_vtables: vtable_param_res +} + +impl Repr for impl_res { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("impl_res {trait_vtables=%s, self_vtables=%s}", + self.trait_vtables.repr(tcx), + self.self_vtables.repr(tcx)) + } +} + +pub type impl_vtable_map = @mut HashMap; + pub struct CrateCtxt { // A mapping from method call sites to traits that have that method. trait_map: resolve::TraitMap, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 32ac5e72928e..932648d4f9b9 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -715,10 +715,6 @@ impl Repr for typeck::method_map_entry { impl Repr for typeck::method_origin { fn repr(&self, tcx: ctxt) -> ~str { match self { - &typeck::method_super(def_id, n) => { - fmt!("method_super(%s, %?)", - def_id.repr(tcx), n) - } &typeck::method_static(def_id) => { fmt!("method_static(%s)", def_id.repr(tcx)) } @@ -729,9 +725,6 @@ impl Repr for typeck::method_origin { fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n, st.repr(tcx)) } - &typeck::method_self(def_id, n) => { - fmt!("method_self(%s, %?)", def_id.repr(tcx), n) - } } } } diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 8a13cab28c3b..eee786524f57 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -86,6 +86,12 @@ pub trait TotalOrd: TotalEq { fn cmp(&self, other: &Self) -> Ordering; } +impl TotalEq for Ordering { + #[inline] + fn equals(&self, other: &Ordering) -> bool { + *self == *other + } +} impl TotalOrd for Ordering { #[inline] fn cmp(&self, other: &Ordering) -> Ordering { diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 0c2a7bb7b400..5ea7585a3dfc 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -96,7 +96,7 @@ impl> Iterator for InvertIterator { fn size_hint(&self) -> (uint, Option) { self.iter.size_hint() } } -impl> DoubleEndedIterator for InvertIterator { +impl> DoubleEndedIterator for InvertIterator { #[inline] fn next_back(&mut self) -> Option { self.iter.next() } } @@ -343,6 +343,18 @@ pub trait IteratorUtil { /// ~~~ fn collect>(&mut self) -> B; + /// Loops through the entire iterator, collecting all of the elements into + /// a unique vector. This is simply collect() specialized for vectors. + /// + /// # Example + /// + /// ~~~ {.rust} + /// let a = [1, 2, 3, 4, 5]; + /// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec(); + /// assert!(a == b); + /// ~~~ + fn to_owned_vec(&mut self) -> ~[A]; + /// Loops through `n` iterations, returning the `n`th element of the /// iterator. /// @@ -539,6 +551,11 @@ impl> IteratorUtil for T { FromIterator::from_iterator(self) } + #[inline] + fn to_owned_vec(&mut self) -> ~[A] { + self.collect() + } + /// Return the `n`th item yielded by an iterator. #[inline] fn nth(&mut self, mut n: uint) -> Option { diff --git a/src/test/auxiliary/issue_3979_traits.rs b/src/test/auxiliary/issue_3979_traits.rs index 1e56dab1559c..eb10553f19c2 100644 --- a/src/test/auxiliary/issue_3979_traits.rs +++ b/src/test/auxiliary/issue_3979_traits.rs @@ -14,12 +14,13 @@ #[crate_type = "lib"]; trait Positioned { - fn SetX(&self, int); + fn SetX(&mut self, int); fn X(&self) -> int; } trait Movable: Positioned { - fn translate(&self, dx: int) { - self.SetX(self.X() + dx); + fn translate(&mut self, dx: int) { + let x = self.X() + dx; + self.SetX(x); } } diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs new file mode 100644 index 000000000000..90a2b9140212 --- /dev/null +++ b/src/test/run-pass/default-method-supertrait-vtable.rs @@ -0,0 +1,36 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +// Tests that we can call a function bounded over a supertrait from +// a default method + +fn require_y(x: T) -> int { x.y() } + +trait Y { + fn y(self) -> int; +} + + +trait Z: Y { + fn x(self) -> int { + require_y(self) + } +} + +impl Y for int { + fn y(self) -> int { self } +} + +impl Z for int; + +fn main() { + assert_eq!(12.x(), 12); +} diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index 9a8b90db185b..39e9f5dcd2d8 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - trait A { fn a_method(&self); } diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index 2a1ded96827d..867301121dae 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test FIXME #5946 trait Positioned { fn SetX(&mut self, S); fn X(&self) -> S; } -trait Movable: Positioned { - fn translate(&self, dx: T) { - self.SetX(self.X() + dx); +trait Movable>: Positioned { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); } } @@ -31,10 +31,10 @@ impl Positioned for Point { } } -impl Movable for Point; +impl Movable for Point; pub fn main() { - let p = Point{ x: 1, y: 2}; + let mut p = Point{ x: 1, y: 2}; p.translate(3); assert_eq!(p.X(), 4); } diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs index 4bde414c4acf..caf6d2023169 100644 --- a/src/test/run-pass/issue-3979-xcrate.rs +++ b/src/test/run-pass/issue-3979-xcrate.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test // tjc: ??? +// xfail-fast // aux-build:issue_3979_traits.rs extern mod issue_3979_traits; use issue_3979_traits::*; diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs index fe10dd5af53d..2e53fb5d3f92 100644 --- a/src/test/run-pass/issue-3979.rs +++ b/src/test/run-pass/issue-3979.rs @@ -1,5 +1,3 @@ -// xfail-test -// Reason: ICE with explicit self // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs new file mode 100644 index 000000000000..ae7e18d532b7 --- /dev/null +++ b/src/test/run-pass/supertrait-default-generics.rs @@ -0,0 +1,42 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// There is some other borrowck bug, so we make the stuff not mut. + +trait Positioned { + fn SetX(&mut self, S); + fn X(&self) -> S; +} + +trait Movable>: Positioned { + fn translate(&mut self, dx: S) { + let x = self.X() + dx; + self.SetX(x); + } +} + +struct Point { x: S, y: S } + +impl Positioned for Point { + fn SetX(&mut self, x: S) { + self.x = x; + } + fn X(&self) -> S { + self.x.clone() + } +} + +impl> Movable for Point; + +pub fn main() { + let mut p = Point{ x: 1, y: 2}; + p.translate(3); + assert_eq!(p.X(), 4); +}