]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/typeck/check/mod.rs
auto merge of #15421 : catharsis/rust/doc-ffi-minor-fixes, r=alexcrichton
[rust.git] / src / librustc / middle / typeck / check / mod.rs
index d808120db99ba8cad928fc1c117fe373db489580..fb29baeea73f2c592d5ad99303d1e3865863b82d 100644 (file)
@@ -397,8 +397,8 @@ fn visit_local(&mut self, local: &ast::Local, _: ()) {
         };
         self.assign(local.id, o_ty);
         debug!("Local variable {} is assigned type {}",
-               self.fcx.pat_to_str(&*local.pat),
-               self.fcx.infcx().ty_to_str(
+               self.fcx.pat_to_string(&*local.pat),
+               self.fcx.infcx().ty_to_string(
                    self.fcx.inh.locals.borrow().get_copy(&local.id)));
         visit::walk_local(self, local, ());
     }
@@ -406,12 +406,12 @@ 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 path, _)
+              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(path.segments.get(0).identifier),
-                       self.fcx.infcx().ty_to_str(
+                       token::get_ident(path1.node),
+                       self.fcx.infcx().ty_to_string(
                            self.fcx.inh.locals.borrow().get_copy(&p.id)));
               }
               _ => {}
@@ -534,7 +534,7 @@ fn span_for_field(tcx: &ty::ctxt, field: &ty::field_ty, struct_id: ast::DefId) -
     let item = match tcx.map.find(struct_id.node) {
         Some(ast_map::NodeItem(item)) => item,
         None => fail!("node not in ast map: {}", struct_id.node),
-        _ => fail!("expected item, found {}", tcx.map.node_to_str(struct_id.node))
+        _ => fail!("expected item, found {}", tcx.map.node_to_string(struct_id.node))
     };
 
     match item.node {
@@ -757,14 +757,16 @@ fn check_method_body(ccx: &CrateCtxt,
     let method_def_id = local_def(method.id);
     let method_ty = ty::method(ccx.tcx, method_def_id);
     let method_generics = &method_ty.generics;
+    let m_body = ast_util::method_body(&*method);
 
     let param_env = ty::construct_parameter_environment(ccx.tcx,
                                                         method_generics,
-                                                        method.body.id);
+                                                        m_body.id);
 
     let fty = ty::node_id_to_type(ccx.tcx, method.id);
 
-    check_bare_fn(ccx, &*method.decl, &*method.body, method.id, fty, param_env);
+    check_bare_fn(ccx, ast_util::method_fn_decl(&*method),
+                  m_body, method.id, fty, param_env);
 }
 
 fn check_impl_methods_against_trait(ccx: &CrateCtxt,
@@ -792,7 +794,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
                 compare_impl_method(ccx.tcx,
                                     &*impl_method_ty,
                                     impl_method.span,
-                                    impl_method.body.id,
+                                    ast_util::method_body(&**impl_method).id,
                                     &**trait_method_ty,
                                     &impl_trait_ref.substs);
             }
@@ -803,7 +805,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
                     format!(
                         "method `{}` is not a member of trait `{}`",
                         token::get_ident(impl_method_ty.ident),
-                        pprust::path_to_str(&ast_trait_ref.path)).as_slice());
+                        pprust::path_to_string(&ast_trait_ref.path)).as_slice());
             }
         }
     }
@@ -815,7 +817,7 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
     for trait_method in trait_methods.iter() {
         let is_implemented =
             impl_methods.iter().any(
-                |m| m.ident.name == trait_method.ident.name);
+                |m| ast_util::method_ident(&**m).name == trait_method.ident.name);
         let is_provided =
             provided_methods.iter().any(
                 |m| m.ident.name == trait_method.ident.name);
@@ -870,7 +872,7 @@ fn compare_impl_method(tcx: &ty::ctxt,
                 format!("method `{}` has a `{}` declaration in the impl, \
                         but not in the trait",
                         token::get_ident(trait_m.ident),
-                        pprust::explicit_self_to_str(
+                        pprust::explicit_self_to_string(
                             impl_m.explicit_self)).as_slice());
             return;
         }
@@ -880,7 +882,7 @@ fn compare_impl_method(tcx: &ty::ctxt,
                 format!("method `{}` has a `{}` declaration in the trait, \
                         but not in the impl",
                         token::get_ident(trait_m.ident),
-                        pprust::explicit_self_to_str(
+                        pprust::explicit_self_to_string(
                             trait_m.explicit_self)).as_slice());
             return;
         }
