]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Auto merge of #27833 - arielb1:robust-construction, r=eddyb
[rust.git] / src / librustc_typeck / check / mod.rs
index 6851fb4667015b8cd9faf685151668f3ea4acacd..be008d522858ce35591be59fd60d0b0a9a2fe335 100644 (file)
@@ -90,7 +90,7 @@
 use middle::infer::type_variable;
 use middle::pat_util::{self, pat_id_map};
 use middle::privacy::{AllPublic, LastMod};
-use middle::region::{self, CodeExtent};
+use middle::region::{self};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
 use middle::traits::{self, report_fulfillment_errors};
 use middle::ty::{FnSig, GenericPredicates, TypeScheme};
 pub mod demand;
 pub mod method;
 mod upvar;
-pub mod wf;
+mod wf;
+mod wfcheck;
 mod cast;
 mod closure;
 mod callee;
@@ -382,7 +383,12 @@ fn visit_item(&mut self, i: &'tcx ast::Item) {
     }
 }
 
-pub fn check_item_types(ccx: &CrateCtxt) {
+pub fn check_wf_old(ccx: &CrateCtxt) {
+    // FIXME(#25759). The new code below is much more reliable but (for now)
+    // only generates warnings. So as to ensure that we continue
+    // getting errors where we used to get errors, we run the old wf
+    // code first and abort if it encounters any errors. If no abort
+    // comes, we run the new code and issue warnings.
     let krate = ccx.tcx.map.krate();
     let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
     visit::walk_crate(&mut visit, krate);
@@ -390,17 +396,34 @@ pub fn check_item_types(ccx: &CrateCtxt) {
     // If types are not well-formed, it leads to all manner of errors
     // downstream, so stop reporting errors at this point.
     ccx.tcx.sess.abort_if_errors();
+}
 
-    let mut visit = CheckItemTypesVisitor { ccx: ccx };
+pub fn check_wf_new(ccx: &CrateCtxt) {
+    let krate = ccx.tcx.map.krate();
+    let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
     visit::walk_crate(&mut visit, krate);
 
+    // If types are not well-formed, it leads to all manner of errors
+    // downstream, so stop reporting errors at this point.
     ccx.tcx.sess.abort_if_errors();
+}
 
+pub fn check_item_types(ccx: &CrateCtxt) {
+    let krate = ccx.tcx.map.krate();
+    let mut visit = CheckItemTypesVisitor { ccx: ccx };
+    visit::walk_crate(&mut visit, krate);
+    ccx.tcx.sess.abort_if_errors();
+}
+
+pub fn check_item_bodies(ccx: &CrateCtxt) {
+    let krate = ccx.tcx.map.krate();
     let mut visit = CheckItemBodiesVisitor { ccx: ccx };
     visit::walk_crate(&mut visit, krate);
 
     ccx.tcx.sess.abort_if_errors();
+}
 
+pub fn check_drop_impls(ccx: &CrateCtxt) {
     for drop_method_did in ccx.tcx.destructors.borrow().iter() {
         if drop_method_did.krate == ast::LOCAL_CRATE {
             let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
@@ -445,9 +468,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             fcx.select_all_obligations_and_apply_defaults();
             upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
-            fcx.select_all_obligations_or_error();
+            fcx.select_obligations_where_possible();
             fcx.check_casts();
-
             fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
             regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
@@ -587,7 +609,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
 
     if let ty::FnConverging(ret_ty) = ret_ty {
         fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
-        fn_sig_tys.push(ret_ty);
+        fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments
     }
 
     debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
@@ -601,6 +623,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) {
+            // The type of the argument must be well-formed.
+            //
+            // NB -- this is now checked in wfcheck, but that
+            // currently only results in warnings, so we issue an
+            // old-style WF obligation here so that we still get the
+            // errors that we used to get.
+            fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
+
             // Create type variables for each argument.
             pat_util::pat_bindings(
                 &tcx.def_map,
@@ -1379,68 +1409,68 @@ fn normalize_associated_type(&self,
                                        cause)
     }
 
-    /// 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.
+    /// Instantiates the type in `did` with the generics in `path` and returns
+    /// it (registering the necessary trait obligations along the way).
     ///
-    /// Note that function is only intended to be used with types (notably, not fns). This is
-    /// because it doesn't do any instantiation of late-bound regions.
+    /// Note that this function is only intended to be used with type-paths,
+    /// not with value-paths.
     pub fn instantiate_type(&self,
-                            span: Span,
-                            def_id: ast::DefId)
-                            -> TypeAndSubsts<'tcx>
+                            did: ast::DefId,
+                            path: &ast::Path)
+                            -> Ty<'tcx>
     {
+        debug!("instantiate_type(did={:?}, path={:?})", did, path);
         let type_scheme =
-            self.tcx().lookup_item_type(def_id);
+            self.tcx().lookup_item_type(did);
         let type_predicates =
-            self.tcx().lookup_predicates(def_id);
-        let substs =
-            self.infcx().fresh_substs_for_generics(
-                span,
-                &type_scheme.generics);
+            self.tcx().lookup_predicates(did);
+        let substs = astconv::ast_path_substs_for_ty(self, self,
+                                                     path.span,
+                                                     PathParamMode::Optional,
+                                                     &type_scheme.generics,
+                                                     path.segments.last().unwrap());
+        debug!("instantiate_type: ty={:?} substs={:?}", &type_scheme.ty, &substs);
         let bounds =
-            self.instantiate_bounds(span, &substs, &type_predicates);
+            self.instantiate_bounds(path.span, &substs, &type_predicates);
         self.add_obligations_for_parameters(
             traits::ObligationCause::new(
-                span,
+                path.span,
                 self.body_id,
-                traits::ItemObligation(def_id)),
+                traits::ItemObligation(did)),
             &bounds);
-        let monotype =
-            self.instantiate_type_scheme(span, &substs, &type_scheme.ty);
 
-        TypeAndSubsts {
-            ty: monotype,
-            substs: substs
-        }
+        self.instantiate_type_scheme(path.span, &substs, &type_scheme.ty)
     }
 
-    /// Returns the type that this AST path refers to. If the path has no type
-    /// parameters and the corresponding type has type parameters, fresh type
-    /// and/or region variables are substituted.
-    ///
-    /// This is used when checking the constructor in struct literals.
-    fn instantiate_struct_literal_ty(&self,
-                                     did: ast::DefId,
-                                     path: &ast::Path)
-                                     -> TypeAndSubsts<'tcx>
+    /// Return the dict-like variant corresponding to a given `Def`.
+    pub fn def_struct_variant(&self,
+                              def: def::Def)
+                              -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
     {
-        let tcx = self.tcx();
-
-        let ty::TypeScheme { generics, ty: decl_ty } =
-            tcx.lookup_item_type(did);
-
-        let substs = astconv::ast_path_substs_for_ty(self, self,
-                                                     path.span,
-                                                     PathParamMode::Optional,
-                                                     &generics,
-                                                     path.segments.last().unwrap());
-
-        let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
+        let (adt, variant) = match def {
+            def::DefVariant(enum_id, variant_id, true) => {
+                let adt = self.tcx().lookup_adt_def(enum_id);
+                (adt, adt.variant_with_id(variant_id))
+            }
+            def::DefTy(did, _) | def::DefStruct(did) => {
+                let typ = self.tcx().lookup_item_type(did);
+                if let ty::TyStruct(adt, _) = typ.ty.sty {
+                    (adt, adt.struct_variant())
+                } else {
+                    return None;
+                }
+            }
+            _ => return None
+        };
 
-        TypeAndSubsts { substs: substs, ty: ty }
+        if let ty::VariantKind::Dict = variant.kind() {
+            Some((adt, variant))
+        } else {
+            None
+        }
     }
 
+
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx().mk_nil());
     }
@@ -1508,10 +1538,19 @@ pub fn register_predicate(&self,
     pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> {
         let t = ast_ty_to_ty(self, self, ast_t);
 
-        let mut bounds_checker = wf::BoundsChecker::new(self,
-                                                        self.body_id,
-                                                        None);
-        bounds_checker.check_ty(t, ast_t.span);
+        // Generally speaking, we must check that types entered by the
+        // user are well-formed. This is not true for `_`, since those
+        // types are generated by inference. Now, you might think that
+        // we could as well generate a WF obligation -- but
+        // unfortunately that breaks code like `foo as *const _`,
+        // because those type variables wind up being unconstrained
+        // until very late. Nasty. Probably it'd be best to refactor
+        // that code path, but that's tricky because of
+        // defaults. Argh!
+        match ast_t.node {
+            ast::TyInfer => { }
+            _ => { self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); }
+        }
 
         t
     }
@@ -1630,15 +1669,38 @@ pub fn register_region_obligation(&self,
         fulfillment_cx.register_region_obligation(ty, region, cause);
     }
 
-    pub fn add_default_region_param_bounds(&self,
-                                           substs: &Substs<'tcx>,
-                                           expr: &ast::Expr)
+    /// Registers an obligation for checking later, during regionck, that the type `ty` must
+    /// outlive the region `r`.
+    pub fn register_wf_obligation(&self,
+                                  ty: Ty<'tcx>,
+                                  span: Span,
+                                  code: traits::ObligationCauseCode<'tcx>)
+    {
+        // WF obligations never themselves fail, so no real need to give a detailed cause:
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
+    }
+
+    pub fn register_old_wf_obligation(&self,
+                                      ty: Ty<'tcx>,
+                                      span: Span,
+                                      code: traits::ObligationCauseCode<'tcx>)
+    {
+        // Registers an "old-style" WF obligation that uses the
+        // implicator code.  This is basically a buggy version of
+        // `register_wf_obligation` that is being kept around
+        // temporarily just to help with phasing in the newer rules.
+        //
+        // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_region_obligation(ty, ty::ReEmpty, cause);
+    }
+
+    /// Registers obligations that all types appearing in `substs` are well-formed.
+    pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &ast::Expr)
     {
         for &ty in &substs.types {
-            let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id));
-            let cause = traits::ObligationCause::new(expr.span, self.body_id,
-                                                     traits::MiscObligation);
-            self.register_region_obligation(ty, default_bound, cause);
+            self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
         }
     }
 
