]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
tidy
[rust.git] / src / librustc_typeck / check / mod.rs
index ca6bd21fefd39aa276b4fce028f10376722fcbca..b14aa8fcfb12fc63250ed20e851e595953e80390 100644 (file)
@@ -750,20 +750,20 @@ fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
 fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) {
     debug_assert!(crate_num == LOCAL_CRATE);
     tcx.par_body_owners(|body_owner_def_id| {
-        tcx.ensure().typeck_tables_of(body_owner_def_id.to_def_id());
+        tcx.ensure().typeck_tables_of(body_owner_def_id);
     });
 }
 
 fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) {
-    wfcheck::check_item_well_formed(tcx, def_id);
+    wfcheck::check_item_well_formed(tcx, def_id.expect_local());
 }
 
 fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) {
-    wfcheck::check_trait_item(tcx, def_id);
+    wfcheck::check_trait_item(tcx, def_id.expect_local());
 }
 
 fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: DefId) {
-    wfcheck::check_impl_item(tcx, def_id);
+    wfcheck::check_impl_item(tcx, def_id.expect_local());
 }
 
 pub fn provide(providers: &mut Providers<'_>) {
@@ -831,6 +831,13 @@ fn primary_body_of(
 }
 
 fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+    // FIXME(#71104) some `LocalDefId` do not seem to have a corresponding `HirId`.
+    if let Some(def_id) = def_id.as_local() {
+        if tcx.hir().opt_local_def_id_to_hir_id(def_id).is_none() {
+            return false;
+        }
+    }
+
     // Closures' tables come from their outermost function,
     // as they are part of the same "inference environment".
     let outer_def_id = tcx.closure_base_def_id(def_id);
@@ -838,11 +845,8 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         return tcx.has_typeck_tables(outer_def_id);
     }
 
-    // FIXME(#71104) Should really be using just `as_local_hir_id` but
-    // some `LocalDefId` do not seem to have a corresponding HirId.
-    if let Some(id) =
-        def_id.as_local().and_then(|def_id| tcx.hir().opt_local_def_id_to_hir_id(def_id))
-    {
+    if let Some(def_id) = def_id.as_local() {
+        let id = tcx.hir().local_def_id_to_hir_id(def_id);
         primary_body_of(tcx, id).is_some()
     } else {
         false
@@ -977,7 +981,7 @@ fn diagnostic_only_typeck_tables_of<'tcx>(
 ) -> &ty::TypeckTables<'tcx> {
     assert!(def_id.is_local());
     let fallback = move || {
-        let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id).unwrap());
+        let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id.expect_local()));
         tcx.sess.delay_span_bug(span, "diagnostic only typeck table used");
         tcx.types.err
     };
@@ -996,7 +1000,7 @@ fn typeck_tables_of_with_fallback<'tcx>(
         return tcx.typeck_tables_of(outer_def_id);
     }
 
-    let id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    let id = tcx.hir().as_local_hir_id(def_id.expect_local());
     let span = tcx.hir().span(id);
 
     // Figure out what primary body this item has.
@@ -1305,7 +1309,6 @@ fn check_fn<'a, 'tcx>(
     let hir = tcx.hir();
 
     let declared_ret_ty = fn_sig.output();
-    fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
     let revealed_ret_ty =
         fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
     debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
@@ -1333,8 +1336,8 @@ fn check_fn<'a, 'tcx>(
         fcx.resume_yield_tys = Some((resume_ty, yield_ty));
     }
 
-    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id));
-    let outer_hir_id = hir.as_local_hir_id(outer_def_id).unwrap();
+    let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id());
+    let outer_hir_id = hir.as_local_hir_id(outer_def_id.expect_local());
     GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body);
 
     // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
