diff --git a/src/libcore/f32.rs b/src/libcore/f32.rs index ed6908d110d6d..7ddf81629ebe4 100644 --- a/src/libcore/f32.rs +++ b/src/libcore/f32.rs @@ -138,6 +138,18 @@ pub pure fn logarithm(n: f32, b: f32) -> f32 { return log2(n) / log2(b); } +impl f32 : cmp::Eq { + pure fn eq(&self, other: &f32) -> bool { (*self) == (*other) } + pure fn ne(&self, other: &f32) -> bool { (*self) != (*other) } +} + +impl f32 : cmp::Ord { + pure fn lt(&self, other: &f32) -> bool { (*self) < (*other) } + pure fn le(&self, other: &f32) -> bool { (*self) <= (*other) } + pure fn ge(&self, other: &f32) -> bool { (*self) >= (*other) } + pure fn gt(&self, other: &f32) -> bool { (*self) > (*other) } +} + impl f32: num::Num { pure fn add(other: &f32) -> f32 { return self + *other; } pure fn sub(other: &f32) -> f32 { return self - *other; } diff --git a/src/libcore/f64.rs b/src/libcore/f64.rs index 2d13dc86e2fa5..c2d99d1ed40ce 100644 --- a/src/libcore/f64.rs +++ b/src/libcore/f64.rs @@ -157,6 +157,18 @@ pub pure fn logarithm(n: f64, b: f64) -> f64 { return log2(n) / log2(b); } +impl f64 : cmp::Eq { + pure fn eq(&self, other: &f64) -> bool { (*self) == (*other) } + pure fn ne(&self, other: &f64) -> bool { (*self) != (*other) } +} + +impl f64 : cmp::Ord { + pure fn lt(&self, other: &f64) -> bool { (*self) < (*other) } + pure fn le(&self, other: &f64) -> bool { (*self) <= (*other) } + pure fn ge(&self, other: &f64) -> bool { (*self) >= (*other) } + pure fn gt(&self, other: &f64) -> bool { (*self) > (*other) } +} + impl f64: num::Num { pure fn add(other: &f64) -> f64 { return self + *other; } pure fn sub(other: &f64) -> f64 { return self - *other; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index d318c279999c2..37491ae0b714d 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -37,6 +37,7 @@ pub trait Times { pub trait CopyableIter { pure fn filter_to_vec(pred: fn(a: A) -> bool) -> ~[A]; pure fn map_to_vec(op: fn(v: A) -> B) -> ~[B]; + pure fn flat_map_to_vec>(op: fn(A) -> IB) -> ~[B]; pure fn to_vec() -> ~[A]; pure fn find(p: fn(a: A) -> bool) -> Option; } diff --git a/src/libcore/path.rs b/src/libcore/path.rs index f0fefee9d06d2..a9a99565cf139 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -44,6 +44,9 @@ pub trait GenericPath { pure fn with_filestem((&str)) -> self; pure fn with_filetype((&str)) -> self; + pure fn dir_path() -> self; + pure fn file_path() -> self; + pure fn push((&str)) -> self; pure fn push_rel((&self)) -> self; pure fn push_many((&[~str])) -> self; diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 561732057cf3c..a06564a470e67 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -811,13 +811,22 @@ pub struct RecvPacketBuffered { } } -impl RecvPacketBuffered : Selectable { +impl RecvPacketBuffered { fn unwrap() -> *Packet { let mut p = None; p <-> self.p; option::unwrap(move p) } + fn reuse_buffer() -> BufferResource { + //error!("recv reuse_buffer"); + let mut tmp = None; + tmp <-> self.buffer; + option::unwrap(move tmp) + } +} + +impl RecvPacketBuffered : Selectable { pure fn header() -> *PacketHeader { match self.p { Some(packet) => unsafe { @@ -829,13 +838,6 @@ impl RecvPacketBuffered : Selectable { None => fail ~"packet already consumed" } } - - fn reuse_buffer() -> BufferResource { - //error!("recv reuse_buffer"); - let mut tmp = None; - tmp <-> self.buffer; - option::unwrap(move tmp) - } } pub fn RecvPacketBuffered(p: *Packet) @@ -1046,7 +1048,7 @@ pub fn PortSet() -> PortSet{ } } -impl PortSet : Recv { +impl PortSet { fn add(port: pipes::Port) { self.ports.push(move port) @@ -1057,6 +1059,9 @@ impl PortSet : Recv { self.add(move po); move ch } +} + +impl PortSet : Recv { fn try_recv() -> Option { let mut result = None; diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 3fa37a2fb8e5d..d9b18947779fb 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -34,9 +34,7 @@ pub fn MovePtrAdaptor(v: V) -> MovePtrAdaptor { MovePtrAdaptor { inner: move v } } -/// Abstract type-directed pointer-movement using the MovePtr trait -impl MovePtrAdaptor: TyVisitor { - +impl MovePtrAdaptor { #[inline(always)] fn bump(sz: uint) { do self.inner.move_ptr() |p| { @@ -60,7 +58,10 @@ impl MovePtrAdaptor: TyVisitor { fn bump_past() { self.bump(sys::size_of::()); } +} +/// Abstract type-directed pointer-movement using the MovePtr trait +impl MovePtrAdaptor: TyVisitor { fn visit_bot() -> bool { self.align_to::<()>(); if ! self.inner.visit_bot() { return false; } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 21f1b2d8698f5..d2784135704be 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1330,16 +1330,12 @@ fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, debug!("find_vtable_in_fn_ctxt(n_param=%u, n_bound=%u, ps=%?)", n_param, n_bound, param_substs_to_str(tcx, ps)); - let mut vtable_off = n_bound, i = 0u; // Vtables are stored in a flat array, finding the right one is // somewhat awkward - for vec::each(*ps.bounds) |bounds| { - if i >= n_param { break; } - for vec::each(**bounds) |bound| { - match *bound { ty::bound_trait(_) => vtable_off += 1u, _ => () } - } - i += 1u; - } + let first_n_bounds = ps.bounds.view(0, n_param); + let vtables_to_skip = + ty::count_traits_and_supertraits(tcx, first_n_bounds); + let vtable_off = vtables_to_skip + n_bound; ps.vtables.get()[vtable_off] } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 616a193a9b43e..16249c65e1b11 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -243,17 +243,7 @@ fn trans_static_method_callee(bcx: block, // 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 + ty::count_traits_and_supertraits(bcx.tcx(), *trait_polyty.bounds) }; let mname = if method_id.crate == ast::local_crate { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ad6ca83fe4ea0..d52f507e53e9e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -204,6 +204,8 @@ export DerivedFieldInfo; export AutoAdjustment; export AutoRef; export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowFn; +export iter_bound_traits_and_supertraits; +export count_traits_and_supertraits; // Data types @@ -4530,6 +4532,64 @@ pure fn determine_inherited_purity(parent_purity: ast::purity, } } +// Iterate over a type parameter's bounded traits and any supertraits +// of those traits, ignoring kinds. +fn iter_bound_traits_and_supertraits(tcx: ctxt, + bounds: param_bounds, + f: &fn(t) -> bool) { + for bounds.each |bound| { + + let bound_trait_ty = match *bound { + ty::bound_trait(bound_t) => bound_t, + + ty::bound_copy | ty::bound_send | + ty::bound_const | ty::bound_owned => { + loop; // skip non-trait bounds + } + }; + + let mut worklist = ~[]; + + let init_trait_ty = bound_trait_ty; + + worklist.push(init_trait_ty); + + let mut i = 0; + while i < worklist.len() { + let init_trait_ty = worklist[i]; + i += 1; + + let init_trait_id = match ty_to_def_id(init_trait_ty) { + Some(id) => id, + None => tcx.sess.bug( + ~"trait type should have def_id") + }; + + // Add supertraits to worklist + let supertraits = trait_supertraits(tcx, + init_trait_id); + for supertraits.each |supertrait| { + worklist.push(supertrait.tpt.ty); + } + + if !f(init_trait_ty) { + return; + } + } + } +} + +fn count_traits_and_supertraits(tcx: ctxt, + boundses: &[param_bounds]) -> uint { + let mut total = 0; + for boundses.each |bounds| { + for iter_bound_traits_and_supertraits(tcx, *bounds) |_trait_ty| { + total += 1; + } + } + return total; +} + impl mt : cmp::Eq { pure fn eq(&self, other: &mt) -> bool { (*self).ty == (*other).ty && (*self).mutbl == (*other).mutbl diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 78cd677725738..b4f5441c981a7 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -241,7 +241,7 @@ impl LookupContext { loop { match get(self_ty).sty { ty_param(p) => { - self.push_inherent_candidates_from_param(p); + self.push_inherent_candidates_from_param(self_ty, p); } ty_trait(did, ref substs, vstore) => { self.push_inherent_candidates_from_trait( @@ -305,7 +305,8 @@ impl LookupContext { } } - fn push_inherent_candidates_from_param(&self, param_ty: param_ty) { + 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(); @@ -313,8 +314,9 @@ impl LookupContext { let tcx = self.tcx(); let mut next_bound_idx = 0; // count only trait bounds let bounds = tcx.ty_param_bounds.get(param_ty.def_id.node); + for vec::each(*bounds) |bound| { - let bound_t = match *bound { + let bound_trait_ty = match *bound { ty::bound_trait(bound_t) => bound_t, ty::bound_copy | ty::bound_send | @@ -323,56 +325,64 @@ impl LookupContext { } }; - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - let (trait_id, bound_substs) = match ty::get(bound_t).sty { - ty::ty_trait(i, substs, _) => (i, substs), + let bound_substs = match ty::get(bound_trait_ty).sty { + ty::ty_trait(_, substs, _) => substs, _ => { self.bug(fmt!("add_candidates_from_param: \ non-trait bound %s", - self.ty_to_str(bound_t))); + self.ty_to_str(bound_trait_ty))); } }; + // Loop over the trait and all of its supertraits. - let worklist = dvec::DVec(); - worklist.push((trait_id, move bound_substs)); + let mut worklist = ~[]; + + let init_trait_ty = bound_trait_ty; + let init_substs = bound_substs; + + // Replace any appearance of `self` with the type of the + // generic parameter itself. Note that this is the only + // case where this replacement is necessary: in all other + // cases, we are either invoking a method directly from an + // impl or class (where the self type is not permitted), + // or from a trait type (in which case methods that refer + // to self are not permitted). + let init_substs = {self_ty: Some(rcvr_ty), ..init_substs}; + + worklist.push((init_trait_ty, init_substs)); let mut i = 0; while i < worklist.len() { - let (trait_id, bound_substs) = worklist[i]; + let (init_trait_ty, init_substs) = worklist[i]; i += 1; - // Replace any appearance of `self` with the type of the - // generic parameter itself. Note that this is the only - // case where this replacement is necessary: in all other - // cases, we are either invoking a method directly from an - // impl or class (where the self type is not permitted), - // or from a trait type (in which case methods that refer - // to self are not permitted). - let rcvr_ty = ty::mk_param(tcx, param_ty.idx, - param_ty.def_id); - let rcvr_substs = {self_ty: Some(rcvr_ty), ..bound_substs}; + let init_trait_id = ty::ty_to_def_id(init_trait_ty).get(); // Add all the supertraits of this trait to the worklist. - debug!("finding supertraits for %d:%d", trait_id.crate, - trait_id.node); - let instantiated_trait_refs = ty::trait_supertraits( - tcx, trait_id); - for instantiated_trait_refs.each |instantiated_trait_ref| { - debug!("adding supertrait"); + let supertraits = ty::trait_supertraits(tcx, + init_trait_id); + for supertraits.each |supertrait| { + debug!("adding supertrait: %?", + supertrait.def_id); let new_substs = ty::subst_substs( tcx, - &instantiated_trait_ref.tpt.substs, - &rcvr_substs); + &supertrait.tpt.substs, + &init_substs); + + // Again replacing the self type + let new_substs = {self_ty: Some(rcvr_ty), ..new_substs}; - worklist.push( - (instantiated_trait_ref.def_id, new_substs)); + worklist.push((supertrait.tpt.ty, new_substs)); } - let trait_methods = ty::trait_methods(tcx, trait_id); + + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, init_trait_id); let pos = { // FIXME #3453 can't use trait_methods.position match vec::position(*trait_methods, @@ -381,6 +391,8 @@ impl LookupContext { { Some(pos) => pos, None => { + debug!("trait doesn't contain method: %?", + init_trait_id); loop; // check next trait or bound } } @@ -389,18 +401,21 @@ impl LookupContext { let (rcvr_ty, rcvr_substs) = self.create_rcvr_ty_and_substs_for_method( - method.self_ty, rcvr_ty, move rcvr_substs); + method.self_ty, rcvr_ty, move init_substs); - self.inherent_candidates.push(Candidate { + let cand = Candidate { rcvr_ty: rcvr_ty, rcvr_substs: rcvr_substs, num_method_tps: method.tps.len(), self_mode: get_mode_from_self_type(method.self_ty), - origin: method_param({trait_id:trait_id, + origin: method_param({trait_id:init_trait_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); } } } @@ -775,6 +790,8 @@ impl LookupContext { let relevant_candidates = candidates.filter_to_vec(|c| self.is_relevant(self_ty, &c)); + let relevant_candidates = self.merge_candidates(relevant_candidates); + if relevant_candidates.len() == 0 { return None; } @@ -791,6 +808,52 @@ impl LookupContext { Some(self.confirm_candidate(self_ty, &relevant_candidates[0])) } + fn merge_candidates(&self, candidates: &[Candidate]) -> ~[Candidate] { + let mut merged = ~[]; + let mut i = 0; + while i < candidates.len() { + let candidate_a = candidates[i]; + + let mut skip = false; + + let mut j = i + 1; + while j < candidates.len() { + let candidate_b = candidates[j]; + debug!("attempting to merge %? and %?", + candidate_a, candidate_b); + let candidates_same = match (&candidate_a.origin, + &candidate_b.origin) { + (&method_param(p1), &method_param(p2)) => { + let same_trait = p1.trait_id == p2.trait_id; + let same_method = p1.method_num == p2.method_num; + let same_param = p1.param_num == p2.param_num; + // The bound number may be different because + // multiple bounds may lead to the same trait + // impl + same_trait && same_method && same_param + } + _ => false + }; + if candidates_same { + skip = true; + break; + } + j += 1; + } + + i += 1; + + if skip { + // There are more than one of these and we need only one + loop; + } else { + merged.push(candidate_a); + } + } + + return merged; + } + fn confirm_candidate(&self, self_ty: ty::t, candidate: &Candidate) diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 7de2de708cc98..99999ca2ae10d 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -67,28 +67,43 @@ fn lookup_vtables(vcx: &VtableContext, let tcx = vcx.tcx(); let mut result = ~[], i = 0u; for substs.tps.each |ty| { - for vec::each(*bounds[i]) |bound| { - match *bound { - ty::bound_trait(i_ty) => { - let i_ty = ty::subst(tcx, substs, i_ty); - match lookup_vtable_covariant(vcx, location_info, *ty, i_ty, - allow_unsafe, is_early) { - Some(vtable) => result.push(vtable), - None => { - vcx.tcx().sess.span_fatal( - location_info.span, - fmt!("failed to find an implementation of trait \ - %s for %s", - ty_to_str(vcx.tcx(), i_ty), - ty_to_str(vcx.tcx(), *ty))); - } + for ty::iter_bound_traits_and_supertraits( + tcx, bounds[i]) |trait_ty| { + + debug!("about to subst: %?, %?", + ty_to_str(tcx, trait_ty), + ty::substs_to_str(tcx, substs)); + + let new_substs = {self_ty: Some(*ty), ..*substs}; + let trait_ty = ty::subst(tcx, &new_substs, trait_ty); + + debug!("after subst: %?", + ty_to_str(tcx, trait_ty)); + + match lookup_vtable(vcx, location_info, *ty, trait_ty, + allow_unsafe, is_early) { + Some(vtable) => result.push(vtable), + None => { + vcx.tcx().sess.span_fatal( + location_info.span, + fmt!("failed to find an implementation of \ + trait %s for %s", + ty_to_str(vcx.tcx(), trait_ty), + ty_to_str(vcx.tcx(), *ty))); } - } - _ => () } } i += 1u; } + debug!("lookup_vtables result(\ + location_info=%?, + # bounds=%?, \ + substs=%s, \ + result=%?", + location_info, + bounds.len(), + ty::substs_to_str(vcx.tcx(), substs), + result); @result } @@ -112,70 +127,15 @@ fn relate_trait_tys(vcx: &VtableContext, location_info: &LocationInfo, } // Look up the vtable to use when treating an item of type `t` as if it has -// type `trait_ty`. This does allow subtraits. -fn lookup_vtable_covariant(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - trait_ty: ty::t, - allow_unsafe: bool, - is_early: bool) - -> Option { - debug!("lookup_vtable_covariant(ty: %s, trait_ty=%s)", - vcx.infcx.ty_to_str(ty), - vcx.infcx.ty_to_str(trait_ty)); - - let worklist = dvec::DVec(); - worklist.push(trait_ty); - while worklist.len() > 0 { - let trait_ty = worklist.pop(); - let result = lookup_vtable_invariant(vcx, location_info, ty, trait_ty, - allow_unsafe, is_early); - if result.is_some() { - return result; - } - - // Add subtraits to the worklist, if applicable. - match ty::get(trait_ty).sty { - ty::ty_trait(trait_id, _, _) => { - let table = vcx.ccx.coherence_info.supertrait_to_subtraits; - match table.find(trait_id) { - None => {} - Some(subtraits) => { - for subtraits.each |subtrait_id| { - // XXX: This is wrong; subtraits should themselves - // have substs. - let substs = - { self_r: None, self_ty: None, tps: ~[] }; - let trait_ty = ty::mk_trait(vcx.tcx(), - *subtrait_id, - substs, - ty::vstore_box); - worklist.push(trait_ty); - } - } - } - } - _ => { - vcx.tcx().sess.impossible_case(location_info.span, - "lookup_vtable_covariant: \ - non-trait in worklist"); - } - } - } - - return None; -} - -// Look up the vtable to use when treating an item of type `t` as if it has -// type `trait_ty`. This does not allow subtraits. -fn lookup_vtable_invariant(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - trait_ty: ty::t, - allow_unsafe: bool, - is_early: bool) - -> Option { - debug!("lookup_vtable_invariant(ty=%s, trait_ty=%s)", +// type `trait_ty` +fn lookup_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ty: ty::t, + allow_unsafe: bool, + is_early: bool) + -> Option { + debug!("lookup_vtable(ty=%s, trait_ty=%s)", vcx.infcx.ty_to_str(ty), vcx.infcx.ty_to_str(trait_ty)); let _i = indenter(); @@ -183,7 +143,7 @@ fn lookup_vtable_invariant(vcx: &VtableContext, let (trait_id, trait_substs, trait_vstore) = match ty::get(trait_ty).sty { ty::ty_trait(did, substs, vstore) => (did, substs, vstore), _ => tcx.sess.impossible_case(location_info.span, - "lookup_vtable_invariant: \ + "lookup_vtable: \ don't know how to handle a non-trait") }; let ty = match fixup_ty(vcx, location_info, ty, is_early) { @@ -201,32 +161,35 @@ fn lookup_vtable_invariant(vcx: &VtableContext, match ty::get(ty).sty { ty::ty_param({idx: n, def_id: did}) => { let mut n_bound = 0; - for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| { - match *bound { - ty::bound_send | ty::bound_copy | ty::bound_const | - ty::bound_owned => { - /* ignore */ - } - ty::bound_trait(ity) => { - match ty::get(ity).sty { - ty::ty_trait(idid, _, _) => { - if trait_id == idid { - debug!("(checking vtable) @0 relating \ - ty to trait ty with did %?", - idid); - relate_trait_tys(vcx, location_info, - trait_ty, ity); - return Some(vtable_param(n, n_bound)); - } - } - _ => tcx.sess.impossible_case( - location_info.span, - "lookup_vtable_invariant: in loop, \ - don't know how to handle a non-trait ity") + let bounds = tcx.ty_param_bounds.get(did.node); + for ty::iter_bound_traits_and_supertraits( + tcx, bounds) |ity| { + debug!("checking bounds trait %?", + vcx.infcx.ty_to_str(ity)); + + match ty::get(ity).sty { + ty::ty_trait(idid, _, _) => { + if trait_id == idid { + debug!("(checking vtable) @0 \ + relating ty to trait \ + ty with did %?", + idid); + relate_trait_tys(vcx, location_info, + trait_ty, ity); + let vtable = vtable_param(n, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); } - n_bound += 1u; } + _ => tcx.sess.impossible_case( + location_info.span, + "lookup_vtable: in loop, \ + don't know how to handle a \ + non-trait ity") } + + n_bound += 1; } } @@ -321,8 +284,6 @@ fn lookup_vtable_invariant(vcx: &VtableContext, // impl. let {substs: substs, ty: for_ty} = impl_self_ty(vcx, location_info, im.did); - let im_bs = ty::lookup_item_type(tcx, - im.did).bounds; match infer::mk_subty(vcx.infcx, false, location_info.span, @@ -407,6 +368,8 @@ fn lookup_vtable_invariant(vcx: &VtableContext, // to. connect_trait_tps requires these // lists of types to unify pairwise. + let im_bs = ty::lookup_item_type(tcx, + im.did).bounds; connect_trait_tps(vcx, location_info, substs_f.tps, @@ -531,8 +494,9 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { Some(ref substs) => { let def = cx.tcx.def_map.get(ex.id); let did = ast_util::def_id_of_def(def); - debug!("early resolve expr: def %?", def); let item_ty = ty::lookup_item_type(cx.tcx, did); + debug!("early resolve expr: def %? %?, %?, %?", ex.id, did, def, + fcx.infcx().ty_to_str(item_ty.ty)); if has_trait_bounds(*item_ty.bounds) { for item_ty.bounds.each |bounds| { debug!("early_resolve_expr: looking up vtables for bound \ @@ -565,6 +529,7 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { ast::expr_field(_, _, _) => ex.id, _ => ex.callee_id }; + let substs = fcx.node_ty_substs(callee_id); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), @@ -589,12 +554,12 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { let ty = fcx.expr_ty(src); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtable_opt = - lookup_vtable_invariant(&vcx, - &location_info_for_expr(ex), - ty, - target_ty, - true, - is_early); + lookup_vtable(&vcx, + &location_info_for_expr(ex), + ty, + target_ty, + true, + is_early); match vtable_opt { None => { // Try the new-style boxed trait; "@int as @Trait". @@ -615,12 +580,12 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { let location_info = &location_info_for_expr(ex); let vtable_opt = - lookup_vtable_invariant(&vcx, - location_info, - mt.ty, - target_ty, - true, - is_early); + lookup_vtable(&vcx, + location_info, + mt.ty, + target_ty, + true, + is_early); match vtable_opt { Some(vtable) => { // Map this expression to that diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 97968e11ffa92..d441f11959d07 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -144,9 +144,6 @@ struct CoherenceInfo { // the associated trait must be imported at the call site. extension_methods: HashMap>, - // A mapping from a supertrait to its subtraits. - supertrait_to_subtraits: HashMap>, - // A mapping from an implementation ID to the method info and trait method // ID of the provided (a.k.a. default) methods in the traits that that // implementation implements. @@ -157,7 +154,6 @@ fn CoherenceInfo() -> CoherenceInfo { CoherenceInfo { inherent_methods: HashMap(), extension_methods: HashMap(), - supertrait_to_subtraits: HashMap(), provided_methods: HashMap(), } } @@ -204,9 +200,6 @@ impl CoherenceChecker { item_class(struct_def, _) => { self.check_implementation(item, struct_def.traits); } - item_trait(_, supertraits, _) => { - self.register_inherited_trait(item, supertraits); - } _ => { // Nothing to do. } @@ -215,12 +208,8 @@ impl CoherenceChecker { .. *default_simple_visitor() })); - // Check trait coherence. - for self.crate_context.coherence_info.extension_methods.each - |def_id, items| { - - self.check_implementation_coherence(def_id, items); - } + // Check that there are no overlapping trait instances + self.check_implementation_coherence(); // Check whether traits with base types are in privileged scopes. self.check_privileged_scopes(crate); @@ -377,27 +366,6 @@ impl CoherenceChecker { } } - fn register_inherited_trait(item: @item, supertraits: ~[@trait_ref]) { - // XXX: This is wrong. We need to support substitutions; e.g. - // trait Foo : Bar. - let supertrait_to_subtraits = - self.crate_context.coherence_info.supertrait_to_subtraits; - let subtrait_id = local_def(item.id); - for supertraits.each |supertrait| { - let supertrait_id = self.trait_ref_to_trait_def_id(*supertrait); - match supertrait_to_subtraits.find(supertrait_id) { - None => { - let new_vec = @dvec::DVec(); - new_vec.push(subtrait_id); - supertrait_to_subtraits.insert(supertrait_id, new_vec); - } - Some(existing_vec) => { - existing_vec.push(subtrait_id); - } - } - } - } - fn add_inherent_method(base_def_id: def_id, implementation: @Impl) { let implementation_list; match self.crate_context.coherence_info.inherent_methods @@ -432,29 +400,57 @@ impl CoherenceChecker { implementation_list.push(implementation); } - fn check_implementation_coherence(_trait_def_id: def_id, - implementations: @DVec<@Impl>) { + fn check_implementation_coherence() { + let coherence_info = &self.crate_context.coherence_info; + let extension_methods = &coherence_info.extension_methods; + + for extension_methods.each_key |trait_id| { + self.check_implementation_coherence_of(trait_id); + } + } + + fn check_implementation_coherence_of(trait_def_id: def_id) { // Unify pairs of polytypes. - for range(0, implementations.len()) |i| { - let implementation_a = implementations.get_elt(i); + do self.iter_impls_of_trait(trait_def_id) |a| { + let implementation_a = a; let polytype_a = self.get_self_type_for_implementation(implementation_a); - for range(i + 1, implementations.len()) |j| { - let implementation_b = implementations.get_elt(j); - let polytype_b = - self.get_self_type_for_implementation(implementation_b); + do self.iter_impls_of_trait(trait_def_id) |b| { + let implementation_b = b; - if self.polytypes_unify(polytype_a, polytype_b) { - let session = self.crate_context.tcx.sess; - session.span_err(self.span_of_impl(implementation_b), - ~"conflicting implementations for a \ - trait"); - session.span_note(self.span_of_impl(implementation_a), - ~"note conflicting implementation \ - here"); + // An impl is coherent with itself + if a.did != b.did { + let polytype_b = self.get_self_type_for_implementation( + implementation_b); + + if self.polytypes_unify(polytype_a, polytype_b) { + let session = self.crate_context.tcx.sess; + session.span_err(self.span_of_impl(implementation_b), + ~"conflicting implementations for a \ + trait"); + session.span_note(self.span_of_impl(implementation_a), + ~"note conflicting implementation \ + here"); + } + } + } + } + } + + fn iter_impls_of_trait(trait_def_id: def_id, + f: &fn(@Impl)) { + + let coherence_info = &self.crate_context.coherence_info; + let extension_methods = &coherence_info.extension_methods; + + match extension_methods.find(trait_def_id) { + Some(impls) => { + for uint::range(0, impls.len()) |i| { + f(impls[i]); } } + None => { /* no impls? */ } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0c6fe58576810..9dda2da458a45 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -465,22 +465,27 @@ fn check_methods_against_trait(ccx: @crate_ctxt, } } - for vec::each(*ty::trait_methods(tcx, did)) |trait_m| { - match vec::find(impl_ms, |impl_m| trait_m.ident == impl_m.mty.ident) { - Some(ref cm) => { + // Check that each method we impl is a method on the trait + // Trait methods we don't implement must be default methods, but if not + // we'll catch it in coherence + let trait_ms = ty::trait_methods(tcx, did); + for impl_ms.each |impl_m| { + match trait_ms.find(|trait_m| trait_m.ident == impl_m.mty.ident) { + Some(ref trait_m) => { compare_impl_method( - ccx.tcx, vec::len(tps), cm, trait_m, + ccx.tcx, tps.len(), impl_m, trait_m, &tpt.substs, selfty); } None => { - // If we couldn't find an implementation for trait_m in - // the impl, then either this method has a default - // implementation or we're using the trait-provided - // version. Either way, we handle this later, during the - // coherence phase. + // This method is not part of the trait + tcx.sess.span_err( + impl_m.span, + fmt!("method `%s` is not a member of trait `%s`", + tcx.sess.str_of(impl_m.mty.ident), + path_to_str(a_trait_ty.path, tcx.sess.intr()))); } - } // match - } // |trait_m| + } + } } // fn fn convert_field(ccx: @crate_ctxt, diff --git a/src/libstd/map.rs b/src/libstd/map.rs index d68970679ad99..b1909bfb067a2 100644 --- a/src/libstd/map.rs +++ b/src/libstd/map.rs @@ -390,7 +390,7 @@ pub mod chained { } } - impl T: ToStr { + impl T { fn to_writer(wr: io::Writer) { if self.count == 0u { wr.write_str(~"{}"); @@ -410,7 +410,9 @@ pub mod chained { }; wr.write_str(~" }"); } + } + impl T: ToStr { pure fn to_str() -> ~str unsafe { // Meh -- this should be safe do io::with_str_writer |wr| { self.to_writer(wr) } diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 2dd0c2b286d8f..cd874dc9ce86b 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -824,9 +824,6 @@ impl TcpSocketBuf: io::Reader { bytes[0] as int } } - fn unread_byte(amt: int) { - self.data.buf.unshift(amt as u8); - } fn eof() -> bool { self.end_of_stream } diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index 3f9d308584d45..dd773d25687e1 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -101,7 +101,6 @@ impl SmallIntMap: map::Map { } pure fn get(key: uint) -> V { get(self, key) } pure fn find(key: uint) -> Option { find(self, key) } - fn rehash() { fail } fn update_with_key(key: uint, val: V, ff: fn(uint, V, V) -> V) -> bool { match self.find(key) { diff --git a/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs new file mode 100644 index 0000000000000..99f4119b1ccee --- /dev/null +++ b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs @@ -0,0 +1,11 @@ +pub trait Foo { fn f() -> int; } +pub trait Bar { fn g() -> int; } +pub trait Baz { fn h() -> int; } + +pub struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } +impl A : Baz { fn h() -> int { 30 } } + + diff --git a/src/test/auxiliary/trait_inheritance_auto_xc_aux.rs b/src/test/auxiliary/trait_inheritance_auto_xc_aux.rs new file mode 100644 index 0000000000000..8fe7b72f8e7d8 --- /dev/null +++ b/src/test/auxiliary/trait_inheritance_auto_xc_aux.rs @@ -0,0 +1,7 @@ +trait Foo { fn f() -> int; } +trait Bar { fn g() -> int; } +trait Baz { fn h() -> int; } + +trait Quux: Foo, Bar, Baz { } + +impl T: Quux { } diff --git a/src/test/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs b/src/test/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs new file mode 100644 index 0000000000000..00029d11bf4cb --- /dev/null +++ b/src/test/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs @@ -0,0 +1,12 @@ + +pub trait Foo { + fn f() -> int; +} + +pub struct A { + x: int +} + +impl A : Foo { + fn f() -> int { 10 } +} diff --git a/src/test/auxiliary/trait_inheritance_overloading_xc.rs b/src/test/auxiliary/trait_inheritance_overloading_xc.rs index 235a174c838f0..ceeee89de6a56 100644 --- a/src/test/auxiliary/trait_inheritance_overloading_xc.rs +++ b/src/test/auxiliary/trait_inheritance_overloading_xc.rs @@ -1,9 +1,31 @@ -pub trait MyNum : Add, Sub, Mul { +use cmp::Eq; + +pub trait MyNum : Add, Sub, Mul, Eq { +} + +pub struct MyInt { + val: int +} + +pub impl MyInt : Add { + pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) } +} + +pub impl MyInt : Sub { + pure fn sub(&self, other: &MyInt) -> MyInt { mi(self.val - other.val) } +} + +pub impl MyInt : Mul { + pure fn mul(&self, other: &MyInt) -> MyInt { mi(self.val * other.val) } } -pub impl int : MyNum { - pure fn add(other: &int) -> int { self + *other } - pure fn sub(&self, other: &int) -> int { *self - *other } - pure fn mul(&self, other: &int) -> int { *self * *other } +pub impl MyInt : Eq { + pure fn eq(&self, other: &MyInt) -> bool { self.val == other.val } + + pure fn ne(&self, other: &MyInt) -> bool { !self.eq(other) } } +pub impl MyInt : MyNum; + +pure fn mi(v: int) -> MyInt { MyInt { val: v } } + diff --git a/src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs b/src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs new file mode 100644 index 0000000000000..b65b0d9d4accc --- /dev/null +++ b/src/test/compile-fail/trait-impl-can-not-have-untraitful-methods.rs @@ -0,0 +1,7 @@ +trait A { } + +impl int: A { + fn foo() { } //~ ERROR method `foo` is not a member of trait `A` +} + +fn main() { } \ No newline at end of file diff --git a/src/test/compile-fail/trait-inheritance-missing-requirement.rs b/src/test/compile-fail/trait-inheritance-missing-requirement.rs new file mode 100644 index 0000000000000..3105f72415af4 --- /dev/null +++ b/src/test/compile-fail/trait-inheritance-missing-requirement.rs @@ -0,0 +1,23 @@ +// xfail-test +// error-pattern: what + +trait Foo { + fn f(); +} + +trait Bar : Foo { + fn g(); +} + +struct A { + x: int +} + +// Can't implement Bar without an impl of Foo +impl A : Bar { + fn g() { } +} + +fn main() { +} + diff --git a/src/test/run-pass/trait-inheritance-auto-xc-2.rs b/src/test/run-pass/trait-inheritance-auto-xc-2.rs new file mode 100644 index 0000000000000..4eac97102506a --- /dev/null +++ b/src/test/run-pass/trait-inheritance-auto-xc-2.rs @@ -0,0 +1,23 @@ +// xfail-fast +// aux-build:trait_inheritance_auto_xc_2_aux.rs + +extern mod aux(name = "trait_inheritance_auto_xc_2_aux"); + +// aux defines impls of Foo, Bar and Baz for A +use aux::{Foo, Bar, Baz, A}; + +// We want to extend all Foo, Bar, Bazes to Quuxes +pub trait Quux: Foo, Bar, Baz { } +impl T: Quux { } + +fn f(a: &T) { + assert a.f() == 10; + assert a.g() == 20; + assert a.h() == 30; +} + +fn main() { + let a = &A { x: 3 }; + f(a); +} + diff --git a/src/test/run-pass/trait-inheritance-auto-xc.rs b/src/test/run-pass/trait-inheritance-auto-xc.rs new file mode 100644 index 0000000000000..4bc62fab51b5a --- /dev/null +++ b/src/test/run-pass/trait-inheritance-auto-xc.rs @@ -0,0 +1,24 @@ +// xfail-fast +// aux-build:trait_inheritance_auto_xc_aux.rs + +extern mod aux(name = "trait_inheritance_auto_xc_aux"); + +use aux::{Foo, Bar, Baz, Quux}; + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } +impl A : Baz { fn h() -> int { 30 } } + +fn f(a: &T) { + assert a.f() == 10; + assert a.g() == 20; + assert a.h() == 30; +} + +fn main() { + let a = &A { x: 3 }; + f(a); +} + diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs new file mode 100644 index 0000000000000..29de9f111dcbd --- /dev/null +++ b/src/test/run-pass/trait-inheritance-auto.rs @@ -0,0 +1,27 @@ +// Testing that this impl turns A into a Quux, because +// A is already a Foo Bar Baz +impl T: Quux { } + +trait Foo { fn f() -> int; } +trait Bar { fn g() -> int; } +trait Baz { fn h() -> int; } + +trait Quux: Foo, Bar, Baz { } + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } +impl A : Baz { fn h() -> int { 30 } } + +fn f(a: &T) { + assert a.f() == 10; + assert a.g() == 20; + assert a.h() == 30; +} + +fn main() { + let a = &A { x: 3 }; + f(a); +} + diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs new file mode 100644 index 0000000000000..dd3f53cfbdd35 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs @@ -0,0 +1,18 @@ +trait Foo { fn f() -> int; } +trait Bar : Foo { fn g() -> int; } + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } + +// Call a function on Foo, given a T: Bar +fn gg(a: &T) -> int { + a.f() +} + +fn main() { + let a = &A { x: 3 }; + assert gg(a) == 10; +} + diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs new file mode 100644 index 0000000000000..222d8e7291d5c --- /dev/null +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs @@ -0,0 +1,21 @@ +trait Foo { fn f() -> int; } +trait Bar : Foo { fn g() -> int; } +trait Baz : Bar { fn h() -> int; } + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } +impl A : Baz { fn h() -> int { 30 } } + +// Call a function on Foo, given a T: Baz, +// which is inherited via Bar +fn gg(a: &T) -> int { + a.f() +} + +fn main() { + let a = &A { x: 3 }; + assert gg(a) == 10; +} + diff --git a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs new file mode 100644 index 0000000000000..6cb0551652061 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs @@ -0,0 +1,31 @@ +// Testing that we can cast to a subtrait and call subtrait +// methods. Not testing supertrait methods + +trait Foo { + fn f() -> int; +} + +trait Bar : Foo { + fn g() -> int; +} + +struct A { + x: int +} + +impl A : Foo { + fn f() -> int { 10 } +} + +impl A : Bar { + fn g() -> int { 20 } +} + +fn main() { + let a = &A { x: 3 }; + let afoo = a as &Foo; + let abar = a as &Bar; + assert afoo.f() == 10; + assert abar.g() == 20; +} + diff --git a/src/test/run-pass/trait-inheritance-cast.rs b/src/test/run-pass/trait-inheritance-cast.rs new file mode 100644 index 0000000000000..1cd23f497339f --- /dev/null +++ b/src/test/run-pass/trait-inheritance-cast.rs @@ -0,0 +1,33 @@ +// xfail-test +// Testing that supertrait methods can be called on subtrait object types +// It's not clear yet that we want this + +trait Foo { + fn f() -> int; +} + +trait Bar : Foo { + fn g() -> int; +} + +struct A { + x: int +} + +impl A : Foo { + fn f() -> int { 10 } +} + +impl A : Bar { + fn g() -> int { 20 } +} + +fn main() { + let a = &A { x: 3 }; + let afoo = a as &Foo; + let abar = a as &Bar; + assert afoo.f() == 10; + assert abar.g() == 20; + assert abar.f() == 10; +} + diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs new file mode 100644 index 0000000000000..9f588ddb907c7 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -0,0 +1,18 @@ +// xfail-fast +// aux-build:trait_inheritance_cross_trait_call_xc_aux.rs + +extern mod aux(name = "trait_inheritance_cross_trait_call_xc_aux"); + +trait Bar : aux::Foo { + fn g() -> int; +} + +impl aux::A : Bar { + fn g() -> int { self.f() } +} + +fn main() { + let a = &aux::A { x: 3 }; + assert a.g() == 10; +} + diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call.rs b/src/test/run-pass/trait-inheritance-cross-trait-call.rs new file mode 100644 index 0000000000000..a96bfb41f4465 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-cross-trait-call.rs @@ -0,0 +1,17 @@ +trait Foo { fn f() -> int; } +trait Bar : Foo { fn g() -> int; } + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } + +impl A : Bar { + // Testing that this impl can call the impl of Foo + fn g() -> int { self.f() } +} + +fn main() { + let a = &A { x: 3 }; + assert a.g() == 10; +} + diff --git a/src/test/run-pass/trait-inheritance-diamond.rs b/src/test/run-pass/trait-inheritance-diamond.rs new file mode 100644 index 0000000000000..4c18d92a8c0d8 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-diamond.rs @@ -0,0 +1,25 @@ +// B and C both require A, so D does as well, twice, but that's just fine + +trait A { fn a(&self) -> int; } +trait B: A { fn b(&self) -> int; } +trait C: A { fn c(&self) -> int; } +trait D: B, C { fn d(&self) -> int; } + +struct S { bogus: () } + +impl S: A { fn a(&self) -> int { 10 } } +impl S: B { fn b(&self) -> int { 20 } } +impl S: C { fn c(&self) -> int { 30 } } +impl S: D { fn d(&self) -> int { 40 } } + +fn f(x: &T) { + assert x.a() == 10; + assert x.b() == 20; + assert x.c() == 30; + assert x.d() == 40; +} + +fn main() { + let value = &S { bogus: () }; + f(value); +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance-multiple-inheritors.rs b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs new file mode 100644 index 0000000000000..fdc68a31997f9 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs @@ -0,0 +1,20 @@ +trait A { fn a(&self) -> int; } +trait B: A { fn b(&self) -> int; } +trait C: A { fn c(&self) -> int; } + +struct S { bogus: () } + +impl S: A { fn a(&self) -> int { 10 } } +impl S: B { fn b(&self) -> int { 20 } } +impl S: C { fn c(&self) -> int { 30 } } + +// Both B and C inherit from A +fn f(x: &T) { + assert x.a() == 10; + assert x.b() == 20; + assert x.c() == 30; +} + +fn main() { + f(&S { bogus: () }) +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance-multiple-params.rs b/src/test/run-pass/trait-inheritance-multiple-params.rs new file mode 100644 index 0000000000000..0a5330b68f8ba --- /dev/null +++ b/src/test/run-pass/trait-inheritance-multiple-params.rs @@ -0,0 +1,23 @@ +trait A { fn a(&self) -> int; } +trait B: A { fn b(&self) -> int; } +trait C: A { fn c(&self) -> int; } + +struct S { bogus: () } + +impl S: A { fn a(&self) -> int { 10 } } +impl S: B { fn b(&self) -> int { 20 } } +impl S: C { fn c(&self) -> int { 30 } } + +// Multiple type params, multiple levels of inheritance +fn f(x: &X, y: &Y, z: &Z) { + assert x.a() == 10; + assert y.a() == 10; + assert y.b() == 20; + assert z.a() == 10; + assert z.c() == 30; +} + +fn main() { + let s = &S { bogus: () }; + f(s, s, s); +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs new file mode 100644 index 0000000000000..2266b67c23439 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -0,0 +1,14 @@ +use cmp::{Eq, Ord}; +use num::from_int; + +extern mod std; +use std::cmp::FuzzyEq; + +pub trait NumExt: Num, Eq, Ord {} + +pub trait FloatExt: NumExt, FuzzyEq {} + +fn greater_than_one(n: &T) -> bool { *n > from_int(1) } +fn greater_than_one_float(n: &T) -> bool { *n > from_int(1) } + +fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num0.rs b/src/test/run-pass/trait-inheritance-num0.rs new file mode 100644 index 0000000000000..6c3b22894f56a --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num0.rs @@ -0,0 +1,16 @@ +// Extending Num and using inherited static methods + +use num::from_int; + +trait Num { + static fn from_int(i: int) -> self; + fn gt(&self, other: &self) -> bool; +} + +pub trait NumExt: Num { } + +fn greater_than_one(n: &T) -> bool { + n.gt(&from_int(1)) +} + +fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num1.rs b/src/test/run-pass/trait-inheritance-num1.rs new file mode 100644 index 0000000000000..57487f072f389 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num1.rs @@ -0,0 +1,12 @@ +// Using the real Num from core + +use cmp::Ord; +use num::from_int; + +pub trait NumExt: Num, Ord { } + +fn greater_than_one(n: &T) -> bool { + *n > from_int(1) +} + +fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs new file mode 100644 index 0000000000000..5f51f943817d2 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -0,0 +1,96 @@ +// A more complex example of numeric extensions + +use cmp::{Eq, Ord}; +use num::from_int; + +extern mod std; +use std::cmp::FuzzyEq; + +pub trait TypeExt {} + + +pub impl u8: TypeExt {} +pub impl u16: TypeExt {} +pub impl u32: TypeExt {} +pub impl u64: TypeExt {} +pub impl uint: TypeExt {} + +pub impl i8: TypeExt {} +pub impl i16: TypeExt {} +pub impl i32: TypeExt {} +pub impl i64: TypeExt {} +pub impl int: TypeExt {} + +pub impl f32: TypeExt {} +pub impl f64: TypeExt {} +pub impl float: TypeExt {} + + +pub trait NumExt: TypeExt, Eq, Ord, Num {} + +pub impl u8: NumExt {} +pub impl u16: NumExt {} +pub impl u32: NumExt {} +pub impl u64: NumExt {} +pub impl uint: NumExt {} + +pub impl i8: NumExt {} +pub impl i16: NumExt {} +pub impl i32: NumExt {} +pub impl i64: NumExt {} +pub impl int: NumExt {} + +pub impl f32: NumExt {} +pub impl f64: NumExt {} +pub impl float: NumExt {} + + +pub trait UnSignedExt: NumExt {} + +pub impl u8: UnSignedExt {} +pub impl u16: UnSignedExt {} +pub impl u32: UnSignedExt {} +pub impl u64: UnSignedExt {} +pub impl uint: UnSignedExt {} + + +pub trait SignedExt: NumExt {} + +pub impl i8: SignedExt {} +pub impl i16: SignedExt {} +pub impl i32: SignedExt {} +pub impl i64: SignedExt {} +pub impl int: SignedExt {} + +pub impl f32: SignedExt {} +pub impl f64: SignedExt {} +pub impl float: SignedExt {} + + +pub trait IntegerExt: NumExt {} + +pub impl u8: IntegerExt {} +pub impl u16: IntegerExt {} +pub impl u32: IntegerExt {} +pub impl u64: IntegerExt {} +pub impl uint: IntegerExt {} + +pub impl i8: IntegerExt {} +pub impl i16: IntegerExt {} +pub impl i32: IntegerExt {} +pub impl i64: IntegerExt {} +pub impl int: IntegerExt {} + + +pub trait FloatExt: NumExt , FuzzyEq {} + +pub impl f32: FloatExt {} +pub impl f64: FloatExt {} +pub impl float: FloatExt {} + + +fn test_float_ext(n: T) { io::println(fmt!("%?", n < n)) } + +fn main() { + test_float_ext(1f32); +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance-num3.rs b/src/test/run-pass/trait-inheritance-num3.rs new file mode 100644 index 0000000000000..656e63906621c --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num3.rs @@ -0,0 +1,12 @@ +use cmp::{Eq, Ord}; +use num::from_int; + +pub trait NumExt: Eq, Ord, Num {} + +pub impl f32: NumExt {} + +fn num_eq_one(n: T) { io::println(fmt!("%?", n == from_int(1))) } + +fn main() { + num_eq_one(1f32); // you need to actually use the function to trigger the ICE +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs new file mode 100644 index 0000000000000..fa30ceff8ad01 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-num5.rs @@ -0,0 +1,15 @@ +use cmp::{Eq, Ord}; +use num::from_int; + +pub trait NumExt: Eq, Num {} + +pub impl f32: NumExt {} +pub impl int: NumExt {} + +fn num_eq_one() -> T { + from_int(1) +} + +fn main() { + num_eq_one::(); // you need to actually use the function to trigger the ICE +} diff --git a/src/test/run-pass/trait-inheritance-overloading-simple.rs b/src/test/run-pass/trait-inheritance-overloading-simple.rs new file mode 100644 index 0000000000000..13867eed52f1c --- /dev/null +++ b/src/test/run-pass/trait-inheritance-overloading-simple.rs @@ -0,0 +1,25 @@ +use cmp::Eq; + +trait MyNum : Eq { } + +struct MyInt { val: int } + +impl MyInt : Eq { + pure fn eq(&self, other: &MyInt) -> bool { self.val == other.val } + pure fn ne(&self, other: &MyInt) -> bool { !self.eq(other) } +} + +impl MyInt : MyNum; + +fn f(x: T, y: T) -> bool { + return x == y; +} + +pure fn mi(v: int) -> MyInt { MyInt { val: v } } + +fn main() { + let (x, y, z) = (mi(3), mi(5), mi(3)); + assert x != y; + assert x == z; +} + diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index a38a834fb7263..585ce63b38997 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -2,18 +2,19 @@ // aux-build:trait_inheritance_overloading_xc.rs extern mod trait_inheritance_overloading_xc; -use trait_inheritance_overloading_xc::MyNum; +use trait_inheritance_overloading_xc::{MyNum, MyInt}; fn f(x: T, y: T) -> (T, T, T) { return (x + y, x - y, x * y); } +pure fn mi(v: int) -> MyInt { MyInt { val: v } } + fn main() { - let (x, y) = (3, 5); + let (x, y) = (mi(3), mi(5)); let (a, b, c) = f(x, y); - assert a == 8; - assert b == -2; - assert c == 15; + assert a == mi(8); + assert b == mi(-2); + assert c == mi(15); } - diff --git a/src/test/run-pass/trait-inheritance-overloading.rs b/src/test/run-pass/trait-inheritance-overloading.rs index f8bf9faa186f6..def37d1f9505c 100644 --- a/src/test/run-pass/trait-inheritance-overloading.rs +++ b/src/test/run-pass/trait-inheritance-overloading.rs @@ -1,21 +1,39 @@ -trait MyNum : Add, Sub, Mul { +use cmp::Eq; + +trait MyNum : Add, Sub, Mul, Eq { } + +struct MyInt { val: int } + +impl MyInt : Add { + pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) } +} + +impl MyInt : Sub { + pure fn sub(&self, other: &MyInt) -> MyInt { mi(self.val - other.val) } } -impl int : MyNum { - pure fn add(other: &int) -> int { self + *other } - pure fn sub(&self, other: &int) -> int { *self - *other } - pure fn mul(&self, other: &int) -> int { *self * *other } +impl MyInt : Mul { + pure fn mul(&self, other: &MyInt) -> MyInt { mi(self.val * other.val) } } +impl MyInt : Eq { + pure fn eq(&self, other: &MyInt) -> bool { self.val == other.val } + pure fn ne(&self, other: &MyInt) -> bool { !self.eq(other) } +} + +impl MyInt : MyNum; + fn f(x: T, y: T) -> (T, T, T) { return (x + y, x - y, x * y); } +pure fn mi(v: int) -> MyInt { MyInt { val: v } } + fn main() { - let (x, y) = (3, 5); + let (x, y) = (mi(3), mi(5)); let (a, b, c) = f(x, y); - assert a == 8; - assert b == -2; - assert c == 15; + assert a == mi(8); + assert b == mi(-2); + assert c == mi(15); } diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs index 37dd11aadc482..9725b18ca0f19 100644 --- a/src/test/run-pass/trait-inheritance-simple.rs +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -1,31 +1,22 @@ -// xfail-fast -// xfail-test +trait Foo { fn f() -> int; } +trait Bar : Foo { fn g() -> int; } -// Broken on 32 bit, I guess? +struct A { x: int } -trait Foo { - fn f(); -} - -trait Bar : Foo { - fn g(); -} - -struct A { - x: int -} +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } -impl A : Bar { - fn g() { io::println("in g"); } - fn f() { io::println("in f"); } +fn ff(a: &T) -> int { + a.f() } -fn h(a: &T) { - a.f(); +fn gg(a: &T) -> int { + a.g() } fn main() { - let a = A { x: 3 }; - h(&a); + let a = &A { x: 3 }; + assert ff(a) == 10; + assert gg(a) == 20; } diff --git a/src/test/run-pass/trait-inheritance-static.rs b/src/test/run-pass/trait-inheritance-static.rs new file mode 100644 index 0000000000000..a3788d8647b64 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-static.rs @@ -0,0 +1,24 @@ +trait MyNum { + static fn from_int(int) -> self; +} + +pub trait NumExt: MyNum { } + +struct S { v: int } + +impl S: MyNum { + static fn from_int(i: int) -> S { + S { + v: i + } + } +} + +impl S: NumExt { } + +fn greater_than_one() -> T { from_int(1) } + +fn main() { + let v: S = greater_than_one(); + assert v.v == 1; +} diff --git a/src/test/run-pass/trait-inheritance-static2.rs b/src/test/run-pass/trait-inheritance-static2.rs new file mode 100644 index 0000000000000..e6f3f1fb99147 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-static2.rs @@ -0,0 +1,28 @@ +trait MyEq { } + +trait MyNum { + static fn from_int(int) -> self; +} + +pub trait NumExt: MyEq, MyNum { } + +struct S { v: int } + +impl S: MyEq { } + +impl S: MyNum { + static fn from_int(i: int) -> S { + S { + v: i + } + } +} + +impl S: NumExt { } + +fn greater_than_one() -> T { from_int(1) } + +fn main() { + let v: S = greater_than_one(); + assert v.v == 1; +} diff --git a/src/test/run-pass/trait-inheritance-subst.rs b/src/test/run-pass/trait-inheritance-subst.rs new file mode 100644 index 0000000000000..3fdf96b404ed7 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-subst.rs @@ -0,0 +1,26 @@ +pub trait Add { + pure fn add(rhs: &RHS) -> Result; +} + +trait MyNum : Add { } + +struct MyInt { val: int } + +impl MyInt : Add { + pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) } +} + +impl MyInt : MyNum; + +fn f(x: T, y: T) -> T { + return x.add(&y); +} + +pure fn mi(v: int) -> MyInt { MyInt { val: v } } + +fn main() { + let (x, y) = (mi(3), mi(5)); + let z = f(x, y); + assert z.val == 8 +} + diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs new file mode 100644 index 0000000000000..343c567ab97bc --- /dev/null +++ b/src/test/run-pass/trait-inheritance-subst2.rs @@ -0,0 +1,36 @@ +trait Panda { + fn chomp(bamboo: &T) -> T; +} + +trait Add: Panda { + fn add(rhs: &RHS) -> Result; +} + +trait MyNum : Add { } + +struct MyInt { val: int } + +impl MyInt : Panda { + fn chomp(bamboo: &MyInt) -> MyInt { + mi(self.val + bamboo.val) + } +} + +impl MyInt : Add { + fn add(other: &MyInt) -> MyInt { self.chomp(other) } +} + +impl MyInt : MyNum; + +fn f(x: T, y: T) -> T { + return x.add(&y).chomp(&y); +} + +fn mi(v: int) -> MyInt { MyInt { val: v } } + +fn main() { + let (x, y) = (mi(3), mi(5)); + let z = f(x, y); + assert z.val == 13; +} + diff --git a/src/test/run-pass/trait-inheritance-visibility.rs b/src/test/run-pass/trait-inheritance-visibility.rs new file mode 100644 index 0000000000000..1fbe35328b60b --- /dev/null +++ b/src/test/run-pass/trait-inheritance-visibility.rs @@ -0,0 +1,18 @@ +mod traits { + pub trait Foo { fn f() -> int; } + + impl int: Foo { fn f() -> int { 10 } } +} + +trait Quux: traits::Foo { } +impl T: Quux { } + +// Foo is not in scope but because Quux is we can still access +// Foo's methods on a Quux bound typaram +fn f(x: &T) { + assert x.f() == 10; +} + +fn main() { + f(&0) +} \ No newline at end of file diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs new file mode 100644 index 0000000000000..7d4c2cacfeaad --- /dev/null +++ b/src/test/run-pass/trait-inheritance2.rs @@ -0,0 +1,24 @@ +trait Foo { fn f() -> int; } +trait Bar { fn g() -> int; } +trait Baz { fn h() -> int; } + +trait Quux: Foo, Bar, Baz { } + +struct A { x: int } + +impl A : Foo { fn f() -> int { 10 } } +impl A : Bar { fn g() -> int { 20 } } +impl A : Baz { fn h() -> int { 30 } } +impl A : Quux; + +fn f(a: &T) { + assert a.f() == 10; + assert a.g() == 20; + assert a.h() == 30; +} + +fn main() { + let a = &A { x: 3 }; + f(a); +} +