@@ -1674,34 +1736,19 @@ pub fn add_obligations_for_parameters(&self,
         }
     }
 
-    // Only for fields! Returns <none> for methods>
-    // Indifferent to privacy flags
-    pub fn lookup_field_ty(&self,
-                           span: Span,
-                           class_id: ast::DefId,
-                           items: &[ty::FieldTy],
-                           fieldname: ast::Name,
-                           substs: &subst::Substs<'tcx>)
-                           -> Option<Ty<'tcx>>
-    {
-        let o_field = items.iter().find(|f| f.name == fieldname);
-        o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs))
-               .map(|t| self.normalize_associated_types_in(span, &t))
-    }
-
-    pub fn lookup_tup_field_ty(&self,
-                               span: Span,
-                               class_id: ast::DefId,
-                               items: &[ty::FieldTy],
-                               idx: usize,
-                               substs: &subst::Substs<'tcx>)
-                               -> Option<Ty<'tcx>>
+    // FIXME(arielb1): use this instead of field.ty everywhere
+    pub fn field_ty(&self,
+                    span: Span,
+                    field: ty::FieldDef<'tcx>,
+                    substs: &Substs<'tcx>)
+                    -> Ty<'tcx>
     {
-        let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
-        o_field.map(|f| self.tcx().lookup_field_type(class_id, f.id, substs))
-               .map(|t| self.normalize_associated_types_in(span, &t))
+        self.normalize_associated_types_in(span,
+                                           &field.ty(self.tcx(), substs))
     }
 
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
     fn check_casts(&self) {
         let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
         for cast in deferred_cast_checks.drain(..) {
@@ -2385,6 +2432,12 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         1
     };
 
+    // All the input types from the fn signature must outlive the call
+    // so as to validate implied bounds.
+    for &fn_input_ty in fn_inputs {
+        fcx.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation);
+    }
+
     let mut expected_arg_tys = expected_arg_tys;
     let expected_arg_count = fn_inputs.len();
     let formal_tys = if tuple_arguments == TupleArguments {
@@ -2493,7 +2546,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                     Expectation::rvalue_hint(fcx.tcx(), ty)
                 });
 
-                check_expr_with_unifier(fcx, &**arg,
+                check_expr_with_unifier(fcx,
+                                        &**arg,
                                         expected.unwrap_or(ExpectHasType(formal_ty)),
                                         NoPreference, || {
                     // 2. Coerce to the most detailed type that could be coerced
@@ -2878,11 +2932,11 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                                   lvalue_pref,
                                                   |base_t, _| {
                 match base_t.sty {
-                    ty::TyStruct(base_id, substs) => {
+                    ty::TyStruct(base_def, substs) => {
                         debug!("struct named {:?}",  base_t);
-                        let fields = tcx.lookup_struct_fields(base_id);
-                        fcx.lookup_field_ty(expr.span, base_id, &fields[..],
-                                            field.node.name, &(*substs))
+                        base_def.struct_variant()
+                                .find_field_named(field.node.name)
+                                .map(|f| fcx.field_ty(expr.span, f, substs))
                     }
                     _ => None
                 }
@@ -2919,8 +2973,8 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                             actual)
                 },
                 expr_t, None);
-            if let ty::TyStruct(did, _) = expr_t.sty {
-                suggest_field_names(did, field, tcx, vec![]);
+            if let ty::TyStruct(def, _) = expr_t.sty {
+                suggest_field_names(def.struct_variant(), field, tcx, vec![]);
             }
         }
 
@@ -2928,23 +2982,22 @@ fn check_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     }
 
     // displays hints about the closest matches in field names
-    fn suggest_field_names<'tcx>(id : DefId,
-                                 field : &ast::SpannedIdent,
-                                 tcx : &ty::ctxt<'tcx>,
+    fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>,
+                                 field: &ast::SpannedIdent,
+                                 tcx: &ty::ctxt<'tcx>,
                                  skip : Vec<InternedString>) {
         let name = field.node.name.as_str();
         // only find fits with at least one matching letter
         let mut best_dist = name.len();
-        let fields = tcx.lookup_struct_fields(id);
         let mut best = None;
-        for elem in &fields {
+        for elem in &variant.fields {
             let n = elem.name.as_str();
             // ignore already set fields
             if skip.iter().any(|x| *x == n) {
                 continue;
             }
             // ignore private fields from non-local crates
-            if id.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public {
+            if variant.did.krate != ast::LOCAL_CRATE && elem.vis != Visibility::Public {
                 continue;
             }
             let dist = lev_distance(&n, &name);
@@ -2965,7 +3018,6 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                 lvalue_pref: LvaluePreference,
                                 base: &'tcx ast::Expr,
                                 idx: codemap::Spanned<usize>) {
-        let tcx = fcx.ccx.tcx;
         check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
         let expr_t = structurally_resolved_type(fcx, expr.span,
                                                 fcx.expr_ty(base));
@@ -2979,13 +3031,14 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                                   lvalue_pref,
                                                   |base_t, _| {
                 match base_t.sty {
-                    ty::TyStruct(base_id, substs) => {
-                        tuple_like = tcx.is_tuple_struct(base_id);
+                    ty::TyStruct(base_def, substs) => {
+                        tuple_like = base_def.struct_variant().is_tuple_struct();
                         if tuple_like {
                             debug!("tuple struct named {:?}",  base_t);
-                            let fields = tcx.lookup_struct_fields(base_id);
-                            fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..],
-                                                    idx.node, &(*substs))
+                            base_def.struct_variant()
+                                    .fields
+                                    .get(idx.node)
+                                    .map(|f| fcx.field_ty(expr.span, f, substs))
                         } else {
                             None
                         }
@@ -3025,75 +3078,62 @@ fn check_tup_field<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         fcx.write_error(expr.id);
     }
 
-    fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                                struct_ty: Ty<'tcx>,
-                                                span: Span,
-                                                class_id: ast::DefId,
-                                                node_id: ast::NodeId,
-                                                substitutions: &'tcx subst::Substs<'tcx>,
-                                                field_types: &[ty::FieldTy],
-                                                ast_fields: &'tcx [ast::Field],
-                                                check_completeness: bool,
-                                                enum_id_opt: Option<ast::DefId>)  {
+    fn report_unknown_field<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                      ty: Ty<'tcx>,
+                                      variant: ty::VariantDef<'tcx>,
+                                      field: &ast::Field,
+                                      skip_fields: &[ast::Field]) {
+        fcx.type_error_message(
+            field.ident.span,
+            |actual| if let ty::TyEnum(..) = ty.sty {
+                format!("struct variant `{}::{}` has no field named `{}`",
+                        actual, variant.name.as_str(), field.ident.node)
+            } else {
+                format!("structure `{}` has no field named `{}`",
+                        actual, field.ident.node)
+            },
+            ty,
+            None);
+        // prevent all specified fields from being suggested
+        let skip_fields = skip_fields.iter().map(|ref x| x.ident.node.name.as_str());
+        suggest_field_names(variant, &field.ident, fcx.tcx(), skip_fields.collect());
+    }
+
+
+    fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                          adt_ty: Ty<'tcx>,
+                                          span: Span,
+                                          variant: ty::VariantDef<'tcx>,
+                                          ast_fields: &'tcx [ast::Field],
+                                          check_completeness: bool) {
         let tcx = fcx.ccx.tcx;
+        let substs = match adt_ty.sty {
+            ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+            _ => tcx.sess.span_bug(span, "non-ADT passed to check_expr_struct_fields")
+        };
 
-        let mut class_field_map = FnvHashMap();
-        let mut fields_found = 0;
-        for field in field_types {
-            class_field_map.insert(field.name, (field.id, false));
+        let mut remaining_fields = FnvHashMap();
+        for field in &variant.fields {
+            remaining_fields.insert(field.name, field);
         }
 
         let mut error_happened = false;
 
         // Typecheck each field.
         for field in ast_fields {
-            let mut expected_field_type = tcx.types.err;
-
-            let pair = class_field_map.get(&field.ident.node.name).cloned();
-            match pair {
-                None => {
-                    fcx.type_error_message(
-                        field.ident.span,
-                        |actual| match enum_id_opt {
-                            Some(enum_id) => {
-                                let variant_type = tcx.enum_variant_with_id(enum_id,
-                                                                            class_id);
-                                format!("struct variant `{}::{}` has no field named `{}`",
-                                        actual, variant_type.name.as_str(),
-                                        field.ident.node)
-                            }
-                            None => {
-                                format!("structure `{}` has no field named `{}`",
-                                        actual,
-                                        field.ident.node)
-                            }
-                        },
-                        struct_ty,
-                        None);
-                    // prevent all specified fields from being suggested
-                    let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str());
-                    let actual_id = match enum_id_opt {
-                        Some(_) => class_id,
-                        None => struct_ty.ty_to_def_id().unwrap()
-                    };
-                    suggest_field_names(actual_id, &field.ident, tcx, skip_fields.collect());
-                    error_happened = true;
-                }
-                Some((_, true)) => {
+            let expected_field_type;
+
+            if let Some(v_field) = remaining_fields.remove(&field.ident.node.name) {
+                expected_field_type = fcx.field_ty(field.span, v_field, substs);
+            } else {
+                error_happened = true;
+                expected_field_type = tcx.types.err;
+                if let Some(_) = variant.find_field_named(field.ident.node.name) {
                     span_err!(fcx.tcx().sess, field.ident.span, E0062,
                         "field `{}` specified more than once",
                         field.ident.node);
-                    error_happened = true;
-                }
-                Some((field_id, false)) => {
-                    expected_field_type =
-                        tcx.lookup_field_type(class_id, field_id, substitutions);
-                    expected_field_type =
-                        fcx.normalize_associated_types_in(
-                            field.span, &expected_field_type);
-                    class_field_map.insert(
-                        field.ident.node.name, (field_id, true));
-                    fields_found += 1;
+                } else {
+                    report_unknown_field(fcx, adt_ty, variant, field, ast_fields);
                 }
             }
 
@@ -3102,106 +3142,19 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type);
         }
 
-        if error_happened {
-            fcx.write_error(node_id);
-        }
-
-        if check_completeness && !error_happened {
             // Make sure the programmer specified all the fields.
-            assert!(fields_found <= field_types.len());
-            if fields_found < field_types.len() {
-                let mut missing_fields = Vec::new();
-                for class_field in field_types {
-                    let name = class_field.name;
-                    let (_, seen) = *class_field_map.get(&name).unwrap();
-                    if !seen {
-                        missing_fields.push(
-                            format!("`{}`", name))
-                    }
-                }
-
-                span_err!(tcx.sess, span, E0063,
-                    "missing field{}: {}",
-                    if missing_fields.len() == 1 {""} else {"s"},
-                    missing_fields.join(", "));
-             }
-        }
-
-        if !error_happened {
-            fcx.write_ty(node_id, fcx.ccx.tcx.mk_struct(class_id, substitutions));
-        }
-    }
-
-    fn check_struct_constructor<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                         id: ast::NodeId,
-                                         span: codemap::Span,
-                                         class_id: ast::DefId,
-                                         fields: &'tcx [ast::Field],
-                                         base_expr: Option<&'tcx ast::Expr>) {
-        let tcx = fcx.ccx.tcx;
-
-        // Generate the struct type.
-        let TypeAndSubsts {
-            ty: mut struct_type,
-            substs: struct_substs
-        } = fcx.instantiate_type(span, class_id);
-
-        // Look up and check the fields.
-        let class_fields = tcx.lookup_struct_fields(class_id);
-        check_struct_or_variant_fields(fcx,
-                                       struct_type,
-                                       span,
-                                       class_id,
-                                       id,
-                                       fcx.ccx.tcx.mk_substs(struct_substs),
-                                       &class_fields[..],
-                                       fields,
-                                       base_expr.is_none(),
-                                       None);
-        if fcx.node_ty(id).references_error() {
-            struct_type = tcx.types.err;
-        }
-
-        // Check the base expression if necessary.
-        match base_expr {
-            None => {}
-            Some(base_expr) => {
-                check_expr_has_type(fcx, &*base_expr, struct_type);
-            }
+        if check_completeness &&
+            !error_happened &&
+            !remaining_fields.is_empty()
+        {
+            span_err!(tcx.sess, span, E0063,
+                      "missing field{}: {}",
+                      if remaining_fields.len() == 1 {""} else {"s"},
+                      remaining_fields.keys()
+                                      .map(|n| format!("`{}`", n))
+                                      .collect::<Vec<_>>()
+                                      .join(", "));
         }
-
-        // Write in the resulting type.
-        fcx.write_ty(id, struct_type);
-    }
-
-    fn check_struct_enum_variant<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
-                                          id: ast::NodeId,
-                                          span: codemap::Span,
-                                          enum_id: ast::DefId,
-                                          variant_id: ast::DefId,
-                                          fields: &'tcx [ast::Field]) {
-        let tcx = fcx.ccx.tcx;
-
-        // Look up the number of type parameters and the raw type, and
-        // determine whether the enum is region-parameterized.
-        let TypeAndSubsts {
-            ty: enum_type,
-            substs: substitutions
-        } = fcx.instantiate_type(span, enum_id);
-
-        // Look up and check the enum variant fields.
-        let variant_fields = tcx.lookup_struct_fields(variant_id);
-        check_struct_or_variant_fields(fcx,
-                                       enum_type,
-                                       span,
-                                       variant_id,
-                                       id,
-                                       fcx.ccx.tcx.mk_substs(substitutions),
-                                       &variant_fields[..],
-                                       fields,
-                                       true,
-                                       Some(enum_id));
-        fcx.write_ty(id, enum_type);
     }
 
     fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@@ -3220,6 +3173,42 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         }
     }
 
+    fn check_expr_struct<'a, 'tcx>(fcx: &FnCtxt<'a,'tcx>,
+                                   expr: &ast::Expr,
+                                   path: &ast::Path,
+                                   fields: &'tcx [ast::Field],
+                                   base_expr: &'tcx Option<P<ast::Expr>>)
+    {
+        let tcx = fcx.tcx();
+
+        // Find the relevant variant
+        let def = lookup_full_def(tcx, path.span, expr.id);
+        let (adt, variant) = match fcx.def_struct_variant(def) {
+            Some((adt, variant)) => (adt, variant),
+            None => {
+                span_err!(fcx.tcx().sess, path.span, E0071,
+                          "`{}` does not name a structure",
+                          pprust::path_to_string(path));
+                check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
+                return;
+            }
+        };
+
+        let expr_ty = fcx.instantiate_type(def.def_id(), path);
+        fcx.write_ty(expr.id, expr_ty);
+
+        check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
+                                 base_expr.is_none());
+
+        if let &Some(ref base_expr) = base_expr {
+            check_expr_has_type(fcx, base_expr, expr_ty);
+            if adt.adt_kind() == ty::AdtKind::Enum {
+                span_err!(tcx.sess, base_expr.span, E0436,
+                          "functional record update syntax requires a struct");
+            }
+        }
+    }
+
     type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, Ty);
 
     let tcx = fcx.ccx.tcx;
@@ -3415,7 +3404,9 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
-          constrain_path_type_parameters(fcx, expr);
+          fcx.opt_node_ty_substs(expr.id, |item_substs| {
+              fcx.add_wf_bounds(&item_substs.substs, expr);
+          });
       }
       ast::ExprInlineAsm(ref ia) => {
           for &(_, ref input) in &ia.inputs {
@@ -3528,16 +3519,18 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
       }
       ast::ExprCall(ref callee, ref args) => {
           callee::check_call(fcx, expr, &**callee, &args[..], expected);
+
+          // we must check that return type of called functions is WF:
+          let ret_ty = fcx.expr_ty(expr);
+          fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
       }
       ast::ExprMethodCall(ident, ref tps, ref args) => {
-        check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref);
-        let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
-        let  args_err = arg_tys.fold(false,
-             |rest_err, a| {
-              rest_err || a.references_error()});
-        if args_err {
-            fcx.write_error(id);
-        }
+          check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref);
+          let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
+          let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
+          if args_err {
+              fcx.write_error(id);
+          }
       }
       ast::ExprCast(ref e, ref t) => {
         if let ast::TyFixedLengthVec(_, ref count_expr) = t.node {
@@ -3668,83 +3661,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
         }
       }
       ast::ExprStruct(ref path, ref fields, ref base_expr) => {
-        // Resolve the path.
-        let def = lookup_full_def(tcx, path.span, id);
-        let struct_id = match def {
-            def::DefVariant(enum_id, variant_id, true) => {
-                if let &Some(ref base_expr) = base_expr {
-                    span_err!(tcx.sess, base_expr.span, E0436,
-                              "functional record update syntax requires a struct");
-                    fcx.write_error(base_expr.id);
-                }
-                check_struct_enum_variant(fcx, id, expr.span, enum_id,
-                                          variant_id, &fields[..]);
-                enum_id
-            }
-            def::DefTrait(def_id) => {
-                span_err!(tcx.sess, path.span, E0159,
-                    "use of trait `{}` as a struct constructor",
-                    pprust::path_to_string(path));
-                check_struct_fields_on_error(fcx,
-                                             id,
-                                             &fields[..],
-                                             base_expr);
-                def_id
-            },
-            def => {
-                // Verify that this was actually a struct.
-                let typ = fcx.ccx.tcx.lookup_item_type(def.def_id());
-                match typ.ty.sty {
-                    ty::TyStruct(struct_did, _) => {
-                        check_struct_constructor(fcx,
-                                                 id,
-                                                 expr.span,
-                                                 struct_did,
-                                                 &fields[..],
-                                                 base_expr.as_ref().map(|e| &**e));
-                    }
-                    _ => {
-                        span_err!(tcx.sess, path.span, E0071,
-                            "`{}` does not name a structure",
-                            pprust::path_to_string(path));
-                        check_struct_fields_on_error(fcx,
-                                                     id,
-                                                     &fields[..],
-                                                     base_expr);
-                    }
-                }
-
-                def.def_id()
-            }
-        };
-
-        // Turn the path into a type and verify that that type unifies with
-        // the resulting structure type. This is needed to handle type
-        // parameters correctly.
-        let actual_structure_type = fcx.expr_ty(&*expr);
-        if !actual_structure_type.references_error() {
-            let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path);
-            match fcx.mk_subty(false,
-                               infer::Misc(path.span),
-                               actual_structure_type,
-                               type_and_substs.ty) {
-                Ok(()) => {}
-                Err(type_error) => {
-                    span_err!(fcx.tcx().sess, path.span, E0235,
-                                 "structure constructor specifies a \
-                                         structure of type `{}`, but this \
-                                         structure has type `{}`: {}",
-                                         fcx.infcx()
-                                            .ty_to_string(type_and_substs.ty),
-                                         fcx.infcx()
-                                            .ty_to_string(
-                                                actual_structure_type),
-                                         type_error);
-                    tcx.note_and_explain_type_err(&type_error, path.span);
-                }
-            }
-        }
-
+        check_expr_struct(fcx, expr, path, fields, base_expr);
         fcx.require_expr_have_sized_type(expr, traits::StructInitializerSized);
       }
       ast::ExprField(ref base, ref field) => {
@@ -3835,6 +3752,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                 };
 
                 if let Some(did) = did {
+                    let def = tcx.lookup_adt_def(did);
                     let predicates = tcx.lookup_predicates(did);
                     let substs = Substs::new_type(vec![idx_type], vec![]);
                     let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates);
