diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-10-05 11:50:53 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-10-05 11:52:08 -0700 |
| commit | 1b732145ec569cd67e2a5d0cc4dd37d5cd60c961 (patch) | |
| tree | f322c22432d6427d6665ea4f3c5615526d06fb5d | |
| parent | c56a7e5c25c2a411ba119f3a17bfa6db0b1722ed (diff) | |
rustc: Implement simple trait inheritance.
Generic trait inheritance, cross-crate trait inheritance, and vtable-based trait inheritance don't work yet.
| -rw-r--r-- | src/rustc/middle/resolve.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/vtable.rs | 102 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/coherence.rs | 37 | ||||
| -rw-r--r-- | src/test/run-pass/trait-inheritance-simple.rs | 26 |
4 files changed, 136 insertions, 35 deletions
diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index eca0687f2fd..5f30346a28e 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -4181,9 +4181,9 @@ impl Resolver { } return self.resolve_identifier(path.idents.last(), - namespace, - check_ribs, - path.span); + namespace, + check_ribs, + path.span); } fn resolve_identifier(identifier: ident, diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index e8595b2f50a..e8926468b3a 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -51,8 +51,8 @@ fn lookup_vtables(fcx: @fn_ctxt, match *bound { ty::bound_trait(i_ty) => { let i_ty = ty::subst(tcx, substs, i_ty); - match lookup_vtable(fcx, expr, *ty, i_ty, allow_unsafe, - is_early) { + match lookup_vtable_covariant(fcx, expr, *ty, i_ty, + allow_unsafe, is_early) { Some(vtable) => result.push(vtable), None => { fcx.tcx().sess.span_fatal( @@ -91,20 +91,67 @@ fn relate_trait_tys(fcx: @fn_ctxt, expr: @ast::expr, demand::suptype(fcx, expr.span, exp_trait_ty, act_trait_ty) } -/* -Look up the vtable to use when treating an item of type <t> -as if it has type <trait_ty> -*/ -fn lookup_vtable(fcx: @fn_ctxt, - expr: @ast::expr, - ty: ty::t, - trait_ty: ty::t, - allow_unsafe: bool, - is_early: bool) - -> Option<vtable_origin> -{ +// 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(fcx: @fn_ctxt, + expr: @ast::expr, + ty: ty::t, + trait_ty: ty::t, + allow_unsafe: bool, + is_early: bool) + -> Option<vtable_origin> { + let worklist = dvec::DVec(); + worklist.push(trait_ty); + while worklist.len() > 0 { + let trait_ty = worklist.pop(); + let result = lookup_vtable_invariant(fcx, expr, 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 = fcx.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(fcx.ccx.tcx, + *subtrait_id, + substs, + ty::vstore_box); + worklist.push(trait_ty); + } + } + } + } + _ => { + fcx.ccx.tcx.sess.impossible_case(expr.span, + "lookup_vtable_covariant: \ + non-trait in worklist"); + } + } + } - debug!("lookup_vtable(ty=%s, trait_ty=%s)", + 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(fcx: @fn_ctxt, + expr: @ast::expr, + 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)", fcx.infcx().ty_to_str(ty), fcx.inh.infcx.ty_to_str(trait_ty)); let _i = indenter(); @@ -112,7 +159,7 @@ fn lookup_vtable(fcx: @fn_ctxt, let (trait_id, trait_substs) = match ty::get(trait_ty).sty { ty::ty_trait(did, substs, _) => (did, substs), _ => tcx.sess.impossible_case(expr.span, - "lookup_vtable: \ + "lookup_vtable_invariant: \ don't know how to handle a non-trait") }; let ty = match fixup_ty(fcx, expr, ty, is_early) { @@ -150,7 +197,7 @@ fn lookup_vtable(fcx: @fn_ctxt, } _ => tcx.sess.impossible_case( expr.span, - "lookup_vtable: in loop, \ + "lookup_vtable_invariant: in loop, \ don't know how to handle a non-trait ity") } n_bound += 1u; @@ -462,13 +509,14 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { let target_ty = fcx.expr_ty(ex); match ty::get(target_ty).sty { ty::ty_trait(*) => { - /* - Look up vtables for the type we're casting to, - passing in the source and target type - */ + // Look up vtables for the type we're casting to, passing in the + // source and target type. + // + // XXX: This is invariant and shouldn't be. --pcw + let ty = fcx.expr_ty(src); - let vtable_opt = lookup_vtable(fcx, ex, ty, target_ty, true, - is_early); + let vtable_opt = lookup_vtable_invariant(fcx, ex, ty, target_ty, + true, is_early); match vtable_opt { None => { // Try the new-style boxed trait; "@int as @Trait". @@ -476,10 +524,10 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { let ty = structurally_resolved_type(fcx, ex.span, ty); match ty::get(ty).sty { ty::ty_box(boxed_ty) => { - let vtable_opt = lookup_vtable(fcx, ex, - boxed_ty.ty, - target_ty, true, - is_early); + let vtable_opt = + lookup_vtable_invariant(fcx, ex, boxed_ty.ty, + target_ty, true, + is_early); match vtable_opt { Some(vtable) => { /* diff --git a/src/rustc/middle/typeck/coherence.rs b/src/rustc/middle/typeck/coherence.rs index e9238e30c66..89cd696eb6f 100644 --- a/src/rustc/middle/typeck/coherence.rs +++ b/src/rustc/middle/typeck/coherence.rs @@ -126,12 +126,16 @@ struct CoherenceInfo { // Contains implementations of methods associated with a trait. For these, // the associated trait must be imported at the call site. extension_methods: HashMap<def_id,@DVec<@Impl>>, + + // A mapping from a supertrait to its subtraits. + supertrait_to_subtraits: HashMap<def_id,@DVec<def_id>> } fn CoherenceInfo() -> CoherenceInfo { CoherenceInfo { inherent_methods: HashMap(), - extension_methods: HashMap() + extension_methods: HashMap(), + supertrait_to_subtraits: HashMap() } } @@ -161,7 +165,6 @@ struct CoherenceChecker { } impl CoherenceChecker { - // Create a mapping containing a MethodInfo for every provided // method in every trait. fn build_provided_methods_map(crate: @crate) { @@ -225,9 +228,9 @@ impl CoherenceChecker { } fn check_coherence(crate: @crate) { - - // Check implementations. This populates the tables containing the - // inherent methods and extension methods. + // Check implementations and traits. This populates the tables + // containing the inherent methods and extension methods. It also + // builds up the trait inheritance table. visit_crate(*crate, (), mk_simple_visitor(@{ visit_item: |item| { debug!("(checking coherence) item '%s'", @@ -240,6 +243,9 @@ 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. } @@ -324,6 +330,27 @@ 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<int>. + 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 diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs new file mode 100644 index 00000000000..fcd4cf1de6b --- /dev/null +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -0,0 +1,26 @@ +trait Foo { + fn f(); +} + +trait Bar : Foo { + fn g(); +} + +struct A { + x: int +} + +impl A : Bar { + fn g() { io::println("in g"); } + fn f() { io::println("in f"); } +} + +fn h<T:Foo>(a: &T) { + a.f(); +} + +fn main() { + let a = A { x: 3 }; + h(&a); +} + |