@@ -917,51 +919,8 @@ fn compare_impl_method(tcx: &ty::ctxt,
         return;
     }
 
-    let it = trait_m.generics.types.get_vec(subst::FnSpace).iter()
-        .zip(impl_m.generics.types.get_vec(subst::FnSpace).iter());
-
-    for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
-        // Check that the impl does not require any builtin-bounds
-        // that the trait does not guarantee:
-        let extra_bounds =
-            impl_param_def.bounds.builtin_bounds -
-            trait_param_def.bounds.builtin_bounds;
-        if !extra_bounds.is_empty() {
-           tcx.sess.span_err(
-               impl_m_span,
-               format!("in method `{}`, \
-                       type parameter {} requires `{}`, \
-                       which is not required by \
-                       the corresponding type parameter \
-                       in the trait declaration",
-                       token::get_ident(trait_m.ident),
-                       i,
-                       extra_bounds.user_string(tcx)).as_slice());
-           return;
-        }
-
-        // FIXME(#2687)---we should be checking that the bounds of the
-        // trait imply the bounds of the subtype, but it appears we
-        // are...not checking this.
-        if impl_param_def.bounds.trait_bounds.len() !=
-            trait_param_def.bounds.trait_bounds.len()
-        {
-            let found = impl_param_def.bounds.trait_bounds.len();
-            let expected =  trait_param_def.bounds.trait_bounds.len();
-            tcx.sess.span_err(
-                impl_m_span,
-                format!("in method `{}`, type parameter {} has {} trait \
-                         bound{}, but the corresponding type parameter in \
-                         the trait declaration has {} trait bound{}",
-                        token::get_ident(trait_m.ident),
-                        i,
-                        found,
-                        if found == 1 {""} else {"s"},
-                        expected,
-                        if expected == 1 {""} else {"s"}).as_slice());
-            return;
-        }
-    }
+    let it = trait_m.generics.types.get_slice(subst::FnSpace).iter()
+        .zip(impl_m.generics.types.get_slice(subst::FnSpace).iter());
 
     // This code is best explained by example. Consider a trait:
     //
@@ -1032,11 +991,75 @@ fn compare_impl_method(tcx: &ty::ctxt,
     let trait_to_skol_substs =
         trait_to_impl_substs
         .subst(tcx, &impl_to_skol_substs)
-        .with_method(skol_tps.get_vec(subst::FnSpace).clone(),
-                     skol_regions.get_vec(subst::FnSpace).clone());
+        .with_method(Vec::from_slice(skol_tps.get_slice(subst::FnSpace)),
+                     Vec::from_slice(skol_regions.get_slice(subst::FnSpace)));
     let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
     let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
 
+    // Check bounds.
+    for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
+        // Check that the impl does not require any builtin-bounds
+        // that the trait does not guarantee:
+        let extra_bounds =
+            impl_param_def.bounds.builtin_bounds -
+            trait_param_def.bounds.builtin_bounds;
+        if !extra_bounds.is_empty() {
+           tcx.sess.span_err(
+               impl_m_span,
+               format!("in method `{}`, \
+                       type parameter {} requires `{}`, \
+                       which is not required by \
+                       the corresponding type parameter \
+                       in the trait declaration",
+                       token::get_ident(trait_m.ident),
+                       i,
+                       extra_bounds.user_string(tcx)).as_slice());
+           return;
+        }
+
+        // Check that the trait bounds of the trait imply the bounds of its
+        // implementation.
+        //
+        // FIXME(pcwalton): We could be laxer here regarding sub- and super-
+        // traits, but I doubt that'll be wanted often, so meh.
+        for impl_trait_bound in impl_param_def.bounds.trait_bounds.iter() {
+            let impl_trait_bound =
+                impl_trait_bound.subst(tcx, &impl_to_skol_substs);
+
+            let mut ok = false;
+            for trait_bound in trait_param_def.bounds.trait_bounds.iter() {
+                let trait_bound =
+                    trait_bound.subst(tcx, &trait_to_skol_substs);
+                let infcx = infer::new_infer_ctxt(tcx);
+                match infer::mk_sub_trait_refs(&infcx,
+                                               true,
+                                               infer::Misc(impl_m_span),
+                                               trait_bound,
+                                               impl_trait_bound.clone()) {
+                    Ok(_) => {
+                        ok = true;
+                        break
+                    }
+                    Err(_) => continue,
+                }
+            }
+
+            if !ok {
+                tcx.sess.span_err(impl_m_span,
+                                  format!("in method `{}`, type parameter {} \
+                                           requires bound `{}`, which is not \
+                                           required by the corresponding \
+                                           type parameter in the trait \
+                                           declaration",
+                                          token::get_ident(trait_m.ident),
+                                          i,
+                                          ppaux::trait_ref_to_string(
+                                              tcx,
+                                              &*impl_trait_bound)).as_slice())
+            }
+        }
+    }
+
     // Check the impl method type IM is a subtype of the trait method
     // type TM. To see why this makes sense, think of a vtable. The
     // expected type of the function pointers in the vtable is the
