about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2013-07-18 17:20:58 -0700
committerMichael Sullivan <sully@msully.net>2013-07-23 17:06:32 -0700
commitfbbbc98ea4aaa59c7266ab4b60f18050a046634e (patch)
tree1a86ae54f1eaa9e69230a0233d4c0e9fb91fef28 /src
parent4b9759e20fc8a23b3d87765ebb8943adc357ce33 (diff)
downloadrust-fbbbc98ea4aaa59c7266ab4b60f18050a046634e.tar.gz
rust-fbbbc98ea4aaa59c7266ab4b60f18050a046634e.zip
Refactor a bunch of lookup_vtable to reduce rightward drift and clean things up.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/common.rs4
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs453
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs5
3 files changed, 241 insertions, 221 deletions
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index fef6607bbed..e3a661b4b00 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -1109,7 +1109,9 @@ pub fn find_vtable(tcx: ty::ctxt,
     debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)",
            n_param, n_bound, ps.repr(tcx));
 
-    ps.vtables.get()[n_param][n_bound].clone()
+    let tables = ps.vtables.expect("vtables missing where they are needed");
+    let param_bounds = tables[n_param];
+    param_bounds[n_bound].clone()
 }
 
 pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index da09f79d031..0052629cd2d 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -16,11 +16,10 @@ use middle::typeck::check::{structurally_resolved_type};
 use middle::typeck::infer::fixup_err_to_str;
 use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
 use middle::typeck::infer;
-use middle::typeck::{CrateCtxt, vtable_origin, vtable_res};
+use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res};
 use middle::typeck::{vtable_static, vtable_param, vtable_self};
 use middle::subst::Subst;
 use util::common::indenter;
-use util::ppaux::tys_to_str;
 use util::ppaux;
 
 use std::hashmap::HashSet;
@@ -84,41 +83,10 @@ fn lookup_vtables(vcx: &VtableContext,
            substs.repr(vcx.tcx()));
     let _i = indenter();
 
-    let tcx = vcx.tcx();
     let mut result = ~[];
-    let mut i = 0u;
-    for substs.tps.iter().advance |ty| {
-        // ty is the value supplied for the type parameter A...
-        let mut param_result = ~[];
-
-        for ty::each_bound_trait_and_supertraits(
-            tcx, type_param_defs[i].bounds) |trait_ref|
-        {
-            // ...and here trait_ref is each bound that was declared on A,
-            // expressed in terms of the type parameters.
-
-            debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx));
-
-            // Substitute the values of the type parameters that may
-            // appear in the bound.
-            let trait_ref = trait_ref.subst(tcx, substs);
-
-            debug!("after subst: %s", trait_ref.repr(tcx));
-
-            match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) {
-                Some(vtable) => param_result.push(vtable),
-                None => {
-                    vcx.tcx().sess.span_fatal(
-                        location_info.span,
-                        fmt!("failed to find an implementation of \
-                              trait %s for %s",
-                             vcx.infcx.trait_ref_to_str(trait_ref),
-                             vcx.infcx.ty_to_str(*ty)));
-                }
-            }
-        }
-        result.push(@param_result);
-        i += 1u;
+    for substs.tps.iter().zip(type_param_defs.iter()).advance |(ty, def)| {
+        result.push(lookup_vtables_for_param(vcx, location_info, Some(substs),
+                                             &*def.bounds, *ty, is_early));
     }
     debug!("lookup_vtables result(\
             location_info=%?, \
@@ -132,25 +100,58 @@ fn lookup_vtables(vcx: &VtableContext,
     @result
 }
 
