rustc: Implement simple trait inheritance.
Generic trait inheritance, cross-crate trait inheritance, and vtable-based trait inheritance don't work yet.
This commit is contained in:
parent
c56a7e5c25
commit
1b732145ec
@ -4181,9 +4181,9 @@ fn resolve_path(path: @path, namespace: Namespace, check_ribs: bool,
|
||||
}
|
||||
|
||||
return self.resolve_identifier(path.idents.last(),
|
||||
namespace,
|
||||
check_ribs,
|
||||
path.span);
|
||||
namespace,
|
||||
check_ribs,
|
||||
path.span);
|
||||
}
|
||||
|
||||
fn resolve_identifier(identifier: ident,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
debug!("lookup_vtable(ty=%s, trait_ty=%s)",
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) => {
|
||||
/*
|
||||
|
@ -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 @@ trait `%s` with id %d",
|
||||
}
|
||||
|
||||
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 @@ fn check_coherence(crate: @crate) {
|
||||
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 @@ fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
26
src/test/run-pass/trait-inheritance-simple.rs
Normal file
26
src/test/run-pass/trait-inheritance-simple.rs
Normal file
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user