@@ -1080,8 +1103,8 @@ fn check_cast(fcx: &FnCtxt,
 
     let t_e = fcx.expr_ty(e);
 
-    debug!("t_1={}", fcx.infcx().ty_to_str(t_1));
-    debug!("t_e={}", fcx.infcx().ty_to_str(t_e));
+    debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
+    debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
 
     if ty::type_is_error(t_e) {
         fcx.write_error(id);
@@ -1105,13 +1128,13 @@ fn check_cast(fcx: &FnCtxt,
         fcx.type_error_message(span, |actual| {
             format!("cast from nil: `{}` as `{}`",
                     actual,
-                    fcx.infcx().ty_to_str(t_1))
+                    fcx.infcx().ty_to_string(t_1))
         }, t_e, None);
     } else if ty::type_is_nil(t_1) {
         fcx.type_error_message(span, |actual| {
             format!("cast to nil: `{}` as `{}`",
                     actual,
-                    fcx.infcx().ty_to_str(t_1))
+                    fcx.infcx().ty_to_string(t_1))
         }, t_e, None);
     }
 
@@ -1128,7 +1151,7 @@ fn check_cast(fcx: &FnCtxt,
                 format!("illegal cast; cast through an \
                          integer first: `{}` as `{}`",
                         actual,
-                        fcx.infcx().ty_to_str(t_1))
+                        fcx.infcx().ty_to_string(t_1))
             }, t_e, None);
         }
         // casts from C-like enums are allowed
@@ -1146,24 +1169,9 @@ fn check_cast(fcx: &FnCtxt,
            .span_err(span,
                      "cannot cast as `bool`, compare with zero instead");
     } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
