]> git.lizzy.rs Git - rust.git/commitdiff
Implement trait inheritance for bounded type parameters
authorBrian Anderson <banderson@mozilla.com>
Wed, 28 Nov 2012 20:34:30 +0000 (12:34 -0800)
committerBrian Anderson <banderson@mozilla.com>
Fri, 30 Nov 2012 02:10:11 +0000 (18:10 -0800)
38 files changed:
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/vtable.rs
src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs [new file with mode: 0644]
src/test/auxiliary/trait_inheritance_auto_xc_aux.rs [new file with mode: 0644]
src/test/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs [new file with mode: 0644]
src/test/auxiliary/trait_inheritance_overloading_xc.rs
src/test/compile-fail/trait-inheritance-missing-requirement.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-auto-xc-2.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-auto-xc.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-auto.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-call-bound-inherited.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-call-bound-inherited2.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-cast.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-cross-trait-call.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-diamond.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-multiple-inheritors.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-multiple-params.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num0.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num1.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num2.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num3.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-num5.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-overloading-simple.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-overloading-xc-exe.rs
src/test/run-pass/trait-inheritance-overloading.rs
src/test/run-pass/trait-inheritance-simple.rs
src/test/run-pass/trait-inheritance-static.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-static2.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-subst.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-subst2.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance-visibility.rs [new file with mode: 0644]
src/test/run-pass/trait-inheritance2.rs [new file with mode: 0644]

index 73d6741feea795a9f37a92591360a829627502ca..5f0f3bc9593d1dd28e2e0af28cd7987f636e8e69 100644 (file)
@@ -1330,16 +1330,12 @@ fn find_vtable(tcx: ty::ctxt, ps: &param_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]
 }
 
index 4633310e60656c7d35e256c09d4578bc2ed856fe..ba6ec2a44c99e4c7dd9892437dc852479fa6c4dd 100644 (file)
@@ -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 {
index ad6ca83fe4ea04c5318aeb20688f39c5ee272786..d52f507e53e9ec6a213828356bac58bee20637ba 100644 (file)
 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 @@ fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr, span: span) -> uint {
     }
 }
 
+// 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
index 78cd677725738376bb98b3897406bb052fb57d8a..b4f5441c981a79509ca9f14fad5914441a1740fb 100644 (file)
@@ -241,7 +241,7 @@ fn push_inherent_candidates(&self, self_ty: ty::t) {
         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 @@ fn push_extension_candidates(&self, self_ty: ty::t) {
         }
     }
 
-    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 @@ fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
         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 @@ fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
                 }
             };
 
-            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 @@ fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
                     {
                         Some(pos) => pos,
                         None => {
+                            debug!("trait doesn't contain method: %?",
+                                   init_trait_id);
                             loop; // check next trait or bound
                         }
                     }
@@ -389,18 +401,21 @@ fn push_inherent_candidates_from_param(&self, param_ty: param_ty) {
 
                 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 @@ fn consider_candidates(&self,
         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 @@ fn consider_candidates(&self,
         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)
index 674bb8d6f85b9f4bf32119a745e89af5cef90ea8..99999ca2ae10df3c3b64eaec6d07f4177d94a7bf 100644 (file)
@@ -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,32 +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<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();
 
@@ -145,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) {
@@ -163,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;
             }
         }
 