@@ -1374,7 +1377,25 @@ fn check_fn<'a, 'tcx>(
 
     inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
 
-    fcx.check_return_expr(&body.value);
+    if let ty::Dynamic(..) = declared_ret_ty.kind {
+        // FIXME: We need to verify that the return type is `Sized` after the return expression has
+        // been evaluated so that we have types available for all the nodes being returned, but that
+        // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
+        // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
+        // while keeping the current ordering we will ignore the tail expression's type because we
+        // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
+        // because we will trigger "unreachable expression" lints unconditionally.
+        // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
+        // case that a newcomer might make, returning a bare trait, and in that case we populate
+        // the tail expression's type so that the suggestion will be correct, but ignore all other
+        // possible cases.
+        fcx.check_expr(&body.value);
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type");
+    } else {
+        fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+        fcx.check_return_expr(&body.value);
+    }
 
     // We insert the deferred_generator_interiors entry after visiting the body.
     // This ensures that all nested generators appear before the entry of this generator.
@@ -1431,7 +1452,7 @@ fn check_fn<'a, 'tcx>(
     // Check that the main return type implements the termination trait.
     if let Some(term_id) = tcx.lang_items().termination() {
         if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) {
-            let main_id = hir.as_local_hir_id(def_id).unwrap();
+            let main_id = hir.as_local_hir_id(def_id.expect_local());
             if main_id == fn_id {
                 let substs = tcx.mk_substs_trait(declared_ret_ty, &[]);
                 let trait_ref = ty::TraitRef::new(term_id, substs);
@@ -1453,7 +1474,7 @@ fn check_fn<'a, 'tcx>(
 
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
     if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
-        if panic_impl_did == hir.local_def_id(fn_id) {
+        if panic_impl_did == hir.local_def_id(fn_id).to_def_id() {
             if let Some(panic_info_did) = tcx.lang_items().panic_info() {
                 if declared_ret_ty.kind != ty::Never {
                     sess.span_err(decl.output.span(), "return type should be `!`");
@@ -1497,7 +1518,7 @@ fn check_fn<'a, 'tcx>(
 
     // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
     if let Some(alloc_error_handler_did) = tcx.lang_items().oom() {
-        if alloc_error_handler_did == hir.local_def_id(fn_id) {
+        if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() {
             if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() {
                 if declared_ret_ty.kind != ty::Never {
                     sess.span_err(decl.output.span(), "return type should be `!`");
@@ -1549,8 +1570,8 @@ fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
         check_simd(tcx, span, def_id);
     }
 
-    check_transparent(tcx, span, def_id);
-    check_packed(tcx, span, def_id);
+    check_transparent(tcx, span, def);
+    check_packed(tcx, span, def);
 }
 
 fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
@@ -1558,14 +1579,14 @@ fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
-    check_transparent(tcx, span, def_id);
+    check_transparent(tcx, span, def);
     check_union_fields(tcx, span, def_id);
-    check_packed(tcx, span, def_id);
+    check_packed(tcx, span, def);
 }
 
 /// When the `#![feature(untagged_unions)]` gate is active,
 /// check that the fields of the `union` does not contain fields that need dropping.
-fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool {
+fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {
     let item_type = tcx.type_of(item_def_id);
     if let ty::Adt(def, substs) = item_type.kind {
         assert!(def.is_union());
@@ -1597,7 +1618,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: DefId) -> bool {
 /// projections that would result in "inheriting lifetimes".
 fn check_opaque<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
     substs: SubstsRef<'tcx>,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
@@ -1608,9 +1629,8 @@ fn check_opaque<'tcx>(
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
 /// in "inheriting lifetimes".
-fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: DefId, span: Span) {
-    let item =
-        tcx.hir().expect_item(tcx.hir().as_local_hir_id(def_id).expect("opaque type is not local"));
+fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
+    let item = tcx.hir().expect_item(tcx.hir().as_local_hir_id(def_id));
     debug!(
         "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
         def_id, span, item
@@ -1639,11 +1659,15 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
     }
 
     let prohibit_opaque = match item.kind {
-        ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn, .. })
-        | ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn, .. }) => {
+        ItemKind::OpaqueTy(hir::OpaqueTy {
+            origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+            ..
+        }) => {
             let mut visitor = ProhibitOpaqueVisitor {
-                opaque_identity_ty: tcx
-                    .mk_opaque(def_id, InternalSubsts::identity_for_item(tcx, def_id)),
+                opaque_identity_ty: tcx.mk_opaque(
+                    def_id.to_def_id(),
+                    InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+                ),
                 generics: tcx.generics_of(def_id),
             };
             debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
@@ -1680,12 +1704,13 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
 /// Checks that an opaque type does not contain cycles.
 fn check_opaque_for_cycles<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    def_id: LocalDefId,
     substs: SubstsRef<'tcx>,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
-    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
+    if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs)
+    {
         if let hir::OpaqueTyOrigin::AsyncFn = origin {
             struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing",)
                 .span_label(span, "recursive `async fn`")
@@ -1717,7 +1742,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     debug!(
         "check_item_type(it.hir_id={}, it.name={})",
         it.hir_id,
-        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id))
+        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
     );
     let _indenter = indenter();
     match it.kind {
@@ -1745,7 +1770,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
         }
         hir::ItemKind::Trait(_, _, _, _, ref items) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
-            check_on_unimplemented(tcx, def_id, it);
+            check_on_unimplemented(tcx, def_id.to_def_id(), it);
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
@@ -1764,7 +1789,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
         hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
             let def_id = tcx.hir().local_def_id(it.hir_id);
 
-            let substs = InternalSubsts::identity_for_item(tcx, def_id);
+            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
             check_opaque(tcx, def_id, substs, it.span, &origin);
         }
         hir::ItemKind::TyAlias(..) => {
@@ -1827,7 +1852,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     }
 }
 
-fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) {
+fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) {
     // Only restricted on wasm32 target for now
     if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
         return;
@@ -1847,7 +1872,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span)
     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
     // the consumer's responsibility to ensure all bytes that have been read
     // have defined values.
-    match tcx.const_eval_poly(id) {
+    match tcx.const_eval_poly(id.to_def_id()) {
         Ok(ConstValue::ByRef { alloc, .. }) => {
             if alloc.relocations().len() != 0 {
                 let msg = "statics with a custom `#[link_section]` must be a \
@@ -1864,7 +1889,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span)
 fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
     let item_def_id = tcx.hir().local_def_id(item.hir_id);
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id);
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
 }
 
 fn report_forbidden_specialization(
@@ -1968,7 +1993,7 @@ fn check_specialization_validity<'tcx>(
 fn check_impl_items_against_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     full_impl_span: Span,
-    impl_id: DefId,
+    impl_id: LocalDefId,
     impl_trait_ref: ty::TraitRef<'tcx>,
     impl_item_refs: &[hir::ImplItemRef<'_>],
 ) {
@@ -2109,13 +2134,19 @@ fn check_impl_items_against_trait<'tcx>(
                 }
             }
 
-            check_specialization_validity(tcx, trait_def, &ty_trait_item, impl_id, impl_item);
+            check_specialization_validity(
+                tcx,
+                trait_def,
+                &ty_trait_item,
+                impl_id.to_def_id(),
+                impl_item,
+            );
         }
     }
 
     // Check for missing items from trait
     let mut missing_items = Vec::new();
-    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) {
+    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
         for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item.ident, trait_item.kind)
@@ -2251,26 +2282,39 @@ fn fn_sig_suggestion(
     sig: &ty::FnSig<'_>,
     ident: Ident,
     predicates: ty::GenericPredicates<'_>,
+    assoc: &ty::AssocItem,
 ) -> String {
     let args = sig
         .inputs()
         .iter()
-        .map(|ty| {
+        .enumerate()
+        .map(|(i, ty)| {
             Some(match ty.kind {
-                ty::Param(param) if param.name == kw::SelfUpper => "self".to_string(),
-                ty::Ref(reg, ref_ty, mutability) => {
+                ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
+                ty::Ref(reg, ref_ty, mutability) if i == 0 => {
                     let reg = match &format!("{}", reg)[..] {
                         "'_" | "" => String::new(),
                         reg => format!("{} ", reg),
                     };
-                    match ref_ty.kind {
-                        ty::Param(param) if param.name == kw::SelfUpper => {
-                            format!("&{}{}self", reg, mutability.prefix_str())
+                    if assoc.fn_has_self_parameter {
+                        match ref_ty.kind {
+                            ty::Param(param) if param.name == kw::SelfUpper => {
+                                format!("&{}{}self", reg, mutability.prefix_str())
+                            }
+
+                            _ => format!("self: {}", ty),
                         }
-                        _ => format!("_: {:?}", ty),
+                    } else {
+                        format!("_: {:?}", ty)
+                    }
+                }
+                _ => {
+                    if assoc.fn_has_self_parameter && i == 0 {
+                        format!("self: {:?}", ty)
+                    } else {
+                        format!("_: {:?}", ty)
                     }
                 }
-                _ => format!("_: {:?}", ty),
             })
         })
         .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
@@ -2309,6 +2353,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
                 tcx.fn_sig(assoc.def_id).skip_binder(),
                 assoc.ident,
                 tcx.predicates_of(assoc.def_id),
+                assoc,
             )
         }
         ty::AssocKind::Type => format!("type {} = Type;", assoc.ident),
@@ -2325,7 +2370,7 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
-fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
+fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool {
     let rty = tcx.type_of(item_def_id);
 
     // Check that it is possible to represent this type. This call identifies
@@ -2335,7 +2380,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
         Representability::SelfRecursive(spans) => {
-            let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id);
+            let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id());
             for span in spans {
                 err.span_label(span, "recursive without indirection");
             }
@@ -2347,7 +2392,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool {
     true
 }
 
-pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
+pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
     let t = tcx.type_of(def_id);
     if let ty::Adt(def, substs) = t.kind {
         if def.is_struct() {
@@ -2381,10 +2426,10 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
     }
 }
 
-fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
-    let repr = tcx.adt_def(def_id).repr;
+fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) {
+    let repr = def.repr;
     if repr.packed() {
-        for attr in tcx.get_attrs(def_id).iter() {
+        for attr in tcx.get_attrs(def.did).iter() {
             for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) {
                 if let attr::ReprPacked(pack) = r {
                     if let Some(repr_pack) = repr.pack {
@@ -2410,7 +2455,7 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
             )
             .emit();
         } else {
-            if let Some(def_spans) = check_packed_inner(tcx, def_id, &mut vec![]) {
+            if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) {
                 let mut err = struct_span_err!(
                     tcx.sess,
                     sp,
@@ -2419,34 +2464,32 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
                 );
 
                 let hir = tcx.hir();
-                if let Some(hir_id) = hir.as_local_hir_id(def_spans[0].0) {
-                    if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
-                        err.span_note(
-                            tcx.def_span(def_spans[0].0),
-                            &format!("`{}` has a `#[repr(align)]` attribute", ident),
-                        );
-                    }
+                let hir_id = hir.as_local_hir_id(def_spans[0].0.expect_local());
+                if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
+                    err.span_note(
+                        tcx.def_span(def_spans[0].0),
+                        &format!("`{}` has a `#[repr(align)]` attribute", ident),
+                    );
                 }
 
                 if def_spans.len() > 2 {
                     let mut first = true;
                     for (adt_def, span) in def_spans.iter().skip(1).rev() {
-                        if let Some(hir_id) = hir.as_local_hir_id(*adt_def) {
-                            if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
-                                err.span_note(
-                                    *span,
-                                    &if first {
-                                        format!(
-                                            "`{}` contains a field of type `{}`",
-                                            tcx.type_of(def_id),
-                                            ident
-                                        )
-                                    } else {
-                                        format!("...which contains a field of type `{}`", ident)
-                                    },
-                                );
-                                first = false;
-                            }
+                        let hir_id = hir.as_local_hir_id(adt_def.expect_local());
+                        if let Node::Item(Item { ident, .. }) = hir.get(hir_id) {
+                            err.span_note(
+                                *span,
+                                &if first {
+                                    format!(
+                                        "`{}` contains a field of type `{}`",
+                                        tcx.type_of(def.did),
+                                        ident
+                                    )
+                                } else {
+                                    format!("...which contains a field of type `{}`", ident)
+                                },
+                            );
+                            first = false;
                         }
                     }
                 }
@@ -2531,8 +2574,7 @@ fn bad_non_zero_sized_fields<'tcx>(
     err.emit();
 }
 
-fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
-    let adt = tcx.adt_def(def_id);
+fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) {
     if !adt.repr.transparent() {
         return;
     }
@@ -2549,7 +2591,7 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
     }
 
     if adt.variants.len() != 1 {
-        bad_variant_count(tcx, adt, sp, def_id);
+        bad_variant_count(tcx, adt, sp, adt.did);
         if adt.variants.is_empty() {
             // Don't bother checking the fields. No variants (and thus no fields) exist.
             return;
@@ -2601,7 +2643,7 @@ pub fn check_enum<'tcx>(
     def.destructor(tcx); // force the destructor to be evaluated
 
     if vs.is_empty() {
-        let attributes = tcx.get_attrs(def_id);
+        let attributes = tcx.get_attrs(def_id.to_def_id());
         if let Some(attr) = attr::find_by_name(&attributes, sym::repr) {
             struct_span_err!(
                 tcx.sess,
@@ -2656,7 +2698,7 @@ pub fn check_enum<'tcx>(
         // Check for duplicate discriminant values
         if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
             let variant_did = def.variants[VariantIdx::new(i)].def_id;
-            let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did).unwrap();
+            let variant_i_hir_id = tcx.hir().as_local_hir_id(variant_did.expect_local());
             let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
             let i_span = match variant_i.disr_expr {
                 Some(ref expr) => tcx.hir().span(expr.hir_id),
@@ -2681,7 +2723,7 @@ pub fn check_enum<'tcx>(
     }
 
     check_representable(tcx, sp, def_id);
-    check_transparent(tcx, sp, def_id);
+    check_transparent(tcx, sp, def);
 }
 
 fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) {
@@ -2717,7 +2759,7 @@ fn default_constness_for_trait_bounds(&self) -> hir::Constness {
 
     fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
-        let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+        let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local());
         let item_id = tcx.hir().ty_param_owner(hir_id);
         let item_def_id = tcx.hir().local_def_id(item_id);
         let generics = tcx.generics_of(item_def_id);
@@ -3210,7 +3252,7 @@ fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
 
         let (value, opaque_type_map) =
             self.register_infer_ok_obligations(self.instantiate_opaque_types(
-                parent_def_id,
+                parent_def_id.to_def_id(),
                 self.body_id,
                 self.param_env,
                 value,
@@ -3315,7 +3357,7 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     }
 
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
-        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id).expect_local();
+        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
 
         // HACK(eddyb) emulate what a `WellFormedConst` obligation would do.
@@ -4113,10 +4155,10 @@ fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
                     ty::Float(ast::FloatTy::F32) => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
                     }
-                    ty::Int(ast::IntTy::I8) | ty::Int(ast::IntTy::I16) | ty::Bool => {
+                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
                     }
-                    ty::Uint(ast::UintTy::U8) | ty::Uint(ast::UintTy::U16) => {
+                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
                         variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
                     }
                     ty::FnDef(..) => {
@@ -4351,10 +4393,7 @@ pub fn check_struct_path(
                 ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
                 _ => bug!("unexpected type: {:?}", ty),
             },
-            Res::Def(DefKind::Struct, _)
-            | Res::Def(DefKind::Union, _)
-            | Res::Def(DefKind::TyAlias, _)
-            | Res::Def(DefKind::AssocTy, _)
+            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfTy(..) => match ty.kind {
                 ty::Adt(adt, substs) if !adt.is_enum() => {
                     Some((adt.non_enum_variant(), adt.did, substs))
@@ -4884,15 +4923,16 @@ fn suggest_fn_call(
             };
             let mut msg = "call this function";
             match hir.get_if_local(def_id) {
-                Some(Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }))
-                | Some(Node::ImplItem(hir::ImplItem {
-                    kind: hir::ImplItemKind::Fn(_, body_id),
-                    ..
-                }))
-                | Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                    ..
-                })) => {
+                Some(
+                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
+                    | Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body_id), ..
+                    })
+                    | Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
+                        ..
+                    }),
+                ) => {
                     let body = hir.body(*body_id);
                     sugg_call = body
                         .params
@@ -4934,11 +4974,11 @@ fn suggest_fn_call(
                 }
                 Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
                     sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) {
-                        Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
+                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
+                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
                             msg = "instantiate this tuple variant";
                         }
-                        Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => {
+                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
                             msg = "instantiate this tuple struct";
                         }
                         _ => {}
@@ -5389,7 +5429,7 @@ pub fn instantiate_value_path(
                     is_alias_variant_ctor = true;
                 }
             }
-            Res::Def(DefKind::AssocFn, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
+            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
                 let container = tcx.associated_item(def_id).container;
                 debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
                 match container {