-        fn is_vec(t: ty::t) -> bool {
-            match ty::get(t).sty {
-                ty::ty_vec(..) => true,
-                ty::ty_ptr(ty::mt{ty: t, ..}) |
-                ty::ty_rptr(_, ty::mt{ty: t, ..}) |
-                ty::ty_box(t) |
-                ty::ty_uniq(t) => {
-                    match ty::get(t).sty {
-                        ty::ty_vec(_, None) => true,
-                        _ => false,
-                    }
-                }
-                _ => false
-            }
-        }
         fn types_compatible(fcx: &FnCtxt, sp: Span,
                             t1: ty::t, t2: ty::t) -> bool {
-            if !is_vec(t1) {
+            if !ty::type_is_vec(t1) {
                 // If the type being casted from is not a vector, this special
                 // case does not apply.
                 return false
@@ -1211,7 +1219,14 @@ fn types_compatible(fcx: &FnCtxt, sp: Span,
         fcx.type_error_message(span, |actual| {
             format!("non-scalar cast: `{}` as `{}`",
                     actual,
-                    fcx.infcx().ty_to_str(t_1))
+                    fcx.infcx().ty_to_string(t_1))
+        }, t_e, None);
+    } else if ty::type_is_unsafe_ptr(t_e) && t_1_is_float {
+        fcx.type_error_message(span, |actual| {
+            format!("cannot cast from pointer to float directly: `{}` as `{}`; cast through an \
+                     integer first",
+                    actual,
+                    fcx.infcx().ty_to_string(t_1))
         }, t_e, None);
     }
 
@@ -1280,7 +1295,7 @@ pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> ty::t {
     #[inline]
     pub fn write_ty(&self, node_id: ast::NodeId, ty: ty::t) {
         debug!("write_ty({}, {}) in fcx {}",
-               node_id, ppaux::ty_to_str(self.tcx(), ty), self.tag());
+               node_id, ppaux::ty_to_string(self.tcx(), ty), self.tag());
         self.inh.node_types.borrow_mut().insert(node_id, ty);
     }
 
@@ -1337,7 +1352,7 @@ pub fn to_ty(&self, ast_t: &ast::Ty) -> ty::t {
         ast_ty_to_ty(self, self.infcx(), ast_t)
     }
 
-    pub fn pat_to_str(&self, pat: &ast::Pat) -> String {
+    pub fn pat_to_string(&self, pat: &ast::Pat) -> String {
         pat.repr(self.tcx())
     }
 
@@ -1357,7 +1372,7 @@ pub fn node_ty(&self, id: ast::NodeId) -> ty::t {
             None => {
                 self.tcx().sess.bug(
                     format!("no type for node {}: {} in fcx {}",
-                            id, self.tcx().map.node_to_str(id),
+                            id, self.tcx().map.node_to_string(id),
                             self.tag()).as_slice());
             }
         }
@@ -1369,7 +1384,7 @@ pub fn method_ty_substs(&self, id: ast::NodeId) -> subst::Substs {
             None => {
                 self.tcx().sess.bug(
                     format!("no method entry for node {}: {} in fcx {}",
-                            id, self.tcx().map.node_to_str(id),
+                            id, self.tcx().map.node_to_string(id),
                             self.tag()).as_slice());
             }
         }
@@ -1623,6 +1638,76 @@ fn try_overloaded_deref(fcx: &FnCtxt,
     }
 }
 
+fn try_overloaded_index(fcx: &FnCtxt,
+                        method_call: Option<MethodCall>,
+                        expr: &ast::Expr,
+                        base_expr: Gc<ast::Expr>,
+                        base_ty: ty::t,
+                        index_expr: Gc<ast::Expr>,
+                        lvalue_pref: LvaluePreference)
+                        -> Option<ty::mt> {
+    // Try `IndexMut` first, if preferred.
+    let method = match (lvalue_pref, fcx.tcx().lang_items.index_mut_trait()) {
+        (PreferMutLvalue, Some(trait_did)) => {
+            method::lookup_in_trait(fcx,
+                                    expr.span,
+                                    Some(&*base_expr),
+                                    token::intern("index_mut"),
+                                    trait_did,
+                                    base_ty,
+                                    [],
+                                    DontAutoderefReceiver,
+                                    IgnoreStaticMethods)
+        }
+        _ => None,
+    };
+
+    // Otherwise, fall back to `Index`.
+    let method = match (method, fcx.tcx().lang_items.index_trait()) {
+        (None, Some(trait_did)) => {
+            method::lookup_in_trait(fcx,
+                                    expr.span,
+                                    Some(&*base_expr),
+                                    token::intern("index"),
+                                    trait_did,
+                                    base_ty,
+                                    [],
+                                    DontAutoderefReceiver,
+                                    IgnoreStaticMethods)
+        }
+        (method, _) => method,
+    };
+
+    // Regardless of whether the lookup succeeds, check the method arguments
+    // so that we have *some* type for each argument.
+    let method_type = match method {
+        Some(ref method) => method.ty,
+        None => ty::mk_err()
+    };
+    check_method_argument_types(fcx,
+                                expr.span,
+                                method_type,
+                                expr,
+                                [base_expr, index_expr],
+                                DoDerefArgs,
+                                DontTupleArguments);
+
+    match method {
+        Some(method) => {
+            let ref_ty = ty::ty_fn_ret(method.ty);
+            match method_call {
+                Some(method_call) => {
+                    fcx.inh.method_map.borrow_mut().insert(method_call,
+                                                           method);
+                }
+                None => {}
+            }
+            ty::deref(ref_ty, true)
+        }
+        None => None,
+    }
+}
+
 fn check_method_argument_types(fcx: &FnCtxt,
                                sp: Span,
                                method_fn_ty: ty::t,
@@ -1766,7 +1851,7 @@ fn check_argument_types(fcx: &FnCtxt,
     };
 
     debug!("check_argument_types: formal_tys={:?}",
-           formal_tys.iter().map(|t| fcx.infcx().ty_to_str(*t)).collect::<Vec<String>>());
+           formal_tys.iter().map(|t| fcx.infcx().ty_to_string(*t)).collect::<Vec<String>>());
 
     // Check the arguments.
     // We do this in a pretty awful way: first we typecheck any arguments
@@ -1996,7 +2081,7 @@ pub fn impl_self_ty(vcx: &VtableContext,
     let ity = ty::lookup_item_type(tcx, did);
     let (n_tps, rps, raw_ty) =
         (ity.generics.types.len(subst::TypeSpace),
-         ity.generics.regions.get_vec(subst::TypeSpace),
+         ity.generics.regions.get_slice(subst::TypeSpace),
          ity.ty);
 
     let rps = vcx.infcx.region_vars_for_defs(span, rps);
@@ -2334,7 +2419,7 @@ fn check_binop(fcx: &FnCtxt,
                                              operation `{}` not \
                                              supported for floating \
                                              point SIMD vector `{}`",
-                                            ast_util::binop_to_str(op),
+                                            ast_util::binop_to_string(op),
                                             actual)
                                 },
                                 lhs_t,
@@ -2364,7 +2449,7 @@ fn check_binop(fcx: &FnCtxt,
                                    |actual| {
                     format!("binary operation `{}` cannot be applied \
                              to type `{}`",
-                            ast_util::binop_to_str(op),
+                            ast_util::binop_to_string(op),
                             actual)
                 },
                 lhs_t,
@@ -2381,7 +2466,7 @@ fn check_binop(fcx: &FnCtxt,
                                                  operation `{}=` \
                                                  cannot be applied to \
                                                  type `{}`",
-                                                ast_util::binop_to_str(op),
+                                                ast_util::binop_to_string(op),
                                                 actual)
                                    },
                                    lhs_t,
@@ -2430,7 +2515,7 @@ fn check_user_binop(fcx: &FnCtxt,
                          trait_did, [lhs_expr, rhs], DontAutoderefReceiver, || {
             fcx.type_error_message(ex.span, |actual| {
                 format!("binary operation `{}` cannot be applied to type `{}`",
-                        ast_util::binop_to_str(op),
+                        ast_util::binop_to_string(op),
                         actual)
             }, lhs_resolved_t, None)
         })
@@ -2518,7 +2603,7 @@ fn check_expr_fn(fcx: &FnCtxt,
                                            expected_sig);
         let fty_sig = fn_ty.sig.clone();
         let fty = ty::mk_closure(tcx, fn_ty);
-        debug!("check_expr_fn fty={}", fcx.infcx().ty_to_str(fty));
+        debug!("check_expr_fn fty={}", fcx.infcx().ty_to_string(fty));
 
         fcx.write_ty(expr.id, fty);
 
@@ -2552,7 +2637,7 @@ fn check_field(fcx: &FnCtxt,
             autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
                 match ty::get(base_t).sty {
                     ty::ty_struct(base_id, ref substs) => {
-                        debug!("struct named {}", ppaux::ty_to_str(tcx, base_t));
+                        debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
                         let fields = ty::lookup_struct_fields(tcx, base_id);
                         lookup_field_ty(tcx, base_id, fields.as_slice(),
                                         field.node.name, &(*substs))
@@ -2779,10 +2864,30 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
         fcx.write_ty(id, enum_type);
     }
 
+    type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, ty::t);
+
+    fn check_fn_for_vec_elements_expected(fcx: &FnCtxt,
+                                          expected: Expectation)
+                                         -> (ExprCheckerWithTy, ty::t) {
+        let tcx = fcx.ccx.tcx;
+        let (coerce, t) = match expected {
+            // If we're given an expected type, we can try to coerce to it
+            ExpectHasType(t) if ty::type_is_vec(t) => (true, ty::sequence_element_type(tcx, t)),
+            // Otherwise we just leave the type to be resolved later
+            _ => (false, fcx.infcx().next_ty_var())
+        };
+        if coerce {
+            (check_expr_coercable_to_type, t)
+        } else {
+            (check_expr_has_type, t)
+        }
+    }
+
     let tcx = fcx.ccx.tcx;
     let id = expr.id;
     match expr.node {
         ast::ExprVstore(ev, vst) => {
+            let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
             let typ = match ev.node {
                 ast::ExprVec(ref args) => {
                     let mutability = match vst {
@@ -2791,9 +2896,8 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
                     };
                     let mut any_error = false;
                     let mut any_bot = false;
-                    let t: ty::t = fcx.infcx().next_ty_var();
                     for e in args.iter() {
-                        check_expr_has_type(fcx, &**e, t);
+                        check(fcx, &**e, t);
                         let arg_t = fcx.expr_ty(&**e);
                         if ty::type_is_error(arg_t) {
                             any_error = true;
@@ -2821,8 +2925,7 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
                         ast::ExprVstoreMutSlice => ast::MutMutable,
                         _ => ast::MutImmutable,
                     };
-                    let t = fcx.infcx().next_ty_var();
-                    check_expr_has_type(fcx, &**element, t);
+                    check(fcx, &**element, t);
                     let arg_t = fcx.expr_ty(&**element);
                     if ty::type_is_error(arg_t) {
                         ty::mk_err()
@@ -3211,9 +3314,9 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
         check_cast(fcx, &**e, &**t, id, expr.span);
       }
       ast::ExprVec(ref args) => {
-        let t: ty::t = fcx.infcx().next_ty_var();
+        let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
         for e in args.iter() {
-            check_expr_has_type(fcx, &**e, t);
+            check(fcx, &**e, t);
         }
         let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
                              Some(args.len()));
@@ -3222,8 +3325,8 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
       ast::ExprRepeat(ref element, ref count_expr) => {
         check_expr_has_type(fcx, &**count_expr, ty::mk_uint());
         let count = ty::eval_repeat_count(fcx, &**count_expr);
-        let t: ty::t = fcx.infcx().next_ty_var();
-        check_expr_has_type(fcx, &**element, t);
+        let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
+        check(fcx, &**element, t);
         let element_ty = fcx.expr_ty(&**element);
         if ty::type_is_error(element_ty) {
             fcx.write_error(id);
@@ -3272,17 +3375,34 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
         // Resolve the path.
         let def = tcx.def_map.borrow().find(&id).map(|i| *i);
         match def {
-            Some(def::DefStruct(type_def_id)) => {
-                check_struct_constructor(fcx, id, expr.span, type_def_id,
-                                         fields.as_slice(), base_expr);
-            }
             Some(def::DefVariant(enum_id, variant_id, _)) => {
                 check_struct_enum_variant(fcx, id, expr.span, enum_id,
                                           variant_id, fields.as_slice());
             }
+            Some(def) => {
+                // Verify that this was actually a struct.
+                let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id());
+                match ty::get(typ.ty).sty {
+                    ty::ty_struct(struct_did, _) => {
+                        check_struct_constructor(fcx,
+                                                 id,
+                                                 expr.span,
+                                                 struct_did,
+                                                 fields.as_slice(),
+                                                 base_expr);
+                    }
+                    _ => {
+                        tcx.sess
+                           .span_err(path.span,
+                                     format!("`{}` does not name a structure",
+                                             pprust::path_to_string(
+                                                 path)).as_slice())
+                    }
+                }
+            }
             _ => {
                 tcx.sess.span_bug(path.span,
-                                  "structure constructor does not name a structure type");
+                                  "structure constructor wasn't resolved")
             }
         }
       }
@@ -3299,7 +3419,7 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
           } else if ty::type_is_error(idx_t) || ty::type_is_bot(idx_t) {
               fcx.write_ty(id, idx_t);
           } else {
-              let (base_t, autoderefs, field_ty) =
+              let (_, autoderefs, field_ty) =
                 autoderef(fcx, expr.span, raw_base_t, Some(base.id),
                           lvalue_pref, |base_t, _| ty::index(base_t));
               match field_ty {
@@ -3309,27 +3429,33 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
                       fcx.write_autoderef_adjustment(base.id, autoderefs);
                   }
                   None => {
-                      let resolved = structurally_resolved_type(fcx,
-                                                                expr.span,
-                                                                raw_base_t);
-                      let ret_ty = lookup_op_method(fcx,
-                                                    expr,
-                                                    resolved,
-                                                    token::intern("index"),
-                                                    tcx.lang_items.index_trait(),
-                                                    [base.clone(), idx.clone()],
-                                                    AutoderefReceiver,
-                                                    || {
-                        fcx.type_error_message(expr.span,
-                                               |actual| {
-                                                    format!("cannot index a \
-                                                             value of type \
-                                                             `{}`", actual)
-                                               },
-                                               base_t,
-                                               None);
-                      });
-                      fcx.write_ty(id, ret_ty);
+                      // This is an overloaded method.
+                      let base_t = structurally_resolved_type(fcx,
+                                                              expr.span,
+                                                              raw_base_t);
+                      let method_call = MethodCall::expr(expr.id);
+                      match try_overloaded_index(fcx,
+                                                 Some(method_call),
+                                                 expr,
+                                                 *base,
+                                                 base_t,
+                                                 *idx,
+                                                 lvalue_pref) {
+                          Some(mt) => fcx.write_ty(id, mt.ty),
+                          None => {
+                                fcx.type_error_message(expr.span,
+                                                       |actual| {
+                                                        format!("cannot \
+                                                                 index a \
+                                                                 value of \
+                                                                 type `{}`",
+                                                                actual)
+                                                       },
+                                                       base_t,
+                                                       None);
+                                fcx.write_ty(id, ty::mk_err())
+                          }
+                      }
                   }
               }
           }
@@ -3337,10 +3463,10 @@ fn check_struct_enum_variant(fcx: &FnCtxt,
     }
 
     debug!("type of expr({}) {} is...", expr.id,
-           syntax::print::pprust::expr_to_str(expr));
+           syntax::print::pprust::expr_to_string(expr));
     debug!("... {}, expected is {}",
-           ppaux::ty_to_str(tcx, fcx.expr_ty(expr)),
-           expected.repr(tcx))
+           ppaux::ty_to_string(tcx, fcx.expr_ty(expr)),
+           expected.repr(tcx));
 
     unifier();
 }
@@ -3675,7 +3801,7 @@ pub fn check_instantiable(tcx: &ty::ctxt,
                      format!("this type cannot be instantiated without an \
                               instance of itself; consider using \
                               `Option<{}>`",
-                             ppaux::ty_to_str(tcx, item_ty)).as_slice());
+                             ppaux::ty_to_string(tcx, item_ty)).as_slice());
         false
     } else {
         true
@@ -3736,7 +3862,7 @@ pub fn check_enum_variants_sized(ccx: &CrateCtxt,
                                         dynamically sized types may only \
                                         appear as the final type in a \
                                         variant",
-                                       ppaux::ty_to_str(ccx.tcx,
+                                       ppaux::ty_to_string(ccx.tcx,
                                                         *t)).as_slice());
                     }
                 }