@@ -3844,7 +3762,7 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                                      traits::ItemObligation(did)),
                         &bounds);
 
-                    tcx.mk_struct(did, tcx.mk_substs(substs))
+                    tcx.mk_struct(def, tcx.mk_substs(substs))
                 } else {
                     span_err!(tcx.sess, expr.span, E0236, "no lang item for range syntax");
                     fcx.tcx().types.err
@@ -3853,8 +3771,10 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
             None => {
                 // Neither start nor end => RangeFull
                 if let Some(did) = tcx.lang_items.range_full_struct() {
-                    let substs = Substs::new_type(vec![], vec![]);
-                    tcx.mk_struct(did, tcx.mk_substs(substs))
+                    tcx.mk_struct(
+                        tcx.lookup_adt_def(did),
+                        tcx.mk_substs(Substs::empty())
+                    )
                 } else {
                     span_err!(tcx.sess, expr.span, E0237, "no lang item for range syntax");
                     fcx.tcx().types.err
@@ -3953,14 +3873,6 @@ fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 }
 
-fn constrain_path_type_parameters(fcx: &FnCtxt,
-                                  expr: &ast::Expr)
-{
-    fcx.opt_node_ty_substs(expr.id, |item_substs| {
-        fcx.add_default_region_param_bounds(&item_substs.substs, expr);
-    });
-}
-
 impl<'tcx> Expectation<'tcx> {
     /// Provide an expectation for an rvalue expression given an *optional*
     /// hint, which is not required for type safety (the resulting type might
@@ -4305,15 +4217,14 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
         return;
     }
     match t.sty {
-        ty::TyStruct(did, substs) => {
-            let fields = tcx.lookup_struct_fields(did);
+        ty::TyStruct(def, substs) => {
+            let fields = &def.struct_variant().fields;
             if fields.is_empty() {
                 span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
                 return;
             }
-            let e = tcx.lookup_field_type(did, fields[0].id, substs);
-            if !fields.iter().all(
-                         |f| tcx.lookup_field_type(did, f.id, substs) == e) {
+            let e = fields[0].ty(tcx, substs);
+            if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
                 span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous");
                 return;
             }
@@ -4381,10 +4292,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         let def_id = local_def(id);
 
-        // ty::enum_variants guards against discriminant overflows, so
-        // we need not check for that.
-        let variants = ccx.tcx.enum_variants(def_id);
-
+        let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
         for (v, variant) in vs.iter().zip(variants.iter()) {
             let current_disr_val = variant.disr_val;
 
@@ -4393,7 +4301,7 @@ fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 Some(i) => {
                     span_err!(ccx.tcx.sess, v.span, E0081,
                         "discriminant value `{}` already exists", disr_vals[i]);
-                    span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].id.node),
+                    span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node),
                         "conflicting discriminant here")
                 }
                 None => {}
@@ -4733,6 +4641,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         }
     }
 
+    debug!("instantiate_path: type of {:?} is {:?}",
+           node_id,
+           ty_substituted);
     fcx.write_ty(node_id, ty_substituted);
     fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
     return;