From 6277b1fef617610c32b36dba1b06f937488ca5a9 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Fri, 12 Aug 2016 14:18:59 -0400
Subject: [PATCH] separate main items from addl items in metadata

---
 src/librustc_metadata/encoder.rs | 398 ++++++++++++++++++-------------
 1 file changed, 232 insertions(+), 166 deletions(-)

diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 8b76dd62692..8611e744bc4 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -443,18 +443,18 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
 impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
     fn encode_info_for_struct_ctor(&mut self,
                                    name: Name,
-                                   struct_def: &hir::VariantData,
+                                   ctor_id: ast::NodeId,
+                                   variant: ty::VariantDef<'tcx>,
                                    struct_id: NodeId) {
         let ecx = self.ecx();
-        let ctor_id = struct_def.id();
         let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
 
         self.record(ctor_def_id, |this| {
             encode_def_id_and_key(ecx, this.rbml_w, ctor_def_id);
-            encode_family(this.rbml_w, match *struct_def {
-                hir::VariantData::Struct(..) => 'S',
-                hir::VariantData::Tuple(..) => 's',
-                hir::VariantData::Unit(..) => 'u',
+            encode_family(this.rbml_w, match variant.kind {
+                ty::VariantKind::Struct => 'S',
+                ty::VariantKind::Tuple => 's',
+                ty::VariantKind::Unit => 'u',
             });
             this.encode_bounds_and_type_for_item(ctor_id);
             encode_name(this.rbml_w, name);
@@ -874,15 +874,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                     encode_stability(this.rbml_w, stab);
                     encode_deprecation(this.rbml_w, depr);
                 });
-
-                self.encode_enum_variant_info(def_id, vis);
             }
             hir::ItemStruct(ref struct_def, _) => {
                 /* Index the class*/
-                let def = ecx.tcx.lookup_adt_def(def_id);
-                let variant = def.struct_variant();
-
                 self.record(def_id, |this| {
+                    let def = ecx.tcx.lookup_adt_def(def_id);
+                    let variant = def.struct_variant();
+
                     /* Now, make an item for the class itself */
                     encode_def_id_and_key(ecx, this.rbml_w, def_id);
                     encode_family(this.rbml_w, match *struct_def {
@@ -917,15 +915,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                                              def_to_u64(ctor_did));
                     }
                 });
-
-                for field in &variant.fields {
-                    self.encode_field(field);
-                }
-
-                // If this is a tuple-like struct, encode the type of the constructor.
-                if !struct_def.is_struct() {
-                    self.encode_info_for_struct_ctor(item.name, struct_def, item.id);
-                }
             }
             hir::ItemDefaultImpl(unsafety, _) => {
                 self.record(def_id, |this| {
@@ -938,13 +927,13 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                     encode_trait_ref(this.rbml_w, ecx, trait_ref, tag_item_trait_ref);
                 });
             }
-            hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
-                // We need to encode information about the default methods we
-                // have inherited, so we drive this based on the impl structure.
-                let impl_items = tcx.impl_items.borrow();
-                let items = &impl_items[&def_id];
-
+            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
                 self.record(def_id, |this| {
+                    // We need to encode information about the default methods we
+                    // have inherited, so we drive this based on the impl structure.
+                    let impl_items = tcx.impl_items.borrow();
+                    let items = &impl_items[&def_id];
+
                     encode_def_id_and_key(ecx, this.rbml_w, def_id);
                     encode_family(this.rbml_w, 'i');
                     this.encode_bounds_and_type_for_item(item.id);
@@ -1003,40 +992,8 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                     encode_stability(this.rbml_w, stab);
                     encode_deprecation(this.rbml_w, depr);
                 });
-
-                // Iterate down the trait items, emitting them. We rely on the
-                // assumption that all of the actually implemented trait items
-                // appear first in the impl structure, in the same order they do
-                // in the ast. This is a little sketchy.
-                let num_implemented_methods = ast_items.len();
-                for (i, &trait_item_def_id) in items.iter().enumerate() {
-                    let ast_item = if i < num_implemented_methods {
-                        Some(&ast_items[i])
-                    } else {
-                        None
-                    };
-
-                    match tcx.impl_or_trait_item(trait_item_def_id.def_id()) {
-                        ty::ConstTraitItem(ref associated_const) => {
-                            self.encode_info_for_associated_const(&associated_const,
-                                                                  item.id,
-                                                                  ast_item)
-                        }
-                        ty::MethodTraitItem(ref method_type) => {
-                            self.encode_info_for_method(&method_type,
-                                                        false,
-                                                        item.id,
-                                                        ast_item)
-                        }
-                        ty::TypeTraitItem(ref associated_type) => {
-                            self.encode_info_for_associated_type(&associated_type,
-                                                                 item.id,
-                                                                 ast_item)
-                        }
-                    }
-                }
             }
-            hir::ItemTrait(_, _, _, ref ms) => {
+            hir::ItemTrait(_, _, _, _) => {
                 self.record(def_id, |this| {
                     encode_def_id_and_key(ecx, this.rbml_w, def_id);
                     encode_family(this.rbml_w, 'I');
@@ -1081,110 +1038,6 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                     // Encode inherent implementations for this trait.
                     encode_inherent_implementations(ecx, this.rbml_w, def_id);
                 });
-
-                // Now output the trait item info for each trait item.
-                let r = tcx.trait_item_def_ids(def_id);
-                for (i, &item_def_id) in r.iter().enumerate() {
-                    assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
-
-                    self.record(item_def_id.def_id(), |this| {
-                        this.encode_parent_item(def_id);
-
-                        let stab = tcx.lookup_stability(item_def_id.def_id());
-                        let depr = tcx.lookup_deprecation(item_def_id.def_id());
-                        encode_stability(this.rbml_w, stab);
-                        encode_deprecation(this.rbml_w, depr);
-
-                        let trait_item_type =
-                            tcx.impl_or_trait_item(item_def_id.def_id());
-                        let is_nonstatic_method;
-                        match trait_item_type {
-                            ty::ConstTraitItem(associated_const) => {
-                                encode_name(this.rbml_w, associated_const.name);
-                                encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id);
-                                this.encode_visibility(associated_const.vis);
-
-                                encode_family(this.rbml_w, 'C');
-
-                                this.encode_bounds_and_type_for_item(
-                                    ecx.local_id(associated_const.def_id));
-
-                                is_nonstatic_method = false;
-                            }
-                            ty::MethodTraitItem(method_ty) => {
-                                let method_def_id = item_def_id.def_id();
-
-                                this.encode_method_ty_fields(&method_ty);
-
-                                match method_ty.explicit_self {
-                                    ty::ExplicitSelfCategory::Static => {
-                                        encode_family(this.rbml_w,
-                                                      STATIC_METHOD_FAMILY);
-                                    }
-                                    _ => {
-                                        encode_family(this.rbml_w,
-                                                      METHOD_FAMILY);
-                                    }
-                                }
-                                this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id));
-
-                                is_nonstatic_method = method_ty.explicit_self !=
-                                    ty::ExplicitSelfCategory::Static;
-                            }
-                            ty::TypeTraitItem(associated_type) => {
-                                encode_name(this.rbml_w, associated_type.name);
-                                encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id);
-                                encode_item_sort(this.rbml_w, 't');
-                                encode_family(this.rbml_w, 'y');
-
-                                if let Some(ty) = associated_type.ty {
-                                    this.encode_type(ty);
-                                }
-
-                                is_nonstatic_method = false;
-                            }
-                        }
-
-                        let trait_item = &ms[i];
-                        encode_attributes(this.rbml_w, &trait_item.attrs);
-                        match trait_item.node {
-                            hir::ConstTraitItem(_, ref default) => {
-                                if default.is_some() {
-                                    encode_item_sort(this.rbml_w, 'C');
-                                } else {
-                                    encode_item_sort(this.rbml_w, 'c');
-                                }
-
-                                encode_inlined_item(ecx, this.rbml_w,
-                                                    InlinedItemRef::TraitItem(def_id, trait_item));
-                                this.encode_mir(trait_item.id);
-                            }
-                            hir::MethodTraitItem(ref sig, ref body) => {
-                                // If this is a static method, we've already
-                                // encoded this.
-                                if is_nonstatic_method {
-                                    this.encode_bounds_and_type_for_item(
-                                        ecx.local_id(item_def_id.def_id()));
-                                }
-
-                                if body.is_some() {
-                                    encode_item_sort(this.rbml_w, 'p');
-                                    encode_inlined_item(ecx,
-                                                        this.rbml_w,
-                                                        InlinedItemRef::TraitItem(
-                                                            def_id,
-                                                            trait_item));
-                                    this.encode_mir(trait_item.id);
-                                } else {
-                                    encode_item_sort(this.rbml_w, 'r');
-                                }
-                                this.encode_method_argument_names(&sig.decl);
-                            }
-
-                            hir::TypeTraitItem(..) => {}
-                        }
-                    });
-                }
             }
             hir::ItemExternCrate(_) | hir::ItemUse(_) => {
                 // these are encoded separately
@@ -1192,6 +1045,218 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
         }
     }
 