@@ -3801,7 +3927,7 @@ fn do_check(ccx: &CrateCtxt,
 
             match v.node.disr_expr {
                 Some(e) => {
-                    debug!("disr expr, checking {}", pprust::expr_to_str(&*e));
+                    debug!("disr expr, checking {}", pprust::expr_to_string(&*e));
 
                     let inh = blank_inherited_fields(ccx);
                     let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id);
@@ -4102,12 +4228,10 @@ pub fn instantiate_path(fcx: &FnCtxt,
     // a problem.
     for &space in ParamSpace::all().iter() {
         adjust_type_parameters(fcx, span, space, type_defs, &mut substs);
-        assert_eq!(substs.types.get_vec(space).len(),
-                   type_defs.get_vec(space).len());
+        assert_eq!(substs.types.len(space), type_defs.len(space));
 
         adjust_region_parameters(fcx, span, space, region_defs, &mut substs);
-        assert_eq!(substs.regions().get_vec(space).len(),
-                   region_defs.get_vec(space).len());
+        assert_eq!(substs.regions().len(space), region_defs.len(space));
     }
 
     fcx.write_ty_substs(node_id, polytype.ty, ty::ItemSubsts {
@@ -4159,8 +4283,8 @@ fn push_explicit_parameters_from_segment_to_substs(
          */
 
         {
-            let type_count = type_defs.get_vec(space).len();
-            assert_eq!(substs.types.get_vec(space).len(), 0);
+            let type_count = type_defs.len(space);
+            assert_eq!(substs.types.len(space), 0);
             for (i, &typ) in segment.types.iter().enumerate() {
                 let t = fcx.to_ty(&*typ);
                 if i < type_count {
@@ -4174,14 +4298,14 @@ fn push_explicit_parameters_from_segment_to_substs(
                              but found {} parameter(s)",
                             type_count,
                             segment.types.len()).as_slice());
-                    substs.types.get_mut_vec(space).truncate(0);
+                    substs.types.truncate(space, 0);
                 }
             }
         }
 
         {
-            let region_count = region_defs.get_vec(space).len();
-            assert_eq!(substs.regions().get_vec(space).len(), 0);
+            let region_count = region_defs.len(space);
+            assert_eq!(substs.regions().len(space), 0);
             for (i, lifetime) in segment.lifetimes.iter().enumerate() {
                 let r = ast_region_to_region(fcx.tcx(), lifetime);
                 if i < region_count {
@@ -4194,7 +4318,7 @@ fn push_explicit_parameters_from_segment_to_substs(
                              expected {} parameter(s) but found {} parameter(s)",
                             region_count,
                             segment.lifetimes.len()).as_slice());
-                    substs.mut_regions().get_mut_vec(space).truncate(0);
+                    substs.mut_regions().truncate(space, 0);
                 }
             }
         }
@@ -4207,8 +4331,8 @@ fn adjust_type_parameters(
         defs: &VecPerParamSpace<ty::TypeParameterDef>,
         substs: &mut Substs)
     {
-        let provided_len = substs.types.get_vec(space).len();
-        let desired = defs.get_vec(space).as_slice();
+        let provided_len = substs.types.len(space);
+        let desired = defs.get_slice(space);
         let required_len = desired.iter()
                               .take_while(|d| d.default.is_none())
                               .count();
@@ -4228,8 +4352,8 @@ fn adjust_type_parameters(
         // Nothing specified at all: supply inference variables for
         // everything.
         if provided_len == 0 {
-            let provided = substs.types.get_mut_vec(space);
-            *provided = fcx.infcx().next_ty_vars(desired.len());
+            substs.types.replace(space,
+                                 fcx.infcx().next_ty_vars(desired.len()));
             return;
         }
 
@@ -4246,8 +4370,8 @@ fn adjust_type_parameters(
                             qualifier,
                             required_len,
                             provided_len).as_slice());
-            let provided = substs.types.get_mut_vec(space);
-            *provided = Vec::from_elem(desired.len(), ty::mk_err());
+            substs.types.replace(space,
+                                 Vec::from_elem(desired.len(), ty::mk_err()));
             return;
         }
 
@@ -4263,7 +4387,7 @@ fn adjust_type_parameters(
             let default = default.subst_spanned(fcx.tcx(), substs, Some(span));
             substs.types.push(space, default);
         }
-        assert_eq!(substs.types.get_vec(space).len(), desired.len());
+        assert_eq!(substs.types.len(space), desired.len());
 
         debug!("Final substs: {}", substs.repr(fcx.tcx()));
     }
@@ -4275,20 +4399,22 @@ fn adjust_region_parameters(
         defs: &VecPerParamSpace<ty::RegionParameterDef>,
         substs: &mut Substs)
     {
-        let provided = substs.mut_regions().get_mut_vec(space);
-        let desired = defs.get_vec(space);
+        let provided_len = substs.mut_regions().len(space);
+        let desired = defs.get_slice(space);
 
         // Enforced by `push_explicit_parameters_from_segment_to_substs()`.
-        assert!(provided.len() <= desired.len());
+        assert!(provided_len <= desired.len());
 
         // If nothing was provided, just use inference variables.
-        if provided.len() == 0 {
-            *provided = fcx.infcx().region_vars_for_defs(span, desired);
+        if provided_len == 0 {
+            substs.mut_regions().replace(
+                space,
+                fcx.infcx().region_vars_for_defs(span, desired));
             return;
         }
 
         // If just the right number were provided, everybody is happy.
-        if provided.len() == desired.len() {
+        if provided_len == desired.len() {
             return;
         }
 
@@ -4301,9 +4427,11 @@ fn adjust_region_parameters(
                          expected {} parameter(s) \
                          but found {} parameter(s)",
                 desired.len(),
-                provided.len()).as_slice());
+                provided_len).as_slice());
 
-        *provided = fcx.infcx().region_vars_for_defs(span, desired);
+        substs.mut_regions().replace(
+            space,
+            fcx.infcx().region_vars_for_defs(span, desired));
     }
 }
 
@@ -4403,7 +4531,7 @@ pub fn check_bounds_are_used(ccx: &CrateCtxt,
                              tps: &OwnedSlice<ast::TyParam>,
                              ty: ty::t) {
     debug!("check_bounds_are_used(n_tps={}, ty={})",
-           tps.len(), ppaux::ty_to_str(ccx.tcx, ty));
+           tps.len(), ppaux::ty_to_string(ccx.tcx, ty));
 
     // make a vector of booleans initially false, set to true when used
     if tps.len() == 0u { return; }
@@ -4721,7 +4849,7 @@ fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
                            fty,
                            || {
                 format!("intrinsic has wrong type: expected `{}`",
-                        ppaux::ty_to_str(ccx.tcx, fty))
+                        ppaux::ty_to_string(ccx.tcx, fty))
             });
     }
 }