]> git.lizzy.rs Git - rust.git/commitdiff
typeck/kind -- stop using old trait framework.
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 12 Sep 2014 15:47:33 +0000 (11:47 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 15 Sep 2014 19:28:12 +0000 (15:28 -0400)
- Unify the "well-formedness" checking that typeck was already doing with what
  was taking place in kind.
- Move requirements that things be sized into typeck.
- I left the checking on upvars in kind, though I think it should eventually be
  refactored into regionck (which would perhaps be renamed).

This reflects a general plan to convert typeck so that it registers
obligations or other pending things for conditions it cannot check
eventually. This makes it easier to identify all the conditions that
apply to an AST expression, but can also influence inference in somec
cases (e.g., `Send` implies `'static`, so I already had to promote a lot
of the checking that `kind.rs` was doing into typeck, this branch just
continues the process).

src/librustc/middle/kind.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs [deleted file]
src/librustc/middle/typeck/check/vtable2.rs [new file with mode: 0644]
src/librustc/middle/typeck/check/wf.rs [new file with mode: 0644]
src/librustc/middle/typeck/check/writeback.rs
src/librustc/middle/typeck/infer/coercion.rs

index 33f7680d873c376a47bcc8d220e31071864dd21b..aeb0c155a3f4851ea100ff3904c671b4d6945892 100644 (file)
 
 use middle::freevars::freevar_entry;
 use middle::freevars;
+use middle::mem_categorization::Typer;
 use middle::subst;
-use middle::ty::ParameterEnvironment;
 use middle::ty;
 use middle::ty_fold::TypeFoldable;
 use middle::ty_fold;
-use middle::typeck::check::vtable;
-use middle::typeck::{MethodCall, NoAdjustment};
-use middle::typeck;
-use util::ppaux::{Repr, ty_to_string};
+use util::ppaux::{ty_to_string};
 use util::ppaux::UserString;
 
-use std::collections::HashSet;
 use syntax::ast::*;
-use syntax::ast_util;
 use syntax::attr;
 use syntax::codemap::Span;
 use syntax::print::pprust::{expr_to_string, ident_to_string};
 use syntax::visit::Visitor;
 use syntax::visit;
 
-// Kind analysis pass.
-//
-// There are several kinds defined by various operations. The most restrictive
-// kind is noncopyable. The noncopyable kind can be extended with any number
-// of the following attributes.
-//
-//  Send: Things that can be sent on channels or included in spawned closures. It
-//  includes scalar types as well as classes and unique types containing only
-//  sendable types.
-//  'static: Things that do not contain references.
-//
-// This pass ensures that type parameters are only instantiated with types
-// whose kinds are equal or less general than the way the type parameter was
-// annotated (with the `Send` bound).
-//
-// It also verifies that noncopyable kinds are not copied. Sendability is not
-// applied, since none of our language primitives send. Instead, the sending
-// primitives in the stdlib are explicitly annotated to only take sendable
-// types.
+// Kind analysis pass. This pass does some ad-hoc checks that are more
+// convenient to do after type checking is complete and all checks are
+// known. These are generally related to the builtin bounds `Copy` and
+// `Sized`. Note that many of the builtin bound properties that used
+// to be checked here are actually checked by trait checking these
+// days.
 
-pub struct Context<'a, 'tcx: 'a> {
+pub struct Context<'a,'tcx:'a> {
     tcx: &'a ty::ctxt<'tcx>,
-    struct_and_enum_bounds_checked: HashSet<ty::t>,
-    parameter_environments: Vec<ParameterEnvironment>,
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
@@ -77,17 +57,11 @@ fn visit_item(&mut self, i: &Item) {
     fn visit_pat(&mut self, p: &Pat) {
         check_pat(self, p);
     }
-
-    fn visit_local(&mut self, l: &Local) {
-        check_local(self, l);
-    }
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
     let mut ctx = Context {
         tcx: tcx,
-        struct_and_enum_bounds_checked: HashSet::new(),
-        parameter_environments: Vec::new(),
     };
     visit::walk_crate(&mut ctx, tcx.map.krate());
     tcx.sess.abort_if_errors();
@@ -135,27 +109,11 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
                               .find(&trait_ref.ref_id)
                               .expect("trait ref not in def map!");
     let trait_def_id = ast_trait_def.def_id();
-    let trait_def = cx.tcx.trait_defs.borrow()
-                          .find_copy(&trait_def_id)
-                          .expect("trait def not in trait-defs map!");
-
-    // If this trait has builtin-kind supertraits, meet them.
-    let self_ty: ty::t = ty::node_id_to_type(cx.tcx, it.id);
-    debug!("checking impl with self type {}", ty::get(self_ty).sty);
-    check_builtin_bounds(
-        cx, self_ty, trait_def.bounds.builtin_bounds,
-        |missing| {
-            span_err!(cx.tcx.sess, self_type.span, E0142,
-                      "the type `{}', which does not fulfill `{}`, \
-                       cannot implement this trait",
-                      ty_to_string(cx.tcx, self_ty), missing.user_string(cx.tcx));
-            span_note!(cx.tcx.sess, self_type.span,
-                       "types implementing this trait must fulfill `{}`",
-                       trait_def.bounds.user_string(cx.tcx));
-        });
 
     // If this is a destructor, check kinds.
-    if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) {
+    if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) &&
+        !attr::contains_name(it.attrs.as_slice(), "unsafe_destructor")
+    {
         match self_type.node {
             TyPath(_, ref bounds, path_node_id) => {
                 assert!(bounds.is_none());
@@ -172,133 +130,50 @@ fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_t
 }
 
 fn check_item(cx: &mut Context, item: &Item) {
-    if !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") {
-        match item.node {
-            ItemImpl(_, ref trait_ref, ref self_type, _) => {
-                let parameter_environment =
-                    ParameterEnvironment::for_item(cx.tcx, item.id);
-                cx.parameter_environments.push(parameter_environment);
-
-                // Check bounds on the `self` type.
-                check_bounds_on_structs_or_enums_in_type_if_possible(
-                    cx,
-                    item.span,
-                    ty::node_id_to_type(cx.tcx, item.id));
-
-                match trait_ref {
-                    &Some(ref trait_ref) => {
-                        check_impl_of_trait(cx, item, trait_ref, &**self_type);
-
-                        // Check bounds on the trait ref.
-                        match ty::impl_trait_ref(cx.tcx,
-                                                 ast_util::local_def(item.id)) {
-                            None => {}
-                            Some(trait_ref) => {
-                                check_bounds_on_structs_or_enums_in_trait_ref(
-                                    cx,
-                                    item.span,
-                                    &*trait_ref);
-
-                                let trait_def = ty::lookup_trait_def(cx.tcx, trait_ref.def_id);
-                                for (ty, type_param_def) in trait_ref.substs.types
-                                                                  .iter()
-                                                                  .zip(trait_def.generics
-                                                                                .types
-                                                                                .iter()) {
-                                    check_typaram_bounds(cx, item.span, *ty, type_param_def);
-                                }
-                            }
-                        }
-                    }
-                    &None => {}
-                }
-
-                drop(cx.parameter_environments.pop());
-            }
-            ItemEnum(..) => {
-                let parameter_environment =
-                    ParameterEnvironment::for_item(cx.tcx, item.id);
-                cx.parameter_environments.push(parameter_environment);
-
-                let def_id = ast_util::local_def(item.id);
-                for variant in ty::enum_variants(cx.tcx, def_id).iter() {
-                    for arg in variant.args.iter() {
-                        check_bounds_on_structs_or_enums_in_type_if_possible(
-                            cx,
-                            item.span,
-                            *arg)
-                    }
-                }
-
-                drop(cx.parameter_environments.pop());
-            }
-            ItemStruct(..) => {
-                let parameter_environment =
-                    ParameterEnvironment::for_item(cx.tcx, item.id);
-                cx.parameter_environments.push(parameter_environment);
-
-                let def_id = ast_util::local_def(item.id);
-                for field in ty::lookup_struct_fields(cx.tcx, def_id).iter() {
-                    check_bounds_on_structs_or_enums_in_type_if_possible(
-                        cx,
-                        item.span,
-                        ty::node_id_to_type(cx.tcx, field.id.node))
-                }
-
-                drop(cx.parameter_environments.pop());
-
-            }
-            ItemStatic(..) => {
-                let parameter_environment =
-                    ParameterEnvironment::for_item(cx.tcx, item.id);
-                cx.parameter_environments.push(parameter_environment);
-
-                check_bounds_on_structs_or_enums_in_type_if_possible(
-                    cx,
-                    item.span,
-                    ty::node_id_to_type(cx.tcx, item.id));
-
-                drop(cx.parameter_environments.pop());
-            }
-            _ => {}
+    match item.node {
+        ItemImpl(_, Some(ref trait_ref), ref self_type, _) => {
+            check_impl_of_trait(cx, item, trait_ref, &**self_type);
         }
+        _ => {}
     }
 
     visit::walk_item(cx, item)
 }
 
-fn check_local(cx: &mut Context, local: &Local) {
-    check_bounds_on_structs_or_enums_in_type_if_possible(
-        cx,
-        local.span,
-        ty::node_id_to_type(cx.tcx, local.id));
-
-    visit::walk_local(cx, local)
-}
-
 // Yields the appropriate function to check the kind of closed over
 // variables. `id` is the NodeId for some expression that creates the
 // closure.
 fn with_appropriate_checker(cx: &Context,
                             id: NodeId,
+                            fn_span: Span,
                             b: |checker: |&Context, &freevar_entry||) {
-    fn check_for_uniq(cx: &Context, fv: &freevar_entry, bounds: ty::BuiltinBounds) {
+    fn check_for_uniq(cx: &Context,
+                      fn_span: Span,
+                      fv: &freevar_entry,
+                      bounds: ty::BuiltinBounds) {
         // all captured data must be owned, regardless of whether it is
         // moved in or copied in.
         let id = fv.def.def_id().node;
         let var_t = ty::node_id_to_type(cx.tcx, id);
 
-        check_freevar_bounds(cx, fv.span, var_t, bounds, None);
+        check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None);
     }
 
-    fn check_for_block(cx: &Context, fv: &freevar_entry,
-                       bounds: ty::BuiltinBounds, region: ty::Region) {
+    fn check_for_block(cx: &Context,
+                       fn_span: Span,
+                       fn_id: NodeId,
+                       fv: &freevar_entry,
+                       bounds: ty::BuiltinBounds) {
         let id = fv.def.def_id().node;
         let var_t = ty::node_id_to_type(cx.tcx, id);
-        // FIXME(#3569): Figure out whether the implicit borrow is actually
-        // mutable. Currently we assume all upvars are referenced mutably.
-        let implicit_borrowed_type = ty::mk_mut_rptr(cx.tcx, region, var_t);
-        check_freevar_bounds(cx, fv.span, implicit_borrowed_type,
+        let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id };
+        let upvar_borrow = cx.tcx.upvar_borrow(upvar_id);
+        let implicit_borrowed_type =
+            ty::mk_rptr(cx.tcx,
+                        upvar_borrow.region,
+                        ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
+                                 ty: var_t });
+        check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type,
                              bounds, Some(var_t));
     }
 
@@ -315,12 +190,16 @@ fn check_for_bare(cx: &Context, fv: &freevar_entry) {
             bounds: bounds,
             ..
         }) => {
-            b(|cx, fv| check_for_uniq(cx, fv, bounds.builtin_bounds))
+            b(|cx, fv| check_for_uniq(cx, fn_span, fv,
+                                      bounds.builtin_bounds))
         }
 
         ty::ty_closure(box ty::ClosureTy {
-            store: ty::RegionTraitStore(region, _), bounds, ..
-        }) => b(|cx, fv| check_for_block(cx, fv, bounds.builtin_bounds, region)),
+            store: ty::RegionTraitStore(..), bounds, ..
+        }) => {
+            b(|cx, fv| check_for_block(cx, fn_span, id, fv,
+                                       bounds.builtin_bounds))
+        }
 
         ty::ty_bare_fn(_) => {
             b(check_for_bare)
@@ -346,8 +225,8 @@ fn check_fn(
     sp: Span,
     fn_id: NodeId) {
 
-    // Check kinds on free variables:
-    with_appropriate_checker(cx, fn_id, |chk| {
+    // <Check kinds on free variables:
+    with_appropriate_checker(cx, fn_id, sp, |chk| {
         freevars::with_freevars(cx.tcx, fn_id, |freevars| {
             for fv in freevars.iter() {
                 chk(cx, fv);
@@ -357,21 +236,10 @@ fn check_fn(
 
     match fk {
         visit::FkFnBlock(..) => {
-            let ty = ty::node_id_to_type(cx.tcx, fn_id);
-            check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
-
             visit::walk_fn(cx, fk, decl, body, sp)
         }
         visit::FkItemFn(..) | visit::FkMethod(..) => {
-            let parameter_environment = ParameterEnvironment::for_item(cx.tcx,
-                                                                       fn_id);
-            cx.parameter_environments.push(parameter_environment);
-
-            let ty = ty::node_id_to_type(cx.tcx, fn_id);
-            check_bounds_on_structs_or_enums_in_type_if_possible(cx, sp, ty);
-
             visit::walk_fn(cx, fk, decl, body, sp);
-            drop(cx.parameter_environments.pop());
         }
     }
 }
@@ -379,30 +247,7 @@ fn check_fn(
 pub fn check_expr(cx: &mut Context, e: &Expr) {
     debug!("kind::check_expr({})", expr_to_string(e));
 
-    // Handle any kind bounds on type parameters
-    check_bounds_on_type_parameters(cx, e);
-
-    // Check bounds on structures or enumerations in the type of the
-    // expression.
-    let expression_type = ty::expr_ty(cx.tcx, e);
-    check_bounds_on_structs_or_enums_in_type_if_possible(cx,
-                                                         e.span,
-                                                         expression_type);
-
     match e.node {
-        ExprCast(ref source, _) => {
-            let source_ty = ty::expr_ty(cx.tcx, &**source);
-            let target_ty = ty::expr_ty(cx.tcx, e);
-            let method_call = MethodCall {
-                expr_id: e.id,
-                adjustment: NoAdjustment,
-            };
-            check_trait_cast(cx,
-                             source_ty,
-                             target_ty,
-                             source.span,
-                             method_call);
-        }
         ExprRepeat(ref element, ref count_expr) => {
             let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
             if count > 1 {
@@ -427,174 +272,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
         _ => {}
     }
 
-    // Search for auto-adjustments to find trait coercions.
-    match cx.tcx.adjustments.borrow().find(&e.id) {
-        Some(adjustment) => {
-            match adjustment {
-                adj if ty::adjust_is_object(adj) => {
-                    let source_ty = ty::expr_ty(cx.tcx, e);
-                    let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
-                    let method_call = MethodCall {
-                        expr_id: e.id,
-                        adjustment: typeck::AutoObject,
-                    };
-                    check_trait_cast(cx,
-                                     source_ty,
-                                     target_ty,
-                                     e.span,
-                                     method_call);
-                }
-                _ => {}
-            }
-        }
-        None => {}
-    }
-
     visit::walk_expr(cx, e);
 }
-
-fn check_bounds_on_type_parameters(cx: &mut Context, e: &Expr) {
-    let method_map = cx.tcx.method_map.borrow();
-    let method_call = typeck::MethodCall::expr(e.id);
-    let method = method_map.find(&method_call);
-
-    // Find the values that were provided (if any)
-    let item_substs = cx.tcx.item_substs.borrow();
-    let (types, is_object_call) = match method {
-        Some(method) => {
-            let is_object_call = match method.origin {
-                typeck::MethodObject(..) => true,
-                typeck::MethodStatic(..) |
-                typeck::MethodStaticUnboxedClosure(..) |
-                typeck::MethodParam(..) => false
-            };
-            (&method.substs.types, is_object_call)
-        }
-        None => {
-            match item_substs.find(&e.id) {
-                None => { return; }
-                Some(s) => { (&s.substs.types, false) }
-            }
-        }
-    };
-
-    // Find the relevant type parameter definitions
-    let def_map = cx.tcx.def_map.borrow();
-    let type_param_defs = match e.node {
-        ExprPath(_) => {
-            let did = def_map.get_copy(&e.id).def_id();
-            ty::lookup_item_type(cx.tcx, did).generics.types.clone()
-        }
-        _ => {
-            // Type substitutions should only occur on paths and
-            // method calls, so this needs to be a method call.
-
-            // Even though the callee_id may have been the id with
-            // node_type_substs, e.id is correct here.
-            match method {
-                Some(method) => {
-                    ty::method_call_type_param_defs(cx.tcx, method.origin)
-                }
-                None => {
-                    cx.tcx.sess.span_bug(e.span,
-                                         "non path/method call expr has type substs??");
-                }
-            }
-        }
-    };
-
-    // Check that the value provided for each definition meets the
-    // kind requirements
-    for type_param_def in type_param_defs.iter() {
-        let ty = *types.get(type_param_def.space, type_param_def.index);
-
-        // If this is a call to an object method (`foo.bar()` where
-        // `foo` has a type like `Trait`), then the self type is
-        // unknown (after all, this is a virtual call). In that case,
-        // we will have put a ty_err in the substitutions, and we can
-        // just skip over validating the bounds (because the bounds
-        // would have been enforced when the object instance was
-        // created).
-        if is_object_call && type_param_def.space == subst::SelfSpace {
-            assert_eq!(type_param_def.index, 0);
-            assert!(ty::type_is_error(ty));
-            continue;
-        }
-
-        debug!("type_param_def space={} index={} ty={}",
-               type_param_def.space, type_param_def.index, ty.repr(cx.tcx));
-        check_typaram_bounds(cx, e.span, ty, type_param_def)
-    }
-
-    // Check the vtable.
-    let vtable_map = cx.tcx.vtable_map.borrow();
-    let vtable_res = match vtable_map.find(&method_call) {
-        None => return,
-        Some(vtable_res) => vtable_res,
-    };
-    check_type_parameter_bounds_in_vtable_result(cx, e.span, vtable_res);
-}
-
-fn check_type_parameter_bounds_in_vtable_result(
-        cx: &mut Context,
-        span: Span,
-        vtable_res: &typeck::vtable_res) {
-    for origins in vtable_res.iter() {
-        for origin in origins.iter() {
-            let (type_param_defs, substs) = match *origin {
-                typeck::vtable_static(def_id, ref tys, _) => {
-                    let type_param_defs =
-                        ty::lookup_item_type(cx.tcx, def_id).generics
-                                                            .types
-                                                            .clone();
-                    (type_param_defs, (*tys).clone())
-                }
-                _ => {
-                    // Nothing to do here.
-                    continue
-                }
-            };
-            for type_param_def in type_param_defs.iter() {
-                let typ = substs.types.get(type_param_def.space,
-                                           type_param_def.index);
-                check_typaram_bounds(cx, span, *typ, type_param_def)
-            }
-        }
-    }
-}
-
-fn check_trait_cast(cx: &mut Context,
-                    source_ty: ty::t,
-                    target_ty: ty::t,
-                    span: Span,
-                    method_call: MethodCall) {
-    match ty::get(target_ty).sty {
-        ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
-            match ty::get(ty).sty {
-                ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
-                     match cx.tcx.vtable_map.borrow().find(&method_call) {
-                        None => {
-                            cx.tcx.sess.span_bug(span,
-                                                 "trait cast not in vtable \
-                                                  map?!")
-                        }
-                        Some(vtable_res) => {
-                            check_type_parameter_bounds_in_vtable_result(
-                                cx,
-                                span,
-                                vtable_res)
-                        }
-                    };
-                    check_trait_cast_bounds(cx, span, source_ty,
-                                            bounds.builtin_bounds);
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
-}
-
 fn check_ty(cx: &mut Context, aty: &Ty) {
     match aty.node {
         TyPath(_, _, id) => {
@@ -651,77 +330,7 @@ pub fn check_typaram_bounds(cx: &Context,
     });
 }
 
-fn check_bounds_on_structs_or_enums_in_type_if_possible(cx: &mut Context,
-                                                        span: Span,
-                                                        ty: ty::t) {
-    // If we aren't in a function, structure, or enumeration context, we don't
-    // have enough information to ensure that bounds on structures or
-    // enumerations are satisfied. So we don't perform the check.
-    if cx.parameter_environments.len() == 0 {
-        return
-    }
-
-    // If we've already checked for this type, don't do it again. This
-    // massively speeds up kind checking.
-    if cx.struct_and_enum_bounds_checked.contains(&ty) {
-        return
-    }
-    cx.struct_and_enum_bounds_checked.insert(ty);
-
-    ty::walk_ty(ty, |ty| {
-        match ty::get(ty).sty {
-            ty::ty_struct(type_id, ref substs) |
-            ty::ty_enum(type_id, ref substs) => {
-                let polytype = ty::lookup_item_type(cx.tcx, type_id);
-
-                // Check builtin bounds.
-                for (ty, type_param_def) in substs.types
-                                                  .iter()
-                                                  .zip(polytype.generics
-                                                               .types
-                                                               .iter()) {
-                    check_typaram_bounds(cx, span, *ty, type_param_def);
-                }
-
-                // Check trait bounds.
-                let parameter_environment =
-                    cx.parameter_environments.get(cx.parameter_environments
-                                                    .len() - 1);
-                debug!(
-                    "check_bounds_on_structs_or_enums_in_type_if_possible(): \
-                     checking {}",
-                    ty.repr(cx.tcx));
-                vtable::check_param_bounds(cx.tcx,
-                                           span,
-                                           parameter_environment,
-                                           &polytype.generics.types,
-                                           substs,
-                                           |missing| {
-                    cx.tcx
-                      .sess
-                      .span_err(span,
-                                format!("instantiating a type parameter with \
-                                         an incompatible type `{}`, which \
-                                         does not fulfill `{}`",
-                                        ty_to_string(cx.tcx, ty),
-                                        missing.user_string(
-                                            cx.tcx)).as_slice());
-                })
-            }
-            _ => {}
-        }
-    });
-}
-
-fn check_bounds_on_structs_or_enums_in_trait_ref(cx: &mut Context,
-                                                 span: Span,
-                                                 trait_ref: &ty::TraitRef) {
-    for ty in trait_ref.substs.types.iter() {
-        check_bounds_on_structs_or_enums_in_type_if_possible(cx, span, *ty)
-    }
-}
-
-pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
+pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t,
                             bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
 {
     check_builtin_bounds(cx, ty, bounds, |missing| {
@@ -741,7 +350,7 @@ pub fn check_freevar_bounds(cx: &Context, sp: Span, ty: ty::t,
                     ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
             }
         }
-        span_note!(cx.tcx.sess, sp,
+        span_note!(cx.tcx.sess, fn_span,
             "this closure's environment must satisfy `{}`",
             bounds.user_string(cx.tcx));
     });
index c26505fdc65787fe381d9219500cd3041ebb8feb..d0b94cb3abb8b12f8500b247dbdd3639e20a6bc9 100644 (file)
@@ -5423,7 +5423,7 @@ pub fn to_mutbl_lossy(self) -> ast::Mutability {
          * Returns a mutability `m` such that an `&m T` pointer could
          * be used to obtain this borrow kind. Because borrow kinds
          * are richer than mutabilities, we sometimes have to pick a
-         * mutability that is stornger than necessary so that it at
+         * mutability that is stronger than necessary so that it at
          * least *would permit* the borrow in question.
          */
 
index 1602dfeaa280afbcd7317ff7e52ffffb6bfe74b6..46aba94a5f12a0ab773f463d7be43bd46ebae106 100644 (file)
@@ -555,11 +555,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
                             None);
                 match tcx.def_map.borrow().find(&pat.id) {
                     Some(def) => {
-                        let item_type = ty::lookup_item_type(tcx, def.def_id());
-                        let substitutions = fcx.infcx().fresh_substs_for_type(
-                            pat.span, &item_type.generics);
+                        let struct_ty = fcx.instantiate_item_type(pat.span, def.def_id());
                         check_struct_pat(pcx, pat.span, fields.as_slice(),
-                                         etc, def.def_id(), &substitutions);
+                                         etc, def.def_id(), &struct_ty.substs);
                     }
                     None => {
                         tcx.sess.span_bug(pat.span,
index ecda5890fc5b43952b0a3d5dfbb3176a6111bc37..074074c13ae907995231cc57a0abc81ac6f20911 100644 (file)
@@ -82,6 +82,7 @@ trait `ToString` imported, and I call `to_string()` on a value of type `T`,
 
 use middle::subst;
 use middle::subst::Subst;
+use middle::traits;
 use middle::ty::*;
 use middle::ty;
 use middle::typeck::astconv::AstConv;
@@ -91,7 +92,6 @@ trait `ToString` imported, and I call `to_string()` on a value of type `T`,
 use middle::typeck::MethodCallee;
 use middle::typeck::{MethodOrigin, MethodParam};
 use middle::typeck::{MethodStatic, MethodStaticUnboxedClosure, MethodObject};
-use middle::typeck::{param_index};
 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
 use middle::typeck::TypeAndSubsts;
 use util::common::indenter;
@@ -538,14 +538,12 @@ fn push_unboxed_closure_call_candidate_if_applicable(
             return
         }
 
-        let vcx = self.fcx.vtable_context();
-
         // Get the tupled type of the arguments.
         let arguments_type = *closure_function_type.sig.inputs.get(0);
         let return_type = closure_function_type.sig.output;
 
         let closure_region =
-            vcx.infcx.next_region_var(infer::MiscVariable(self.span));
+            self.fcx.infcx().next_region_var(infer::MiscVariable(self.span));
         let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(),
                                                           closure_did,
                                                           closure_region);
@@ -555,7 +553,7 @@ fn push_unboxed_closure_call_candidate_if_applicable(
             rcvr_substs: subst::Substs::new_trait(
                 vec![arguments_type, return_type],
                 vec![],
-                *vcx.infcx.next_ty_vars(1).get(0)),
+                *self.fcx.infcx().next_ty_vars(1).get(0)),
             method_ty: method,
             origin: MethodStaticUnboxedClosure(closure_did),
         });
@@ -618,7 +616,7 @@ fn push_inherent_candidates_from_object(&mut self,
 
         self.push_inherent_candidates_from_bounds_inner(
             &[trait_ref.clone()],
-            |_this, new_trait_ref, m, method_num, _bound_num| {
+            |_this, new_trait_ref, m, method_num| {
                 let vtable_index =
                     get_method_index(tcx, &*new_trait_ref,
                                      trait_ref.clone(), method_num);
@@ -633,7 +631,7 @@ fn push_inherent_candidates_from_object(&mut self,
                     rcvr_substs: new_trait_ref.substs.clone(),
                     method_ty: Rc::new(m),
                     origin: MethodObject(MethodObject {
-                        trait_id: new_trait_ref.def_id,
+                        trait_ref: new_trait_ref,
                         object_trait_id: did,
                         method_num: method_num,
                         real_index: vtable_index
@@ -652,8 +650,7 @@ fn push_inherent_candidates_from_param(&mut self,
             rcvr_ty,
             param_ty.space,
             param_ty.idx,
-            restrict_to,
-            param_index { space: param_ty.space, index: param_ty.idx });
+            restrict_to);
     }
 
 
@@ -661,13 +658,12 @@ fn push_inherent_candidates_from_bounds(&mut self,
                                             self_ty: ty::t,
                                             space: subst::ParamSpace,
                                             index: uint,
-                                            restrict_to: Option<DefId>,
-                                            param: param_index) {
+                                            restrict_to: Option<DefId>) {
         let bounds =
             self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
             .as_slice();
         self.push_inherent_candidates_from_bounds_inner(bounds,
-            |this, trait_ref, m, method_num, bound_num| {
+            |this, trait_ref, m, method_num| {
                 match restrict_to {
                     Some(trait_did) => {
                         if trait_did != trait_ref.def_id {
@@ -701,10 +697,8 @@ fn push_inherent_candidates_from_bounds(&mut self,
                     rcvr_substs: trait_ref.substs.clone(),
                     method_ty: m,
                     origin: MethodParam(MethodParam {
-                        trait_id: trait_ref.def_id,
+                        trait_ref: trait_ref,
                         method_num: method_num,
-                        param_num: param,
-                        bound_num: bound_num,
                     })
                 })
         })
@@ -718,15 +712,16 @@ fn push_inherent_candidates_from_bounds_inner(
         mk_cand: |this: &mut LookupContext,
                   tr: Rc<TraitRef>,
                   m: Rc<ty::Method>,
-                  method_num: uint,
-                  bound_num: uint|
-                  -> Option<Candidate>) {
+                  method_num: uint|
+                  -> Option<Candidate>)
+    {
         let tcx = self.tcx();
-        let mut next_bound_idx = 0; // count only trait bounds
-
-        ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| {
-            let this_bound_idx = next_bound_idx;
-            next_bound_idx += 1;
+        let mut cache = HashSet::new();
+        for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
+            // Already visited this trait, skip it.
+            if !cache.insert(bound_trait_ref.def_id) {
+                continue;
+            }
 
             let trait_items = ty::trait_items(tcx, bound_trait_ref.def_id);
             match trait_items.iter().position(|ti| {
@@ -745,8 +740,7 @@ fn push_inherent_candidates_from_bounds_inner(
                     match mk_cand(self,
                                   bound_trait_ref,
                                   method,
-                                  pos,
-                                  this_bound_idx) {
+                                  pos) {
                         Some(cand) => {
                             debug!("pushing inherent candidate for param: {}",
                                    cand.repr(self.tcx()));
@@ -761,8 +755,7 @@ fn push_inherent_candidates_from_bounds_inner(
                     // check next trait or bound
                 }
             }
-            true
-        });
+        }
     }
 
 
@@ -773,7 +766,7 @@ fn push_inherent_impl_candidates_for_type(&mut self, did: DefId) {
 
         let impl_items = self.tcx().impl_items.borrow();
         for impl_infos in self.tcx().inherent_impls.borrow().find(&did).iter() {
-            for impl_did in impl_infos.borrow().iter() {
+            for impl_did in impl_infos.iter() {
                 let items = impl_items.get(impl_did);
                 self.push_candidates_from_impl(*impl_did,
                                                items.as_slice(),
@@ -825,11 +818,10 @@ fn push_candidates_from_impl(&mut self,
         // determine the `self` of the impl with fresh
         // variables for each parameter:
         let span = self.self_expr.map_or(self.span, |e| e.span);
-        let vcx = self.fcx.vtable_context();
         let TypeAndSubsts {
             substs: impl_substs,
             ty: impl_ty
-        } = impl_self_ty(&vcx, span, impl_did);
+        } = impl_self_ty(self.fcx, span, impl_did);
 
         let condition = match method.explicit_self {
             ByReferenceExplicitSelfCategory(_, mt) if mt == MutMutable =>
@@ -877,7 +869,7 @@ fn search_for_autoderefd_method(&self,
                        adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty));
                 match adjustment {
                     Some((self_expr_id, adj)) => {
-                        self.fcx.write_adjustment(self_expr_id, adj);
+                        self.fcx.write_adjustment(self_expr_id, self.span, adj);
                     }
                     None => {}
                 }
@@ -1109,7 +1101,9 @@ fn search_for_autoptrd_method(&self, self_ty: ty::t, autoderefs: uint)
 
             ty_err => None,
 
-            ty_infer(TyVar(_)) => {
+            ty_infer(TyVar(_)) |
+            ty_infer(SkolemizedTy(_)) |
+            ty_infer(SkolemizedIntTy(_)) => {
                 self.bug(format!("unexpected type: {}",
                                  self.ty_to_string(self_ty)).as_slice());
             }
@@ -1150,6 +1144,7 @@ fn search_for_some_kind_of_autorefd_method(
                         Some(self_expr_id) => {
                             self.fcx.write_adjustment(
                                 self_expr_id,
+                                self.span,
                                 ty::AutoDerefRef(ty::AutoDerefRef {
                                     autoderefs: autoderefs,
                                     autoref: Some(kind(region, *mutbl))
@@ -1209,7 +1204,7 @@ fn consider_candidates(&self, rcvr_ty: ty::t,
 
             // return something so we don't get errors for every mutability
             return Some(MethodCallee {
-                origin: relevant_candidates.get(0).origin,
+                origin: relevant_candidates.get(0).origin.clone(),
                 ty: ty::mk_err(),
                 substs: subst::Substs::empty()
             });
@@ -1237,12 +1232,14 @@ fn filter_candidates(&self, rcvr_ty: ty::t, candidates: &[Candidate]) -> Vec<Can
                        candidate_b.repr(self.tcx()));
                 match (&candidate_a.origin, &candidate_b.origin) {
                     (&MethodParam(ref p1), &MethodParam(ref 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
+                        let same_trait =
+                            p1.trait_ref.def_id == p2.trait_ref.def_id;
+                        let same_method =
+                            p1.method_num == p2.method_num;
+                        // it's ok to compare self-ty with `==` here because
+                        // they are always a TyParam
+                        let same_param =
+                            p1.trait_ref.self_ty() == p2.trait_ref.self_ty();
                         same_trait && same_method && same_param
                     }
                     _ => false
@@ -1369,13 +1366,13 @@ fn confirm_candidate(&self, rcvr_ty: ty::t, candidate: &Candidate)
             }
         }
 
-        self.fcx.add_region_obligations_for_parameters(
-            self.span,
+        self.fcx.add_obligations_for_parameters(
+            traits::ObligationCause::misc(self.span),
             &all_substs,
             &candidate.method_ty.generics);
 
         MethodCallee {
-            origin: candidate.origin,
+            origin: candidate.origin.clone(),
             ty: fty,
             substs: all_substs
         }
@@ -1452,10 +1449,10 @@ fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
             MethodStaticUnboxedClosure(_) => bad = false,
             // FIXME: does this properly enforce this on everything now
             // that self has been merged in? -sully
-            MethodParam(MethodParam { trait_id: trait_id, .. }) |
-            MethodObject(MethodObject { trait_id: trait_id, .. }) => {
+            MethodParam(MethodParam { trait_ref: ref trait_ref, .. }) |
+            MethodObject(MethodObject { trait_ref: ref trait_ref, .. }) => {
                 bad = self.tcx().destructor_for_type.borrow()
-                          .contains_key(&trait_id);
+                          .contains_key(&trait_ref.def_id);
             }
         }
 
@@ -1602,10 +1599,10 @@ fn report_candidate(&self, idx: uint, origin: &MethodOrigin) {
                 self.report_static_candidate(idx, did)
             }
             MethodParam(ref mp) => {
-                self.report_param_candidate(idx, (*mp).trait_id)
+                self.report_param_candidate(idx, mp.trait_ref.def_id)
             }
             MethodObject(ref mo) => {
-                self.report_trait_candidate(idx, mo.trait_id)
+                self.report_trait_candidate(idx, mo.trait_ref.def_id)
             }
         }
     }
index 375fc75bf62f5388cf2a6be9d68d5c1c5961b92c..20fe8186adf40fe50100022eb2ae24fae60d0cf8 100644 (file)
@@ -87,6 +87,7 @@
 use middle::pat_util;
 use middle::subst;
 use middle::subst::{Subst, Substs, VecPerParamSpace, ParamSpace};
+use middle::traits;
 use middle::ty::{FnSig, VariantInfo};
 use middle::ty::{Polytype};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::typeck::check::method::{DontAutoderefReceiver};
 use middle::typeck::check::method::{IgnoreStaticMethods, ReportStaticMethods};
 use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
-use middle::typeck::check::vtable::VtableContext;
 use middle::typeck::CrateCtxt;
 use middle::typeck::infer::{resolve_type, force_tvar};
 use middle::typeck::infer;
 use middle::typeck::rscope::RegionScope;
 use middle::typeck::{lookup_def_ccx};
 use middle::typeck::no_params;
-use middle::typeck::{require_same_types, vtable_map};
-use middle::typeck::{MethodCall, MethodMap};
+use middle::typeck::{require_same_types};
+use middle::typeck::{MethodCall, MethodMap, ObjectCastMap};
 use middle::typeck::{TypeAndSubsts};
 use middle::typeck;
 use middle::lang_items::TypeIdLangItem;
 use syntax;
 
 pub mod _match;
-pub mod vtable;
+pub mod vtable2; // New trait code
 pub mod writeback;
 pub mod regionmanip;
 pub mod regionck;
 pub mod demand;
 pub mod method;
+pub mod wf;
 
 /// Fields that are part of a `FnCtxt` which are inherited by
 /// closures defined within the function.  For example:
@@ -170,9 +171,9 @@ pub struct Inherited<'a, 'tcx: 'a> {
     item_substs: RefCell<NodeMap<ty::ItemSubsts>>,
     adjustments: RefCell<NodeMap<ty::AutoAdjustment>>,
     method_map: MethodMap,
-    vtable_map: vtable_map,
     upvar_borrow_map: RefCell<ty::UpvarBorrowMap>,
     unboxed_closures: RefCell<DefIdMap<ty::UnboxedClosure>>,
+    object_cast_map: ObjectCastMap,
 
     // A mapping from each fn's id to its signature, with all bound
     // regions replaced with free ones. Unlike the other tables, this
@@ -190,7 +191,7 @@ pub struct Inherited<'a, 'tcx: 'a> {
     // then in some expression `let x = Foo { ... }` it will
     // instantiate the type parameter `T` with a fresh type `$0`. At
     // the same time, it will record a region obligation of
-    // `$0:'static`. This will get checked later by regionck.  (We
+    // `$0:'static`. This will get checked later by regionck. (We
     // can't generally check these things right away because we have
     // to wait until types are resolved.)
     //
@@ -204,6 +205,9 @@ pub struct Inherited<'a, 'tcx: 'a> {
     // obligations (otherwise, it's easy to fail to walk to a
     // particular node-id).
     region_obligations: RefCell<NodeMap<Vec<RegionObligation>>>,
+
+    // Tracks trait obligations incurred during this function body.
+    fulfillment_cx: RefCell<traits::FulfillmentContext>,
 }
 
 struct RegionObligation {
@@ -335,11 +339,12 @@ fn new(tcx: &'a ty::ctxt<'tcx>,
             item_substs: RefCell::new(NodeMap::new()),
             adjustments: RefCell::new(NodeMap::new()),
             method_map: RefCell::new(FnvHashMap::new()),
-            vtable_map: RefCell::new(FnvHashMap::new()),
+            object_cast_map: RefCell::new(NodeMap::new()),
             upvar_borrow_map: RefCell::new(HashMap::new()),
             unboxed_closures: RefCell::new(DefIdMap::new()),
             fn_sig_map: RefCell::new(NodeMap::new()),
             region_obligations: RefCell::new(NodeMap::new()),
+            fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
         }
     }
 }
@@ -369,20 +374,12 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
         free_substs: subst::Substs::empty(),
         bounds: subst::VecPerParamSpace::empty(),
         implicit_region_bound: ty::ReStatic,
+        caller_obligations: subst::VecPerParamSpace::empty(),
     };
     Inherited::new(ccx.tcx, param_env)
 }
 
 struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
-struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
-
-impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, i: &ast::Item) {
-        check_type_well_formed(self.ccx, i);
-        visit::walk_item(self, i);
-    }
-}
-
 
 impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &ast::Item) {
@@ -404,8 +401,7 @@ fn visit_item(&mut self, i: &ast::Item) {
 
 pub fn check_item_types(ccx: &CrateCtxt) {
     let krate = ccx.tcx.map.krate();
-
-    let mut visit = CheckTypeWellFormedVisitor { ccx: ccx };
+    let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
     visit::walk_crate(&mut visit, krate);
 
     // If types are not well-formed, it leads to all manner of errors
@@ -437,9 +433,10 @@ fn check_bare_fn(ccx: &CrateCtxt,
             let fcx = check_fn(ccx, fn_ty.fn_style, id, &fn_ty.sig,
                                decl, id, body, &inh);
 
-            vtable::resolve_in_block(&fcx, body);
+            vtable2::select_all_fcx_obligations_or_error(&fcx);
             regionck::regionck_fn(&fcx, id, body);
             writeback::resolve_type_vars_in_fn(&fcx, decl, body);
+            vtable2::check_builtin_bound_obligations(&fcx); // must happen after writeback
         }
         _ => ccx.tcx.sess.impossible_case(body.span,
                                  "check_bare_fn: function type expected")
@@ -451,19 +448,21 @@ struct GatherLocalsVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
-    fn assign(&mut self, nid: ast::NodeId, ty_opt: Option<ty::t>) {
-            match ty_opt {
-                None => {
-                    // infer the variable's type
-                    let var_id = self.fcx.infcx().next_ty_var_id();
-                    let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
-                    self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
-                }
-                Some(typ) => {
-                    // take type that the user specified
-                    self.fcx.inh.locals.borrow_mut().insert(nid, typ);
-                }
+    fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option<ty::t>) -> ty::t {
+        match ty_opt {
+            None => {
+                // infer the variable's type
+                let var_id = self.fcx.infcx().next_ty_var_id();
+                let var_ty = ty::mk_var(self.fcx.tcx(), var_id);
+                self.fcx.inh.locals.borrow_mut().insert(nid, var_ty);
+                var_ty
             }
+            Some(typ) => {
+                // take type that the user specified
+                self.fcx.inh.locals.borrow_mut().insert(nid, typ);
+                typ
+            }
+        }
     }
 }
 
@@ -474,7 +473,7 @@ fn visit_local(&mut self, local: &ast::Local) {
             ast::TyInfer => None,
             _ => Some(self.fcx.to_ty(&*local.ty))
         };
-        self.assign(local.id, o_ty);
+        self.assign(local.span, local.id, o_ty);
         debug!("Local variable {} is assigned type {}",
                self.fcx.pat_to_string(&*local.pat),
                self.fcx.infcx().ty_to_string(
@@ -484,19 +483,23 @@ fn visit_local(&mut self, local: &ast::Local) {
 
     // Add pattern bindings.
     fn visit_pat(&mut self, p: &ast::Pat) {
-            match p.node {
-              ast::PatIdent(_, ref path1, _)
-                  if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
-                self.assign(p.id, None);
-                debug!("Pattern binding {} is assigned to {}",
-                       token::get_ident(path1.node),
-                       self.fcx.infcx().ty_to_string(
-                           self.fcx.inh.locals.borrow().get_copy(&p.id)));
-              }
-              _ => {}
-            }
-            visit::walk_pat(self, p);
-
+        match p.node {
+            ast::PatIdent(_, ref path1, _)
+                if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
+                    let var_ty = self.assign(p.span, p.id, None);
+
+                    self.fcx.require_type_is_sized(var_ty, p.span,
+                                                   traits::VariableType(p.id));
+
+                    debug!("Pattern binding {} is assigned to {} with type {}",
+                           token::get_ident(path1.node),
+                           self.fcx.infcx().ty_to_string(
+                               self.fcx.inh.locals.borrow().get_copy(&p.id)),
+                           var_ty.repr(self.fcx.tcx()));
+                }
+            _ => {}
+        }
+        visit::walk_pat(self, p);
     }
 
     fn visit_block(&mut self, b: &ast::Block) {
@@ -592,11 +595,14 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
         // Add formal parameters.
         for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
             // Create type variables for each argument.
-            pat_util::pat_bindings(&tcx.def_map,
-                                   &*input.pat,
-                                   |_bm, pat_id, _sp, _path| {
-                                       visit.assign(pat_id, None);
-                                   });
+            pat_util::pat_bindings(
+                &tcx.def_map,
+                &*input.pat,
+                |_bm, pat_id, sp, _path| {
+                    let var_ty = visit.assign(sp, pat_id, None);
+                    fcx.require_type_is_sized(var_ty, sp,
+                                              traits::VariableType(pat_id));
+                });
 
             // Check the pattern.
             let pcx = pat_ctxt {
@@ -713,71 +719,6 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
     }
 }
 
-fn check_type_well_formed(ccx: &CrateCtxt, item: &ast::Item) {
-    /*!
-     * Checks that the field types (in a struct def'n) or
-     * argument types (in an enum def'n) are well-formed,
-     * meaning that they do not require any constraints not
-     * declared in the struct definition itself.
-     * For example, this definition would be illegal:
-     *
-     *     struct Ref<'a, T> { x: &'a T }
-     *
-     * because the type did not declare that `T:'a`.
-     *
-     * We do this check as a pre-pass before checking fn bodies
-     * because if these constraints are not included it frequently
-     * leads to confusing errors in fn bodies. So it's better to check
-     * the types first.
-     */
-
-    debug!("check_type_well_formed(it.id={}, it.ident={})",
-           item.id,
-           ty::item_path_str(ccx.tcx, local_def(item.id)));
-
-    match item.node {
-        ast::ItemStruct(..) => {
-            check_type_defn(ccx, item, |fcx| {
-                ty::struct_fields(ccx.tcx, local_def(item.id),
-                                  &fcx.inh.param_env.free_substs)
-                    .iter()
-                    .map(|f| f.mt.ty)
-                    .collect()
-            });
-        }
-        ast::ItemEnum(..) => {
-            check_type_defn(ccx, item, |fcx| {
-                ty::substd_enum_variants(ccx.tcx, local_def(item.id),
-                                         &fcx.inh.param_env.free_substs)
-                    .iter()
-                    .flat_map(|variant| {
-                        variant.args
-                            .iter()
-                            .map(|&arg_ty| arg_ty)
-                    })
-                    .collect()
-            });
-        }
-        _ => {}
-    }
-
-    fn check_type_defn(ccx: &CrateCtxt,
-                       item: &ast::Item,
-                       lookup_fields: |&FnCtxt| -> Vec<ty::t>)
-    {
-        let item_def_id = local_def(item.id);
-        let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
-        let param_env =
-            ty::construct_parameter_environment(ccx.tcx,
-                                                &polytype.generics,
-                                                item.id);
-        let inh = Inherited::new(ccx.tcx, param_env);
-        let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
-        let field_tys = lookup_fields(&fcx);
-        regionck::regionck_type_defn(&fcx, item.span, field_tys.as_slice());
-    }
-}
-
 pub fn check_item_sized(ccx: &CrateCtxt, it: &ast::Item) {
     debug!("check_item(it.id={}, it.ident={})",
            it.id,
@@ -836,7 +777,6 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
                                                ast_trait_ref,
                                                &*impl_trait_ref,
                                                impl_items.as_slice());
-                vtable::resolve_impl(ccx.tcx, it, &impl_pty.generics, &*impl_trait_ref);
             }
             None => { }
         }
@@ -1409,10 +1349,12 @@ fn method2<'b>() { .. case 2, could be ok .. }
 }
 
 fn check_cast(fcx: &FnCtxt,
+              cast_expr: &ast::Expr,
               e: &ast::Expr,
-              t: &ast::Ty,
-              id: ast::NodeId,
-              span: Span) {
+              t: &ast::Ty) {
+    let id = cast_expr.id;
+    let span = cast_expr.span;
+
     // Find the type of `e`. Supply hints based on the type we are casting to,
     // if appropriate.
     let t_1 = fcx.to_ty(t);
@@ -1443,6 +1385,7 @@ fn check_cast(fcx: &FnCtxt,
 
     if ty::type_is_trait(t_1) {
         // This will be looked up later on.
+        vtable2::check_object_cast(fcx, cast_expr, e, t_1);
         fcx.write_ty(id, t_1);
         return
     }
@@ -1582,14 +1525,6 @@ pub fn infcx<'b>(&'b self) -> &'b infer::InferCtxt<'a, 'tcx> {
     pub fn err_count_since_creation(&self) -> uint {
         self.ccx.tcx.sess.err_count() - self.err_count_on_creation
     }
-
-    pub fn vtable_context<'a>(&'a self) -> VtableContext<'a, 'tcx> {
-        VtableContext {
-            infcx: self.infcx(),
-            param_env: &self.inh.param_env,
-            unboxed_closures: &self.inh.unboxed_closures,
-        }
-    }
 }
 
 impl<'a, 'tcx> RegionScope for infer::InferCtxt<'a, 'tcx> {
@@ -1629,6 +1564,14 @@ pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
         self.inh.node_types.borrow_mut().insert(node_id, ty);
     }
 
+    pub fn write_object_cast(&self,
+                             key: ast::NodeId,
+                             trait_ref: Rc<ty::TraitRef>) {
+        debug!("write_object_cast key={} trait_ref={}",
+               key, trait_ref.repr(self.tcx()));
+        self.inh.object_cast_map.borrow_mut().insert(key, trait_ref);
+    }
+
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts) {
         if !substs.substs.is_noop() {
             debug!("write_substs({}, {}) in fcx {}",
@@ -1651,10 +1594,12 @@ pub fn write_ty_substs(&self,
 
     pub fn write_autoderef_adjustment(&self,
                                       node_id: ast::NodeId,
+                                      span: Span,
                                       derefs: uint) {
         if derefs == 0 { return; }
         self.write_adjustment(
             node_id,
+            span,
             ty::AutoDerefRef(ty::AutoDerefRef {
                 autoderefs: derefs,
                 autoref: None })
@@ -1663,11 +1608,109 @@ pub fn write_autoderef_adjustment(&self,
 
     pub fn write_adjustment(&self,
                             node_id: ast::NodeId,
+                            span: Span,
                             adj: ty::AutoAdjustment) {
         debug!("write_adjustment(node_id={:?}, adj={:?})", node_id, adj);
+
+        // Careful: adjustments can imply trait obligations if we are
+        // casting from a concrete type to an object type. I think
+        // it'd probably be nicer to move the logic that creates the
+        // obligation into the code that creates the adjustment, but
+        // that's a bit awkward, so instead we go digging and pull the
+        // obligation out here.
+        self.register_adjustment_obligations(span, &adj);
         self.inh.adjustments.borrow_mut().insert(node_id, adj);
     }
 
+    fn register_adjustment_obligations(&self,
+                                       span: Span,
+                                       adj: &ty::AutoAdjustment) {
+        match *adj {
+            ty::AutoAddEnv(..) => { }
+            ty::AutoDerefRef(ref d_r) => {
+                match d_r.autoref {
+                    Some(ref a_r) => {
+                        self.register_autoref_obligations(span, a_r);
+                    }
+                    None => {}
+                }
+            }
+        }
+    }
+
+    fn register_autoref_obligations(&self,
+                                    span: Span,
+                                    autoref: &ty::AutoRef) {
+        match *autoref {
+            ty::AutoUnsize(ref unsize) => {
+                self.register_unsize_obligations(span, unsize);
+            }
+            ty::AutoPtr(_, _, None) |
+            ty::AutoUnsafe(_, None) => {
+            }
+            ty::AutoPtr(_, _, Some(ref a_r)) |
+            ty::AutoUnsafe(_, Some(ref a_r)) => {
+                self.register_autoref_obligations(span, &**a_r)
+            }
+            ty::AutoUnsizeUniq(ref unsize) => {
+                self.register_unsize_obligations(span, unsize);
+            }
+        }
+    }
+
+    fn register_unsize_obligations(&self,
+                                   span: Span,
+                                   unsize: &ty::UnsizeKind) {
+        debug!("register_unsize_obligations: unsize={:?}", unsize);
+
+        match *unsize {
+            ty::UnsizeLength(..) => {}
+            ty::UnsizeStruct(ref u, _) => {
+                self.register_unsize_obligations(span, &**u)
+            }
+            ty::UnsizeVtable(ref ty_trait, self_ty) => {
+                vtable2::register_object_cast_obligations(self,
+                                                          span,
+                                                          ty_trait,
+                                                          self_ty);
+            }
+        }
+    }
+
+    pub fn instantiate_item_type(&self,
+                                 span: Span,
+                                 def_id: ast::DefId)
+                                 -> TypeAndSubsts
+    {
+        /*!
+         * Returns the type of `def_id` with all generics replaced by
+         * by fresh type/region variables. Also returns the
+         * substitution from the type parameters on `def_id` to the
+         * fresh variables.  Registers any trait obligations specified
+         * on `def_id` at the same time.
+         */
+
+        let polytype =
+            ty::lookup_item_type(self.tcx(), def_id);
+        let substs =
+            self.infcx().fresh_substs_for_generics(
+                span,
+                &polytype.generics);
+        self.add_obligations_for_parameters(
+            traits::ObligationCause::new(
+                span,
+                traits::ItemObligation(def_id)),
+            &substs,
+            &polytype.generics);
+        let monotype =
+            polytype.ty.subst(self.tcx(), &substs);
+
+        TypeAndSubsts {
+            ty: monotype,
+            substs: substs
+        }
+    }
+
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, ty::mk_nil());
     }
@@ -1678,8 +1721,56 @@ pub fn write_error(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, ty::mk_err());
     }
 
+    pub fn require_type_meets(&self,
+                              ty: ty::t,
+                              span: Span,
+                              code: traits::ObligationCauseCode,
+                              bound: ty::BuiltinBound)
+    {
+        self.register_obligation(
+            traits::obligation_for_builtin_bound(
+                self.tcx(),
+                traits::ObligationCause::new(span, code),
+                ty,
+                bound));
+    }
+
+    pub fn require_type_is_sized(&self,
+                                 ty: ty::t,
+                                 span: Span,
+                                 code: traits::ObligationCauseCode)
+    {
+        self.require_type_meets(ty, span, code, ty::BoundSized);
+    }
+
+    pub fn require_expr_have_sized_type(&self,
+                                        expr: &ast::Expr,
+                                        code: traits::ObligationCauseCode)
+    {
+        self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
+    }
+
+    pub fn register_obligation(&self,
+                               obligation: traits::Obligation)
+    {
+        debug!("register_obligation({})",
+               obligation.repr(self.tcx()));
+
+        self.inh.fulfillment_cx
+            .borrow_mut()
+            .register_obligation(self.tcx(), obligation);
+    }
+
     pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
-        ast_ty_to_ty(self, self.infcx(), ast_t)
+        let t = ast_ty_to_ty(self, self.infcx(), ast_t);
+
+        let mut bounds_checker = wf::BoundsChecker::new(self,
+                                                        ast_t.span,
+                                                        self.body_id,
+                                                        None);
+        bounds_checker.check_ty(t);
+
+        t
     }
 
     pub fn pat_to_string(&self, pat: &ast::Pat) -> String {
@@ -1761,7 +1852,7 @@ pub fn mk_assignty(&self,
             Ok(None) => Ok(()),
             Err(ref e) => Err((*e)),
             Ok(Some(adjustment)) => {
-                self.write_adjustment(expr.id, adjustment);
+                self.write_adjustment(expr.id, expr.span, adjustment);
                 Ok(())
             }
         }
@@ -1829,10 +1920,10 @@ pub fn register_region_obligation(&self,
                                   origin: origin });
     }
 
-    pub fn add_region_obligations_for_parameters(&self,
-                                                 span: Span,
-                                                 substs: &Substs,
-                                                 generics: &ty::Generics)
+    pub fn add_obligations_for_parameters(&self,
+                                          cause: traits::ObligationCause,
+                                          substs: &Substs,
+                                          generics: &ty::Generics)
     {
         /*!
          * Given a set of generic parameter definitions (`generics`)
@@ -1853,10 +1944,31 @@ pub fn add_region_obligations_for_parameters(&self,
          * locally.
          */
 
-        debug!("add_region_obligations_for_parameters(substs={}, generics={})",
+        debug!("add_obligations_for_parameters(substs={}, generics={})",
                substs.repr(self.tcx()),
                generics.repr(self.tcx()));
 
+        self.add_trait_obligations_for_generics(cause, substs, generics);
+        self.add_region_obligations_for_generics(cause, substs, generics);
+    }
+
+    fn add_trait_obligations_for_generics(&self,
+                                          cause: traits::ObligationCause,
+                                          substs: &Substs,
+                                          generics: &ty::Generics) {
+        let obligations =
+            traits::obligations_for_generics(self.tcx(),
+                                             cause,
+                                             generics,
+                                             substs);
+        obligations.map_move(|o| self.register_obligation(o));
+    }
+
+    fn add_region_obligations_for_generics(&self,
+                                           cause: traits::ObligationCause,
+                                           substs: &Substs,
+                                           generics: &ty::Generics)
+    {
         assert_eq!(generics.types.iter().len(),
                    substs.types.iter().len());
         for (type_def, &type_param) in
@@ -1867,8 +1979,8 @@ pub fn add_region_obligations_for_parameters(&self,
                                          idx: type_def.index,
                                          def_id: type_def.def_id };
             let bounds = type_def.bounds.subst(self.tcx(), substs);
-            add_region_obligations_for_type_parameter(
-                self, span, param_ty, &bounds, type_param);
+            self.add_region_obligations_for_type_parameter(
+                cause.span, param_ty, &bounds, type_param);
         }
 
         assert_eq!(generics.regions.iter().len(),
@@ -1878,42 +1990,40 @@ pub fn add_region_obligations_for_parameters(&self,
                 substs.regions().iter())
         {
             let bounds = region_def.bounds.subst(self.tcx(), substs);
-            add_region_obligations_for_region_parameter(
-                self, span, bounds.as_slice(), region_param);
-        }
-
-        fn add_region_obligations_for_type_parameter(
-            fcx: &FnCtxt,
-            span: Span,
-            param_ty: ty::ParamTy,
-            param_bound: &ty::ParamBounds,
-            ty: ty::t)
-        {
-            // For each declared region bound `T:r`, `T` must outlive `r`.
-            let region_bounds =
-                ty::required_region_bounds(
-                    fcx.tcx(),
-                    param_bound.opt_region_bound.as_slice(),
-                    param_bound.builtin_bounds,
-                    param_bound.trait_bounds.as_slice());
-            for &r in region_bounds.iter() {
-                let origin = infer::RelateParamBound(span, param_ty, ty);
-                fcx.register_region_obligation(origin, ty, r);
-            }
+            self.add_region_obligations_for_region_parameter(
+                cause.span, bounds.as_slice(), region_param);
         }
+    }
 
-        fn add_region_obligations_for_region_parameter(
-            fcx: &FnCtxt,
-            span: Span,
-            region_bounds: &[ty::Region],
-            region_param: ty::Region)
-        {
-            for &b in region_bounds.iter() {
-                // For each bound `region:b`, `b <= region` must hold
-                // (i.e., `region` must outlive `b`).
-                let origin = infer::RelateRegionParamBound(span);
-                fcx.mk_subr(origin, b, region_param);
-            }
+    fn add_region_obligations_for_type_parameter(&self,
+                                                 span: Span,
+                                                 param_ty: ty::ParamTy,
+                                                 param_bound: &ty::ParamBounds,
+                                                 ty: ty::t)
+    {
+        // For each declared region bound `T:r`, `T` must outlive `r`.
+        let region_bounds =
+            ty::required_region_bounds(
+                self.tcx(),
+                param_bound.opt_region_bound.as_slice(),
+                param_bound.builtin_bounds,
+                param_bound.trait_bounds.as_slice());
+        for &r in region_bounds.iter() {
+            let origin = infer::RelateParamBound(span, param_ty, ty);
+            self.register_region_obligation(origin, ty, r);
+        }
+    }
+
+    fn add_region_obligations_for_region_parameter(&self,
+                                                   span: Span,
+                                                   region_bounds: &[ty::Region],
+                                                   region_param: ty::Region)
+    {
+        for &b in region_bounds.iter() {
+            // For each bound `region:b`, `b <= region` must hold
+            // (i.e., `region` must outlive `b`).
+            let origin = infer::RelateRegionParamBound(span);
+            self.mk_subr(origin, b, region_param);
         }
     }
 }
@@ -2272,7 +2382,7 @@ fn check_method_argument_types(fcx: &FnCtxt,
 fn check_argument_types(fcx: &FnCtxt,
                         sp: Span,
                         fn_inputs: &[ty::t],
-                        callee_expr: &ast::Expr,
+                        _callee_expr: &ast::Expr,
                         args: &[P<ast::Expr>],
                         deref_args: DerefArgs,
                         variadic: bool,
@@ -2369,7 +2479,7 @@ fn check_argument_types(fcx: &FnCtxt,
         // an "opportunistic" vtable resolution of any trait
         // bounds on the call.
         if check_blocks {
-            vtable::early_resolve_expr(callee_expr, fcx, true);
+            vtable2::select_fcx_obligations_where_possible(fcx);
         }
 
         // For variadic functions, we don't have a declared type for all of
@@ -2568,16 +2678,15 @@ fn check_expr_with_lvalue_pref(fcx: &FnCtxt, expr: &ast::Expr,
     check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ())
 }
 
-
 // determine the `self` type, using fresh variables for all variables
 // declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
 // would return ($0, $1) where $0 and $1 are freshly instantiated type
 // variables.
-pub fn impl_self_ty(vcx: &VtableContext,
+pub fn impl_self_ty(fcx: &FnCtxt,
                     span: Span, // (potential) receiver for this impl
                     did: ast::DefId)
                     -> TypeAndSubsts {
-    let tcx = vcx.tcx();
+    let tcx = fcx.tcx();
 
     let ity = ty::lookup_item_type(tcx, did);
     let (n_tps, rps, raw_ty) =
@@ -2585,8 +2694,8 @@ pub fn impl_self_ty(vcx: &VtableContext,
          ity.generics.regions.get_slice(subst::TypeSpace),
          ity.ty);
 
-    let rps = vcx.infcx.region_vars_for_defs(span, rps);
-    let tps = vcx.infcx.next_ty_vars(n_tps);
+    let rps = fcx.inh.infcx.region_vars_for_defs(span, rps);
+    let tps = fcx.inh.infcx.next_ty_vars(n_tps);
     let substs = subst::Substs::new_type(tps, rps);
     let substd_ty = raw_ty.subst(tcx, &substs);
 
@@ -3260,7 +3369,7 @@ fn check_field(fcx: &FnCtxt,
         match field_ty {
             Some(field_ty) => {
                 fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, autoderefs);
+                fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
                 return;
             }
             None => {}
@@ -3344,7 +3453,7 @@ fn check_tup_field(fcx: &FnCtxt,
         match field_ty {
             Some(field_ty) => {
                 fcx.write_ty(expr.id, field_ty);
-                fcx.write_autoderef_adjustment(base.id, autoderefs);
+                fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
                 return;
             }
             None => {}
@@ -3467,15 +3576,11 @@ fn check_struct_constructor(fcx: &FnCtxt,
                                 base_expr: Option<&ast::Expr>) {
         let tcx = fcx.ccx.tcx;
 
-        // Look up the number of type parameters and the raw type, and
-        // determine whether the class is region-parameterized.
-        let item_type = ty::lookup_item_type(tcx, class_id);
-        let raw_type = item_type.ty;
-
         // Generate the struct type.
-        let substitutions = fcx.infcx().fresh_substs_for_type(
-            span, &item_type.generics);
-        let mut struct_type = raw_type.subst(tcx, &substitutions);
+        let TypeAndSubsts {
+            ty: mut struct_type,
+            substs: struct_substs
+        } = fcx.instantiate_item_type(span, class_id);
 
         // Look up and check the fields.
         let class_fields = ty::lookup_struct_fields(tcx, class_id);
@@ -3484,7 +3589,7 @@ fn check_struct_constructor(fcx: &FnCtxt,
                                        span,
                                        class_id,
                                        id,
-                                       substitutions,
+                                       struct_substs,
                                        class_fields.as_slice(),
                                        fields,
                                        base_expr.is_none());
@@ -3517,9 +3622,10 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
 
         // Look up the number of type parameters and the raw type, and
         // determine whether the enum is region-parameterized.
-        let item_type = ty::lookup_item_type(tcx, enum_id);
-        let substitutions = fcx.infcx().fresh_substs_for_type(span, &item_type.generics);
-        let enum_type = item_type.ty.subst(tcx, &substitutions);
+        let TypeAndSubsts {
+            ty: enum_type,
+            substs: substitutions
+        } = fcx.instantiate_item_type(span, enum_id);
 
         // Look up and check the enum variant fields.
         let variant_fields = ty::lookup_struct_fields(tcx, variant_id);
@@ -3619,6 +3725,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
             span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression");
         }
 
+        fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized);
+
         // Overwrite result of check_binop...this preserves existing behavior
         // but seems quite dubious with regard to user-defined methods
         // and so forth. - Niko
@@ -3833,6 +3941,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
         check_expr_has_type(fcx, &**rhs, lhs_ty);
         let rhs_ty = fcx.expr_ty(&**rhs);
 
+        fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized);
+
         if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
             fcx.write_error(id);
         } else if ty::type_is_bot(lhs_ty) || ty::type_is_bot(rhs_ty) {
@@ -3863,7 +3973,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
       ast::ExprForLoop(ref pat, ref head, ref block, _) => {
         check_expr(fcx, &**head);
         let typ = lookup_method_for_for_loop(fcx, &**head, expr.id);
-        vtable::early_resolve_expr(expr, fcx, true);
+        vtable2::select_fcx_obligations_where_possible(fcx);
 
         let pcx = pat_ctxt {
             fcx: fcx,
@@ -3958,7 +4068,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
             }
             _ => {}
         }
-        check_cast(fcx, &**e, &**t, id, expr.span);
+        check_cast(fcx, expr, &**e, &**t);
       }
       ast::ExprVec(ref args) => {
         let uty = match expected {
@@ -4015,6 +4125,16 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
             }
         };
 
+        if count > 1 {
+            // For [foo, ..n] where n > 1, `foo` must have
+            // Copy type:
+            fcx.require_type_meets(
+                t,
+                expr.span,
+                traits::RepeatVec,
+                ty::BoundCopy);
+        }
+
         if ty::type_is_error(element_ty) {
             fcx.write_error(id);
         } else if ty::type_is_bot(element_ty) {
@@ -4143,6 +4263,8 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                 }
             }
         }
+
+        fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized);
       }
       ast::ExprField(ref base, ref field, ref tys) => {
         check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice());
@@ -4167,7 +4289,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
                   Some(ty) => {
                       check_expr_has_type(fcx, &**idx, ty::mk_uint());
                       fcx.write_ty(id, ty);
-                      fcx.write_autoderef_adjustment(base.id, autoderefs);
+                      fcx.write_autoderef_adjustment(base.id, base.span, autoderefs);
                   }
                   None => {
                       // This is an overloaded method.
@@ -4520,8 +4642,10 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
 
     check_expr_with_hint(fcx, e, declty);
     demand::coerce(fcx, e.span, declty, e);
+    vtable2::select_all_fcx_obligations_or_error(fcx);
     regionck::regionck_expr(fcx, e);
     writeback::resolve_type_vars_in_expr(fcx, e);
+    vtable2::check_builtin_bound_obligations(fcx);
 }
 
 /// Checks whether a type can be represented in memory. In particular, it
@@ -5009,8 +5133,11 @@ pub fn instantiate_path(fcx: &FnCtxt,
         assert_eq!(substs.regions().len(space), region_defs.len(space));
     }
 
-    fcx.add_region_obligations_for_parameters(
-        span, &substs, &polytype.generics);
+    fcx.add_obligations_for_parameters(
+        traits::ObligationCause::new(span,
+                                     traits::ItemObligation(def.def_id())),
+        &substs,
+        &polytype.generics);
 
     fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts {
         substs: substs,
index 95b7e03e6d9aa99464724be57ab48f9f0863d4c6..45ffddf3fe80e57d881a9526dc3727149a7dfce7 100644 (file)
@@ -155,18 +155,9 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) {
     fcx.infcx().resolve_regions_and_report_errors();
 }
 
-pub fn regionck_type_defn(fcx: &FnCtxt,
-                          span: Span,
-                          component_tys: &[ty::t]) {
-    let mut rcx = Rcx::new(fcx, 0);
-    for &component_ty in component_tys.iter() {
-        // Check that each type outlives the empty region. Since the
-        // empty region is a subregion of all others, this can't fail
-        // unless the type does not meet the well-formedness
-        // requirements.
-        type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
-                          component_ty, ty::ReEmpty);
-    }
+pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
+    let mut rcx = Rcx::new(fcx, item.id);
+    rcx.visit_region_obligations(item.id);
     fcx.infcx().resolve_regions_and_report_errors();
 }
 
@@ -179,6 +170,26 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
     fcx.infcx().resolve_regions_and_report_errors();
 }
 
+pub fn regionck_ensure_component_tys_wf(fcx: &FnCtxt,
+                                        span: Span,
+                                        component_tys: &[ty::t]) {
+    /*!
+     * Checks that the types in `component_tys` are well-formed.
+     * This will add constraints into the region graph.
+     * Does *not* run `resolve_regions_and_report_errors` and so forth.
+     */
+
+    let mut rcx = Rcx::new(fcx, 0);
+    for &component_ty in component_tys.iter() {
+        // Check that each type outlives the empty region. Since the
+        // empty region is a subregion of all others, this can't fail
+        // unless the type does not meet the well-formedness
+        // requirements.
+        type_must_outlive(&mut rcx, infer::RelateRegionParamBound(span),
+                          component_ty, ty::ReEmpty);
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // INTERNALS
 
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
deleted file mode 100644 (file)
index 9a70cf5..0000000
+++ /dev/null
@@ -1,1077 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-use middle::ty;
-use middle::ty::{AutoDerefRef, ParamTy};
-use middle::ty_fold::TypeFolder;
-use middle::typeck::astconv::AstConv;
-use middle::typeck::check::{FnCtxt, impl_self_ty};
-use middle::typeck::check::{structurally_resolved_type};
-use middle::typeck::check::regionmanip;
-use middle::typeck::check::writeback;
-use middle::typeck::infer::fixup_err_to_string;
-use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
-use middle::typeck::infer;
-use middle::typeck::{MethodCall, TypeAndSubsts};
-use middle::typeck::{param_index, vtable_error, vtable_origin, vtable_param};
-use middle::typeck::{vtable_param_res, vtable_res, vtable_static};
-use middle::typeck::{vtable_unboxed_closure};
-use middle::subst;
-use middle::subst::{Subst, VecPerParamSpace};
-use util::common::indenter;
-use util::nodemap::DefIdMap;
-use util::ppaux;
-use util::ppaux::Repr;
-
-use std::cell::RefCell;
-use std::rc::Rc;
-use std::collections::HashSet;
-use syntax::ast;
-use syntax::ast_util;
-use syntax::codemap::Span;
-use syntax::print::pprust::expr_to_string;
-use syntax::visit;
-use syntax::visit::Visitor;
-
-// vtable resolution looks for places where trait bounds are
-// substituted in and figures out which vtable is used. There is some
-// extra complication thrown in to support early "opportunistic"
-// vtable resolution. This is a hacky mechanism that is invoked while
-// typechecking function calls (after typechecking non-closure
-// arguments and before typechecking closure arguments) in the hope of
-// solving for the trait parameters from the impl. (For example,
-// determining that if a parameter bounded by BaseIter<A> is
-// instantiated with Option<int>, that A = int.)
-//
-// In early resolution mode, no vtables are recorded, and a number of
-// errors are ignored. Early resolution only works if a type is
-// *fully* resolved. (We could be less restrictive than that, but it
-// would require much more care, and this seems to work decently in
-// practice.)
-//
-// While resolution on a single type requires the type to be fully
-// resolved, when resolving a substitution against a list of bounds,
-// we do not require all of the types to be resolved in advance.
-// Furthermore, we process substitutions in reverse order, which
-// allows resolution on later parameters to give information on
-// earlier params referenced by the typeclass bounds.
-// It may be better to do something more clever, like processing fully
-// resolved types first.
-
-/// A vtable context includes an inference context, a parameter environment,
-/// and a list of unboxed closure types.
-pub struct VtableContext<'a, 'tcx: 'a> {
-    pub infcx: &'a infer::InferCtxt<'a, 'tcx>,
-    pub param_env: &'a ty::ParameterEnvironment,
-    pub unboxed_closures: &'a RefCell<DefIdMap<ty::UnboxedClosure>>,
-}
-
-impl<'a, 'tcx> VtableContext<'a, 'tcx> {
-    pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.infcx.tcx }
-}
-
-fn lookup_vtables(vcx: &VtableContext,
-                  span: Span,
-                  type_param_defs: &VecPerParamSpace<ty::TypeParameterDef>,
-                  substs: &subst::Substs,
-                  is_early: bool)
-                  -> VecPerParamSpace<vtable_param_res> {
-    debug!("lookup_vtables(\
-           type_param_defs={}, \
-           substs={}",
-           type_param_defs.repr(vcx.tcx()),
-           substs.repr(vcx.tcx()));
-
-    // We do this backwards for reasons discussed above.
-    let result = type_param_defs.map_rev(|def| {
-        let ty = *substs.types.get(def.space, def.index);
-        lookup_vtables_for_param(vcx, span, Some(substs),
-                                 &def.bounds, ty, is_early)
-    });
-
-    debug!("lookup_vtables result(\
-            type_param_defs={}, \
-            substs={}, \
-            result={})",
-           type_param_defs.repr(vcx.tcx()),
-           substs.repr(vcx.tcx()),
-           result.repr(vcx.tcx()));
-
-    result
-}
-
-fn lookup_vtables_for_param(vcx: &VtableContext,
-                            span: Span,
-                            // None for substs means the identity
-                            substs: Option<&subst::Substs>,
-                            type_param_bounds: &ty::ParamBounds,
-                            ty: ty::t,
-                            is_early: bool)
-                            -> vtable_param_res {
-    let tcx = vcx.tcx();
-
-    debug!("lookup_vtables_for_param(ty={}, type_param_bounds={}, is_early={})",
-           ty.repr(vcx.tcx()),
-           type_param_bounds.repr(vcx.tcx()),
-           is_early);
-
-    // ty is the value supplied for the type parameter A...
-    let mut param_result = Vec::new();
-
-    ty::each_bound_trait_and_supertraits(tcx,
-                                         type_param_bounds.trait_bounds
-                                                          .as_slice(),
-                                         |trait_ref| {
-        // ...and here trait_ref is each bound that was declared on A,
-        // expressed in terms of the type parameters.
-
-        debug!("matching ty={} trait_ref={}",
-               ty.repr(vcx.tcx()),
-               trait_ref.repr(vcx.tcx()));
-
-        ty::populate_implementations_for_trait_if_necessary(tcx,
-                                                            trait_ref.def_id);
-
-        // Substitute the values of the type parameters that may
-        // appear in the bound.
-        let trait_ref = substs.as_ref().map_or(trait_ref.clone(), |substs| {
-            debug!("about to subst: {}, {}",
-                   trait_ref.repr(tcx), substs.repr(tcx));
-            trait_ref.subst(tcx, *substs)
-        });
-
-        debug!("after subst: {}", trait_ref.repr(tcx));
-
-        match lookup_vtable(vcx, span, ty, trait_ref.clone(), is_early) {
-            Some(vtable) => param_result.push(vtable),
-            None => {
-                vcx.tcx().sess.span_err(span,
-                    format!("failed to find an implementation of \
-                          trait {} for {}",
-                         vcx.infcx.trait_ref_to_string(&*trait_ref),
-                         vcx.infcx.ty_to_string(ty)).as_slice());
-                param_result.push(vtable_error)
-            }
-        }
-        true
-    });
-
-    debug!("lookup_vtables_for_param result(\
-            type_param_bounds={}, \
-            ty={}, \
-            result={})",
-           type_param_bounds.repr(vcx.tcx()),
-           ty.repr(vcx.tcx()),
-           param_result.repr(vcx.tcx()));
-
-    param_result
-}
-
-fn relate_trait_refs(vcx: &VtableContext,
-                     span: Span,
-                     act_trait_ref: Rc<ty::TraitRef>,
-                     exp_trait_ref: Rc<ty::TraitRef>) {
-    /*!
-     *
-     * Checks that an implementation of `act_trait_ref` is suitable
-     * for use where `exp_trait_ref` is required and reports an
-     * error otherwise.
-     */
-
-    match infer::mk_sub_trait_refs(vcx.infcx,
-                                   false,
-                                   infer::RelateTraitRefs(span),
-                                   act_trait_ref.clone(),
-                                   exp_trait_ref.clone()) {
-        Ok(()) => {} // Ok.
-        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)
-            {
-                let tcx = vcx.tcx();
-                span_err!(tcx.sess, span, E0095, "expected {}, found {} ({})",
-                          ppaux::trait_ref_to_string(tcx, &r_exp_trait_ref),
-                          ppaux::trait_ref_to_string(tcx, &r_act_trait_ref),
-                          ty::type_err_to_str(tcx, err));
-            }
-        }
-    }
-}
-
-// Look up the vtable implementing the trait `trait_ref` at type `t`
-fn lookup_vtable(vcx: &VtableContext,
-                 span: Span,
-                 ty: ty::t,
-                 trait_ref: Rc<ty::TraitRef>,
-                 is_early: bool)
-                 -> Option<vtable_origin>
-{
-    debug!("lookup_vtable(ty={}, trait_ref={})",
-           ty.repr(vcx.tcx()),
-           trait_ref.repr(vcx.tcx()));
-    let _i = indenter();
-
-    let ty = match fixup_ty(vcx, span, ty, is_early) {
-        Some(ty) => ty,
-        None => {
-            // fixup_ty can only fail if this is early resolution
-            assert!(is_early);
-            // The type has unconstrained type variables in it, so we can't
-            // do early resolution on it. Return some completely bogus vtable
-            // information: we aren't storing it anyways.
-            return Some(vtable_error);
-        }
-    };
-
-    if ty::type_is_error(ty) {
-        return Some(vtable_error);
-    }
-
-    // If the type is self or a param, we look at the trait/supertrait
-    // bounds to see if they include the trait we are looking for.
-    let vtable_opt = match ty::get(ty).sty {
-        ty::ty_param(ParamTy {space, idx: n, ..}) => {
-            let env_bounds = &vcx.param_env.bounds;
-            let type_param_bounds = &env_bounds.get(space, n).trait_bounds;
-            lookup_vtable_from_bounds(vcx,
-                                      span,
-                                      type_param_bounds.as_slice(),
-                                      param_index {
-                                          space: space,
-                                          index: n,
-                                      },
-                                      trait_ref.clone())
-        }
-
-        // Default case just falls through
-        _ => None
-    };
-
-    if vtable_opt.is_some() { return vtable_opt; }
-
-    // If we aren't a self type or param, or it was, but we didn't find it,
-    // do a search.
-    search_for_vtable(vcx, span, ty, trait_ref, is_early)
-}
-
-// Given a list of bounds on a type, search those bounds to see if any
-// of them are the vtable we are looking for.
-fn lookup_vtable_from_bounds(vcx: &VtableContext,
-                             span: Span,
-                             bounds: &[Rc<ty::TraitRef>],
-                             param: param_index,
-                             trait_ref: Rc<ty::TraitRef>)
-                             -> Option<vtable_origin> {
-    let tcx = vcx.tcx();
-
-    let mut n_bound = 0;
-    let mut ret = None;
-    ty::each_bound_trait_and_supertraits(tcx, bounds, |bound_trait_ref| {
-        debug!("checking bounds trait {}",
-               bound_trait_ref.repr(vcx.tcx()));
-
-        if bound_trait_ref.def_id == trait_ref.def_id {
-            relate_trait_refs(vcx, span, bound_trait_ref, trait_ref.clone());
-            let vtable = vtable_param(param, n_bound);
-            debug!("found param vtable: {:?}",
-                   vtable);
-            ret = Some(vtable);
-            false
-        } else {
-            n_bound += 1;
-            true
-        }
-    });
-    ret
-}
-
-fn search_for_unboxed_closure_vtable(vcx: &VtableContext,
-                                     span: Span,
-                                     ty: ty::t,
-                                     trait_ref: Rc<ty::TraitRef>)
-                                     -> Option<vtable_origin> {
-    let tcx = vcx.tcx();
-    let closure_def_id = match ty::get(ty).sty {
-        ty::ty_unboxed_closure(closure_def_id, _) => closure_def_id,
-        _ => return None,
-    };
-
-    let fn_traits = [
-        (ty::FnUnboxedClosureKind, tcx.lang_items.fn_trait()),
-        (ty::FnMutUnboxedClosureKind, tcx.lang_items.fn_mut_trait()),
-        (ty::FnOnceUnboxedClosureKind, tcx.lang_items.fn_once_trait()),
-    ];
-    for tuple in fn_traits.iter() {
-        let kind = match tuple {
-            &(kind, Some(ref fn_trait)) if *fn_trait == trait_ref.def_id => {
-                kind
-            }
-            _ => continue,
-        };
-
-        // Check to see whether the argument and return types match.
-        let unboxed_closures = tcx.unboxed_closures.borrow();
-        let closure_type = match unboxed_closures.find(&closure_def_id) {
-            Some(closure) => {
-                if closure.kind != kind {
-                    continue
-                }
-                closure.closure_type.clone()
-            }
-            None => {
-                // Try the inherited unboxed closure type map.
-                let unboxed_closures = vcx.unboxed_closures.borrow();
-                match unboxed_closures.find(&closure_def_id) {
-                    Some(closure) => {
-                        if closure.kind != kind {
-                            continue
-                        }
-                        closure.closure_type.clone()
-                    }
-                    None => {
-                        tcx.sess.span_bug(span,
-                                          "didn't find unboxed closure type \
-                                           in tcx map or inh map")
-                    }
-                }
-            }
-        };
-
-        // FIXME(pcwalton): This is a bogus thing to do, but
-        // it'll do for now until we get the new trait-bound
-        // region skolemization working.
-        let (_, new_signature) =
-            regionmanip::replace_late_bound_regions_in_fn_sig(
-                tcx,
-                &closure_type.sig,
-                |br| {
-                    vcx.infcx.next_region_var(infer::LateBoundRegion(span,
-                                                                     br))
-                });
-
-        let arguments_tuple = *new_signature.inputs.get(0);
-        let corresponding_trait_ref = Rc::new(ty::TraitRef {
-            def_id: trait_ref.def_id,
-            substs: subst::Substs::new_trait(
-                vec![arguments_tuple, new_signature.output],
-                Vec::new(),
-                ty)
-        });
-
-        relate_trait_refs(vcx, span, corresponding_trait_ref, trait_ref);
-        return Some(vtable_unboxed_closure(closure_def_id))
-    }
-
-    None
-}
-
-fn search_for_vtable(vcx: &VtableContext,
-                     span: Span,
-                     ty: ty::t,
-                     trait_ref: Rc<ty::TraitRef>,
-                     is_early: bool)
-                     -> Option<vtable_origin> {
-    let tcx = vcx.tcx();
-
-    // First, check to see whether this is a call to the `call` method of an
-    // unboxed closure. If so, and the arguments match, we're done.
-    match search_for_unboxed_closure_vtable(vcx,
-                                            span,
-                                            ty,
-                                            trait_ref.clone()) {
-        Some(vtable_origin) => return Some(vtable_origin),
-        None => {}
-    }
-
-    // Nope. Continue.
-
-    let mut found = Vec::new();
-    let mut impls_seen = HashSet::new();
-
-    // Load the implementations from external metadata if necessary.
-    ty::populate_implementations_for_trait_if_necessary(tcx,
-                                                        trait_ref.def_id);
-
-    let impls = match tcx.trait_impls.borrow().find_copy(&trait_ref.def_id) {
-        Some(impls) => impls,
-        None => {
-            return None;
-        }
-    };
-    // impls is the list of all impls in scope for trait_ref.
-    for &impl_did in impls.borrow().iter() {
-        // im is one specific impl of trait_ref.
-
-        // First, ensure we haven't processed this impl yet.
-        if impls_seen.contains(&impl_did) {
-            continue;
-        }
-        impls_seen.insert(impl_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, impl_did);
-        let of_trait_ref = r.expect("trait_ref missing on trait impl");
-        if of_trait_ref.def_id != trait_ref.def_id { continue; }
-
-        // 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.
-        //
-        // FIXME: document a bit more what this means
-        let TypeAndSubsts {
-            substs: substs,
-            ty: for_ty
-        } = impl_self_ty(vcx, span, impl_did);
-        match infer::mk_eqty(vcx.infcx,
-                             false,
-                             infer::RelateSelfType(span),
-                             ty,
-                             for_ty) {
-            Err(_) => continue,
-            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 {} and its substs are {}",
-               for_ty.repr(tcx),
-               substs.types.repr(tcx));
-
-        // 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.
-
-        let of_trait_ref = of_trait_ref.subst(tcx, &substs);
-
-        debug!("(checking vtable) num 2 relating trait \
-                ty {} to of_trait_ref {}",
-               vcx.infcx.trait_ref_to_string(&*trait_ref),
-               vcx.infcx.trait_ref_to_string(&*of_trait_ref));
-
-        relate_trait_refs(vcx, span, of_trait_ref, trait_ref.clone());
-
-
-        // 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.
-
-        // Resolve any sub bounds. Note that there still may be free
-        // type variables in substs. This might still be OK: the
-        // process of looking up bounds might constrain some of them.
-        //
-        // This does not check built-in traits because those are handled
-        // later in the kind checking pass.
-        let im_generics =
-            ty::lookup_item_type(tcx, impl_did).generics;
-        let subres = lookup_vtables(vcx,
-                                    span,
-                                    &im_generics.types,
-                                    &substs,
-                                    is_early);
-
-        // substs might contain type variables, so we call
-        // fixup_substs to resolve them.
-        let substs_f = match fixup_substs(vcx, span,
-                                          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_error);
-            }
-        };
-
-        debug!("The fixed-up substs are {} - \
-                they will be unified with the bounds for \
-                the target ty, {}",
-               substs_f.types.repr(tcx),
-               trait_ref.repr(tcx));
-
-        // 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.
-        // I am a little confused about this, since it seems to be
-        // very similar to the relate_trait_refs we already do,
-        // but problems crop up if it is removed, so... -sully
-        connect_trait_tps(vcx, span, &substs_f, trait_ref.clone(), impl_did);
-
-        // 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(impl_did, substs_f, subres));
-    }
-
-    match found.len() {
-        0 => { return None }
-        1 => return Some(found.get(0).clone()),
-        _ => {
-            if !is_early {
-                span_err!(vcx.tcx().sess, span, E0096,
-                          "multiple applicable methods in scope");
-            }
-            return Some(found.get(0).clone());
-        }
-    }
-}
-
-
-fn fixup_substs(vcx: &VtableContext,
-                span: Span,
-                id: ast::DefId,
-                substs: subst::Substs,
-                is_early: bool)
-                -> Option<subst::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::region_existential_bound(ty::ReStatic));
-    fixup_ty(vcx, span, t, is_early).map(|t_f| {
-        match ty::get(t_f).sty {
-          ty::ty_trait(ref inner) => inner.substs.clone(),
-          _ => fail!("t_f should be a trait")
-        }
-    })
-}
-
-fn fixup_ty(vcx: &VtableContext,
-            span: Span,
-            ty: ty::t,
-            is_early: bool)
-            -> Option<ty::t> {
-    let tcx = vcx.tcx();
-    match resolve_type(vcx.infcx, Some(span), ty, resolve_and_force_all_but_regions) {
-        Ok(new_type) => Some(new_type),
-        Err(e) if !is_early => {
-            tcx.sess.span_err(span,
-                format!("cannot determine a type for this bounded type \
-                         parameter: {}",
-                        fixup_err_to_string(e)).as_slice());
-            Some(ty::mk_err())
-        }
-        Err(_) => {
-            None
-        }
-    }
-}
-
-fn connect_trait_tps(vcx: &VtableContext,
-                     span: Span,
-                     impl_substs: &subst::Substs,
-                     trait_ref: Rc<ty::TraitRef>,
-                     impl_did: ast::DefId) {
-    let tcx = vcx.tcx();
-
-    let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) {
-        Some(t) => t,
-        None => vcx.tcx().sess.span_bug(span,
-                                  "connect_trait_tps invoked on a type impl")
-    };
-
-    let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
-    relate_trait_refs(vcx, span, impl_trait_ref, trait_ref);
-}
-
-fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) {
-    debug!("insert_vtables(vtable_key={}, vtables={})",
-           vtable_key, vtables.repr(fcx.tcx()));
-    fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables);
-}
-
-pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
-    fn mutability_allowed(a_mutbl: ast::Mutability,
-                          b_mutbl: ast::Mutability) -> bool {
-        a_mutbl == b_mutbl ||
-        (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
-    }
-
-    debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
-           ex.id, is_early, expr_to_string(ex));
-    let _indent = indenter();
-
-    let cx = fcx.ccx;
-    let check_object_cast = |src_ty: ty::t, target_ty: ty::t| {
-      debug!("check_object_cast {} to {}",
-             fcx.infcx().ty_to_string(src_ty),
-             fcx.infcx().ty_to_string(target_ty));
-      // Check that a cast is of correct types.
-      match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) {
-          (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt))
-          | (&ty::ty_ptr(ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt))
-            if !mutability_allowed(mt.mutbl, mutbl) => {
-              match ty::get(ty).sty {
-                  ty::ty_trait(..) => {
-                      span_err!(fcx.tcx().sess, ex.span, E0097, "types differ in mutability");
-                  }
-                  _ => {}
-              }
-          }
-          (&ty::ty_uniq(..), &ty::ty_uniq(..) )
-          | (&ty::ty_ptr(..), &ty::ty_ptr(..) )
-          | (&ty::ty_ptr(..), &ty::ty_rptr(..)) => {}
-          (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
-              infer::mk_subr(fcx.infcx(),
-                             infer::RelateObjectBound(ex.span),
-                             r_t,
-                             r_s);
-          }
-          (&ty::ty_uniq(ty), _) => {
-              match ty::get(ty).sty {
-                  ty::ty_trait(..) => {
-                      span_err!(fcx.ccx.tcx.sess, ex.span, E0098,
-                                "can only cast an boxed pointer to a boxed object, not a {}",
-                                ty::ty_sort_string(fcx.tcx(), src_ty));
-                  }
-                  _ => {}
-              }
-
-          }
-          (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => {
-              match ty::get(ty).sty {
-                  ty::ty_trait(..) => {
-                      span_err!(fcx.ccx.tcx.sess, ex.span, E0099,
-                                "can only cast an &-pointer to an &-object, not a {}",
-                                ty::ty_sort_string(fcx.tcx(), src_ty));
-                  }
-                  _ => {}
-              }
-          }
-          (&ty::ty_ptr(ty::mt{ty, ..}), _) => {
-              match ty::get(ty).sty {
-                  ty::ty_trait(..) => {
-                      span_err!(fcx.ccx.tcx.sess, ex.span, E0160,
-                                "can only cast an *-pointer or &-pointer to an *-object, not a {}",
-                                ty::ty_sort_string(fcx.tcx(), src_ty));
-                  }
-                  _ => {}
-              }
-          }
-          _ => {}
-      }
-    };
-    let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| {
-      // Look up vtables for the type we're casting to,
-      // passing in the source and target type.  The source
-      // must be a pointer type suitable to the object sigil,
-      // e.g.: `&x as &Trait` or `box x as Box<Trait>`
-      // Bounds of type's contents are not checked here, but in kind.rs.
-      match ty::get(target_ty).sty {
-          ty::ty_trait(box ty::TyTrait {
-              def_id: target_def_id, substs: ref target_substs, ..
-          }) => {
-              let vcx = fcx.vtable_context();
-
-              // Take the type parameters from the object
-              // type, but set the Self type (which is
-              // unknown, for the object type) to be the type
-              // we are casting from.
-              let mut target_types = target_substs.types.clone();
-              assert!(target_types.get_self().is_none());
-              target_types.push(subst::SelfSpace, src_ty);
-
-              let target_trait_ref = Rc::new(ty::TraitRef {
-                  def_id: target_def_id,
-                  substs: subst::Substs {
-                      regions: target_substs.regions.clone(),
-                      types: target_types
-                  }
-              });
-
-              let param_bounds = ty::ParamBounds {
-                  opt_region_bound: None,
-                  builtin_bounds: ty::empty_builtin_bounds(),
-                  trait_bounds: vec!(target_trait_ref)
-              };
-
-              let vtables =
-                    lookup_vtables_for_param(&vcx,
-                                             ex.span,
-                                             None,
-                                             &param_bounds,
-                                             src_ty,
-                                             is_early);
-
-              if !is_early {
-                  let mut r = VecPerParamSpace::empty();
-                  r.push(subst::SelfSpace, vtables);
-                  insert_vtables(fcx, key, r);
-              }
-          }
-          _ => {}
-      }
-    };
-    match ex.node {
-      ast::ExprPath(..) => {
-        fcx.opt_node_ty_substs(ex.id, |item_substs| {
-            debug!("vtable resolution on parameter bounds for expr {}",
-                   ex.repr(fcx.tcx()));
-            let def = cx.tcx.def_map.borrow().get_copy(&ex.id);
-            let did = def.def_id();
-            let item_ty = ty::lookup_item_type(cx.tcx, did);
-            debug!("early resolve expr: def {:?} {:?}, {:?}, {}", ex.id, did, def,
-                   fcx.infcx().ty_to_string(item_ty.ty));
-            debug!("early_resolve_expr: looking up vtables for type params {}",
-                   item_ty.generics.types.repr(fcx.tcx()));
-            let vcx = fcx.vtable_context();
-            let vtbls = lookup_vtables(&vcx, ex.span,
-                                       &item_ty.generics.types,
-                                       &item_substs.substs, is_early);
-            if !is_early {
-                insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
-            }
-        });
-      }
-
-      // Must resolve bounds on methods with bounded params
-      ast::ExprBinary(_, _, _) |
-      ast::ExprUnary(_, _) |
-      ast::ExprAssignOp(_, _, _) |
-      ast::ExprIndex(_, _) |
-      ast::ExprMethodCall(_, _, _) |
-      ast::ExprForLoop(..) |
-      ast::ExprCall(..) => {
-        match fcx.inh.method_map.borrow().find(&MethodCall::expr(ex.id)) {
-          Some(method) => {
-              debug!("vtable resolution on parameter bounds for method call {}",
-                     ex.repr(fcx.tcx()));
-              let type_param_defs =
-                  ty::method_call_type_param_defs(fcx, method.origin);
-              let substs = fcx.method_ty_substs(ex.id);
-              let vcx = fcx.vtable_context();
-              let vtbls = lookup_vtables(&vcx, ex.span,
-                                         &type_param_defs,
-                                         &substs, is_early);
-              if !is_early {
-                  insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
-              }
-          }
-          None => {}
-        }
-      }
-      ast::ExprCast(ref src, _) => {
-          debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
-          let target_ty = fcx.expr_ty(ex);
-          let src_ty = structurally_resolved_type(fcx, ex.span,
-                                                  fcx.expr_ty(&**src));
-          check_object_cast(src_ty, target_ty);
-          match (ty::deref(src_ty, false), ty::deref(target_ty, false)) {
-              (Some(s), Some(t)) => {
-                  let key = MethodCall::expr(ex.id);
-                  resolve_object_cast(s.ty, t.ty, key)
-              }
-              _ => {}
-          }
-      }
-      _ => ()
-    }
-
-    // Search for auto-adjustments to find trait coercions
-    match fcx.inh.adjustments.borrow().find(&ex.id) {
-        Some(adjustment) => {
-            match *adjustment {
-                _ if ty::adjust_is_object(adjustment) => {
-                    let src_ty = structurally_resolved_type(fcx, ex.span,
-                                                            fcx.expr_ty(ex));
-                    match ty::type_of_adjust(fcx.tcx(), adjustment) {
-                        Some(target_ty) => {
-                            check_object_cast(src_ty, target_ty)
-                        }
-                        None => {}
-                    }
-
-                    match trait_cast_types(fcx, adjustment, src_ty, ex.span) {
-                        Some((s, t)) => {
-                            let key = MethodCall::autoobject(ex.id);
-                            resolve_object_cast(s, t, key)
-                        }
-                        None => fail!("Couldn't extract types from adjustment")
-                    }
-                }
-                AutoDerefRef(ref adj) => {
-                    for autoderef in range(0, adj.autoderefs) {
-                        let method_call = MethodCall::autoderef(ex.id, autoderef);
-                        match fcx.inh.method_map.borrow().find(&method_call) {
-                            Some(method) => {
-                                debug!("vtable resolution on parameter bounds for autoderef {}",
-                                       ex.repr(fcx.tcx()));
-                                let type_param_defs =
-                                    ty::method_call_type_param_defs(cx.tcx, method.origin);
-                                let vcx = fcx.vtable_context();
-                                let vtbls = lookup_vtables(&vcx, ex.span,
-                                                           &type_param_defs,
-                                                           &method.substs, is_early);
-                                if !is_early {
-                                    insert_vtables(fcx, method_call, vtbls);
-                                }
-                            }
-                            None => {}
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-        None => {}
-    }
-}
-
-// When we coerce (possibly implicitly) from a concrete type to a trait type, this
-// function returns the concrete type and trait. This might happen arbitrarily
-// deep in the adjustment. This function will fail if the adjustment does not
-// match the source type.
-// This function will always return types if ty::adjust_is_object is true for the
-// adjustment
-fn trait_cast_types(fcx: &FnCtxt,
-                    adj: &ty::AutoAdjustment,
-                    src_ty: ty::t,
-                    sp: Span)
-                    -> Option<(ty::t, ty::t)> {
-    fn trait_cast_types_autoref(fcx: &FnCtxt,
-                                autoref: &ty::AutoRef,
-                                src_ty: ty::t,
-                                sp: Span)
-                                -> Option<(ty::t, ty::t)> {
-        fn trait_cast_types_unsize(fcx: &FnCtxt,
-                                   k: &ty::UnsizeKind,
-                                   src_ty: ty::t,
-                                   sp: Span)
-                                   -> Option<(ty::t, ty::t)> {
-            match k {
-                &ty::UnsizeVtable(bounds, def_id, ref substs) => {
-                    Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds)))
-                }
-                &ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty {
-                    ty::ty_struct(_, ref substs) => {
-                        let ty_substs = substs.types.get_slice(subst::TypeSpace);
-                        let field_ty = structurally_resolved_type(fcx, sp, ty_substs[tp_index]);
-                        trait_cast_types_unsize(fcx, k, field_ty, sp)
-                    }
-                    _ => fail!("Failed to find a ty_struct to correspond with \
-                                UnsizeStruct whilst walking adjustment. Found {}",
-                                ppaux::ty_to_string(fcx.tcx(), src_ty))
-                },
-                _ => None
-            }
-        }
-
-        match autoref {
-            &ty::AutoUnsize(ref k) |
-            &ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp),
-            &ty::AutoPtr(_, _, Some(box ref autoref)) |
-            &ty::AutoUnsafe(_, Some(box ref autoref)) => {
-                trait_cast_types_autoref(fcx, autoref, src_ty, sp)
-            }
-            _ => None
-        }
-    }
-
-    match adj {
-        &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => {
-            let mut derefed_type = src_ty;
-            for _ in range(0, autoderefs) {
-                derefed_type = ty::deref(derefed_type, true).unwrap().ty;
-                derefed_type = structurally_resolved_type(fcx, sp, derefed_type)
-            }
-            trait_cast_types_autoref(fcx, autoref, derefed_type, sp)
-        }
-        _ => None
-    }
-}
-
-pub fn resolve_impl(tcx: &ty::ctxt,
-                    impl_item: &ast::Item,
-                    impl_generics: &ty::Generics,
-                    impl_trait_ref: &ty::TraitRef) {
-    /*!
-     * The situation is as follows. We have some trait like:
-     *
-     *    trait Foo<A:Clone> : Bar {
-     *        fn method() { ... }
-     *    }
-     *
-     * and an impl like:
-     *
-     *    impl<B:Clone> Foo<B> for int { ... }
-     *
-     * We want to validate that the various requirements of the trait
-     * are met:
-     *
-     *    A:Clone, Self:Bar
-     *
-     * But of course after substituting the types from the impl:
-     *
-     *    B:Clone, int:Bar
-     *
-     * We store these results away as the "impl_res" for use by the
-     * default methods.
-     */
-
-    debug!("resolve_impl(impl_item.id={})",
-           impl_item.id);
-
-    let param_env = ty::construct_parameter_environment(tcx,
-                                                        impl_generics,
-                                                        impl_item.id);
-
-    // The impl_trait_ref in our example above would be
-    //     `Foo<B> for int`
-    let impl_trait_ref = impl_trait_ref.subst(tcx, &param_env.free_substs);
-    debug!("impl_trait_ref={}", impl_trait_ref.repr(tcx));
-
-    let infcx = &infer::new_infer_ctxt(tcx);
-    let unboxed_closures = RefCell::new(DefIdMap::new());
-    let vcx = VtableContext {
-        infcx: infcx,
-        param_env: &param_env,
-        unboxed_closures: &unboxed_closures,
-    };
-
-    // Resolve the vtables for the trait reference on the impl.  This
-    // serves many purposes, best explained by example. Imagine we have:
-    //
-    //    trait A<T:B> : C { fn x(&self) { ... } }
-    //
-    // and
-    //
-    //    impl A<int> for uint { ... }
-    //
-    // In that case, the trait ref will be `A<int> for uint`. Resolving
-    // this will first check that the various types meet their requirements:
-    //
-    // 1. Because of T:B, int must implement the trait B
-    // 2. Because of the supertrait C, uint must implement the trait C.
-    //
-    // Simultaneously, the result of this resolution (`vtbls`), is precisely
-    // the set of vtable information needed to compile the default method
-    // `x()` adapted to the impl. (After all, a default method is basically
-    // the same as:
-    //
-    //     fn default_x<T:B, Self:A>(...) { .. .})
-
-    let trait_def = ty::lookup_trait_def(tcx, impl_trait_ref.def_id);
-    let vtbls = lookup_vtables(&vcx,
-                                   impl_item.span,
-                                   &trait_def.generics.types,
-                                   &impl_trait_ref.substs,
-                                   false);
-
-    infcx.resolve_regions_and_report_errors();
-
-    let vtbls = writeback::resolve_impl_res(infcx, impl_item.span, &vtbls);
-    let impl_def_id = ast_util::local_def(impl_item.id);
-
-    debug!("impl_vtables for {} are {}",
-           impl_def_id.repr(tcx),
-           vtbls.repr(tcx));
-
-    tcx.impl_vtables.borrow_mut().insert(impl_def_id, vtbls);
-}
-
-/// Resolve vtables for a method call after typeck has finished.
-/// Used by trans to monomorphize artificial method callees (e.g. drop).
-pub fn trans_resolve_method(tcx: &ty::ctxt, id: ast::NodeId,
-                            substs: &subst::Substs) -> vtable_res {
-    let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
-    let unboxed_closures = RefCell::new(DefIdMap::new());
-    let vcx = VtableContext {
-        infcx: &infer::new_infer_ctxt(tcx),
-        param_env: &ty::construct_parameter_environment(tcx, &ty::Generics::empty(), id),
-        unboxed_closures: &unboxed_closures,
-    };
-
-    lookup_vtables(&vcx,
-                   tcx.map.span(id),
-                   &generics.types,
-                   substs,
-                   false)
-}
-
-impl<'a, 'b, 'tcx, 'v> Visitor<'v> for &'a FnCtxt<'b, 'tcx> {
-    fn visit_expr(&mut self, ex: &ast::Expr) {
-        early_resolve_expr(ex, *self, false);
-        visit::walk_expr(self, ex);
-    }
-    fn visit_item(&mut self, _: &ast::Item) {
-        // no-op
-    }
-}
-
-// Detect points where a trait-bounded type parameter is
-// instantiated, resolve the impls for the parameters.
-pub fn resolve_in_block(mut fcx: &FnCtxt, bl: &ast::Block) {
-    visit::walk_block(&mut fcx, bl);
-}
-
-/// Used in the kind checker after typechecking has finished. Calls
-/// `any_missing` if any bounds were missing.
-pub fn check_param_bounds(tcx: &ty::ctxt,
-                          span: Span,
-                          parameter_environment: &ty::ParameterEnvironment,
-                          type_param_defs:
-                            &VecPerParamSpace<ty::TypeParameterDef>,
-                          substs: &subst::Substs,
-                          any_missing: |&ty::TraitRef|) {
-    let unboxed_closures = RefCell::new(DefIdMap::new());
-    let vcx = VtableContext {
-        infcx: &infer::new_infer_ctxt(tcx),
-        param_env: parameter_environment,
-        unboxed_closures: &unboxed_closures,
-    };
-    let vtable_param_results =
-        lookup_vtables(&vcx, span, type_param_defs, substs, false);
-    for (vtable_param_result, type_param_def) in
-            vtable_param_results.iter().zip(type_param_defs.iter()) {
-        for (vtable_result, trait_ref) in
-                vtable_param_result.iter()
-                                   .zip(type_param_def.bounds
-                                                      .trait_bounds
-                                                      .iter()) {
-            match *vtable_result {
-                vtable_error => any_missing(&**trait_ref),
-                vtable_static(..) |
-                vtable_param(..) |
-                vtable_unboxed_closure(..) => {}
-            }
-        }
-    }
-}
-
diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs
new file mode 100644 (file)
index 0000000..f75d262
--- /dev/null
@@ -0,0 +1,407 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::subst::{SelfSpace};
+use middle::traits;
+use middle::traits::{SelectionError, Overflow,
+                     OutputTypeParameterMismatch, Unimplemented};
+use middle::traits::{Obligation, obligation_for_builtin_bound};
+use middle::traits::{FulfillmentError, Ambiguity};
+use middle::traits::{ObligationCause};
+use middle::ty;
+use middle::typeck::check::{FnCtxt,
+                            structurally_resolved_type};
+use middle::typeck::infer;
+use std::rc::Rc;
+use syntax::ast;
+use syntax::codemap::Span;
+use util::ppaux::UserString;
+use util::ppaux::Repr;
+
+/// When reporting an error about a failed trait obligation, it's nice
+/// to include some context indicating why we were checking that
+/// obligation in the first place. The span is often enough but
+/// sometimes it's not. Currently this enum is a bit of a hack and I
+/// suspect it should be carried in the obligation or more deeply
+/// integrated somehow.
+pub enum ErrorReportingContext {
+    GenericContext,
+    ImplSupertraitCheck,
+}
+
+pub fn check_object_cast(fcx: &FnCtxt,
+                         cast_expr: &ast::Expr,
+                         source_expr: &ast::Expr,
+                         target_object_ty: ty::t)
+{
+    debug!("check_object_cast(cast_expr={}, target_object_ty={})",
+           cast_expr.repr(fcx.tcx()),
+           target_object_ty.repr(fcx.tcx()));
+
+    // Look up vtables for the type we're casting to,
+    // passing in the source and target type.  The source
+    // must be a pointer type suitable to the object sigil,
+    // e.g.: `&x as &Trait` or `box x as Box<Trait>`
+    let source_ty = fcx.expr_ty(source_expr);
+    let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
+    debug!("source_ty={}", source_ty.repr(fcx.tcx()));
+    match (&ty::get(source_ty).sty, &ty::get(target_object_ty).sty) {
+        (&ty::ty_uniq(referent_ty), &ty::ty_uniq(object_trait_ty)) => {
+            let object_trait = object_trait(&object_trait_ty);
+
+            // Ensure that if ~T is cast to ~Trait, then T : Trait
+            push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
+        }
+
+        (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
+                                                mutbl: referent_mutbl }),
+         &ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
+                                              mutbl: target_mutbl })) =>
+        {
+            let object_trait = object_trait(&object_trait_ty);
+            if !mutability_allowed(referent_mutbl, target_mutbl) {
+                fcx.tcx().sess.span_err(source_expr.span,
+                                        "types differ in mutability");
+            } else {
+                // Ensure that if &'a T is cast to &'b Trait, then T : Trait
+                push_cast_obligation(fcx, cast_expr,
+                                     object_trait,
+                                     referent_ty);
+
+                // Ensure that if &'a T is cast to &'b Trait, then 'b <= 'a
+                infer::mk_subr(fcx.infcx(),
+                               infer::RelateObjectBound(source_expr.span),
+                               target_region,
+                               referent_region);
+            }
+        }
+
+        (_, &ty::ty_uniq(..)) => {
+            fcx.ccx.tcx.sess.span_err(
+                source_expr.span,
+                format!("can only cast an boxed pointer \
+                         to a boxed object, not a {}",
+                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
+        }
+
+        (_, &ty::ty_rptr(..)) => {
+            fcx.ccx.tcx.sess.span_err(
+                source_expr.span,
+                format!("can only cast a &-pointer \
+                         to an &-object, not a {}",
+                        ty::ty_sort_string(fcx.tcx(), source_ty)).as_slice());
+        }
+
+        _ => {
+            fcx.tcx().sess.span_bug(
+                source_expr.span,
+                "expected object type");
+        }
+    }
+
+    // Because we currently give unsound lifetimes to the "ty_box", I
+    // could have written &'static ty::TyTrait here, but it seems
+    // gratuitously unsafe.
+    fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait {
+        match ty::get(*t).sty {
+            ty::ty_trait(ref ty_trait) => &**ty_trait,
+            _ => fail!("expected ty_trait")
+        }
+    }
+
+    fn mutability_allowed(a_mutbl: ast::Mutability,
+                          b_mutbl: ast::Mutability)
+                          -> bool {
+        a_mutbl == b_mutbl ||
+            (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
+    }
+
+    fn push_cast_obligation(fcx: &FnCtxt,
+                            cast_expr: &ast::Expr,
+                            object_trait: &ty::TyTrait,
+                            referent_ty: ty::t) {
+        let object_trait_ref =
+            register_object_cast_obligations(fcx,
+                                             cast_expr.span,
+                                             object_trait,
+                                             referent_ty);
+
+        // Finally record the object_trait_ref for use during trans
+        // (it would prob be better not to do this, but it's just kind
+        // of a pain to have to reconstruct it).
+        fcx.write_object_cast(cast_expr.id, object_trait_ref);
+    }
+}
+
+pub fn register_object_cast_obligations(fcx: &FnCtxt,
+                                        span: Span,
+                                        object_trait: &ty::TyTrait,
+                                        referent_ty: ty::t)
+                                        -> Rc<ty::TraitRef>
+{
+    // This is just for better error reporting. Kinda goofy. The object type stuff
+    // needs some refactoring so there is a more convenient type to pass around.
+    let object_trait_ty =
+        ty::mk_trait(fcx.tcx(),
+                     object_trait.def_id,
+                     object_trait.substs.clone(),
+                     object_trait.bounds);
+
+    debug!("register_object_cast_obligations: referent_ty={} object_trait_ty={}",
+           referent_ty.repr(fcx.tcx()),
+           object_trait_ty.repr(fcx.tcx()));
+
+    // Take the type parameters from the object type, but set
+    // the Self type (which is unknown, for the object type)
+    // to be the type we are casting from.
+    let mut object_substs = object_trait.substs.clone();
+    assert!(object_substs.self_ty().is_none());
+    object_substs.types.push(SelfSpace, referent_ty);
+
+    // Create the obligation for casting from T to Trait.
+    let object_trait_ref =
+        Rc::new(ty::TraitRef { def_id: object_trait.def_id,
+                               substs: object_substs });
+    let object_obligation =
+        Obligation::new(
+            ObligationCause::new(span,
+                                 traits::ObjectCastObligation(object_trait_ty)),
+            object_trait_ref.clone());
+    fcx.register_obligation(object_obligation);
+
+    // Create additional obligations for all the various builtin
+    // bounds attached to the object cast. (In other words, if the
+    // object type is Foo+Send, this would create an obligation
+    // for the Send check.)
+    for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
+        fcx.register_obligation(
+            obligation_for_builtin_bound(
+                fcx.tcx(),
+                ObligationCause::new(span,
+                                     traits::ObjectCastObligation(object_trait_ty)),
+                referent_ty,
+                builtin_bound));
+    }
+
+    object_trait_ref
+}
+
+pub fn select_all_fcx_obligations_or_error(fcx: &FnCtxt) {
+    debug!("select_all_fcx_obligations_or_error");
+
+    let mut fulfillment_cx = fcx.inh.fulfillment_cx.borrow_mut();
+    let r =
+        fulfillment_cx.select_all_or_error(
+            fcx.infcx(),
+            &fcx.inh.param_env,
+            &*fcx.inh.unboxed_closures.borrow());
+    match r {
+        Ok(()) => { }
+        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+    }
+}
+
+pub fn check_builtin_bound_obligations(fcx: &FnCtxt) {
+    /*!
+     * Hacky second pass to check builtin-bounds obligations *after*
+     * writeback occurs.
+     */
+
+    match
+        fcx.inh.fulfillment_cx.borrow()
+                              .check_builtin_bound_obligations(fcx.infcx())
+    {
+        Ok(()) => { }
+        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+    }
+}
+
+fn resolve_trait_ref(fcx: &FnCtxt, obligation: &Obligation)
+                     -> (ty::TraitRef, ty::t)
+{
+    let trait_ref =
+        fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+            &*obligation.trait_ref);
+    let self_ty =
+        trait_ref.substs.self_ty().unwrap();
+    (trait_ref, self_ty)
+}
+
+pub fn report_fulfillment_errors(fcx: &FnCtxt,
+                                 errors: &Vec<FulfillmentError>) {
+    for error in errors.iter() {
+        report_fulfillment_error(fcx, error);
+    }
+}
+
+pub fn report_fulfillment_error(fcx: &FnCtxt,
+                                error: &FulfillmentError) {
+    match error.code {
+        SelectionError(ref e) => {
+            report_selection_error(fcx, &error.obligation, e);
+        }
+        Ambiguity => {
+            maybe_report_ambiguity(fcx, &error.obligation);
+        }
+    }
+}
+
+pub fn report_selection_error(fcx: &FnCtxt,
+                              obligation: &Obligation,
+                              error: &SelectionError) {
+    match *error {
+        Unimplemented => {
+            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+            if !ty::type_is_error(self_ty) {
+                fcx.tcx().sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "the trait `{}` is not implemented for the type `{}`",
+                        trait_ref.user_string(fcx.tcx()),
+                        self_ty.user_string(fcx.tcx())).as_slice());
+                note_obligation_cause(fcx, obligation);
+            }
+        }
+        Overflow => {
+            report_overflow(fcx, obligation);
+        }
+        OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
+            let expected_trait_ref =
+                fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
+                    &**expected_trait_ref);
+            let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+            if !ty::type_is_error(self_ty) {
+                fcx.tcx().sess.span_err(
+                    obligation.cause.span,
+                    format!(
+                        "type mismatch: the type `{}` implements the trait `{}`, \
+                         but the trait `{}` is required ({})",
+                        self_ty.user_string(fcx.tcx()),
+                        expected_trait_ref.user_string(fcx.tcx()),
+                        trait_ref.user_string(fcx.tcx()),
+                        ty::type_err_to_str(fcx.tcx(), e)).as_slice());
+                note_obligation_cause(fcx, obligation);
+            }
+        }
+    }
+}
+
+pub fn report_overflow(fcx: &FnCtxt, obligation: &Obligation) {
+    let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+    if ty::type_is_error(self_ty) {
+        fcx.tcx().sess.span_err(
+            obligation.cause.span,
+            format!(
+                "could not locate an impl of the trait `{}` for \
+                 the type `{}` due to overflow; possible cyclic \
+                 dependency between impls",
+                trait_ref.user_string(fcx.tcx()),
+                self_ty.user_string(fcx.tcx())).as_slice());
+        note_obligation_cause(fcx, obligation);
+    }
+}
+
+pub fn maybe_report_ambiguity(fcx: &FnCtxt, obligation: &Obligation) {
+    // Unable to successfully determine, probably means
+    // insufficient type information, but could mean
+    // ambiguous impls. The latter *ought* to be a
+    // coherence violation, so we don't report it here.
+    let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
+    debug!("maybe_report_ambiguity(trait_ref={}, self_ty={}, obligation={})",
+           trait_ref.repr(fcx.tcx()),
+           self_ty.repr(fcx.tcx()),
+           obligation.repr(fcx.tcx()));
+    if ty::type_is_error(self_ty) {
+    } else if ty::type_needs_infer(self_ty) {
+        fcx.tcx().sess.span_err(
+            obligation.cause.span,
+            format!(
+                "unable to infer enough type information to \
+             locate the impl of the trait `{}` for \
+             the type `{}`; type annotations required",
+            trait_ref.user_string(fcx.tcx()),
+            self_ty.user_string(fcx.tcx())).as_slice());
+        note_obligation_cause(fcx, obligation);
+    } else if fcx.tcx().sess.err_count() == 0 {
+         // Ambiguity. Coherence should have reported an error.
+        fcx.tcx().sess.span_bug(
+            obligation.cause.span,
+            format!(
+                "coherence failed to report ambiguity: \
+                 cannot locate the impl of the trait `{}` for \
+                 the type `{}`",
+                trait_ref.user_string(fcx.tcx()),
+                self_ty.user_string(fcx.tcx())).as_slice());
+    }
+}
+
+pub fn select_fcx_obligations_where_possible(fcx: &FnCtxt) {
+    /*! Select as many obligations as we can at present. */
+
+    match
+        fcx.inh.fulfillment_cx
+        .borrow_mut()
+        .select_where_possible(fcx.infcx(),
+                               &fcx.inh.param_env,
+                               &*fcx.inh.unboxed_closures.borrow())
+    {
+        Ok(()) => { }
+        Err(errors) => { report_fulfillment_errors(fcx, &errors); }
+    }
+}
+
+fn note_obligation_cause(fcx: &FnCtxt,
+                         obligation: &Obligation) {
+    let tcx = fcx.tcx();
+    let trait_name = ty::item_path_str(tcx, obligation.trait_ref.def_id);
+    match obligation.cause.code {
+        traits::MiscObligation => { }
+        traits::ItemObligation(item_def_id) => {
+            let item_name = ty::item_path_str(tcx, item_def_id);
+            tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "the trait `{}` must be implemented because it is required by `{}`",
+                    trait_name,
+                    item_name).as_slice());
+        }
+        traits::ObjectCastObligation(object_ty) => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "the trait `{}` must be implemented for the cast \
+                     to the object type `{}`",
+                    trait_name,
+                    fcx.infcx().ty_to_string(object_ty)).as_slice());
+        }
+        traits::RepeatVec => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                format!(
+                    "the `Copy` trait is required because the \
+                     repeated element will be copied").as_slice());
+        }
+        traits::VariableType(_) => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "all local variables must have a statically known size");
+        }
+        traits::AssignmentLhsSized => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "the left-hand-side of an assignment must have a statically known size");
+        }
+        traits::StructInitializerSized => {
+            tcx.sess.span_note(
+                obligation.cause.span,
+                "structs must have a statically known size to be initialized");
+        }
+    }
+}
diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs
new file mode 100644 (file)
index 0000000..73c0a4e
--- /dev/null
@@ -0,0 +1,365 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::subst::{Subst};
+use middle::traits;
+use middle::ty;
+use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::typeck::astconv::AstConv;
+use middle::typeck::check::{FnCtxt, Inherited, blank_fn_ctxt, vtable2, regionck};
+use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
+use middle::typeck::CrateCtxt;
+use util::ppaux::Repr;
+
+use std::collections::HashSet;
+use syntax::ast;
+use syntax::ast_util::{local_def};
+use syntax::codemap::Span;
+use syntax::visit;
+use syntax::visit::Visitor;
+
+pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
+    ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
+    cache: HashSet<ty::t>
+}
+
+impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+    pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) -> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+        CheckTypeWellFormedVisitor { ccx: ccx, cache: HashSet::new() }
+    }
+
+    fn check_item_well_formed(&mut self, ccx: &CrateCtxt, item: &ast::Item) {
+        /*!
+         * Checks that the field types (in a struct def'n) or
+         * argument types (in an enum def'n) are well-formed,
+         * meaning that they do not require any constraints not
+         * declared in the struct definition itself.
+         * For example, this definition would be illegal:
+         *
+         *     struct Ref<'a, T> { x: &'a T }
+         *
+         * because the type did not declare that `T:'a`.
+         *
+         * We do this check as a pre-pass before checking fn bodies
+         * because if these constraints are not included it frequently
+         * leads to confusing errors in fn bodies. So it's better to check
+         * the types first.
+         */
+
+        debug!("check_item_well_formed(it.id={}, it.ident={})",
+               item.id,
+               ty::item_path_str(ccx.tcx, local_def(item.id)));
+
+        let ccx = self.ccx;
+        match item.node {
+            ast::ItemImpl(..) => {
+                self.check_impl(item);
+            }
+            ast::ItemFn(..) => {
+                self.check_item_type(item);
+            }
+            ast::ItemStatic(..) => {
+                self.check_item_type(item);
+            }
+            ast::ItemStruct(..) => {
+                self.check_type_defn(item, |fcx| {
+                    ty::struct_fields(ccx.tcx, local_def(item.id),
+                                      &fcx.inh.param_env.free_substs)
+                        .iter()
+                        .map(|f| f.mt.ty)
+                        .collect()
+                });
+            }
+            ast::ItemEnum(..) => {
+                self.check_type_defn(item, |fcx| {
+                    ty::substd_enum_variants(ccx.tcx, local_def(item.id),
+                                             &fcx.inh.param_env.free_substs)
+                        .iter()
+                        .flat_map(|variant| {
+                            variant.args
+                                .iter()
+                                .map(|&arg_ty| arg_ty)
+                        })
+                        .collect()
+                });
+            }
+            _ => {}
+        }
+    }
+
+    fn with_fcx(&mut self,
+                ccx: &CrateCtxt,
+                item: &ast::Item,
+                f: |&mut CheckTypeWellFormedVisitor, &FnCtxt|) {
+        let item_def_id = local_def(item.id);
+        let polytype = ty::lookup_item_type(ccx.tcx, item_def_id);
+        let param_env =
+            ty::construct_parameter_environment(ccx.tcx,
+                                                item.span,
+                                                &polytype.generics,
+                                                item.id);
+        let inh = Inherited::new(ccx.tcx, param_env);
+        let fcx = blank_fn_ctxt(ccx, &inh, polytype.ty, item.id);
+        f(self, &fcx);
+        vtable2::select_all_fcx_obligations_or_error(&fcx);
+        regionck::regionck_item(&fcx, item);
+        vtable2::check_builtin_bound_obligations(&fcx);
+    }
+
+    fn check_type_defn(&mut self,
+                       item: &ast::Item,
+                       lookup_fields: |&FnCtxt| -> Vec<ty::t>)
+    {
+        /*!
+         * In a type definition, we check that to ensure that the types of the fields are
+         * well-formed.
+         */
+
+        self.with_fcx(self.ccx, item, |this, fcx| {
+            let field_tys = lookup_fields(fcx);
+            let mut bounds_checker = BoundsChecker::new(fcx, item.span,
+                                                        item.id, Some(&mut this.cache));
+            for &ty in field_tys.iter() {
+                // Regions are checked below.
+                bounds_checker.check_traits_in_ty(ty);
+            }
+
+            regionck::regionck_ensure_component_tys_wf(
+                fcx, item.span, field_tys.as_slice());
+        });
+    }
+
+    fn check_item_type(&mut self,
+                       item: &ast::Item)
+    {
+        self.with_fcx(self.ccx, item, |this, fcx| {
+            let mut bounds_checker = BoundsChecker::new(fcx, item.span,
+                                                        item.id, Some(&mut this.cache));
+            let polytype = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
+            let item_ty = polytype.ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
+            bounds_checker.check_traits_in_ty(item_ty);
+        });
+    }
+
+    fn check_impl(&mut self,
+                  item: &ast::Item)
+    {
+        self.with_fcx(self.ccx, item, |this, fcx| {
+            let mut bounds_checker = BoundsChecker::new(fcx, item.span,
+                                                        item.id, Some(&mut this.cache));
+
+            let self_ty = ty::node_id_to_type(fcx.tcx(), item.id);
+            let self_ty = self_ty.subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
+
+            bounds_checker.check_traits_in_ty(self_ty);
+
+            let trait_ref = match ty::impl_trait_ref(fcx.tcx(), local_def(item.id)) {
+                None => { return; }
+                Some(t) => { t }
+            };
+            let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs);
+
+            // We are stricter on the trait-ref in an impl than the
+            // self-type.  In particular, we enforce region
+            // relationships. The reason for this is that (at least
+            // presently) "appyling" an impl does not require that the
+            // application site check the well-formedness constraints on the
+            // trait reference. Instead, this is done at the impl site.
+            // Arguably this is wrong and we should treat the trait-reference
+            // the same way as we treat the self-type.
+            bounds_checker.check_trait_ref(&trait_ref);
+
+            let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_ref.def_id);
+
+            let cause =
+                traits::ObligationCause::new(
+                    item.span,
+                    traits::ItemObligation(trait_ref.def_id));
+
+            // Find the supertrait bounds. This will add `int:Bar`.
+            //
+            // FIXME -- This is a bit ill-factored. There is very similar
+            // code in traits::util::obligations_for_generics.
+            fcx.add_region_obligations_for_type_parameter(item.span,
+                                                          ty::ParamTy::for_self(trait_ref.def_id),
+                                                          &trait_def.bounds,
+                                                          trait_ref.self_ty());
+            for builtin_bound in trait_def.bounds.builtin_bounds.iter() {
+                fcx.register_obligation(
+                    traits::obligation_for_builtin_bound(fcx.tcx(),
+                                                         cause,
+                                                         trait_ref.self_ty(),
+                                                         builtin_bound));
+            }
+            for trait_bound in trait_def.bounds.trait_bounds.iter() {
+                let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs);
+                fcx.register_obligation(
+                    traits::Obligation::new(cause, trait_bound));
+            }
+        });
+    }
+}
+
+impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+    fn visit_item(&mut self, i: &'v ast::Item) {
+        self.check_item_well_formed(self.ccx, i);
+        visit::walk_item(self, i);
+    }
+}
+
+pub struct BoundsChecker<'cx,'tcx:'cx> {
+    fcx: &'cx FnCtxt<'cx,'tcx>,
+    span: Span,
+    scope_id: ast::NodeId,
+    binding_count: uint,
+    cache: Option<&'cx mut HashSet<ty::t>>,
+}
+
+impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
+    pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
+               span: Span,
+               scope_id: ast::NodeId,
+               cache: Option<&'cx mut HashSet<ty::t>>)
+               -> BoundsChecker<'cx,'tcx> {
+        BoundsChecker { fcx: fcx, span: span, scope_id: scope_id,
+                        cache: cache, binding_count: 0 }
+    }
+
+    pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef) {
+        /*!
+         * Given a trait ref like `A : Trait<B>`, where `Trait` is
+         * defined as (say):
+         *
+         *     trait Trait<B:OtherTrait> : Copy { ... }
+         *
+         * This routine will check that `B : OtherTrait` and `A :
+         * Trait<B>`. It will also recursively check that the types
+         * `A` and `B` are well-formed.
+         *
+         * Note that it does not (currently, at least)
+         * check that `A : Copy` (that check is delegated to the point
+         * where impl `A : Trait<B>` is implemented).
+         */
+
+        let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
+
+        self.fcx.add_obligations_for_parameters(
+            traits::ObligationCause::new(
+                self.span,
+                traits::ItemObligation(trait_ref.def_id)),
+            &trait_ref.substs,
+            &trait_def.generics);
+
+        for &ty in trait_ref.substs.types.iter() {
+            self.check_traits_in_ty(ty);
+        }
+    }
+
+    pub fn check_ty(&mut self, ty: ty::t) {
+        ty.fold_with(self);
+    }
+
+    fn check_traits_in_ty(&mut self, ty: ty::t) {
+        // When checking types outside of a type def'n, we ignore
+        // region obligations. See discussion below in fold_ty().
+        self.binding_count += 1;
+        ty.fold_with(self);
+        self.binding_count -= 1;
+    }
+}
+
+impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.fcx.tcx()
+    }
+
+    fn fold_ty(&mut self, t: ty::t) -> ty::t {
+        debug!("BoundsChecker t={}",
+               t.repr(self.tcx()));
+
+        match self.cache {
+            Some(ref mut cache) => {
+                if !cache.insert(t) {
+                    // Already checked this type! Don't check again.
+                    debug!("cached");
+                    return t;
+                }
+            }
+            None => { }
+        }
+
+        match ty::get(t).sty{
+            ty::ty_struct(type_id, ref substs) |
+            ty::ty_enum(type_id, ref substs) => {
+                let polytype = ty::lookup_item_type(self.fcx.tcx(), type_id);
+
+                if self.binding_count == 0 {
+                    self.fcx.add_obligations_for_parameters(
+                        traits::ObligationCause::new(self.span,
+                                                     traits::ItemObligation(type_id)),
+                        substs,
+                        &polytype.generics);
+                } else {
+                    // There are two circumstances in which we ignore
+                    // region obligations.
+                    //
+                    // The first is when we are inside of a closure
+                    // type. This is because in that case the region
+                    // obligations for the parameter types are things
+                    // that the closure body gets to assume and the
+                    // caller must prove at the time of call. In other
+                    // words, if there is a type like `<'a, 'b> | &'a
+                    // &'b int |`, it is well-formed, and caller will
+                    // have to show that `'b : 'a` at the time of
+                    // call.
+                    //
+                    // The second is when we are checking for
+                    // well-formedness outside of a type def'n or fn
+                    // body. This is for a similar reason: in general,
+                    // we only do WF checking for regions in the
+                    // result of expressions and type definitions, so
+                    // to as allow for implicit where clauses.
+                    //
+                    // (I believe we should do the same for traits, but
+                    // that will require an RFC. -nmatsakis)
+                    self.fcx.add_trait_obligations_for_generics(
+                        traits::ObligationCause::new(self.span,
+                                                     traits::ItemObligation(type_id)),
+                        substs,
+                        &polytype.generics);
+                }
+
+                self.fold_substs(substs);
+            }
+            ty::ty_bare_fn(ty::BareFnTy{sig: ref fn_sig, ..}) |
+            ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => {
+                self.binding_count += 1;
+
+                let (_, fn_sig) =
+                    replace_late_bound_regions_in_fn_sig(
+                        self.fcx.tcx(), fn_sig,
+                        |br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
+                                                       bound_region: br}));
+
+                debug!("late-bound regions replaced: {}",
+                       fn_sig.repr(self.tcx()));
+
+                self.fold_sig(&fn_sig);
+
+                self.binding_count -= 1;
+            }
+            ref sty => {
+                self.fold_sty(sty);
+            }
+        }
+
+        t // we're not folding to produce a new type, so just return `t` here
+    }
+}
index 4716ffe700b502db96ebd69284aaa8c2ee42b557..ffe019b314a87c32289482e5fc30073b84f26506 100644 (file)
@@ -44,6 +44,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &ast::Expr) {
     wbcx.visit_expr(e);
     wbcx.visit_upvar_borrow_map();
     wbcx.visit_unboxed_closures();
+    wbcx.visit_object_cast_map();
 }
 
 pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
     }
     wbcx.visit_upvar_borrow_map();
     wbcx.visit_unboxed_closures();