+    /// In some cases, along with the item itself, we also
+    /// encode some sub-items. Usually we want some info from the item
+    /// so it's easier to do that here then to wait until we would encounter
+    /// normally in the visitor walk.
+    fn encode_addl_info_for_item(&mut self,
+                                 item: &hir::Item) {
+        let def_id = self.ecx.tcx.map.local_def_id(item.id);
+        match item.node {
+            hir::ItemStatic(..) |
+            hir::ItemConst(..) |
+            hir::ItemFn(..) |
+            hir::ItemMod(..) |
+            hir::ItemForeignMod(..) |
+            hir::ItemExternCrate(..) |
+            hir::ItemUse(..) |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemTy(..) => {
+                // no sub-item recording needed in these cases
+            }
+            hir::ItemEnum(..) => {
+                self.encode_enum_variant_info(def_id, &item.vis);
+            }
+            hir::ItemStruct(ref struct_def, _) => {
+                self.encode_addl_struct_info(def_id, struct_def.id(), item);
+            }
+            hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
+                self.encode_addl_impl_info(def_id, item.id, ast_items);
+            }
+            hir::ItemTrait(_, _, _, ref trait_items) => {
+                self.encode_addl_trait_info(def_id, trait_items);
+            }
+        }
+    }
+
+    fn encode_addl_struct_info(&mut self,
+                               def_id: DefId,
+                               struct_def_id: ast::NodeId,
+                               item: &hir::Item) {
+        let ecx = self.ecx;
+        let def = ecx.tcx.lookup_adt_def(def_id);
+        let variant = def.struct_variant();
+
+        for field in &variant.fields {
+            self.encode_field(field);
+        }
+
+        // If this is a tuple-like struct, encode the type of the constructor.
+        match variant.kind {
+            ty::VariantKind::Struct => {
+                // no value for structs like struct Foo { ... }
+            }
+            ty::VariantKind::Tuple | ty::VariantKind::Unit => {
+                // there is a value for structs like `struct
+                // Foo()` and `struct Foo`
+                self.encode_info_for_struct_ctor(item.name,
+                                                       struct_def_id,
+                                                       variant,
+                                                       item.id);
+            }
+        }
+    }
+
+    fn encode_addl_impl_info(&mut self,
+                             def_id: DefId,
+                             impl_id: ast::NodeId,
+                             ast_items: &[hir::ImplItem]) {
+        let ecx = self.ecx;
+        let impl_items = ecx.tcx.impl_items.borrow();
+        let items = &impl_items[&def_id];
+
+        // Iterate down the trait items, emitting them. We rely on the
+        // assumption that all of the actually implemented trait items
+        // appear first in the impl structure, in the same order they do
+        // in the ast. This is a little sketchy.
+        let num_implemented_methods = ast_items.len();
+        for (i, &trait_item_def_id) in items.iter().enumerate() {
+            let ast_item = if i < num_implemented_methods {
+                Some(&ast_items[i])
+            } else {
+                None
+            };
+
+            match self.ecx.tcx.impl_or_trait_item(trait_item_def_id.def_id()) {
+                ty::ConstTraitItem(ref associated_const) => {
+                    self.encode_info_for_associated_const(&associated_const,
+                                                          impl_id,
+                                                          ast_item)
+                }
+                ty::MethodTraitItem(ref method_type) => {
+                    self.encode_info_for_method(&method_type,
+                                                false,
+                                                impl_id,
+                                                ast_item)
+                }
+                ty::TypeTraitItem(ref associated_type) => {
+                    self.encode_info_for_associated_type(&associated_type,
+                                                         impl_id,
+                                                         ast_item)
+                }
+            }
+        }
+    }
+
+    fn encode_addl_trait_info(&mut self,
+                              def_id: DefId,
+                              trait_items: &[hir::TraitItem]) {
+        // Now output the trait item info for each trait item.
+        let ecx = self.ecx;
+        let tcx = self.ecx.tcx;
+        let r = tcx.trait_item_def_ids(def_id);
+        for (&item_def_id, trait_item) in r.iter().zip(trait_items) {
+            assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
+
+            self.record(item_def_id.def_id(), |this| {
+                this.encode_parent_item(def_id);
+
+                let stab = tcx.lookup_stability(item_def_id.def_id());
+                let depr = tcx.lookup_deprecation(item_def_id.def_id());
+                encode_stability(this.rbml_w, stab);
+                encode_deprecation(this.rbml_w, depr);
+
+                let trait_item_type =
+                    tcx.impl_or_trait_item(item_def_id.def_id());
+                let is_nonstatic_method;
+                match trait_item_type {
+                    ty::ConstTraitItem(associated_const) => {
+                        encode_name(this.rbml_w, associated_const.name);
+                        encode_def_id_and_key(ecx, this.rbml_w, associated_const.def_id);
+                        this.encode_visibility(associated_const.vis);
+
+                        encode_family(this.rbml_w, 'C');
+
+                        this.encode_bounds_and_type_for_item(
+                            ecx.local_id(associated_const.def_id));
+
+                        is_nonstatic_method = false;
+                    }
+                    ty::MethodTraitItem(method_ty) => {
+                        let method_def_id = item_def_id.def_id();
+
+                        this.encode_method_ty_fields(&method_ty);
+
+                        match method_ty.explicit_self {
+                            ty::ExplicitSelfCategory::Static => {
+                                encode_family(this.rbml_w,
+                                              STATIC_METHOD_FAMILY);
+                            }
+                            _ => {
+                                encode_family(this.rbml_w,
+                                              METHOD_FAMILY);
+                            }
+                        }
+                        this.encode_bounds_and_type_for_item(ecx.local_id(method_def_id));
+
+                        is_nonstatic_method = method_ty.explicit_self !=
+                            ty::ExplicitSelfCategory::Static;
+                    }
+                    ty::TypeTraitItem(associated_type) => {
+                        encode_name(this.rbml_w, associated_type.name);
+                        encode_def_id_and_key(ecx, this.rbml_w, associated_type.def_id);
+                        encode_item_sort(this.rbml_w, 't');
+                        encode_family(this.rbml_w, 'y');
+
+                        if let Some(ty) = associated_type.ty {
+                            this.encode_type(ty);
+                        }
+
+                        is_nonstatic_method = false;
+                    }
+                }
+
+                encode_attributes(this.rbml_w, &trait_item.attrs);
+                match trait_item.node {
+                    hir::ConstTraitItem(_, ref default) => {
+                        if default.is_some() {
+                            encode_item_sort(this.rbml_w, 'C');
+                        } else {
+                            encode_item_sort(this.rbml_w, 'c');
+                        }
+
+                        encode_inlined_item(ecx, this.rbml_w,
+                                            InlinedItemRef::TraitItem(def_id, trait_item));
+                        this.encode_mir(trait_item.id);
+                    }
+                    hir::MethodTraitItem(ref sig, ref body) => {
+                        // If this is a static method, we've already
+                        // encoded this.
+                        if is_nonstatic_method {
+                            this.encode_bounds_and_type_for_item(
+                                ecx.local_id(item_def_id.def_id()));
+                        }
+
+                        if body.is_some() {
+                            encode_item_sort(this.rbml_w, 'p');
+                            encode_inlined_item(ecx,
+                                                this.rbml_w,
+                                                InlinedItemRef::TraitItem(
+                                                    def_id,
+                                                    trait_item));
+                            this.encode_mir(trait_item.id);
+                        } else {
+                            encode_item_sort(this.rbml_w, 'r');
+                        }
+                        this.encode_method_argument_names(&sig.decl);
+                    }
+
+                    hir::TypeTraitItem(..) => {}
+                }
+            });
+        }
+    }
+
     fn encode_info_for_foreign_item(&mut self,
                                     nitem: &hir::ForeignItem) {
         let ecx = self.ecx();
@@ -1251,9 +1316,10 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, '
         intravisit::walk_expr(self, ex);
         self.index.encode_info_for_expr(ex);
     }
-    fn visit_item(&mut self, i: &'tcx hir::Item) {
-        intravisit::walk_item(self, i);
-        self.index.encode_info_for_item(i);
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        intravisit::walk_item(self, item);
+        self.index.encode_info_for_item(item);
+        self.index.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
         intravisit::walk_foreign_item(self, ni);