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]
}
// 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 {
export AutoAdjustment;
export AutoRef;
export AutoRefKind, AutoPtr, AutoBorrowVec, AutoBorrowFn;
+export iter_bound_traits_and_supertraits;
+export count_traits_and_supertraits;
// Data types
}
}
+// 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
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(
}
}
- 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();
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 |
}
};
- 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,
{
Some(pos) => pos,
None => {
+ debug!("trait doesn't contain method: %?",
+ init_trait_id);
loop; // check next trait or bound
}
}
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);
}
}
}
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;
}
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)
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
}
}
// 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<vtable_origin> {
- debug!("lookup_vtable_covariant(ty: %s, trait_ty=%s)",
- vcx.infcx.ty_to_str(ty),
- vcx.infcx.ty_to_str(trait_ty));
-
- lookup_vtable_invariant(vcx, location_info, ty, trait_ty,
- allow_unsafe, is_early)
-}
-
-// 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<vtable_origin> {
- 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<vtable_origin> {
+ debug!("lookup_vtable(ty=%s, trait_ty=%s)",
vcx.infcx.ty_to_str(ty), vcx.infcx.ty_to_str(trait_ty));
let _i = indenter();
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) {
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;
}
}
// 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,
// 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,
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 \
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),
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".
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
--- /dev/null
+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 } }
+
+
--- /dev/null
+trait Foo { fn f() -> int; }
+trait Bar { fn g() -> int; }
+trait Baz { fn h() -> int; }
+
+trait Quux: Foo, Bar, Baz { }
+
+impl<T: Foo Bar Baz> T: Quux { }
--- /dev/null
+
+pub trait Foo {
+ fn f() -> int;
+}
+
+pub struct A {
+ x: int
+}
+
+impl A : Foo {
+ fn f() -> int { 10 }
+}
-pub trait MyNum : Add<self,self>, Sub<self,self>, Mul<self,self> {
+use cmp::Eq;
+
+pub trait MyNum : Add<self,self>, Sub<self,self>, Mul<self,self>, Eq {
+}
+
+pub struct MyInt {
+ val: int
+}
+
+pub impl MyInt : Add<MyInt, MyInt> {
+ pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) }
+}
+
+pub impl MyInt : Sub<MyInt, MyInt> {
+ pure fn sub(&self, other: &MyInt) -> MyInt { mi(self.val - other.val) }
+}
+
+pub impl MyInt : Mul<MyInt, MyInt> {
+ 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 } }
+
--- /dev/null
+// 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() {
+}
+
--- /dev/null
+// 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: Foo Bar Baz> T: Quux { }
+
+fn f<T: Quux>(a: &T) {
+ assert a.f() == 10;
+ assert a.g() == 20;
+ assert a.h() == 30;
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ f(a);
+}
+
--- /dev/null
+// 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<T: Quux>(a: &T) {
+ assert a.f() == 10;
+ assert a.g() == 20;
+ assert a.h() == 30;
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ f(a);
+}
+
--- /dev/null
+// Testing that this impl turns A into a Quux, because
+// A is already a Foo Bar Baz
+impl<T: Foo Bar Baz> 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<T: Quux>(a: &T) {
+ assert a.f() == 10;
+ assert a.g() == 20;
+ assert a.h() == 30;
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ f(a);
+}
+
--- /dev/null
+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<T:Bar>(a: &T) -> int {
+ a.f()
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ assert gg(a) == 10;
+}
+
--- /dev/null
+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<T: Baz>(a: &T) -> int {
+ a.f()
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ assert gg(a) == 10;
+}
+
--- /dev/null
+// 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;
+}
+
--- /dev/null
+// 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;
+}
+
--- /dev/null
+// 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;
+}
+
--- /dev/null
+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;
+}
+
--- /dev/null
+// 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<T: D>(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
--- /dev/null
+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<T: B C>(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
--- /dev/null
+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: A, Y: B, Z: C>(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
--- /dev/null
+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<T:NumExt>(n: &T) -> bool { *n > from_int(1) }
+fn greater_than_one_float<T:FloatExt>(n: &T) -> bool { *n > from_int(1) }
+
+fn main() {}
--- /dev/null
+// 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<T:NumExt>(n: &T) -> bool {
+ n.gt(&from_int(1))
+}
+
+fn main() {}
--- /dev/null
+// Using the real Num from core
+
+use cmp::Ord;
+use num::from_int;
+
+pub trait NumExt: Num, Ord { }
+
+fn greater_than_one<T:NumExt>(n: &T) -> bool {
+ *n > from_int(1)
+}
+
+fn main() {}
--- /dev/null
+// 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<T:FloatExt>(n: T) { io::println(fmt!("%?", n < n)) }
+
+fn main() {
+ test_float_ext(1f32);
+}
\ No newline at end of file
--- /dev/null
+use cmp::{Eq, Ord};
+use num::from_int;
+
+pub trait NumExt: Eq, Ord, Num {}
+
+pub impl f32: NumExt {}
+
+fn num_eq_one<T:NumExt>(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
--- /dev/null
+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:NumExt>() -> T {
+ from_int(1)
+}
+
+fn main() {
+ num_eq_one::<int>(); // you need to actually use the function to trigger the ICE
+}
--- /dev/null
+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<T:MyNum>(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;
+}
+
// 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<T:Copy MyNum>(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);
}
-
-trait MyNum : Add<self,self>, Sub<self,self>, Mul<self,self> {
+use cmp::Eq;
+
+trait MyNum : Add<self,self>, Sub<self,self>, Mul<self,self>, Eq { }
+
+struct MyInt { val: int }
+
+impl MyInt : Add<MyInt, MyInt> {
+ pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) }
+}
+
+impl MyInt : Sub<MyInt, MyInt> {
+ 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<MyInt, MyInt> {
+ 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<T:Copy MyNum>(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);
}
-trait Foo {
- fn f();
-}
+trait Foo { fn f() -> int; }
+trait Bar : Foo { fn g() -> int; }
-trait Bar : Foo {
- fn g();
-}
+struct A { x: int }
-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<T:Foo>(a: &T) -> int {
+ a.f()
}
-fn h<T:Foo>(a: &T) {
- a.f();
+fn gg<T:Bar>(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;
}
--- /dev/null
+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:NumExt>() -> T { from_int(1) }
+
+fn main() {
+ let v: S = greater_than_one();
+ assert v.v == 1;
+}
--- /dev/null
+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:NumExt>() -> T { from_int(1) }
+
+fn main() {
+ let v: S = greater_than_one();
+ assert v.v == 1;
+}
--- /dev/null
+pub trait Add<RHS,Result> {
+ pure fn add(rhs: &RHS) -> Result;
+}
+
+trait MyNum : Add<self,self> { }
+
+struct MyInt { val: int }
+
+impl MyInt : Add<MyInt, MyInt> {
+ pure fn add(other: &MyInt) -> MyInt { mi(self.val + other.val) }
+}
+
+impl MyInt : MyNum;
+
+fn f<T:MyNum>(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
+}
+
--- /dev/null
+trait Panda<T> {
+ fn chomp(bamboo: &T) -> T;
+}
+
+trait Add<RHS,Result>: Panda<RHS> {
+ fn add(rhs: &RHS) -> Result;
+}
+
+trait MyNum : Add<self,self> { }
+
+struct MyInt { val: int }
+
+impl MyInt : Panda<MyInt> {
+ fn chomp(bamboo: &MyInt) -> MyInt {
+ mi(self.val + bamboo.val)
+ }
+}
+
+impl MyInt : Add<MyInt, MyInt> {
+ fn add(other: &MyInt) -> MyInt { self.chomp(other) }
+}
+
+impl MyInt : MyNum;
+
+fn f<T:MyNum>(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;
+}
+
--- /dev/null
+mod traits {
+ pub trait Foo { fn f() -> int; }
+
+ impl int: Foo { fn f() -> int { 10 } }
+}
+
+trait Quux: traits::Foo { }
+impl<T: traits::Foo> 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<T: Quux>(x: &T) {
+ assert x.f() == 10;
+}
+
+fn main() {
+ f(&0)
+}
\ No newline at end of file
--- /dev/null
+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<T: Quux Foo Bar Baz>(a: &T) {
+ assert a.f() == 10;
+ assert a.g() == 20;
+ assert a.h() == 30;
+}
+
+fn main() {
+ let a = &A { x: 3 };
+ f(a);
+}
+