-fn fixup_substs(vcx: &VtableContext,
-                location_info: &LocationInfo,
-                id: ast::def_id,
-                substs: ty::substs,
-                is_early: bool)
-                -> Option<ty::substs> {
+fn lookup_vtables_for_param(vcx: &VtableContext,
+                            location_info: &LocationInfo,
+                            // None for substs means the identity
+                            substs: Option<&ty::substs>,
+                            type_param_bounds: &ty::ParamBounds,
+                            ty: ty::t,
+                            is_early: bool) -> vtable_param_res {
     let tcx = vcx.tcx();
-    // use a dummy type just to package up the substs that need fixing up
-    let t = ty::mk_trait(tcx,
-                         id, substs,
-                         ty::RegionTraitStore(ty::re_static),
-                         ast::m_imm,
-                         ty::EmptyBuiltinBounds());
-    do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
-        match ty::get(*t_f).sty {
-          ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
-          _ => fail!("t_f should be a trait")
+
+    // ty is the value supplied for the type parameter A...
+    let mut param_result = ~[];
+
+    for ty::each_bound_trait_and_supertraits(
+        tcx, type_param_bounds) |trait_ref|
+    {
+        // ...and here trait_ref is each bound that was declared on A,
+        // expressed in terms of the type parameters.
+
+        // Substitute the values of the type parameters that may
+        // appear in the bound.
+        let trait_ref = substs.map_default(trait_ref, |substs| {
+            debug!("about to subst: %s, %s",
+                   trait_ref.repr(tcx), substs.repr(tcx));
+            trait_ref.subst(tcx, *substs)
+        });
+
+        debug!("after subst: %s", trait_ref.repr(tcx));
+
+        match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) {
+            Some(vtable) => param_result.push(vtable),
+            None => {
+                vcx.tcx().sess.span_fatal(
+                    location_info.span,
+                    fmt!("failed to find an implementation of \
+                          trait %s for %s",
+                         vcx.infcx.trait_ref_to_str(trait_ref),
+                         vcx.infcx.ty_to_str(ty)));
+            }
         }
     }
+
+    debug!("lookup_vtables_for_param result(\
+            location_info=%?, \
+            type_param_bounds=%s, \
+            ty=%s, \
+            result=%s)",
+           location_info,
+           type_param_bounds.repr(vcx.tcx()),
+           ty.repr(vcx.tcx()),
+           param_result.repr(vcx.tcx()));
+
+    return @param_result;
 }
 
 fn relate_trait_refs(vcx: &VtableContext,
@@ -173,10 +174,15 @@ fn relate_trait_refs(vcx: &VtableContext,
     {
         result::Ok(()) => {} // Ok.
         result::Err(ref err) => {
+            // There is an error, but we need to do some work to make
+            // the message good.
+            // Resolve any type vars in the trait refs
             let r_act_trait_ref =
                 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref);
             let r_exp_trait_ref =
                 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref);
+            // Only print the message if there aren't any previous type errors
+            // inside the types.
             if !ty::trait_ref_contains_error(&r_act_trait_ref) &&
                 !ty::trait_ref_contains_error(&r_exp_trait_ref)
             {
@@ -256,180 +262,184 @@ fn lookup_vtable(vcx: &VtableContext,
         }
 
         _ => {
-            let mut found = ~[];
+            return search_for_vtable(vcx, location_info,
+                                     ty, trait_ref, is_early)
+        }
+    }
 
-            let mut impls_seen = HashSet::new();
+    return None;
+}
 
-            match tcx.trait_impls.find(&trait_ref.def_id) {
-                None => {
-                    // Nothing found. Continue.
-                }
-                Some(implementations) => {
-                    // implementations is the list of all impls in scope for
-                    // trait_ref. (Usually, there's just one.)
-                    for implementations.iter().advance |im| {
-                        // im is one specific impl of trait_ref.
-
-                        // First, ensure we haven't processed this impl yet.
-                        if impls_seen.contains(&im.did) {
-                            loop;
-                        }
-                        impls_seen.insert(im.did);
-
-                        // ty::impl_traits gives us the trait im implements,
-                        // if there is one (there's either zero or one).
-                        //
-                        // If foo implements a trait t, and if t is the
-                        // same trait as trait_ref, we need to
-                        // unify it with trait_ref in order to get all
-                        // the ty vars sorted out.
-                        let r = ty::impl_trait_ref(tcx, im.did);
-                        for r.iter().advance |&of_trait_ref| {
-                            if of_trait_ref.def_id != trait_ref.def_id { loop; }
-
-                            // At this point, we know that of_trait_ref is
-                            // the same trait as trait_ref, but
-                            // possibly applied to different substs.
-                            //
-                            // Next, we check whether the "for" ty in
-                            // the impl is compatible with the type
-                            // that we're casting to a trait. That is,
-                            // if im is:
-                            //
-                            // impl<T> self_ty<T>: some_trait<T> { ... }
-                            //
-                            // we check whether self_ty<T> is the type
-                            // of the thing that we're trying to cast
-                            // to some_trait.  If not, then we try the next
-                            // impl.
-                            //
-                            // FIXME(#5781) this should be mk_eqty not mk_subty
-                            let ty::ty_param_substs_and_ty {
-                                substs: substs,
-                                ty: for_ty
-                            } = impl_self_ty(vcx, location_info, im.did);
-                            match infer::mk_subty(vcx.infcx,
-                                                  false,
-                                                  infer::RelateSelfType(
-                                                      location_info.span),
-                                                  ty,
-                                                  for_ty) {
-                                result::Err(_) => loop,
-                                result::Ok(()) => ()
-                            }
-
-                            // Now, in the previous example, for_ty is
-                            // bound to the type self_ty, and substs
-                            // is bound to [T].
-                            debug!("The self ty is %s and its substs are %s",
-                                   vcx.infcx.ty_to_str(for_ty),
-                                   tys_to_str(vcx.tcx(), substs.tps));
-
-                            // Next, we unify trait_ref -- the type
-                            // that we want to cast to -- with of_trait_ref
-                            // -- the trait that im implements. At
-                            // this point, we require that they be
-                            // unifiable with each other -- that's
-                            // what relate_trait_refs does.
-                            //
-                            // For example, in the above example,
-                            // of_trait_ref would be some_trait<T>, so we
-                            // would be unifying trait_ref<U> (for some
-                            // value of U) with some_trait<T>. This
-                            // would fail if T and U weren't
-                            // compatible.
-
-                            debug!("(checking vtable) @2 relating trait \
-                                    ty %s to of_trait_ref %s",
-                                   vcx.infcx.trait_ref_to_str(trait_ref),
-                                   vcx.infcx.trait_ref_to_str(of_trait_ref));
-
-                            let of_trait_ref = of_trait_ref.subst(tcx, &substs);
-                            relate_trait_refs(
-                                vcx, location_info,
-                                of_trait_ref, trait_ref);
-
-                            // Recall that trait_ref -- the trait type
-                            // we're casting to -- is the trait with
-                            // id trait_ref.def_id applied to the substs
-                            // trait_ref.substs. Now we extract out the
-                            // types themselves from trait_ref.substs.
-
-                            // Recall that substs is the impl self
-                            // type's list of substitutions. That is,
-                            // if this is an impl of some trait for
-                            // foo<T, U>, then substs is [T,
-                            // U]. substs might contain type
-                            // variables, so we call fixup_substs to
-                            // resolve them.
-
-                            let substs_f = match fixup_substs(vcx,
-                                                              location_info,
-                                                              trait_ref.def_id,
-                                                              substs,
-                                                              is_early) {
-                                Some(ref substs) => (*substs).clone(),
-                                None => {
-                                    assert!(is_early);
-                                    // Bail out with a bogus answer
-                                    return Some(vtable_param(0, 0));
-                                }
-                            };
-
-                            debug!("The fixed-up substs are %s - \
-                                    they will be unified with the bounds for \
-                                    the target ty, %s",
-                                   tys_to_str(vcx.tcx(), substs_f.tps),
-                                   vcx.infcx.trait_ref_to_str(trait_ref));
-
-                            // Next, we unify the fixed-up
-                            // substitutions for the impl self ty with
-                            // the substitutions from the trait type
-                            // that we're trying to cast
-                            // to. connect_trait_tps requires these
-                            // lists of types to unify pairwise.
-
-                            let im_generics =
-                                ty::lookup_item_type(tcx, im.did).generics;
-                            connect_trait_tps(vcx,
-                                              location_info,
-                                              &substs_f,
-                                              trait_ref,
-                                              im.did);
-                            let subres = lookup_vtables(
-                                vcx, location_info,
-                                *im_generics.type_param_defs, &substs_f,
-                                is_early);
-
-                            // Finally, we register that we found a
-                            // matching impl, and record the def ID of
-                            // the impl as well as the resolved list
-                            // of type substitutions for the target
-                            // trait.
-                            found.push(vtable_static(im.did,
-                                                     substs_f.tps.clone(),
-                                                     subres));
-                        }
-                    }
-                }
+fn search_for_vtable(vcx: &VtableContext,
+                     location_info: &LocationInfo,
+                     ty: ty::t,
+                     trait_ref: @ty::TraitRef,
+                     is_early: bool)
+    -> Option<vtable_origin>
+{
+    let tcx = vcx.tcx();
+
+    let mut found = ~[];
+    let mut impls_seen = HashSet::new();
+
+    // XXX: this is a bad way to do this, since we do
+    // pointless allocations.
+    let impls = tcx.trait_impls.find(&trait_ref.def_id)
+        .map_default(@mut ~[], |x| **x);
+    // impls is the list of all impls in scope for trait_ref.
+    for impls.iter().advance |im| {
+        // im is one specific impl of trait_ref.
+
+        // First, ensure we haven't processed this impl yet.
+        if impls_seen.contains(&im.did) {
+            loop;
+        }
+        impls_seen.insert(im.did);
+
+        // ty::impl_traits gives us the trait im implements.
+        //
+        // If foo implements a trait t, and if t is the same trait as
+        // trait_ref, we need to unify it with trait_ref in order to
+        // get all the ty vars sorted out.
+        let r = ty::impl_trait_ref(tcx, im.did);
+        let of_trait_ref = r.expect("trait_ref missing on trait impl");
+        if of_trait_ref.def_id != trait_ref.def_id { loop; }
+
+        // At this point, we know that of_trait_ref is the same trait
+        // as trait_ref, but possibly applied to different substs.
+        //
+        // Next, we check whether the "for" ty in the impl is
+        // compatible with the type that we're casting to a
+        // trait. That is, if im is:
+        //
+        // impl<T> some_trait<T> for self_ty<T> { ... }
+        //
+        // we check whether self_ty<T> is the type of the thing that
+        // we're trying to cast to some_trait.  If not, then we try
+        // the next impl.
+        //
+        // XXX: document a bit more what this means
+        //
+        // FIXME(#5781) this should be mk_eqty not mk_subty
+        let ty::ty_param_substs_and_ty {
+            substs: substs,
+            ty: for_ty
+        } = impl_self_ty(vcx, location_info, im.did);
+        match infer::mk_subty(vcx.infcx,
+                              false,
+                              infer::RelateSelfType(
+                                  location_info.span),
+                              ty,
+                              for_ty) {
+            result::Err(_) => loop,
+            result::Ok(()) => ()
+        }
+
+        // Now, in the previous example, for_ty is bound to
+        // the type self_ty, and substs is bound to [T].
+        debug!("The self ty is %s and its substs are %s",
+               vcx.infcx.ty_to_str(for_ty),
+               vcx.infcx.tys_to_str(substs.tps));
+
+        // Next, we unify trait_ref -- the type that we want to cast
+        // to -- with of_trait_ref -- the trait that im implements. At
+        // this point, we require that they be unifiable with each
+        // other -- that's what relate_trait_refs does.
+        //
+        // For example, in the above example, of_trait_ref would be
+        // some_trait<T>, so we would be unifying trait_ref<U> (for
+        // some value of U) with some_trait<T>. This would fail if T
+        // and U weren't compatible.
+
+        debug!("(checking vtable) @2 relating trait \
+                ty %s to of_trait_ref %s",
+               vcx.infcx.trait_ref_to_str(trait_ref),
+               vcx.infcx.trait_ref_to_str(of_trait_ref));
+
+        let of_trait_ref = of_trait_ref.subst(tcx, &substs);
+        relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
+
+        // Recall that trait_ref -- the trait type we're casting to --
+        // is the trait with id trait_ref.def_id applied to the substs
+        // trait_ref.substs. Now we extract out the types themselves
+        // from trait_ref.substs.
+
+        // Recall that substs is the impl self type's list of
+        // substitutions. That is, if this is an impl of some trait
+        // for foo<T, U>, then substs is [T, U]. substs might contain
+        // type variables, so we call fixup_substs to resolve them.
+
+        let substs_f = match fixup_substs(vcx,
+                                          location_info,
+                                          trait_ref.def_id,
+                                          substs,
+                                          is_early) {
+            Some(ref substs) => (*substs).clone(),
+            None => {
+                assert!(is_early);
+                // Bail out with a bogus answer
+                return Some(vtable_param(0, 0));
             }
+        };
+
+        debug!("The fixed-up substs are %s - \
+                they will be unified with the bounds for \
+                the target ty, %s",
+               vcx.infcx.tys_to_str(substs_f.tps),
+               vcx.infcx.trait_ref_to_str(trait_ref));
+
+        // Next, we unify the fixed-up substitutions for the impl self
+        // ty with the substitutions from the trait type that we're
+        // trying to cast to. connect_trait_tps requires these lists
+        // of types to unify pairwise.
+
+        let im_generics =
+            ty::lookup_item_type(tcx, im.did).generics;
+        connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
+        let subres = lookup_vtables(vcx, location_info,
+                                    *im_generics.type_param_defs, &substs_f,
+                                    is_early);
+
+        // Finally, we register that we found a matching impl, and
+        // record the def ID of the impl as well as the resolved list
+        // of type substitutions for the target trait.
+        found.push(vtable_static(im.did, substs_f.tps.clone(), subres));
+    }
 
-            match found.len() {
-                0 => { /* fallthrough */ }
-                1 => return Some(found[0].clone()),
-                _ => {
-                    if !is_early {
-                        vcx.tcx().sess.span_err(
-                            location_info.span,
-                            "multiple applicable methods in scope");
-                    }
-                    return Some(found[0].clone());
-                }
+    match found.len() {
+        0 => { return None }
+        1 => return Some(found[0].clone()),
+        _ => {
+            if !is_early {
+                vcx.tcx().sess.span_err(
+                    location_info.span,
+                    "multiple applicable methods in scope");
             }
+            return Some(found[0].clone());
         }
     }
+}
 
-    return None;
+
+fn fixup_substs(vcx: &VtableContext,
+                location_info: &LocationInfo,
+                id: ast::def_id,
+                substs: ty::substs,
+                is_early: bool)
+                -> Option<ty::substs> {
+    let tcx = vcx.tcx();
+    // use a dummy type just to package up the substs that need fixing up
+    let t = ty::mk_trait(tcx,
+                         id, substs,
+                         ty::RegionTraitStore(ty::re_static),
+                         ast::m_imm,
+                         ty::EmptyBuiltinBounds());
+    do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
+        match ty::get(*t_f).sty {
+          ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
+          _ => fail!("t_f should be a trait")
+        }
+    }
 }
 
 fn fixup_ty(vcx: &VtableContext,
@@ -682,10 +692,13 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
         Some(trait_ref) => {
             let infcx = infer::new_infer_ctxt(ccx.tcx);
             let vcx = VtableContext { ccx: ccx, infcx: infcx };
-            let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
+            let loc_info = location_info_for_item(impl_item);
 
+            // First, check that the impl implements any trait bounds
+            // on the trait.
+            let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
             let vtbls = lookup_vtables(&vcx,
-                                       &location_info_for_item(impl_item),
+                                       &loc_info,
                                        *trait_def.generics.type_param_defs,
                                        &trait_ref.substs,
                                        false);
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 1f0fb135762..eb32f4e59f0 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -653,6 +653,11 @@ impl InferCtxt {
                   self.resolve_type_vars_if_possible(t))
     }
 
+    pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str {
+        let tstrs = ts.map(|t| self.ty_to_str(*t));
+        fmt!("(%s)", tstrs.connect(", "))
+    }
+
     pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str {
         let t = self.resolve_type_vars_in_trait_ref_if_possible(t);
         trait_ref_to_str(self.tcx, &t)