+    wbcx.visit_object_cast_map();
 }
 
 pub fn resolve_impl_res(infcx: &infer::InferCtxt,
@@ -128,8 +130,6 @@ fn visit_expr(&mut self, e: &ast::Expr) {
         self.visit_node_id(ResolvingExpr(e.span), e.id);
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
-        self.visit_vtable_map_entry(ResolvingExpr(e.span),
-                                    MethodCall::expr(e.id));
 
         match e.node {
             ast::ExprFnBlock(_, ref decl, _) |
@@ -235,6 +235,27 @@ fn visit_unboxed_closures(&self) {
         }
     }
 
+    fn visit_object_cast_map(&self) {
+        if self.fcx.writeback_errors.get() {
+            return
+        }
+
+        for (&node_id, trait_ref) in self.fcx
+                                            .inh
+                                            .object_cast_map
+                                            .borrow()
+                                            .iter()
+        {
+            let span = ty::expr_span(self.tcx(), node_id);
+            let reason = ResolvingExpr(span);
+            let closure_ty = self.resolve(trait_ref, reason);
+            self.tcx()
+                .object_cast_map
+                .borrow_mut()
+                .insert(node_id, closure_ty);
+        }
+    }
+
     fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
         // Resolve any borrowings for the node with id `id`
         self.visit_adjustments(reason, id);
@@ -284,13 +305,11 @@ fn visit_adjustments(&self, reason: ResolveReason, id: ast::NodeId) {
                         for autoderef in range(0, adj.autoderefs) {
                             let method_call = MethodCall::autoderef(id, autoderef);
                             self.visit_method_map_entry(reason, method_call);
-                            self.visit_vtable_map_entry(reason, method_call);
                         }
 
                         if adj_object {
                             let method_call = MethodCall::autoobject(id);
                             self.visit_method_map_entry(reason, method_call);
-                            self.visit_vtable_map_entry(reason, method_call);
                         }
 
                         ty::AutoDerefRef(ty::AutoDerefRef {
@@ -329,22 +348,6 @@ fn visit_method_map_entry(&self,
         }
     }
 
-    fn visit_vtable_map_entry(&self,
-                              reason: ResolveReason,
-                              vtable_key: MethodCall) {
-        // Resolve any vtable map entry
-        match self.fcx.inh.vtable_map.borrow_mut().pop(&vtable_key) {
-            Some(origins) => {
-                let r_origins = self.resolve(&origins, reason);
-                debug!("writeback::resolve_vtable_map_entry(\
-                        vtable_key={}, vtables={:?})",
-                       vtable_key, r_origins.repr(self.tcx()));
-                self.tcx().vtable_map.borrow_mut().insert(vtable_key, r_origins);
-            }
-            None => {}
-        }
-    }
-
     fn resolve<T:ResolveIn>(&self, t: &T, reason: ResolveReason) -> T {
         t.resolve_in(&mut Resolver::new(self.fcx, reason))
     }
@@ -504,3 +507,11 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         }
     }
 }
+
+///////////////////////////////////////////////////////////////////////////
+// During type check, we store promises with the result of trait
+// lookup rather than the actual results (because the results are not
+// necessarily available immediately). These routines unwind the
+// promises. It is expected that we will have already reported any
+// errors that may be encountered, so if the promises store an error,
+// a dummy result is returned.
index c66d10138d8bbeddc6fc46896661cfeb9a90dbb8..e0a35dc72a39f4220546a736b335e96d9fb2a812 100644 (file)
@@ -327,10 +327,14 @@ fn coerce_unsized(&self,
 
         let sty_b = &ty::get(b).sty;
         match (sty_a, sty_b) {
-            (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => {
+            (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
                 self.unpack_actual_value(t_a, |sty_a| {
-                    match self.unsize_ty(sty_a, mt_b.ty) {
+                    match self.unsize_ty(t_a, sty_a, mt_b.ty) {
                         Some((ty, kind)) => {
+                            if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
+                                return Err(ty::terr_mutability);
+                            }
+
                             let coercion = Coercion(self.get_ref().trace.clone());
                             let r_borrow = self.get_ref().infcx.next_region_var(coercion);
                             let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
@@ -349,10 +353,14 @@ fn coerce_unsized(&self,
                     }
                 })
             }
-            (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_ptr(mt_b)) => {
+            (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
                 self.unpack_actual_value(t_a, |sty_a| {
-                    match self.unsize_ty(sty_a, mt_b.ty) {
+                    match self.unsize_ty(t_a, sty_a, mt_b.ty) {
                         Some((ty, kind)) => {
+                            if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
+                                return Err(ty::terr_mutability);
+                            }
+
                             let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
                             try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
@@ -510,19 +518,23 @@ fn coerce_object(&self,
                      a: ty::t,
                      sty_a: &ty::sty,
                      b: ty::t,
+                     b_mutbl: ast::Mutability,
                      mk_ty: |ty::t| -> ty::t,
                      mk_adjust: || -> ty::AutoRef) -> CoerceResult
     {
         let tcx = self.get_ref().infcx.tcx;
 
         match *sty_a {
-            ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
+            ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty::get(ty).sty {
                 ty::ty_trait(box ty::TyTrait {
                         def_id,
                         ref substs,
                         bounds,
                         ..
-                    }) => {
+                    }) =>
+                {
+                    debug!("mutbl={} b_mutbl={}", mutbl, b_mutbl);
+
                     let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
                     try!(self.subtype(mk_ty(tr), b));
                     Ok(Some(AutoDerefRef(AutoDerefRef {
@@ -624,3 +636,14 @@ pub fn coerce_unsafe_ptr(&self,
         })))
     }
 }
+
+fn can_coerce_mutbls(from_mutbl: ast::Mutability,
+                     to_mutbl: ast::Mutability)
+                     -> bool {
+    match (from_mutbl, to_mutbl) {
+        (ast::MutMutable, ast::MutMutable) => true,
+        (ast::MutImmutable, ast::MutImmutable) => true,
+        (ast::MutMutable, ast::MutImmutable) => true,
+        (ast::MutImmutable, ast::MutMutable) => false,
+    }
+}