about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-06-15 03:32:16 +0200
committerMazdak Farrokhzad <twingoow@gmail.com>2019-06-15 04:01:39 +0200
commit5057552dc6e8b4d259edcb080c525056da46efa3 (patch)
treec599fec62088cda074498eecff597e724ba6297c
parent5ee36b7ecafc873ae15c4a4aa74f8293103b14c9 (diff)
downloadrust-5057552dc6e8b4d259edcb080c525056da46efa3.tar.gz
rust-5057552dc6e8b4d259edcb080c525056da46efa3.zip
typeck/expr.rs: move check_field + struct helpers here.
-rw-r--r--src/librustc_typeck/check/expr.rs411
-rw-r--r--src/librustc_typeck/check/mod.rs409
2 files changed, 412 insertions, 408 deletions
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index b133526054f..fa9e0d8a857 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -15,12 +15,15 @@ use crate::check::TupleArgumentsFlag::DontTupleArguments;
 use crate::check::method::SelfSource;
 use crate::middle::lang_items;
 use crate::util::common::ErrorReported;
+use crate::util::nodemap::FxHashMap;
+use crate::astconv::AstConv as _;
 
-use errors::Applicability;
+use errors::{Applicability, DiagnosticBuilder};
 use syntax::ast;
 use syntax::ptr::P;
-use syntax::symbol::{kw, sym};
+use syntax::symbol::{Symbol, LocalInternedString, kw, sym};
 use syntax::source_map::Span;
+use syntax::util::lev_distance::find_best_match_for_name;
 use rustc::hir;
 use rustc::hir::{ExprKind, QPath};
 use rustc::hir::def::{CtorKind, Res, DefKind};
@@ -31,11 +34,14 @@ use rustc::ty;
 use rustc::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
+use rustc::ty::{AdtKind, Visibility};
 use rustc::ty::Ty;
 use rustc::ty::TypeFoldable;
 use rustc::ty::subst::InternalSubsts;
 use rustc::traits::{self, ObligationCauseCode};
 
+use std::fmt::Display;
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_expr_eq_type(&self, expr: &'tcx hir::Expr, expected: Ty<'tcx>) {
         let ty = self.check_expr_with_hint(expr, expected);
@@ -1057,6 +1063,407 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         adt_ty
     }
 