@@ -283,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,
@@ -369,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,
@@ -493,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 \
@@ -527,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),
@@ -551,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".
@@ -577,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/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs
new file mode 100644 (file)
index 0000000..99f4119
--- /dev/null
@@ -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 (file)
index 0000000..8fe7b72
--- /dev/null
@@ -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: Foo Bar Baz> 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 (file)
index 0000000..00029d1
--- /dev/null
@@ -0,0 +1,12 @@
+
+pub trait Foo {
+    fn f() -> int;
+}
+
+pub struct A {
+    x: int
+}
+
+impl A : Foo {
+    fn f() -> int { 10 }
+}
index 235a174c838f0b1d3f67444b807f82b7e3e0be5d..ceeee89de6a565502b9420ef45a34d63599d44e0 100644 (file)
@@ -1,9 +1,31 @@
-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 } }
+
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 (file)
index 0000000..3105f72
--- /dev/null
@@ -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 (file)
index 0000000..4eac971
--- /dev/null
@@ -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: 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);
+}
+
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 (file)
index 0000000..4bc62fa
--- /dev/null
@@ -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<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);
+}
+
diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs
new file mode 100644 (file)
index 0000000..29de9f1
--- /dev/null
@@ -0,0 +1,27 @@
+// 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);
+}
+
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 (file)
index 0000000..dd3f53c
--- /dev/null
@@ -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<T:Bar>(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 (file)
index 0000000..222d8e7
--- /dev/null
@@ -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<T: Baz>(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 (file)
index 0000000..6cb0551
--- /dev/null
@@ -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 (file)
index 0000000..1cd23f4
--- /dev/null
@@ -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 (file)
index 0000000..9f588dd
--- /dev/null
@@ -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 (file)
index 0000000..a96bfb4
--- /dev/null
@@ -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 (file)
index 0000000..4c18d92
--- /dev/null
@@ -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<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
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 (file)
index 0000000..fdc68a3
--- /dev/null
@@ -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<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
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 (file)
index 0000000..0a5330b
--- /dev/null
@@ -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: 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
diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs
new file mode 100644 (file)
index 0000000..2266b67
--- /dev/null
@@ -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<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() {}
diff --git a/src/test/run-pass/trait-inheritance-num0.rs b/src/test/run-pass/trait-inheritance-num0.rs
new file mode 100644 (file)
index 0000000..6c3b228
--- /dev/null
@@ -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<T:NumExt>(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 (file)
index 0000000..57487f0
--- /dev/null
@@ -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<T:NumExt>(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 (file)
index 0000000..5f51f94
--- /dev/null
@@ -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<T:FloatExt>(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 (file)
index 0000000..656e639
--- /dev/null
@@ -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<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
diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs
new file mode 100644 (file)
index 0000000..fa30cef
--- /dev/null
@@ -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:NumExt>() -> T {
+    from_int(1)
+}
+
+fn main() {
+    num_eq_one::<int>(); // 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 (file)
index 0000000..13867ee
--- /dev/null
@@ -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<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;
+}
+
index a38a834fb726319cb05ed91108faa5abf347e68a..585ce63b38997bab4b72270b83c8dc90a036bf77 100644 (file)
@@ -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<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);
 }
 
-
index f8bf9faa186f616c4b400952a570894dd5846ee8..def37d1f9505c018777175fa837364fef1937751 100644 (file)
@@ -1,21 +1,39 @@
-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);
 }
 
index fcd4cf1de6b365f377f5a7b68b20838497f6ec6c..9725b18ca0f199ca0d7d189dbf0a44340deed915 100644 (file)
@@ -1,26 +1,22 @@
-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;
 }
 
diff --git a/src/test/run-pass/trait-inheritance-static.rs b/src/test/run-pass/trait-inheritance-static.rs
new file mode 100644 (file)
index 0000000..a3788d8
--- /dev/null
@@ -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:NumExt>() -> 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 (file)
index 0000000..e6f3f1f
--- /dev/null
@@ -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:NumExt>() -> 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 (file)
index 0000000..3fdf96b
--- /dev/null
@@ -0,0 +1,26 @@
+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
+}
+
diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs
new file mode 100644 (file)
index 0000000..343c567
--- /dev/null
@@ -0,0 +1,36 @@
+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;
+}
+
diff --git a/src/test/run-pass/trait-inheritance-visibility.rs b/src/test/run-pass/trait-inheritance-visibility.rs
new file mode 100644 (file)
index 0000000..1fbe353
--- /dev/null
@@ -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: 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
diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs
new file mode 100644 (file)
index 0000000..7d4c2ca
--- /dev/null
@@ -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<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);
+}
+