+    fn check_expr_struct_fields(
+        &self,
+        adt_ty: Ty<'tcx>,
+        expected: Expectation<'tcx>,
+        expr_id: hir::HirId,
+        span: Span,
+        variant: &'tcx ty::VariantDef,
+        ast_fields: &'tcx [hir::Field],
+        check_completeness: bool,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let adt_ty_hint =
+            self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty])
+                .get(0).cloned().unwrap_or(adt_ty);
+        // re-link the regions that EIfEO can erase.
+        self.demand_eqtype(span, adt_ty_hint, adt_ty);
+
+        let (substs, adt_kind, kind_name) = match &adt_ty.sty {
+            &ty::Adt(adt, substs) => {
+                (substs, adt.adt_kind(), adt.variant_descr())
+            }
+            _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
+        };
+
+        let mut remaining_fields = variant.fields.iter().enumerate().map(|(i, field)|
+            (field.ident.modern(), (i, field))
+        ).collect::<FxHashMap<_, _>>();
+
+        let mut seen_fields = FxHashMap::default();
+
+        let mut error_happened = false;
+
+        // Type-check each field.
+        for field in ast_fields {
+            let ident = tcx.adjust_ident(field.ident, variant.def_id);
+            let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
+                seen_fields.insert(ident, field.span);
+                self.write_field_index(field.hir_id, i);
+
+                // We don't look at stability attributes on
+                // struct-like enums (yet...), but it's definitely not
+                // a bug to have constructed one.
+                if adt_kind != AdtKind::Enum {
+                    tcx.check_stability(v_field.did, Some(expr_id), field.span);
+                }
+
+                self.field_ty(field.span, v_field, substs)
+            } else {
+                error_happened = true;
+                if let Some(prev_span) = seen_fields.get(&ident) {
+                    let mut err = struct_span_err!(self.tcx.sess,
+                                                   field.ident.span,
+                                                   E0062,
+                                                   "field `{}` specified more than once",
+                                                   ident);
+
+                    err.span_label(field.ident.span, "used more than once");
+                    err.span_label(*prev_span, format!("first use of `{}`", ident));
+
+                    err.emit();
+                } else {
+                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name);
+                }
+
+                tcx.types.err
+            };
+
+            // Make sure to give a type to the field even if there's
+            // an error, so we can continue type-checking.
+            self.check_expr_coercable_to_type(&field.expr, field_type);
+        }
+
+        // Make sure the programmer specified correct number of fields.
+        if kind_name == "union" {
+            if ast_fields.len() != 1 {
+                tcx.sess.span_err(span, "union expressions should have exactly one field");
+            }
+        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+            let len = remaining_fields.len();
+
+            let mut displayable_field_names = remaining_fields
+                                              .keys()
+                                              .map(|ident| ident.as_str())
+                                              .collect::<Vec<_>>();
+
+            displayable_field_names.sort();
+
+            let truncated_fields_error = if len <= 3 {
+                String::new()
+            } else {
+                format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"})
+            };
+
+            let remaining_fields_names = displayable_field_names.iter().take(3)
+                                        .map(|n| format!("`{}`", n))
+                                        .collect::<Vec<_>>()
+                                        .join(", ");
+
+            struct_span_err!(tcx.sess, span, E0063,
+                             "missing field{} {}{} in initializer of `{}`",
+                             if remaining_fields.len() == 1 { "" } else { "s" },
+                             remaining_fields_names,
+                             truncated_fields_error,
+                             adt_ty)
+                .span_label(span, format!("missing {}{}",
+                                          remaining_fields_names,
+                                          truncated_fields_error))
+                .emit();
+        }
+        error_happened
+    }
+
+    fn check_struct_fields_on_error(
+        &self,
+        fields: &'tcx [hir::Field],
+        base_expr: &'tcx Option<P<hir::Expr>>,
+    ) {
+        for field in fields {
+            self.check_expr(&field.expr);
+        }
+        if let Some(ref base) = *base_expr {
+            self.check_expr(&base);
+        }
+    }
+
+    fn report_unknown_field(
+        &self,
+        ty: Ty<'tcx>,
+        variant: &'tcx ty::VariantDef,
+        field: &hir::Field,
+        skip_fields: &[hir::Field],
+        kind_name: &str,
+    ) {
+        if variant.recovered {
+            return;
+        }
+        let mut err = self.type_error_struct_with_diag(
+            field.ident.span,
+            |actual| match ty.sty {
+                ty::Adt(adt, ..) if adt.is_enum() => {
+                    struct_span_err!(self.tcx.sess, field.ident.span, E0559,
+                                     "{} `{}::{}` has no field named `{}`",
+                                     kind_name, actual, variant.ident, field.ident)
+                }
+                _ => {
+                    struct_span_err!(self.tcx.sess, field.ident.span, E0560,
+                                     "{} `{}` has no field named `{}`",
+                                     kind_name, actual, field.ident)
+                }
+            },
+            ty);
+        // prevent all specified fields from being suggested
+        let skip_fields = skip_fields.iter().map(|ref x| x.ident.as_str());
+        if let Some(field_name) = Self::suggest_field_name(variant,
+                                                           &field.ident.as_str(),
+                                                           skip_fields.collect()) {
+            err.span_suggestion(
+                field.ident.span,
+                "a field with a similar name exists",
+                field_name.to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            match ty.sty {
+                ty::Adt(adt, ..) => {
+                    if adt.is_enum() {
+                        err.span_label(field.ident.span,
+                                       format!("`{}::{}` does not have this field",
+                                               ty, variant.ident));
+                    } else {
+                        err.span_label(field.ident.span,
+                                       format!("`{}` does not have this field", ty));
+                    }
+                    let available_field_names = self.available_field_names(variant);
+                    if !available_field_names.is_empty() {
+                        err.note(&format!("available fields are: {}",
+                                          self.name_series_display(available_field_names)));
+                    }
+                }
+                _ => bug!("non-ADT passed to report_unknown_field")
+            }
+        };
+        err.emit();
+    }
+
+    // Return an hint about the closest match in field names
+    fn suggest_field_name(variant: &'tcx ty::VariantDef,
+                          field: &str,
+                          skip: Vec<LocalInternedString>)
+                          -> Option<Symbol> {
+        let names = variant.fields.iter().filter_map(|field| {
+            // ignore already set fields and private fields from non-local crates
+            if skip.iter().any(|x| *x == field.ident.as_str()) ||
+               (!variant.def_id.is_local() && field.vis != Visibility::Public)
+            {
+                None
+            } else {
+                Some(&field.ident.name)
+            }
+        });
+
+        find_best_match_for_name(names, field, None)
+    }
+
+    fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<ast::Name> {
+        variant.fields.iter().filter(|field| {
+            let def_scope =
+                self.tcx.adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id).1;
+            field.vis.is_accessible_from(def_scope, self.tcx)
+        })
+        .map(|field| field.ident.name)
+        .collect()
+    }
+
+    fn name_series_display(&self, names: Vec<ast::Name>) -> String {
+        // dynamic limit, to never omit just one field
+        let limit = if names.len() == 6 { 6 } else { 5 };
+        let mut display = names.iter().take(limit)
+            .map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
+        if names.len() > limit {
+            display = format!("{} ... and {} others", display, names.len() - limit);
+        }
+        display
+    }
+
+    // Check field access expressions
+    fn check_field(
+        &self,
+        expr: &'tcx hir::Expr,
+        needs: Needs,
+        base: &'tcx hir::Expr,
+        field: ast::Ident,
+    ) -> Ty<'tcx> {
+        let expr_t = self.check_expr_with_needs(base, needs);
+        let expr_t = self.structurally_resolved_type(base.span,
+                                                     expr_t);
+        let mut private_candidate = None;
+        let mut autoderef = self.autoderef(expr.span, expr_t);
+        while let Some((base_t, _)) = autoderef.next() {
+            match base_t.sty {
+                ty::Adt(base_def, substs) if !base_def.is_enum() => {
+                    debug!("struct named {:?}",  base_t);
+                    let (ident, def_scope) =
+                        self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
+                    let fields = &base_def.non_enum_variant().fields;
+                    if let Some(index) = fields.iter().position(|f| f.ident.modern() == ident) {
+                        let field = &fields[index];
+                        let field_ty = self.field_ty(expr.span, field, substs);
+                        // Save the index of all fields regardless of their visibility in case
+                        // of error recovery.
+                        self.write_field_index(expr.hir_id, index);
+                        if field.vis.is_accessible_from(def_scope, self.tcx) {
+                            let adjustments = autoderef.adjust_steps(self, needs);
+                            self.apply_adjustments(base, adjustments);
+                            autoderef.finalize(self);
+
+                            self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
+                            return field_ty;
+                        }
+                        private_candidate = Some((base_def.did, field_ty));
+                    }
+                }
+                ty::Tuple(ref tys) => {
+                    let fstr = field.as_str();
+                    if let Ok(index) = fstr.parse::<usize>() {
+                        if fstr == index.to_string() {
+                            if let Some(field_ty) = tys.get(index) {
+                                let adjustments = autoderef.adjust_steps(self, needs);
+                                self.apply_adjustments(base, adjustments);
+                                autoderef.finalize(self);
+
+                                self.write_field_index(expr.hir_id, index);
+                                return field_ty.expect_ty();
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+        autoderef.unambiguous_final_ty(self);
+
+        if let Some((did, field_ty)) = private_candidate {
+            let struct_path = self.tcx().def_path_str(did);
+            let mut err = struct_span_err!(self.tcx().sess, expr.span, E0616,
+                                           "field `{}` of struct `{}` is private",
+                                           field, struct_path);
+            // Also check if an accessible method exists, which is often what is meant.
+            if self.method_exists(field, expr_t, expr.hir_id, false)
+                && !self.expr_in_place(expr.hir_id)
+            {
+                self.suggest_method_call(
+                    &mut err,
+                    &format!("a method `{}` also exists, call it with parentheses", field),
+                    field,
+                    expr_t,
+                    expr.hir_id,
+                );
+            }
+            err.emit();
+            field_ty
+        } else if field.name == kw::Invalid {
+            self.tcx().types.err
+        } else if self.method_exists(field, expr_t, expr.hir_id, true) {
+            let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
+                               "attempted to take value of method `{}` on type `{}`",
+                               field, expr_t);
+
+            if !self.expr_in_place(expr.hir_id) {
+                self.suggest_method_call(
+                    &mut err,
+                    "use parentheses to call the method",
+                    field,
+                    expr_t,
+                    expr.hir_id
+                );
+            } else {
+                err.help("methods are immutable and cannot be assigned to");
+            }
+
+            err.emit();
+            self.tcx().types.err
+        } else {
+            if !expr_t.is_primitive_ty() {
+                let mut err = self.no_such_field_err(field.span, field, expr_t);
+
+                match expr_t.sty {
+                    ty::Adt(def, _) if !def.is_enum() => {
+                        if let Some(suggested_field_name) =
+                            Self::suggest_field_name(def.non_enum_variant(),
+                                                     &field.as_str(), vec![]) {
+                                err.span_suggestion(
+                                    field.span,
+                                    "a field with a similar name exists",
+                                    suggested_field_name.to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_label(field.span, "unknown field");
+                                let struct_variant_def = def.non_enum_variant();
+                                let field_names = self.available_field_names(struct_variant_def);
+                                if !field_names.is_empty() {
+                                    err.note(&format!("available fields are: {}",
+                                                      self.name_series_display(field_names)));
+                                }
+                            };
+                    }
+                    ty::Array(_, len) => {
+                        if let (Some(len), Ok(user_index)) = (
+                            len.assert_usize(self.tcx),
+                            field.as_str().parse::<u64>()
+                        ) {
+                            let base = self.tcx.sess.source_map()
+                                .span_to_snippet(base.span)
+                                .unwrap_or_else(|_|
+                                    self.tcx.hir().hir_to_pretty_string(base.hir_id));
+                            let help = "instead of using tuple indexing, use array indexing";
+                            let suggestion = format!("{}[{}]", base, field);
+                            let applicability = if len < user_index {
+                                Applicability::MachineApplicable
+                            } else {
+                                Applicability::MaybeIncorrect
+                            };
+                            err.span_suggestion(
+                                expr.span, help, suggestion, applicability
+                            );
+                        }
+                    }
+                    ty::RawPtr(..) => {
+                        let base = self.tcx.sess.source_map()
+                            .span_to_snippet(base.span)
+                            .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id));
+                        let msg = format!("`{}` is a raw pointer; try dereferencing it", base);
+                        let suggestion = format!("(*{}).{}", base, field);
+                        err.span_suggestion(
+                            expr.span,
+                            &msg,
+                            suggestion,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {}
+                }
+                err
+            } else {
+                type_error_struct!(self.tcx().sess, field.span, expr_t, E0610,
+                                   "`{}` is a primitive type and therefore doesn't have fields",
+                                   expr_t)
+            }.emit();
+            self.tcx().types.err
+        }
+    }
+
+    fn no_such_field_err<T: Display>(&self, span: Span, field: T, expr_t: &ty::TyS<'_>)
+        -> DiagnosticBuilder<'_> {
+        type_error_struct!(self.tcx().sess, span, expr_t, E0609,
+                           "no field `{}` on type `{}`",
+                           field, expr_t)
+    }
+
     fn check_expr_index(
         &self,
         base: &'tcx hir::Expr,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ae894a11452..4c8ad66441f 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -106,7 +106,7 @@ use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{
-    self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind, Visibility,
+    self, AdtKind, CanonicalUserType, Ty, TyCtxt, Const, GenericParamDefKind,
     ToPolyTraitRef, ToPredicate, RegionKind, UserType
 };
 use rustc::ty::adjustment::{
@@ -124,13 +124,11 @@ use syntax::attr;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use syntax::source_map::{DUMMY_SP, original_sp};
-use syntax::symbol::{Symbol, LocalInternedString, kw, sym};
-use syntax::util::lev_distance::find_best_match_for_name;
+use syntax::symbol::{kw, sym};
 
 use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::collections::hash_map::Entry;
 use std::cmp;
-use std::fmt::Display;
 use std::iter;
 use std::mem::replace;
 use std::ops::{self, Deref};
@@ -143,7 +141,7 @@ use crate::TypeAndSubsts;
 use crate::lint;
 use crate::util::captures::Captures;
 use crate::util::common::{ErrorReported, indenter};
-use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, HirIdMap};
+use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashSet, HirIdMap};
 
 pub use self::Expectation::*;
 use self::autoderef::Autoderef;
@@ -3266,407 +3264,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expect_args
     }
 
-    // Check field access expressions
-    fn check_field(
-        &self,
-        expr: &'tcx hir::Expr,
-        needs: Needs,
-        base: &'tcx hir::Expr,
-        field: ast::Ident,
-    ) -> Ty<'tcx> {
-        let expr_t = self.check_expr_with_needs(base, needs);
-        let expr_t = self.structurally_resolved_type(base.span,
-                                                     expr_t);
-        let mut private_candidate = None;
-        let mut autoderef = self.autoderef(expr.span, expr_t);
-        while let Some((base_t, _)) = autoderef.next() {
-            match base_t.sty {
-                ty::Adt(base_def, substs) if !base_def.is_enum() => {
-                    debug!("struct named {:?}",  base_t);
-                    let (ident, def_scope) =
-                        self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
-                    let fields = &base_def.non_enum_variant().fields;
-                    if let Some(index) = fields.iter().position(|f| f.ident.modern() == ident) {
-                        let field = &fields[index];
-                        let field_ty = self.field_ty(expr.span, field, substs);
-                        // Save the index of all fields regardless of their visibility in case
-                        // of error recovery.
-                        self.write_field_index(expr.hir_id, index);
-                        if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            let adjustments = autoderef.adjust_steps(self, needs);
-                            self.apply_adjustments(base, adjustments);
-                            autoderef.finalize(self);
-
-                            self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span);
-                            return field_ty;
-                        }
-                        private_candidate = Some((base_def.did, field_ty));
-                    }
-                }
-                ty::Tuple(ref tys) => {
-                    let fstr = field.as_str();
-                    if let Ok(index) = fstr.parse::<usize>() {
-                        if fstr == index.to_string() {
-                            if let Some(field_ty) = tys.get(index) {
-                                let adjustments = autoderef.adjust_steps(self, needs);
-                                self.apply_adjustments(base, adjustments);
-                                autoderef.finalize(self);
-
-                                self.write_field_index(expr.hir_id, index);
-                                return field_ty.expect_ty();
-                            }
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-        autoderef.unambiguous_final_ty(self);
-
-        if let Some((did, field_ty)) = private_candidate {
-            let struct_path = self.tcx().def_path_str(did);
-            let mut err = struct_span_err!(self.tcx().sess, expr.span, E0616,
-                                           "field `{}` of struct `{}` is private",
-                                           field, struct_path);
-            // Also check if an accessible method exists, which is often what is meant.
-            if self.method_exists(field, expr_t, expr.hir_id, false)
-                && !self.expr_in_place(expr.hir_id)
-            {
-                self.suggest_method_call(
-                    &mut err,
-                    &format!("a method `{}` also exists, call it with parentheses", field),
-                    field,
-                    expr_t,
-                    expr.hir_id,
-                );
-            }
-            err.emit();
-            field_ty
-        } else if field.name == kw::Invalid {
-            self.tcx().types.err
-        } else if self.method_exists(field, expr_t, expr.hir_id, true) {
-            let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
-                               "attempted to take value of method `{}` on type `{}`",
-                               field, expr_t);
-
-            if !self.expr_in_place(expr.hir_id) {
-                self.suggest_method_call(
-                    &mut err,
-                    "use parentheses to call the method",
-                    field,
-                    expr_t,
-                    expr.hir_id
-                );
-            } else {
-                err.help("methods are immutable and cannot be assigned to");
-            }
-
-            err.emit();
-            self.tcx().types.err
-        } else {
-            if !expr_t.is_primitive_ty() {
-                let mut err = self.no_such_field_err(field.span, field, expr_t);
-
-                match expr_t.sty {
-                    ty::Adt(def, _) if !def.is_enum() => {
-                        if let Some(suggested_field_name) =
-                            Self::suggest_field_name(def.non_enum_variant(),
-                                                     &field.as_str(), vec![]) {
-                                err.span_suggestion(
-                                    field.span,
-                                    "a field with a similar name exists",
-                                    suggested_field_name.to_string(),
-                                    Applicability::MaybeIncorrect,
-                                );
-                            } else {
-                                err.span_label(field.span, "unknown field");
-                                let struct_variant_def = def.non_enum_variant();
-                                let field_names = self.available_field_names(struct_variant_def);
-                                if !field_names.is_empty() {
-                                    err.note(&format!("available fields are: {}",
-                                                      self.name_series_display(field_names)));
-                                }
-                            };
-                    }
-                    ty::Array(_, len) => {
-                        if let (Some(len), Ok(user_index)) = (
-                            len.assert_usize(self.tcx),
-                            field.as_str().parse::<u64>()
-                        ) {
-                            let base = self.tcx.sess.source_map()
-                                .span_to_snippet(base.span)
-                                .unwrap_or_else(|_|
-                                    self.tcx.hir().hir_to_pretty_string(base.hir_id));
-                            let help = "instead of using tuple indexing, use array indexing";
-                            let suggestion = format!("{}[{}]", base, field);
-                            let applicability = if len < user_index {
-                                Applicability::MachineApplicable
-                            } else {
-                                Applicability::MaybeIncorrect
-                            };
-                            err.span_suggestion(
-                                expr.span, help, suggestion, applicability
-                            );
-                        }
-                    }
-                    ty::RawPtr(..) => {
-                        let base = self.tcx.sess.source_map()
-                            .span_to_snippet(base.span)
-                            .unwrap_or_else(|_| self.tcx.hir().hir_to_pretty_string(base.hir_id));
-                        let msg = format!("`{}` is a raw pointer; try dereferencing it", base);
-                        let suggestion = format!("(*{}).{}", base, field);
-                        err.span_suggestion(
-                            expr.span,
-                            &msg,
-                            suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                    _ => {}
-                }
-                err
-            } else {
-                type_error_struct!(self.tcx().sess, field.span, expr_t, E0610,
-                                   "`{}` is a primitive type and therefore doesn't have fields",
-                                   expr_t)
-            }.emit();
-            self.tcx().types.err
-        }
-    }
-
-    // Return an hint about the closest match in field names
-    fn suggest_field_name(variant: &'tcx ty::VariantDef,
-                          field: &str,
-                          skip: Vec<LocalInternedString>)
-                          -> Option<Symbol> {
-        let names = variant.fields.iter().filter_map(|field| {
-            // ignore already set fields and private fields from non-local crates
-            if skip.iter().any(|x| *x == field.ident.as_str()) ||
-               (!variant.def_id.is_local() && field.vis != Visibility::Public)
-            {
-                None
-            } else {
-                Some(&field.ident.name)
-            }
-        });
-
-        find_best_match_for_name(names, field, None)
-    }
-
-    fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<ast::Name> {
-        variant.fields.iter().filter(|field| {
-            let def_scope =
-                self.tcx.adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id).1;
-            field.vis.is_accessible_from(def_scope, self.tcx)
-        })
-        .map(|field| field.ident.name)
-        .collect()
-    }
-
-    fn name_series_display(&self, names: Vec<ast::Name>) -> String {
-        // dynamic limit, to never omit just one field
-        let limit = if names.len() == 6 { 6 } else { 5 };
-        let mut display = names.iter().take(limit)
-            .map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", ");
-        if names.len() > limit {
-            display = format!("{} ... and {} others", display, names.len() - limit);
-        }
-        display
-    }
-
-    fn no_such_field_err<T: Display>(&self, span: Span, field: T, expr_t: &ty::TyS<'_>)
-        -> DiagnosticBuilder<'_> {
-        type_error_struct!(self.tcx().sess, span, expr_t, E0609,
-                           "no field `{}` on type `{}`",
-                           field, expr_t)
-    }
-
-    fn report_unknown_field(
-        &self,
-        ty: Ty<'tcx>,
-        variant: &'tcx ty::VariantDef,
-        field: &hir::Field,
-        skip_fields: &[hir::Field],
-        kind_name: &str,
-    ) {
-        if variant.recovered {
-            return;
-        }
-        let mut err = self.type_error_struct_with_diag(
-            field.ident.span,
-            |actual| match ty.sty {
-                ty::Adt(adt, ..) if adt.is_enum() => {
-                    struct_span_err!(self.tcx.sess, field.ident.span, E0559,
-                                     "{} `{}::{}` has no field named `{}`",
-                                     kind_name, actual, variant.ident, field.ident)
-                }
-                _ => {
-                    struct_span_err!(self.tcx.sess, field.ident.span, E0560,
-                                     "{} `{}` has no field named `{}`",
-                                     kind_name, actual, field.ident)
-                }
-            },
-            ty);
-        // prevent all specified fields from being suggested
-        let skip_fields = skip_fields.iter().map(|ref x| x.ident.as_str());
-        if let Some(field_name) = Self::suggest_field_name(variant,
-                                                           &field.ident.as_str(),
-                                                           skip_fields.collect()) {
-            err.span_suggestion(
-                field.ident.span,
-                "a field with a similar name exists",
-                field_name.to_string(),
-                Applicability::MaybeIncorrect,
-            );
-        } else {
-            match ty.sty {
-                ty::Adt(adt, ..) => {
-                    if adt.is_enum() {
-                        err.span_label(field.ident.span,
-                                       format!("`{}::{}` does not have this field",
-                                               ty, variant.ident));
-                    } else {
-                        err.span_label(field.ident.span,
-                                       format!("`{}` does not have this field", ty));
-                    }
-                    let available_field_names = self.available_field_names(variant);
-                    if !available_field_names.is_empty() {
-                        err.note(&format!("available fields are: {}",
-                                          self.name_series_display(available_field_names)));
-                    }
-                }
-                _ => bug!("non-ADT passed to report_unknown_field")
-            }
-        };
-        err.emit();
-    }
-
-    fn check_expr_struct_fields(
-        &self,
-        adt_ty: Ty<'tcx>,
-        expected: Expectation<'tcx>,
-        expr_id: hir::HirId,
-        span: Span,
-        variant: &'tcx ty::VariantDef,
-        ast_fields: &'tcx [hir::Field],
-        check_completeness: bool,
-    ) -> bool {
-        let tcx = self.tcx;
-
-        let adt_ty_hint =
-            self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty])
-                .get(0).cloned().unwrap_or(adt_ty);
-        // re-link the regions that EIfEO can erase.
-        self.demand_eqtype(span, adt_ty_hint, adt_ty);
-
-        let (substs, adt_kind, kind_name) = match &adt_ty.sty {
-            &ty::Adt(adt, substs) => {
-                (substs, adt.adt_kind(), adt.variant_descr())
-            }
-            _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
-        };
-
-        let mut remaining_fields = variant.fields.iter().enumerate().map(|(i, field)|
-            (field.ident.modern(), (i, field))
-        ).collect::<FxHashMap<_, _>>();
-
-        let mut seen_fields = FxHashMap::default();
-
-        let mut error_happened = false;
-
-        // Type-check each field.
-        for field in ast_fields {
-            let ident = tcx.adjust_ident(field.ident, variant.def_id);
-            let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
-                seen_fields.insert(ident, field.span);
-                self.write_field_index(field.hir_id, i);
-
-                // We don't look at stability attributes on
-                // struct-like enums (yet...), but it's definitely not
-                // a bug to have constructed one.
-                if adt_kind != AdtKind::Enum {
-                    tcx.check_stability(v_field.did, Some(expr_id), field.span);
-                }
-
-                self.field_ty(field.span, v_field, substs)
-            } else {
-                error_happened = true;
-                if let Some(prev_span) = seen_fields.get(&ident) {
-                    let mut err = struct_span_err!(self.tcx.sess,
-                                                   field.ident.span,
-                                                   E0062,
-                                                   "field `{}` specified more than once",
-                                                   ident);
-
-                    err.span_label(field.ident.span, "used more than once");
-                    err.span_label(*prev_span, format!("first use of `{}`", ident));
-
-                    err.emit();
-                } else {
-                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name);
-                }
-
-                tcx.types.err
-            };
-
-            // Make sure to give a type to the field even if there's
-            // an error, so we can continue type-checking.
-            self.check_expr_coercable_to_type(&field.expr, field_type);
-        }
-
-        // Make sure the programmer specified correct number of fields.
-        if kind_name == "union" {
-            if ast_fields.len() != 1 {
-                tcx.sess.span_err(span, "union expressions should have exactly one field");
-            }
-        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
-            let len = remaining_fields.len();
-
-            let mut displayable_field_names = remaining_fields
-                                              .keys()
-                                              .map(|ident| ident.as_str())
-                                              .collect::<Vec<_>>();
-
-            displayable_field_names.sort();
-
-            let truncated_fields_error = if len <= 3 {
-                String::new()
-            } else {
-                format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"})
-            };
-
-            let remaining_fields_names = displayable_field_names.iter().take(3)
-                                        .map(|n| format!("`{}`", n))
-                                        .collect::<Vec<_>>()
-                                        .join(", ");
-
-            struct_span_err!(tcx.sess, span, E0063,
-                             "missing field{} {}{} in initializer of `{}`",
-                             if remaining_fields.len() == 1 { "" } else { "s" },
-                             remaining_fields_names,
-                             truncated_fields_error,
-                             adt_ty)
-                .span_label(span, format!("missing {}{}",
-                                          remaining_fields_names,
-                                          truncated_fields_error))
-                .emit();
-        }
-        error_happened
-    }
-
-    fn check_struct_fields_on_error(
-        &self,
-        fields: &'tcx [hir::Field],
-        base_expr: &'tcx Option<P<hir::Expr>>,
-    ) {
-        for field in fields {
-            self.check_expr(&field.expr);
-        }
-        if let Some(ref base) = *base_expr {
-            self.check_expr(&base);
-        }
-    }
-
     pub fn check_struct_path(&self,
                              qpath: &QPath,
                              hir_id: hir::HirId)