// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Metadata encoding
-
-#![allow(unused_must_use)] // everything is just a MemWriter, can't fail
-#![allow(non_camel_case_types)]
-
-use astencode::encode_inlined_item;
-use common::*;
use cstore;
-use decoder;
-use def_key;
-use tyencode;
-use index::{self, IndexData};
+use index::Index;
+use schema::*;
-use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls};
+use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
+use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
use rustc::hir::def;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use middle::dependency_format::Linkage;
-use rustc::dep_graph::{DepGraph, DepNode, DepTask};
-use rustc::ty::subst;
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
+use rustc::middle::dependency_format::Linkage;
+use rustc::middle::lang_items;
+use rustc::mir;
use rustc::traits::specialization_graph;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::util::IntTypeExt;
-use rustc::hir::svh::Svh;
use rustc::mir::mir_map::MirMap;
-use rustc::session::config::{self, PanicStrategy};
+use rustc::session::config::{self, CrateTypeRustcMacro};
use rustc::util::nodemap::{FnvHashMap, NodeSet};
-use rustc_serialize::Encodable;
-use std::cell::RefCell;
+use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
+use std::hash::Hash;
+use std::intrinsics;
use std::io::prelude::*;
-use std::io::{Cursor, SeekFrom};
+use std::io::Cursor;
use std::rc::Rc;
use std::u32;
-use syntax::abi::Abi;
-use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
-use errors::Handler;
+use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::attr;
use syntax;
-use syntax_pos::BytePos;
-use rbml::writer::Encoder;
+use syntax_pos;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::Visitor;
use rustc::hir::intravisit;
-use rustc::hir::map::DefKey;
+
+use super::index_builder::{FromId, IndexBuilder, Untracked};
pub struct EncodeContext<'a, 'tcx: 'a> {
- pub diag: &'a Handler,
+ opaque: opaque::Encoder<'a>,
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
- pub reexports: &'a def::ExportMap,
- pub link_meta: &'a LinkMeta,
- pub cstore: &'a cstore::CStore,
- pub type_abbrevs: tyencode::abbrev_map<'tcx>,
- pub reachable: &'a NodeSet,
- pub mir_map: &'a MirMap<'tcx>,
-}
-
-impl<'a, 'tcx> EncodeContext<'a,'tcx> {
- fn local_id(&self, def_id: DefId) -> NodeId {
- self.tcx.map.as_local_node_id(def_id).unwrap()
+ reexports: &'a def::ExportMap,
+ link_meta: &'a LinkMeta,
+ cstore: &'a cstore::CStore,
+ reachable: &'a NodeSet,
+ mir_map: &'a MirMap<'tcx>,
+
+ lazy_state: LazyState,
+ type_shorthands: FnvHashMap<Ty<'tcx>, usize>,
+ predicate_shorthands: FnvHashMap<ty::Predicate<'tcx>, usize>,
+}
+
+macro_rules! encoder_methods {
+ ($($name:ident($ty:ty);)*) => {
+ $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
+ self.opaque.$name(value)
+ })*
}
}
-/// "interned" entries referenced by id
-#[derive(PartialEq, Eq, Hash)]
-pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
+impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
+ type Error = <opaque::Encoder<'a> as Encoder>::Error;
-struct CrateIndex<'a, 'tcx> {
- dep_graph: &'a DepGraph,
- items: IndexData,
- xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
-}
-
-impl<'a, 'tcx> CrateIndex<'a, 'tcx> {
- /// Records that `id` is being emitted at the current offset.
- /// This data is later used to construct the item index in the
- /// metadata so we can quickly find the data for a given item.
- ///
- /// Returns a dep-graph task that you should keep live as long as
- /// the data for this item is being emitted.
- fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
- let position = rbml_w.mark_stable_position();
- self.items.record(id, position);
- self.dep_graph.in_task(DepNode::MetaData(id))
+ fn emit_nil(&mut self) -> Result<(), Self::Error> {
+ Ok(())
}
- fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
- let old_len = self.xrefs.len() as u32;
- *self.xrefs.entry(xref).or_insert(old_len)
+ encoder_methods! {
+ emit_usize(usize);
+ emit_u64(u64);
+ emit_u32(u32);
+ emit_u16(u16);
+ emit_u8(u8);
+
+ emit_isize(isize);
+ emit_i64(i64);
+ emit_i32(i32);
+ emit_i16(i16);
+ emit_i8(i8);
+
+ emit_bool(bool);
+ emit_f64(f64);
+ emit_f32(f32);
+ emit_char(char);
+ emit_str(&str);
}
}
-fn encode_name(rbml_w: &mut Encoder, name: Name) {
- rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
-}
-
-fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
- rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
-}
-
-fn encode_def_key(rbml_w: &mut Encoder, key: DefKey) {
- let simple_key = def_key::simplify_def_key(key);
- rbml_w.start_tag(tag_def_key);
- simple_key.encode(rbml_w);
- rbml_w.end_tag();
-}
-
-/// For every DefId that we create a metadata item for, we include a
-/// serialized copy of its DefKey, which allows us to recreate a path.
-fn encode_def_id_and_key(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- def_id: DefId)
-{
- encode_def_id(rbml_w, def_id);
- let def_key = ecx.tcx.map.def_key(def_id);
- encode_def_key(rbml_w, def_key);
-}
-
-fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a, 'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
- tag: usize) {
- rbml_w.start_tag(tag);
- tyencode::enc_trait_ref(rbml_w.writer, &ecx.ty_str_ctxt(), trait_ref);
- rbml_w.mark_stable_position();
- rbml_w.end_tag();
+impl<'a, 'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
+ self.emit_lazy_distance(lazy.position, Lazy::<T>::min_size())
+ }
}
-// Item info table encoding
-fn encode_family(rbml_w: &mut Encoder, c: char) {
- rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8);
+impl<'a, 'tcx, T> SpecializedEncoder<LazySeq<T>> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, seq: &LazySeq<T>) -> Result<(), Self::Error> {
+ self.emit_usize(seq.len)?;
+ if seq.len == 0 {
+ return Ok(());
+ }
+ self.emit_lazy_distance(seq.position, LazySeq::<T>::min_size(seq.len))
+ }
}
-pub fn def_to_u64(did: DefId) -> u64 {
- assert!(did.index.as_u32() < u32::MAX);
- (did.krate as u64) << 32 | (did.index.as_usize() as u64)
+impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
+ self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands)
+ }
}
-pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String {
- format!("{}:{}", did.krate, did.index.as_usize())
+impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>)
+ -> Result<(), Self::Error> {
+ predicates.parent.encode(self)?;
+ predicates.predicates.len().encode(self)?;
+ for predicate in &predicates.predicates {
+ self.encode_with_shorthand(predicate, predicate, |ecx| &mut ecx.predicate_shorthands)?
+ }
+ Ok(())
+ }
}
-fn encode_item_variances(rbml_w: &mut Encoder,
- ecx: &EncodeContext,
- id: NodeId) {
- let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
- rbml_w.start_tag(tag_item_variances);
- v.encode(rbml_w);
- rbml_w.end_tag();
-}
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ pub fn position(&self) -> usize {
+ self.opaque.position()
+ }
-fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a, 'tcx>,
- index: &mut CrateIndex<'a, 'tcx>,
- id: NodeId) {
- encode_bounds_and_type(rbml_w,
- ecx,
- index,
- &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
- &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
-}
+ fn emit_node<F: FnOnce(&mut Self, usize) -> R, R>(&mut self, f: F) -> R {
+ assert_eq!(self.lazy_state, LazyState::NoNode);
+ let pos = self.position();
+ self.lazy_state = LazyState::NodeStart(pos);
+ let r = f(self, pos);
+ self.lazy_state = LazyState::NoNode;
+ r
+ }
-fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a, 'tcx>,
- index: &mut CrateIndex<'a, 'tcx>,
- scheme: &ty::TypeScheme<'tcx>,
- predicates: &ty::GenericPredicates<'tcx>) {
- encode_generics(rbml_w, ecx, index,
- &scheme.generics, &predicates, tag_item_generics);
- encode_type(ecx, rbml_w, scheme.ty);
-}
+ fn emit_lazy_distance(&mut self, position: usize, min_size: usize)
+ -> Result<(), <Self as Encoder>::Error> {
+ let min_end = position + min_size;
+ let distance = match self.lazy_state {
+ LazyState::NoNode => {
+ bug!("emit_lazy_distance: outside of a metadata node")
+ }
+ LazyState::NodeStart(start) => {
+ assert!(min_end <= start);
+ start - min_end
+ }
+ LazyState::Previous(last_min_end) => {
+ assert!(last_min_end <= position);
+ position - last_min_end
+ }
+ };
+ self.lazy_state = LazyState::Previous(min_end);
+ self.emit_usize(distance)
+ }
-fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
- let id = def_to_u64(vid);
- rbml_w.wr_tagged_u64(tag_items_data_item_variant, id);
- rbml_w.wr_tagged_u64(tag_mod_child, id);
-}
+ pub fn lazy<T: Encodable>(&mut self, value: &T) -> Lazy<T> {
+ self.emit_node(|ecx, pos| {
+ value.encode(ecx).unwrap();
-fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- closure_type: &ty::ClosureTy<'tcx>) {
- tyencode::enc_closure_ty(rbml_w.writer, &ecx.ty_str_ctxt(), closure_type);
- rbml_w.mark_stable_position();
-}
+ assert!(pos + Lazy::<T>::min_size() <= ecx.position());
+ Lazy::with_position(pos)
+ })
+ }
-fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- typ: Ty<'tcx>) {
- rbml_w.start_tag(tag_items_data_item_type);
- tyencode::enc_ty(rbml_w.writer, &ecx.ty_str_ctxt(), typ);
- rbml_w.mark_stable_position();
- rbml_w.end_tag();
-}
+ fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
+ where I: IntoIterator<Item=T>, T: Encodable {
+ self.emit_node(|ecx, pos| {
+ let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
-fn encode_disr_val(_: &EncodeContext,
- rbml_w: &mut Encoder,
- disr_val: ty::Disr) {
- // convert to u64 so just the number is printed, without any type info
- rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
-}
+ assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+ LazySeq::with_position_and_length(pos, len)
+ })
+ }
-fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
- rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
-}
+ fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq<T>
+ where I: IntoIterator<Item=&'b T>, T: 'b + Encodable {
+ self.emit_node(|ecx, pos| {
+ let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
-fn encode_struct_fields(rbml_w: &mut Encoder,
- variant: ty::VariantDef) {
- for f in &variant.fields {
- if variant.kind == ty::VariantKind::Tuple {
- rbml_w.start_tag(tag_item_unnamed_field);
- } else {
- rbml_w.start_tag(tag_item_field);
- encode_name(rbml_w, f.name);
- }
- encode_struct_field_family(rbml_w, f.vis);
- encode_def_id(rbml_w, f.did);
- rbml_w.end_tag();
+ assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+ LazySeq::with_position_and_length(pos, len)
+ })
}
-}
-fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- did: DefId,
- vis: &hir::Visibility,
- index: &mut CrateIndex<'a, 'tcx>) {
- debug!("encode_enum_variant_info(did={:?})", did);
- let repr_hints = ecx.tcx.lookup_repr_hints(did);
- let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
- let mut disr_val = repr_type.initial_discriminant(ecx.tcx);
- let def = ecx.tcx.lookup_adt_def(did);
- for variant in &def.variants {
- let vid = variant.did;
- let variant_node_id = ecx.local_id(vid);
-
- for field in &variant.fields {
- encode_field(ecx, rbml_w, field, index);
+ /// Encode the given value or a previously cached shorthand.
+ fn encode_with_shorthand<T, U, M>(&mut self, value: &T, variant: &U, map: M)
+ -> Result<(), <Self as Encoder>::Error>
+ where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap<T, usize>,
+ T: Clone + Eq + Hash,
+ U: Encodable {
+ let existing_shorthand = map(self).get(value).cloned();
+ if let Some(shorthand) = existing_shorthand {
+ return self.emit_usize(shorthand);
}
- let _task = index.record(vid, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, vid);
- encode_family(rbml_w, match variant.kind {
- ty::VariantKind::Struct => 'V',
- ty::VariantKind::Tuple => 'v',
- ty::VariantKind::Unit => 'w',
- });
- encode_name(rbml_w, variant.name);
- encode_parent_item(rbml_w, did);
- encode_visibility(rbml_w, vis);
-
- let attrs = ecx.tcx.get_attrs(vid);
- encode_attributes(rbml_w, &attrs);
- encode_repr_attrs(rbml_w, ecx, &attrs);
+ let start = self.position();
+ variant.encode(self)?;
+ let len = self.position() - start;
- let stab = ecx.tcx.lookup_stability(vid);
- let depr = ecx.tcx.lookup_deprecation(vid);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
+ // The shorthand encoding uses the same usize as the
+ // discriminant, with an offset so they can't conflict.
+ let discriminant = unsafe {
+ intrinsics::discriminant_value(variant)
+ };
+ assert!(discriminant < SHORTHAND_OFFSET as u64);
+ let shorthand = start + SHORTHAND_OFFSET;
- encode_struct_fields(rbml_w, variant);
+ // Get the number of bits that leb128 could fit
+ // in the same space as the fully encoded type.
+ let leb128_bits = len * 7;
- let specified_disr_val = variant.disr_val;
- if specified_disr_val != disr_val {
- encode_disr_val(ecx, rbml_w, specified_disr_val);
- disr_val = specified_disr_val;
+ // Check that the shorthand is a not longer than the
+ // full encoding itself, i.e. it's an obvious win.
+ if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
+ map(self).insert(value.clone(), shorthand);
}
- encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
-
- rbml_w.end_tag();
- disr_val = disr_val.wrap_incr();
+ Ok(())
}
-}
-/// Iterates through "auxiliary node IDs", which are node IDs that describe
-/// top-level items that are sub-items of the given item. Specifically:
-///
-/// * For newtype structs, iterates through the node ID of the constructor.
-fn each_auxiliary_node_id<F>(item: &hir::Item, callback: F) -> bool where
- F: FnOnce(NodeId) -> bool,
-{
- let mut continue_ = true;
- match item.node {
- hir::ItemStruct(ref struct_def, _) => {
- // If this is a newtype struct, return the constructor.
- if struct_def.is_tuple() {
- continue_ = callback(struct_def.id());
- }
- }
- _ => {}
+ /// For every DefId that we create a metadata item for, we include a
+ /// serialized copy of its DefKey, which allows us to recreate a path.
+ fn encode_def_key(&mut self, def_id: DefId) -> Lazy<hir::map::DefKey> {
+ let tcx = self.tcx;
+ self.lazy(&tcx.map.def_key(def_id))
}
- continue_
-}
-
-fn encode_reexports(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- id: NodeId) {
- debug!("(encoding info for module) encoding reexports for {}", id);
- match ecx.reexports.get(&id) {
- Some(exports) => {
- debug!("(encoding info for module) found reexports for {}", id);
- for exp in exports {
- debug!("(encoding info for module) reexport '{}' ({:?}) for \
- {}",
- exp.name,
- exp.def_id,
- id);
- rbml_w.start_tag(tag_items_data_item_reexport);
- rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
- def_to_u64(exp.def_id));
- rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
- &exp.name.as_str());
- rbml_w.end_tag();
- }
- },
- None => debug!("(encoding info for module) found no reexports for {}", id),
+ fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
+ let tcx = self.tcx;
+ self.lazy_seq(tcx.item_variances(def_id).iter().cloned())
}
-}
-fn encode_info_for_mod(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- md: &hir::Mod,
- attrs: &[ast::Attribute],
- id: NodeId,
- name: Name,
- vis: &hir::Visibility) {
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id));
- encode_family(rbml_w, 'm');
- encode_name(rbml_w, name);
- debug!("(encoding info for module) encoding info for module ID {}", id);
-
- // Encode info about all the module children.
- for item_id in &md.item_ids {
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-
- let item = ecx.tcx.map.expect_item(item_id.id);
- each_auxiliary_node_id(item, |auxiliary_node_id| {
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
- true
- });
+ fn encode_item_type(&mut self, def_id: DefId) -> Lazy<Ty<'tcx>> {
+ let tcx = self.tcx;
+ self.lazy(&tcx.lookup_item_type(def_id).ty)
}
- encode_visibility(rbml_w, vis);
-
- let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id));
- let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id));
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
+ /// Encode data for the given variant of the given ADT. The
+ /// index of the variant is untracked: this is ok because we
+ /// will have to lookup the adt-def by its id, and that gives us
+ /// the right to access any information in the adt-def (including,
+ /// e.g., the length of the various vectors).
+ fn encode_enum_variant_info(&mut self,
+ (enum_did, Untracked(index)):
+ (DefId, Untracked<usize>)) -> Entry<'tcx> {
+ let tcx = self.tcx;
+ let def = tcx.lookup_adt_def(enum_did);
+ let variant = &def.variants[index];
+ let def_id = variant.did;
+
+ let data = VariantData {
+ kind: variant.kind,
+ disr: variant.disr_val.to_u64_unchecked(),
+ struct_ctor: None
+ };
- // Encode the reexports of this module, if this module is public.
- if *vis == hir::Public {
- debug!("(encoding info for module) encoding reexports for {}", id);
- encode_reexports(ecx, rbml_w, id);
+ let enum_id = tcx.map.as_local_node_id(enum_did).unwrap();
+ let enum_vis = &tcx.map.expect_item(enum_id).vis;
+
+ Entry {
+ kind: EntryKind::Variant(self.lazy(&data)),
+ visibility: enum_vis.simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+ children: self.lazy_seq(variant.fields.iter().map(|f| {
+ assert!(f.did.is_local());
+ f.did.index
+ })),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: Some(self.encode_item_type(def_id)),
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: None,
+ mir: None
+ }
}
- encode_attributes(rbml_w, attrs);
-
- rbml_w.end_tag();
-}
-fn encode_struct_field_family(rbml_w: &mut Encoder,
- visibility: ty::Visibility) {
- encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' });
-}
+ fn encode_info_for_mod(&mut self,
+ FromId(id, (md, attrs, vis)):
+ FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>)
+ -> Entry<'tcx> {
+ let tcx = self.tcx;
+ let def_id = tcx.map.local_def_id(id);
+
+ let data = ModData {
+ reexports: match self.reexports.get(&id) {
+ Some(exports) if *vis == hir::Public => {
+ self.lazy_seq_ref(exports)
+ }
+ _ => LazySeq::empty()
+ }
+ };
-fn encode_visibility<T: HasVisibility>(rbml_w: &mut Encoder, visibility: T) {
- let ch = if visibility.is_public() { 'y' } else { 'i' };
- rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
+ Entry {
+ kind: EntryKind::Mod(self.lazy(&data)),
+ visibility: vis.simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(attrs),
+ children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
+ tcx.map.local_def_id(item_id.id).index
+ })),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: None,
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: None,
+ predicates: None,
+
+ ast: None,
+ mir: None
+ }
+ }
}
-trait HasVisibility: Sized {
- fn is_public(self) -> bool;
+trait Visibility {
+ fn simplify(&self) -> ty::Visibility;
}
-impl<'a> HasVisibility for &'a hir::Visibility {
- fn is_public(self) -> bool {
- *self == hir::Public
+impl Visibility for hir::Visibility {
+ fn simplify(&self) -> ty::Visibility {
+ if *self == hir::Public {
+ ty::Visibility::Public
+ } else {
+ ty::Visibility::PrivateExternal
+ }
}
}
-impl HasVisibility for ty::Visibility {
- fn is_public(self) -> bool {
- self == ty::Visibility::Public
+impl Visibility for ty::Visibility {
+ fn simplify(&self) -> ty::Visibility {
+ if *self == ty::Visibility::Public {
+ ty::Visibility::Public
+ } else {
+ ty::Visibility::PrivateExternal
+ }
}
}
-fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
- rbml_w.start_tag(tag_items_data_item_constness);
- let ch = match constness {
- hir::Constness::Const => 'c',
- hir::Constness::NotConst => 'n',
- };
- rbml_w.wr_str(&ch.to_string());
- rbml_w.end_tag();
-}
-
-fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) {
- let ch = match defaultness {
- hir::Defaultness::Default => 'd',
- hir::Defaultness::Final => 'f',
- };
- rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
-}
-
-fn encode_explicit_self(rbml_w: &mut Encoder,
- explicit_self: &ty::ExplicitSelfCategory) {
- let tag = tag_item_trait_method_explicit_self;
-
- // Encode the base self type.
- match *explicit_self {
- ty::ExplicitSelfCategory::Static => {
- rbml_w.wr_tagged_bytes(tag, &['s' as u8]);
- }
- ty::ExplicitSelfCategory::ByValue => {
- rbml_w.wr_tagged_bytes(tag, &['v' as u8]);
- }
- ty::ExplicitSelfCategory::ByBox => {
- rbml_w.wr_tagged_bytes(tag, &['~' as u8]);
- }
- ty::ExplicitSelfCategory::ByReference(_, m) => {
- // FIXME(#4846) encode custom lifetime
- let ch = encode_mutability(m);
- rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]);
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+ fn encode_fields(&mut self,
+ adt_def_id: DefId) {
+ let def = self.tcx.lookup_adt_def(adt_def_id);
+ for (variant_index, variant) in def.variants.iter().enumerate() {
+ for (field_index, field) in variant.fields.iter().enumerate() {
+ self.record(field.did,
+ EncodeContext::encode_field,
+ (adt_def_id, Untracked((variant_index, field_index))));
+ }
}
}
+}
- fn encode_mutability(m: hir::Mutability) -> u8 {
- match m {
- hir::MutImmutable => 'i' as u8,
- hir::MutMutable => 'm' as u8,
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ /// Encode data for the given field of the given variant of the
+ /// given ADT. The indices of the variant/field are untracked:
+ /// this is ok because we will have to lookup the adt-def by its
+ /// id, and that gives us the right to access any information in
+ /// the adt-def (including, e.g., the length of the various
+ /// vectors).
+ fn encode_field(&mut self,
+ (adt_def_id, Untracked((variant_index, field_index))):
+ (DefId, Untracked<(usize, usize)>)) -> Entry<'tcx> {
+ let tcx = self.tcx;
+ let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index];
+ let field = &variant.fields[field_index];
+
+ let def_id = field.did;
+ let variant_id = tcx.map.as_local_node_id(variant.did).unwrap();
+ let variant_data = tcx.map.expect_variant_data(variant_id);
+
+ Entry {
+ kind: EntryKind::Field,
+ visibility: field.vis.simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
+ children: LazySeq::empty(),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: Some(self.encode_item_type(def_id)),
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: None,
+ mir: None
}
}
-}
-fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
- rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
-}
+ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId))
+ -> Entry<'tcx> {
+ let variant = self.tcx.lookup_adt_def(adt_def_id).struct_variant();
-fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- field: ty::FieldDef<'tcx>,
- index: &mut CrateIndex<'a, 'tcx>) {
- let nm = field.name;
- let id = ecx.local_id(field.did);
-
- let _task = index.record(field.did, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- debug!("encode_field: encoding {} {}", nm, id);
- encode_struct_field_family(rbml_w, field.vis);
- encode_name(rbml_w, nm);
- encode_bounds_and_type_for_item(rbml_w, ecx, index, id);
- encode_def_id_and_key(ecx, rbml_w, field.did);
-
- let stab = ecx.tcx.lookup_stability(field.did);
- let depr = ecx.tcx.lookup_deprecation(field.did);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
-
- rbml_w.end_tag();
-}
+ let data = VariantData {
+ kind: variant.kind,
+ disr: variant.disr_val.to_u64_unchecked(),
+ struct_ctor: Some(def_id.index)
+ };
-fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- name: Name,
- struct_def: &hir::VariantData,
- index: &mut CrateIndex<'a, 'tcx>,
- struct_id: NodeId) {
- let ctor_id = struct_def.id();
- let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
-
- let _task = index.record(ctor_def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
- encode_family(rbml_w, match *struct_def {
- hir::VariantData::Struct(..) => 'S',
- hir::VariantData::Tuple(..) => 's',
- hir::VariantData::Unit(..) => 'u',
- });
- encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
- encode_name(rbml_w, name);
- encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
-
- let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id));
- let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id));
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
-
- // indicate that this is a tuple struct ctor, because downstream users will normally want
- // the tuple struct definition, but without this there is no way for them to tell that
- // they actually have a ctor rather than a normal function
- rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
-
- rbml_w.end_tag();
-}
+ Entry {
+ kind: EntryKind::Struct(self.lazy(&data)),
+ visibility: ty::Visibility::Public,
+ def_key: self.encode_def_key(def_id),
+ attributes: LazySeq::empty(),
+ children: LazySeq::empty(),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: Some(self.encode_item_type(def_id)),
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: None,
+ mir: None
+ }
+ }
-fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a, 'tcx>,
- index: &mut CrateIndex<'a, 'tcx>,
- generics: &ty::Generics<'tcx>,
- predicates: &ty::GenericPredicates<'tcx>,
- tag: usize)
-{
- rbml_w.start_tag(tag);
-
- for param in &generics.types {
- rbml_w.start_tag(tag_type_param_def);
- tyencode::enc_type_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
- rbml_w.mark_stable_position();
- rbml_w.end_tag();
+ fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics<'tcx>> {
+ let tcx = self.tcx;
+ self.lazy(tcx.lookup_generics(def_id))
}
- // Region parameters
- for param in &generics.regions {
- rbml_w.start_tag(tag_region_param_def);
- tyencode::enc_region_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
- rbml_w.mark_stable_position();
- rbml_w.end_tag();
+ fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+ let tcx = self.tcx;
+ self.lazy(&tcx.lookup_predicates(def_id))
}
- encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
+ fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+ let tcx = self.tcx;
- rbml_w.end_tag();
-}
+ let node_id = tcx.map.as_local_node_id(def_id).unwrap();
+ let ast_item = tcx.map.expect_trait_item(node_id);
+ let trait_item = tcx.impl_or_trait_item(def_id);
-fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
- _ecx: &EncodeContext<'a,'tcx>,
- index: &mut CrateIndex<'a, 'tcx>,
- predicates: &ty::GenericPredicates<'tcx>)
-{
- for (space, _, predicate) in predicates.predicates.iter_enumerated() {
- let tag = match space {
- subst::TypeSpace => tag_type_predicate,
- subst::SelfSpace => tag_self_predicate,
- subst::FnSpace => tag_fn_predicate
+ let container = |has_body| if has_body {
+ AssociatedContainer::TraitWithDefault
+ } else {
+ AssociatedContainer::TraitRequired
};
- rbml_w.wr_tagged_u32(tag,
- index.add_xref(XRef::Predicate(predicate.clone())));
- }
-}
-
-fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a,'tcx>,
- index: &mut CrateIndex<'a, 'tcx>,
- predicates: &ty::GenericPredicates<'tcx>,
- tag: usize)
-{
- rbml_w.start_tag(tag);
- encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
- rbml_w.end_tag();
-}
+ let kind = match trait_item {
+ ty::ConstTraitItem(ref associated_const) => {
+ EntryKind::AssociatedConst(container(associated_const.has_value))
+ }
+ ty::MethodTraitItem(ref method_ty) => {
+ let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+ FnData {
+ constness: hir::Constness::NotConst,
+ arg_names: self.encode_fn_arg_names(&sig.decl)
+ }
+ } else {
+ bug!()
+ };
+ let data = MethodData {
+ fn_data: fn_data,
+ container: container(method_ty.has_body),
+ explicit_self: self.lazy(&method_ty.explicit_self)
+ };
+ EntryKind::Method(self.lazy(&data))
+ }
+ ty::TypeTraitItem(_) => {
+ EntryKind::AssociatedType(container(false))
+ }
+ };
-fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- index: &mut CrateIndex<'a, 'tcx>,
- method_ty: &ty::Method<'tcx>) {
- encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
- encode_name(rbml_w, method_ty.name);
- encode_generics(rbml_w, ecx, index,
- &method_ty.generics, &method_ty.predicates,
- tag_method_ty_generics);
- encode_visibility(rbml_w, method_ty.vis);
- encode_explicit_self(rbml_w, &method_ty.explicit_self);
- match method_ty.explicit_self {
- ty::ExplicitSelfCategory::Static => {
- encode_family(rbml_w, STATIC_METHOD_FAMILY);
+ Entry {
+ kind: kind,
+ visibility: trait_item.vis().simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&ast_item.attrs),
+ children: LazySeq::empty(),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: match trait_item {
+ ty::ConstTraitItem(_) |
+ ty::MethodTraitItem(_) => {
+ Some(self.encode_item_type(def_id))
+ }
+ ty::TypeTraitItem(ref associated_type) => {
+ associated_type.ty.map(|ty| self.lazy(&ty))
+ }
+ },
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: if let ty::ConstTraitItem(_) = trait_item {
+ let trait_def_id = trait_item.container().id();
+ Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
+ } else {
+ None
+ },
+ mir: self.encode_mir(def_id)
}
- _ => encode_family(rbml_w, METHOD_FAMILY)
}
-}
-fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- index: &mut CrateIndex<'a, 'tcx>,
- associated_const: &ty::AssociatedConst,
- parent_id: NodeId,
- impl_item_opt: Option<&hir::ImplItem>) {
- debug!("encode_info_for_associated_const({:?},{:?})",
- associated_const.def_id,
- associated_const.name);
-
- let _task = index.record(associated_const.def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
-
- encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
- encode_name(rbml_w, associated_const.name);
- encode_visibility(rbml_w, associated_const.vis);
- encode_family(rbml_w, 'C');
-
- encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
- encode_item_sort(rbml_w, 'C');
-
- encode_bounds_and_type_for_item(rbml_w, ecx, index,
- ecx.local_id(associated_const.def_id));
-
- let stab = ecx.tcx.lookup_stability(associated_const.def_id);
- let depr = ecx.tcx.lookup_deprecation(associated_const.def_id);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
-
- if let Some(ii) = impl_item_opt {
- encode_attributes(rbml_w, &ii.attrs);
- encode_defaultness(rbml_w, ii.defaultness);
- encode_inlined_item(ecx,
- rbml_w,
- InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
- ii));
- encode_mir(ecx, rbml_w, ii.id);
- }
+ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+ let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
+ let ast_item = self.tcx.map.expect_impl_item(node_id);
+ let impl_item = self.tcx.impl_or_trait_item(def_id);
+ let impl_def_id = impl_item.container().id();
- rbml_w.end_tag();
-}
+ let container = match ast_item.defaultness {
+ hir::Defaultness::Default => AssociatedContainer::ImplDefault,
+ hir::Defaultness::Final => AssociatedContainer::ImplFinal
+ };
-fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- index: &mut CrateIndex<'a, 'tcx>,
- m: &ty::Method<'tcx>,
- is_default_impl: bool,
- parent_id: NodeId,
- impl_item_opt: Option<&hir::ImplItem>) {
-
- debug!("encode_info_for_method: {:?} {:?}", m.def_id,
- m.name);
- let _task = index.record(m.def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
-
- encode_method_ty_fields(ecx, rbml_w, index, m);
- encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
- encode_item_sort(rbml_w, 'r');
-
- let stab = ecx.tcx.lookup_stability(m.def_id);
- let depr = ecx.tcx.lookup_deprecation(m.def_id);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
-
- let m_node_id = ecx.local_id(m.def_id);
- encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id);
-
- if let Some(impl_item) = impl_item_opt {
- if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
- encode_attributes(rbml_w, &impl_item.attrs);
- let scheme = ecx.tcx.lookup_item_type(m.def_id);
- let any_types = !scheme.generics.types.is_empty();
- let needs_inline = any_types || is_default_impl ||
- attr::requests_inline(&impl_item.attrs);
- if needs_inline || sig.constness == hir::Constness::Const {
- encode_inlined_item(ecx,
- rbml_w,
- InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
- impl_item));
- encode_mir(ecx, rbml_w, impl_item.id);
+ let kind = match impl_item {
+ ty::ConstTraitItem(_) => {
+ EntryKind::AssociatedConst(container)
}
- encode_constness(rbml_w, sig.constness);
- encode_defaultness(rbml_w, impl_item.defaultness);
- encode_method_argument_names(rbml_w, &sig.decl);
- }
- }
-
- rbml_w.end_tag();
-}
-
-fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- index: &mut CrateIndex<'a, 'tcx>,
- associated_type: &ty::AssociatedType<'tcx>,
- parent_id: NodeId,
- impl_item_opt: Option<&hir::ImplItem>) {
- debug!("encode_info_for_associated_type({:?},{:?})",
- associated_type.def_id,
- associated_type.name);
-
- let _task = index.record(associated_type.def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
-
- encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
- encode_name(rbml_w, associated_type.name);
- encode_visibility(rbml_w, associated_type.vis);
- encode_family(rbml_w, 'y');
- encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
- encode_item_sort(rbml_w, 't');
-
- let stab = ecx.tcx.lookup_stability(associated_type.def_id);
- let depr = ecx.tcx.lookup_deprecation(associated_type.def_id);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
-
- if let Some(ii) = impl_item_opt {
- encode_attributes(rbml_w, &ii.attrs);
- encode_defaultness(rbml_w, ii.defaultness);
- } else {
- encode_predicates(rbml_w, ecx, index,
- &ecx.tcx.lookup_predicates(associated_type.def_id),
- tag_item_generics);
- }
-
- if let Some(ty) = associated_type.ty {
- encode_type(ecx, rbml_w, ty);
- }
-
- rbml_w.end_tag();
-}
+ ty::MethodTraitItem(ref method_ty) => {
+ let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ FnData {
+ constness: sig.constness,
+ arg_names: self.encode_fn_arg_names(&sig.decl)
+ }
+ } else {
+ bug!()
+ };
+ let data = MethodData {
+ fn_data: fn_data,
+ container: container,
+ explicit_self: self.lazy(&method_ty.explicit_self)
+ };
+ EntryKind::Method(self.lazy(&data))
+ }
+ ty::TypeTraitItem(_) => {
+ EntryKind::AssociatedType(container)
+ }
+ };
-fn encode_method_argument_names(rbml_w: &mut Encoder,
- decl: &hir::FnDecl) {
- rbml_w.start_tag(tag_method_argument_names);
- for arg in &decl.inputs {
- let tag = tag_method_argument_name;
- if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
- let name = path1.node.as_str();
- rbml_w.wr_tagged_bytes(tag, name.as_bytes());
+ let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item {
+ (true, true)
+ } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ let generics = self.tcx.lookup_generics(def_id);
+ let types = generics.parent_types as usize + generics.types.len();
+ let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
+ let is_const_fn = sig.constness == hir::Constness::Const;
+ (is_const_fn, needs_inline || is_const_fn)
} else {
- rbml_w.wr_tagged_bytes(tag, &[]);
+ (false, false)
+ };
+
+ Entry {
+ kind: kind,
+ visibility: impl_item.vis().simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&ast_item.attrs),
+ children: LazySeq::empty(),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: match impl_item {
+ ty::ConstTraitItem(_) |
+ ty::MethodTraitItem(_) => {
+ Some(self.encode_item_type(def_id))
+ }
+ ty::TypeTraitItem(ref associated_type) => {
+ associated_type.ty.map(|ty| self.lazy(&ty))
+ }
+ },
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: if ast {
+ Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
+ } else {
+ None
+ },
+ mir: if mir {
+ self.encode_mir(def_id)
+ } else {
+ None
+ }
}
}
- rbml_w.end_tag();
-}
-fn encode_repr_attrs(rbml_w: &mut Encoder,
- ecx: &EncodeContext,
- attrs: &[ast::Attribute]) {
- let mut repr_attrs = Vec::new();
- for attr in attrs {
- repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
- attr));
+ fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
+ self.lazy_seq(decl.inputs.iter().map(|arg| {
+ if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
+ path1.node
+ } else {
+ syntax::parse::token::intern("")
+ }
+ }))
}
- rbml_w.start_tag(tag_items_data_item_repr);
- repr_attrs.encode(rbml_w);
- rbml_w.end_tag();
-}
-fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
- let def_id = ecx.tcx.map.local_def_id(node_id);
- if let Some(mir) = ecx.mir_map.map.get(&def_id) {
- rbml_w.start_tag(tag_mir as usize);
- rbml_w.emit_opaque(|opaque_encoder| {
- tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
- Encodable::encode(mir, opaque_encoder)
- })
- }).unwrap();
- rbml_w.end_tag();
+ fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::repr::Mir<'tcx>>> {
+ self.mir_map.map.get(&def_id).map(|mir| self.lazy(mir))
}
-}
-const FN_FAMILY: char = 'f';
-const STATIC_METHOD_FAMILY: char = 'F';
-const METHOD_FAMILY: char = 'h';
-
-// Encodes the inherent implementations of a structure, enumeration, or trait.
-fn encode_inherent_implementations(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- def_id: DefId) {
- match ecx.tcx.inherent_impls.borrow().get(&def_id) {
- None => {}
- Some(implementations) => {
- for &impl_def_id in implementations.iter() {
- rbml_w.start_tag(tag_items_data_item_inherent_impl);
- encode_def_id(rbml_w, impl_def_id);
- rbml_w.end_tag();
+ // Encodes the inherent implementations of a structure, enumeration, or trait.
+ fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
+ match self.tcx.inherent_impls.borrow().get(&def_id) {
+ None => LazySeq::empty(),
+ Some(implementations) => {
+ self.lazy_seq(implementations.iter().map(|&def_id| {
+ assert!(def_id.is_local());
+ def_id.index
+ }))
}
}
}
-}
-fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
- stab_opt.map(|stab| {
- rbml_w.start_tag(tag_items_data_item_stability);
- stab.encode(rbml_w).unwrap();
- rbml_w.end_tag();
- });
-}
+ fn encode_stability(&mut self, def_id: DefId) -> Option<Lazy<attr::Stability>> {
+ self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab))
+ }
-fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>) {
- depr_opt.map(|depr| {
- rbml_w.start_tag(tag_items_data_item_deprecation);
- depr.encode(rbml_w).unwrap();
- rbml_w.end_tag();
- });
-}
+ fn encode_deprecation(&mut self, def_id: DefId) -> Option<Lazy<attr::Deprecation>> {
+ self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
+ }
-fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
- parent_opt.map(|parent| {
- rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
- });
-}
+ fn encode_info_for_item(&mut self,
+ (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> {
+ let tcx = self.tcx;
+
+ debug!("encoding info for item at {}",
+ tcx.sess.codemap().span_to_string(item.span));
+
+ let kind = match item.node {
+ hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
+ hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
+ hir::ItemConst(..) => EntryKind::Const,
+ hir::ItemFn(ref decl, _, constness, ..) => {
+ let data = FnData {
+ constness: constness,
+ arg_names: self.encode_fn_arg_names(&decl)
+ };
-fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- xrefs: FnvHashMap<XRef<'tcx>, u32>)
-{
- let mut xref_positions = vec![0; xrefs.len()];
- rbml_w.start_tag(tag_xref_data);
- for (xref, id) in xrefs.into_iter() {
- xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
- match xref {
- XRef::Predicate(p) => {
- tyencode::enc_predicate(rbml_w.writer, &ecx.ty_str_ctxt(), &p)
+ EntryKind::Fn(self.lazy(&data))
}
- }
- }
- rbml_w.mark_stable_position();
- rbml_w.end_tag();
-
- rbml_w.start_tag(tag_xref_index);
- index::write_dense_index(xref_positions, rbml_w.writer);
- rbml_w.end_tag();
-}
+ hir::ItemMod(ref m) => {
+ return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis)));
+ }
+ hir::ItemForeignMod(_) => EntryKind::ForeignMod,
+ hir::ItemTy(..) => EntryKind::Type,
+ hir::ItemEnum(..) => EntryKind::Enum,
+ hir::ItemStruct(ref struct_def, _) => {
+ let variant = tcx.lookup_adt_def(def_id).struct_variant();
+
+ /* Encode def_ids for each field and method
+ for methods, write all the stuff get_trait_method
+ needs to know*/
+ let struct_ctor = if !struct_def.is_struct() {
+ Some(tcx.map.local_def_id(struct_def.id()).index)
+ } else {
+ None
+ };
+ EntryKind::Struct(self.lazy(&VariantData {
+ kind: variant.kind,
+ disr: variant.disr_val.to_u64_unchecked(),
+ struct_ctor: struct_ctor
+ }))
+ }
+ hir::ItemUnion(..) => {
+ let variant = tcx.lookup_adt_def(def_id).struct_variant();
+
+ EntryKind::Union(self.lazy(&VariantData {
+ kind: variant.kind,
+ disr: variant.disr_val.to_u64_unchecked(),
+ struct_ctor: None
+ }))
+ }
+ hir::ItemDefaultImpl(..) => {
+ let data = ImplData {
+ polarity: hir::ImplPolarity::Positive,
+ parent_impl: None,
+ coerce_unsized_kind: None,
+ trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref))
+ };
-fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- item: &hir::Item,
- index: &mut CrateIndex<'a, 'tcx>) {
- let tcx = ecx.tcx;
-
- debug!("encoding info for item at {}",
- tcx.sess.codemap().span_to_string(item.span));
-
- let vis = &item.vis;
- let def_id = ecx.tcx.map.local_def_id(item.id);
-
- let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
- (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
- tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
- });
-
- match item.node {
- hir::ItemStatic(_, m, _) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- if m == hir::MutMutable {
- encode_family(rbml_w, 'b');
- } else {
- encode_family(rbml_w, 'c');
- }
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- encode_attributes(rbml_w, &item.attrs);
- rbml_w.end_tag();
- }
- hir::ItemConst(_, _) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'C');
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
- encode_mir(ecx, rbml_w, item.id);
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- rbml_w.end_tag();
- }
- hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, FN_FAMILY);
- let tps_len = generics.ty_params.len();
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
- if needs_inline || constness == hir::Constness::Const {
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
- encode_mir(ecx, rbml_w, item.id);
- }
- encode_constness(rbml_w, constness);
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- encode_method_argument_names(rbml_w, &decl);
- rbml_w.end_tag();
- }
- hir::ItemMod(ref m) => {
- let _task = index.record(def_id, rbml_w);
- encode_info_for_mod(ecx,
- rbml_w,
- m,
- &item.attrs,
- item.id,
- item.name,
- &item.vis);
- }
- hir::ItemForeignMod(ref fm) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'n');
- encode_name(rbml_w, item.name);
-
- // Encode all the items in this module.
- for foreign_item in &fm.items {
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
- }
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- rbml_w.end_tag();
- }
- hir::ItemTy(..) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'y');
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- rbml_w.end_tag();
- }
- hir::ItemEnum(ref enum_definition, _) => {
- let _task = index.record(def_id, rbml_w);
-
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 't');
- encode_item_variances(rbml_w, ecx, item.id);
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- encode_repr_attrs(rbml_w, ecx, &item.attrs);
- for v in &enum_definition.variants {
- encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
- }
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
- encode_mir(ecx, rbml_w, item.id);
-
- // Encode inherent implementations for this enumeration.
- encode_inherent_implementations(ecx, rbml_w, def_id);
-
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- rbml_w.end_tag();
-
- encode_enum_variant_info(ecx,
- rbml_w,
- def_id,
- vis,
- index);
- }
- hir::ItemStruct(ref struct_def, _) => {
- /* Index the class*/
- let _task = index.record(def_id, rbml_w);
-
- let def = ecx.tcx.lookup_adt_def(def_id);
- let variant = def.struct_variant();
-
- /* Now, make an item for the class itself */
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, match *struct_def {
- hir::VariantData::Struct(..) => 'S',
- hir::VariantData::Tuple(..) => 's',
- hir::VariantData::Unit(..) => 'u',
- });
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-
- encode_item_variances(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- encode_visibility(rbml_w, vis);
- encode_repr_attrs(rbml_w, ecx, &item.attrs);
-
- /* Encode def_ids for each field and method
- for methods, write all the stuff get_trait_method
- needs to know*/
- encode_struct_fields(rbml_w, variant);
-
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
- encode_mir(ecx, rbml_w, item.id);
-
- // Encode inherent implementations for this structure.
- encode_inherent_implementations(ecx, rbml_w, def_id);
-
- if !struct_def.is_struct() {
- let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
- rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
- def_to_u64(ctor_did));
- }
+ EntryKind::DefaultImpl(self.lazy(&data))
+ }
+ hir::ItemImpl(_, polarity, ..) => {
+ let trait_ref = tcx.impl_trait_ref(def_id);
+ let parent = if let Some(trait_ref) = trait_ref {
+ let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+ trait_def.ancestors(def_id).skip(1).next().and_then(|node| {
+ match node {
+ specialization_graph::Node::Impl(parent) => Some(parent),
+ _ => None,
+ }
+ })
+ } else {
+ None
+ };
- rbml_w.end_tag();
+ let data = ImplData {
+ polarity: polarity,
+ parent_impl: parent,
+ coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow()
+ .get(&def_id).cloned(),
+ trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref))
+ };
- for field in &variant.fields {
- encode_field(ecx, rbml_w, field, index);
- }
+ EntryKind::Impl(self.lazy(&data))
+ }
+ hir::ItemTrait(..) => {
+ let trait_def = tcx.lookup_trait_def(def_id);
+ let data = TraitData {
+ unsafety: trait_def.unsafety,
+ paren_sugar: trait_def.paren_sugar,
+ has_default_impl: tcx.trait_has_default_impl(def_id),
+ trait_ref: self.lazy(&trait_def.trait_ref),
+ super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id))
+ };
- // If this is a tuple-like struct, encode the type of the constructor.
- if !struct_def.is_struct() {
- encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id);
- }
- }
- hir::ItemDefaultImpl(unsafety, _) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'd');
- encode_name(rbml_w, item.name);
- encode_unsafety(rbml_w, unsafety);
-
- let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
- encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
- rbml_w.end_tag();
- }
- hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
- let _task = index.record(def_id, rbml_w);
-
- // 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.get(&def_id).unwrap();
-
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'i');
- encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- encode_unsafety(rbml_w, unsafety);
- encode_polarity(rbml_w, polarity);
-
- match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) {
- Some(&kind) => {
- rbml_w.start_tag(tag_impl_coerce_unsized_kind);
- kind.encode(rbml_w);
- rbml_w.end_tag();
+ EntryKind::Trait(self.lazy(&data))
}
- None => {}
- }
+ hir::ItemExternCrate(_) | hir::ItemUse(_) => {
+ bug!("cannot encode info for item {:?}", item)
+ }
+ };
- for &item_def_id in items {
- rbml_w.start_tag(tag_item_impl_item);
- match item_def_id {
- ty::ConstTraitItemId(item_def_id) => {
- encode_def_id(rbml_w, item_def_id);
- encode_item_sort(rbml_w, 'C');
+ Entry {
+ kind: kind,
+ visibility: item.vis.simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&item.attrs),
+ children: match item.node {
+ hir::ItemForeignMod(ref fm) => {
+ self.lazy_seq(fm.items.iter().map(|foreign_item| {
+ tcx.map.local_def_id(foreign_item.id).index
+ }))
}
- ty::MethodTraitItemId(item_def_id) => {
- encode_def_id(rbml_w, item_def_id);
- encode_item_sort(rbml_w, 'r');
+ hir::ItemEnum(..) => {
+ let def = self.tcx.lookup_adt_def(def_id);
+ self.lazy_seq(def.variants.iter().map(|v| {
+ assert!(v.did.is_local());
+ v.did.index
+ }))
}
- ty::TypeTraitItemId(item_def_id) => {
- encode_def_id(rbml_w, item_def_id);
- encode_item_sort(rbml_w, 't');
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) => {
+ let def = self.tcx.lookup_adt_def(def_id);
+ self.lazy_seq(def.struct_variant().fields.iter().map(|f| {
+ assert!(f.did.is_local());
+ f.did.index
+ }))
}
- }
- rbml_w.end_tag();
- }
- let did = ecx.tcx.map.local_def_id(item.id);
- if let Some(trait_ref) = tcx.impl_trait_ref(did) {
- encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
-
- let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
- let parent = trait_def.ancestors(did)
- .skip(1)
- .next()
- .and_then(|node| match node {
- specialization_graph::Node::Impl(parent) => Some(parent),
- _ => None,
- });
- encode_parent_impl(rbml_w, parent);
- }
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- rbml_w.end_tag();
-
- // 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) => {
- encode_info_for_associated_const(ecx,
- rbml_w,
- index,
- &associated_const,
- item.id,
- ast_item)
+ hir::ItemImpl(..) |
+ hir::ItemTrait(..) => {
+ self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| {
+ assert!(def_id.is_local());
+ def_id.index
+ }))
}
- ty::MethodTraitItem(ref method_type) => {
- encode_info_for_method(ecx,
- rbml_w,
- index,
- &method_type,
- false,
- item.id,
- ast_item)
+ _ => LazySeq::empty()
+ },
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: match item.node {
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) |
+ hir::ItemFn(..) |
+ hir::ItemTy(..) |
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemImpl(..) => {
+ Some(self.encode_item_type(def_id))
}
- ty::TypeTraitItem(ref associated_type) => {
- encode_info_for_associated_type(ecx,
- rbml_w,
- index,
- &associated_type,
- item.id,
- ast_item)
+ _ => None
+ },
+ inherent_impls: self.encode_inherent_implementations(def_id),
+ variances: match item.node {
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemTrait(..) => {
+ self.encode_item_variances(def_id)
}
- }
- }
- }
- hir::ItemTrait(_, _, _, ref ms) => {
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_family(rbml_w, 'I');
- encode_item_variances(rbml_w, ecx, item.id);
- let trait_def = tcx.lookup_trait_def(def_id);
- let trait_predicates = tcx.lookup_predicates(def_id);
- encode_unsafety(rbml_w, trait_def.unsafety);
- encode_paren_sugar(rbml_w, trait_def.paren_sugar);
- encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id));
- encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
- encode_generics(rbml_w, ecx, index,
- &trait_def.generics, &trait_predicates,
- tag_item_generics);
- encode_predicates(rbml_w, ecx, index,
- &tcx.lookup_super_predicates(def_id),
- tag_item_super_predicates);
- encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
- encode_name(rbml_w, item.name);
- encode_attributes(rbml_w, &item.attrs);
- encode_visibility(rbml_w, vis);
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
- rbml_w.start_tag(tag_item_trait_item);
- match method_def_id {
- ty::ConstTraitItemId(const_def_id) => {
- encode_def_id(rbml_w, const_def_id);
- encode_item_sort(rbml_w, 'C');
+ _ => LazySeq::empty()
+ },
+ generics: match item.node {
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) |
+ hir::ItemFn(..) |
+ hir::ItemTy(..) |
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemImpl(..) |
+ hir::ItemTrait(..) => {
+ Some(self.encode_generics(def_id))
+ }
+ _ => None
+ },
+ predicates: match item.node {
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) |
+ hir::ItemFn(..) |
+ hir::ItemTy(..) |
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemImpl(..) |
+ hir::ItemTrait(..) => {
+ Some(self.encode_predicates(def_id))
+ }
+ _ => None
+ },
+
+ ast: match item.node {
+ hir::ItemConst(..) |
+ hir::ItemFn(_, _, hir::Constness::Const, ..) => {
+ Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
}
- ty::MethodTraitItemId(method_def_id) => {
- encode_def_id(rbml_w, method_def_id);
- encode_item_sort(rbml_w, 'r');
+ _ => None
+ },
+ mir: match item.node {
+ hir::ItemConst(..) => {
+ self.encode_mir(def_id)
}
- ty::TypeTraitItemId(type_def_id) => {
- encode_def_id(rbml_w, type_def_id);
- encode_item_sort(rbml_w, 't');
+ hir::ItemFn(_, _, constness, _, ref generics, _) => {
+ let tps_len = generics.ty_params.len();
+ let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
+ if needs_inline || constness == hir::Constness::Const {
+ self.encode_mir(def_id)
+ } else {
+ None
+ }
}
+ _ => None
}
- rbml_w.end_tag();
-
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(method_def_id.def_id()));
}
+ }
+}
- // Encode inherent implementations for this trait.
- encode_inherent_implementations(ecx, rbml_w, def_id);
-
- rbml_w.end_tag();
-
- // 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);
-
- let _task = index.record(item_def_id.def_id(), rbml_w);
- rbml_w.start_tag(tag_items_data_item);
-
- encode_parent_item(rbml_w, def_id);
-
- let stab = tcx.lookup_stability(item_def_id.def_id());
- let depr = tcx.lookup_deprecation(item_def_id.def_id());
- encode_stability(rbml_w, stab);
- encode_deprecation(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(rbml_w, associated_const.name);
- encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
- encode_visibility(rbml_w, associated_const.vis);
-
- encode_family(rbml_w, 'C');
-
- encode_bounds_and_type_for_item(rbml_w, ecx, index,
- ecx.local_id(associated_const.def_id));
-
- is_nonstatic_method = false;
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+ /// 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.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_fields(def_id);
+
+ let def = self.tcx.lookup_adt_def(def_id);
+ for (i, variant) in def.variants.iter().enumerate() {
+ self.record(variant.did,
+ EncodeContext::encode_enum_variant_info,
+ (def_id, Untracked(i)));
}
- ty::MethodTraitItem(method_ty) => {
- let method_def_id = item_def_id.def_id();
-
- encode_method_ty_fields(ecx, rbml_w, index, &method_ty);
+ }
+ hir::ItemStruct(ref struct_def, _) => {
+ self.encode_fields(def_id);
- match method_ty.explicit_self {
- ty::ExplicitSelfCategory::Static => {
- encode_family(rbml_w,
- STATIC_METHOD_FAMILY);
- }
- _ => {
- encode_family(rbml_w,
- METHOD_FAMILY);
- }
+ // If this is a tuple-like struct, encode the type of the constructor.
+ match self.tcx.lookup_adt_def(def_id).struct_variant().kind {
+ ty::VariantKind::Struct => {
+ // no value for structs like struct Foo { ... }
}
- encode_bounds_and_type_for_item(rbml_w, ecx, index,
- ecx.local_id(method_def_id));
-
- is_nonstatic_method = method_ty.explicit_self !=
- ty::ExplicitSelfCategory::Static;
- }
- ty::TypeTraitItem(associated_type) => {
- encode_name(rbml_w, associated_type.name);
- encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
- encode_item_sort(rbml_w, 't');
- encode_family(rbml_w, 'y');
-
- if let Some(ty) = associated_type.ty {
- encode_type(ecx, rbml_w, ty);
+ ty::VariantKind::Tuple | ty::VariantKind::Unit => {
+ // there is a value for structs like `struct
+ // Foo()` and `struct Foo`
+ let ctor_def_id = self.tcx.map.local_def_id(struct_def.id());
+ self.record(ctor_def_id,
+ EncodeContext::encode_struct_ctor,
+ (def_id, ctor_def_id));
}
-
- is_nonstatic_method = false;
}
}
-
- let trait_item = &ms[i];
- encode_attributes(rbml_w, &trait_item.attrs);
- match trait_item.node {
- hir::ConstTraitItem(_, ref default) => {
- if default.is_some() {
- encode_item_sort(rbml_w, 'C');
- } else {
- encode_item_sort(rbml_w, 'c');
- }
-
- encode_inlined_item(ecx, rbml_w,
- InlinedItemRef::TraitItem(def_id, trait_item));
- encode_mir(ecx, rbml_w, trait_item.id);
+ hir::ItemUnion(..) => {
+ self.encode_fields(def_id);
+ }
+ hir::ItemImpl(..) => {
+ for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+ self.record(trait_item_def_id,
+ EncodeContext::encode_info_for_impl_item,
+ trait_item_def_id);
}
- hir::MethodTraitItem(ref sig, ref body) => {
- // If this is a static method, we've already
- // encoded this.
- if is_nonstatic_method {
- // FIXME: I feel like there is something funny
- // going on.
- encode_bounds_and_type_for_item(rbml_w, ecx, index,
- ecx.local_id(item_def_id.def_id()));
- }
-
- if body.is_some() {
- encode_item_sort(rbml_w, 'p');
- encode_inlined_item(ecx, rbml_w,
- InlinedItemRef::TraitItem(def_id, trait_item));
- encode_mir(ecx, rbml_w, trait_item.id);
- } else {
- encode_item_sort(rbml_w, 'r');
- }
- encode_method_argument_names(rbml_w, &sig.decl);
+ }
+ hir::ItemTrait(..) => {
+ for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+ self.record(item_def_id,
+ EncodeContext::encode_info_for_trait_item,
+ item_def_id);
}
-
- hir::TypeTraitItem(..) => {}
}
-
- rbml_w.end_tag();
}
- }
- hir::ItemExternCrate(_) | hir::ItemUse(_) => {
- // these are encoded separately
- }
}
}
-fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- nitem: &hir::ForeignItem,
- index: &mut CrateIndex<'a, 'tcx>) {
- debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
- let def_id = ecx.tcx.map.local_def_id(nitem.id);
- let abi = ecx.tcx.map.get_foreign_abi(nitem.id);
-
- let _task = index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- let parent_id = ecx.tcx.map.get_parent(nitem.id);
- encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
- encode_visibility(rbml_w, &nitem.vis);
- match nitem.node {
- hir::ForeignItemFn(ref fndecl, _) => {
- encode_family(rbml_w, FN_FAMILY);
- encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
- encode_name(rbml_w, nitem.name);
- if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem));
- encode_mir(ecx, rbml_w, nitem.id);
- }
- encode_attributes(rbml_w, &nitem.attrs);
- let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
- let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- encode_method_argument_names(rbml_w, &fndecl);
- }
- hir::ForeignItemStatic(_, mutbl) => {
- if mutbl {
- encode_family(rbml_w, 'b');
- } else {
- encode_family(rbml_w, 'c');
- }
- encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
- encode_attributes(rbml_w, &nitem.attrs);
- let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
- let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
- encode_stability(rbml_w, stab);
- encode_deprecation(rbml_w, depr);
- encode_name(rbml_w, nitem.name);
- }
- }
- rbml_w.end_tag();
-}
-
-fn my_visit_expr(expr: &hir::Expr,
- rbml_w: &mut Encoder,
- ecx: &EncodeContext,
- index: &mut CrateIndex) {
- match expr.node {
- hir::ExprClosure(..) => {
- let def_id = ecx.tcx.map.local_def_id(expr.id);
-
- let _task = index.record(def_id, rbml_w);
-
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(ecx, rbml_w, def_id);
- encode_name(rbml_w, syntax::parse::token::intern("<closure>"));
-
- rbml_w.start_tag(tag_items_closure_ty);
- write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]);
- rbml_w.end_tag();
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ fn encode_info_for_foreign_item(&mut self,
+ (def_id, nitem): (DefId, &hir::ForeignItem))
+ -> Entry<'tcx> {
+ let tcx = self.tcx;
- rbml_w.start_tag(tag_items_closure_kind);
- ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
- rbml_w.end_tag();
+ debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
- assert!(ecx.mir_map.map.contains_key(&def_id));
- encode_mir(ecx, rbml_w, expr.id);
+ let kind = match nitem.node {
+ hir::ForeignItemFn(ref fndecl, _) => {
+ let data = FnData {
+ constness: hir::Constness::NotConst,
+ arg_names: self.encode_fn_arg_names(&fndecl)
+ };
+ EntryKind::ForeignFn(self.lazy(&data))
+ }
+ hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic,
+ hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic
+ };
- rbml_w.end_tag();
+ Entry {
+ kind: kind,
+ visibility: nitem.vis.simplify(),
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&nitem.attrs),
+ children: LazySeq::empty(),
+ stability: self.encode_stability(def_id),
+ deprecation: self.encode_deprecation(def_id),
+
+ ty: Some(self.encode_item_type(def_id)),
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: None,
+ mir: None
}
- _ => { }
}
}
-struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
- rbml_w_for_visit_item: &'a mut Encoder<'b>,
- ecx: &'a EncodeContext<'c, 'tcx>,
- index: &'a mut CrateIndex<'c, 'tcx>,
+struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> {
+ index: IndexBuilder<'a, 'b, 'tcx>,
}
-impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
+impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
intravisit::walk_expr(self, ex);
- my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
+ self.index.encode_info_for_expr(ex);
}
- fn visit_item(&mut self, i: &'tcx hir::Item) {
- intravisit::walk_item(self, i);
- encode_info_for_item(self.ecx, self.rbml_w_for_visit_item, i, self.index);
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ intravisit::walk_item(self, item);
+ let def_id = self.index.tcx.map.local_def_id(item.id);
+ match item.node {
+ hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these
+ _ => self.index.record(def_id,
+ EncodeContext::encode_info_for_item,
+ (def_id, 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);
- encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
+ let def_id = self.index.tcx.map.local_def_id(ni.id);
+ self.index.record(def_id,
+ EncodeContext::encode_info_for_foreign_item,
+ (def_id, ni));
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(self, ty);
-
- if let hir::TyImplTrait(_) = ty.node {
- let rbml_w = &mut *self.rbml_w_for_visit_item;
- let def_id = self.ecx.tcx.map.local_def_id(ty.id);
- let _task = self.index.record(def_id, rbml_w);
- rbml_w.start_tag(tag_items_data_item);
- encode_def_id_and_key(self.ecx, rbml_w, def_id);
- encode_family(rbml_w, 'y');
- encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
- rbml_w.end_tag();
- }
+ self.index.encode_info_for_ty(ty);
}
}
-fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder)
- -> CrateIndex<'a, 'tcx> {
- let krate = ecx.tcx.map.krate();
-
- let mut index = CrateIndex {
- dep_graph: &ecx.tcx.dep_graph,
- items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
- xrefs: FnvHashMap()
- };
- rbml_w.start_tag(tag_items_data);
-
- {
- let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
- encode_info_for_mod(ecx,
- rbml_w,
- &krate.module,
- &[],
- CRATE_NODE_ID,
- syntax::parse::token::intern(&ecx.link_meta.crate_name),
- &hir::Public);
- }
-
- krate.visit_all_items(&mut EncodeVisitor {
- index: &mut index,
- ecx: ecx,
- rbml_w_for_visit_item: &mut *rbml_w,
- });
-
- rbml_w.end_tag();
- index
-}
-
-fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
- rbml_w.start_tag(tag_index);
- index.write_index(rbml_w.writer);
- rbml_w.end_tag();
-}
-
-fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
- if mi.is_word() {
- let name = mi.name();
- rbml_w.start_tag(tag_meta_item_word);
- rbml_w.wr_tagged_str(tag_meta_item_name, &name);
- rbml_w.end_tag();
- } else if mi.is_value_str() {
- let name = mi.name();
- /* FIXME (#623): support other literal kinds */
- let value = mi.value_str().unwrap();
- rbml_w.start_tag(tag_meta_item_name_value);
- rbml_w.wr_tagged_str(tag_meta_item_name, &name);
- rbml_w.wr_tagged_str(tag_meta_item_value, &value);
- rbml_w.end_tag();
- } else { // it must be a list
- let name = mi.name();
- let items = mi.meta_item_list().unwrap();
- rbml_w.start_tag(tag_meta_item_list);
- rbml_w.wr_tagged_str(tag_meta_item_name, &name);
- for inner_item in items {
- encode_meta_item(rbml_w, &inner_item);
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+ fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
+ if let hir::TyImplTrait(_) = ty.node {
+ let def_id = self.tcx.map.local_def_id(ty.id);
+ self.record(def_id,
+ EncodeContext::encode_info_for_anon_ty,
+ def_id);
}
- rbml_w.end_tag();
}
-}
-fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
- rbml_w.start_tag(tag_attributes);
- for attr in attrs {
- rbml_w.start_tag(tag_attribute);
- rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8);
- encode_meta_item(rbml_w, attr.meta());
- rbml_w.end_tag();
+ fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
+ match expr.node {
+ hir::ExprClosure(..) => {
+ let def_id = self.tcx.map.local_def_id(expr.id);
+ self.record(def_id,
+ EncodeContext::encode_info_for_closure,
+ def_id);
+ }
+ _ => { }
+ }
}
- rbml_w.end_tag();
-}
-
-fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) {
- let byte: u8 = match unsafety {
- hir::Unsafety::Normal => 0,
- hir::Unsafety::Unsafe => 1,
- };
- rbml_w.wr_tagged_u8(tag_unsafety, byte);
-}
-
-fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) {
- let byte: u8 = if paren_sugar {1} else {0};
- rbml_w.wr_tagged_u8(tag_paren_sugar, byte);
}
-fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) {
- let byte: u8 = if is_defaulted {1} else {0};
- rbml_w.wr_tagged_u8(tag_defaulted_trait, byte);
-}
-
-fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) {
- rbml_w.start_tag(tag_associated_type_names);
- for &name in names {
- rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str());
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
+ Entry {
+ kind: EntryKind::Type,
+ visibility: ty::Visibility::Public,
+ def_key: self.encode_def_key(def_id),
+ attributes: LazySeq::empty(),
+ children: LazySeq::empty(),
+ stability: None,
+ deprecation: None,
+
+ ty: Some(self.encode_item_type(def_id)),
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: Some(self.encode_generics(def_id)),
+ predicates: Some(self.encode_predicates(def_id)),
+
+ ast: None,
+ mir: None
+ }
}
- rbml_w.end_tag();
-}
-
-fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) {
- let byte: u8 = match polarity {
- hir::ImplPolarity::Positive => 0,
- hir::ImplPolarity::Negative => 1,
- };
- rbml_w.wr_tagged_u8(tag_polarity, byte);
-}
-fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
- fn get_ordered_deps(cstore: &cstore::CStore)
- -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
- // Pull the cnums and name,vers,hash out of cstore
- let mut deps = Vec::new();
- cstore.iter_crate_data(|cnum, val| {
- deps.push((cnum, val.clone()));
- });
+ fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
+ let tcx = self.tcx;
- // Sort by cnum
- deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
+ let data = ClosureData {
+ kind: tcx.closure_kind(def_id),
+ ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id])
+ };
- // Sanity-check the crate numbers
- let mut expected_cnum = 1;
- for &(n, _) in &deps {
- assert_eq!(n, expected_cnum);
- expected_cnum += 1;
+ Entry {
+ kind: EntryKind::Closure(self.lazy(&data)),
+ visibility: ty::Visibility::Public,
+ def_key: self.encode_def_key(def_id),
+ attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+ children: LazySeq::empty(),
+ stability: None,
+ deprecation: None,
+
+ ty: None,
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: None,
+ predicates: None,
+
+ ast: None,
+ mir: self.encode_mir(def_id)
}
-
- deps
}
- // We're just going to write a list of crate 'name-hash-version's, with
- // the assumption that they are numbered 1 to n.
- // FIXME (#2166): This is not nearly enough to support correct versioning
- // but is enough to get transitive crate dependencies working.
- rbml_w.start_tag(tag_crate_deps);
- for (_cnum, dep) in get_ordered_deps(cstore) {
- encode_crate_dep(rbml_w, &dep);
+ fn encode_info_for_items(&mut self) -> Index {
+ let krate = self.tcx.map.krate();
+ let mut index = IndexBuilder::new(self);
+ index.record(DefId::local(CRATE_DEF_INDEX),
+ EncodeContext::encode_info_for_mod,
+ FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
+ let mut visitor = EncodeVisitor {
+ index: index,
+ };
+ krate.visit_all_items(&mut visitor);
+ visitor.index.into_items()
}
- rbml_w.end_tag();
-}
-fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
- rbml_w.start_tag(tag_lang_items);
+ fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
+ self.lazy_seq_ref(attrs)
+ }
- for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() {
- if let Some(def_id) = opt_def_id {
- if def_id.is_local() {
- rbml_w.start_tag(tag_lang_items_item);
- rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
- rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
- rbml_w.end_tag();
+ fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
+ fn get_ordered_deps(cstore: &cstore::CStore)
+ -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
+ // Pull the cnums and name,vers,hash out of cstore
+ let mut deps = Vec::new();
+ cstore.iter_crate_data(|cnum, val| {
+ deps.push((cnum, val.clone()));
+ });
+
+ // Sort by cnum
+ deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
+
+ // Sanity-check the crate numbers
+ let mut expected_cnum = 1;
+ for &(n, _) in &deps {
+ assert_eq!(n, CrateNum::new(expected_cnum));
+ expected_cnum += 1;
}
+
+ deps
}
- }
- for i in &ecx.tcx.lang_items.missing {
- rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32);
+ // We're just going to write a list of crate 'name-hash-version's, with
+ // the assumption that they are numbered 1 to n.
+ // FIXME (#2166): This is not nearly enough to support correct versioning
+ // but is enough to get transitive crate dependencies working.
+ let deps = get_ordered_deps(self.cstore);
+ self.lazy_seq(deps.iter().map(|&(_, ref dep)| {
+ CrateDep {
+ name: syntax::parse::token::intern(dep.name()),
+ hash: dep.hash(),
+ explicitly_linked: dep.explicitly_linked.get()
+ }
+ }))
}
- rbml_w.end_tag(); // tag_lang_items
-}
-
-fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
- rbml_w.start_tag(tag_native_libraries);
-
- for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() {
- match kind {
- cstore::NativeStatic => {} // these libraries are not propagated
- cstore::NativeFramework | cstore::NativeUnknown => {
- rbml_w.start_tag(tag_native_libraries_lib);
- rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32);
- rbml_w.wr_tagged_str(tag_native_libraries_name, lib);
- rbml_w.end_tag();
+ fn encode_lang_items(&mut self)
+ -> (LazySeq<(DefIndex, usize)>, LazySeq<lang_items::LangItem>) {
+ let tcx = self.tcx;
+ let lang_items = tcx.lang_items.items().iter();
+ (self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
+ if let Some(def_id) = opt_def_id {
+ if def_id.is_local() {
+ return Some((def_id.index, i));
+ }
}
- }
+ None
+ })), self.lazy_seq_ref(&tcx.lang_items.missing))
}
- rbml_w.end_tag();
-}
-
-fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
- match ecx.tcx.sess.plugin_registrar_fn.get() {
- Some(id) => {
- let def_id = ecx.tcx.map.local_def_id(id);
- rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
- }
- None => {}
+ fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> {
+ let used_libraries = self.tcx.sess.cstore.used_libraries();
+ self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| {
+ match kind {
+ cstore::NativeStatic => None, // these libraries are not propagated
+ cstore::NativeFramework | cstore::NativeUnknown => {
+ Some((kind, lib))
+ }
+ }
+ }))
}
-}
-
-fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) {
- rbml_w.start_tag(tag_codemap);
- let codemap = ecx.tcx.sess.codemap();
-
- for filemap in &codemap.files.borrow()[..] {
- if filemap.lines.borrow().is_empty() || filemap.is_imported() {
+ fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
+ let codemap = self.tcx.sess.codemap();
+ let all_filemaps = codemap.files.borrow();
+ self.lazy_seq_ref(all_filemaps.iter().filter(|filemap| {
// No need to export empty filemaps, as they can't contain spans
// that need translation.
// Also no need to re-export imported filemaps, as any downstream
// crate will import them from their original source.
- continue;
- }
-
- rbml_w.start_tag(tag_codemap_filemap);
- rbml_w.emit_opaque(|opaque_encoder| {
- filemap.encode(opaque_encoder)
- }).unwrap();
- rbml_w.end_tag();
+ !filemap.lines.borrow().is_empty() && !filemap.is_imported()
+ }).map(|filemap| &**filemap))
}
- rbml_w.end_tag();
-}
-
-/// Serialize the text of the exported macros
-fn encode_macro_defs(rbml_w: &mut Encoder,
- krate: &hir::Crate) {
- rbml_w.start_tag(tag_macro_defs);
- for def in &krate.exported_macros {
- rbml_w.start_tag(tag_macro_def);
-
- encode_name(rbml_w, def.name);
- encode_attributes(rbml_w, &def.attrs);
- let &BytePos(lo) = &def.span.lo;
- let &BytePos(hi) = &def.span.hi;
- rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo);
- rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi);
-
- rbml_w.wr_tagged_str(tag_macro_def_body,
- &::syntax::print::pprust::tts_to_string(&def.body));
-
- rbml_w.end_tag();
- }
- rbml_w.end_tag();
-}
-
-fn encode_struct_field_attrs(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- krate: &hir::Crate) {
- struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
- ecx: &'a EncodeContext<'b, 'tcx>,
- rbml_w: &'a mut Encoder<'c>,
- }
-
- impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> {
- fn visit_struct_field(&mut self, field: &hir::StructField) {
- self.rbml_w.start_tag(tag_struct_field);
- let def_id = self.ecx.tcx.map.local_def_id(field.id);
- encode_def_id(self.rbml_w, def_id);
- encode_attributes(self.rbml_w, &field.attrs);
- self.rbml_w.end_tag();
- }
+ /// Serialize the text of the exported macros
+ fn encode_macro_defs(&mut self) -> LazySeq<MacroDef> {
+ let tcx = self.tcx;
+ self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| {
+ MacroDef {
+ name: def.name,
+ attrs: def.attrs.to_vec(),
+ span: def.span,
+ body: ::syntax::print::pprust::tts_to_string(&def.body)
+ }
+ }))
}
-
- rbml_w.start_tag(tag_struct_fields);
- krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w });
- rbml_w.end_tag();
}
-
-
struct ImplVisitor<'a, 'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impls: FnvHashMap<DefId, Vec<DefId>>
+ impls: FnvHashMap<DefId, Vec<DefIndex>>
}
impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) {
self.impls.entry(trait_ref.def_id)
.or_insert(vec![])
- .push(impl_id);
+ .push(impl_id.index);
}
}
}
}
-/// Encodes an index, mapping each trait to its (local) implementations.
-fn encode_impls<'a>(ecx: &'a EncodeContext,
- krate: &hir::Crate,
- rbml_w: &'a mut Encoder) {
- let mut visitor = ImplVisitor {
- tcx: ecx.tcx,
- impls: FnvHashMap()
- };
- krate.visit_all_items(&mut visitor);
-
- rbml_w.start_tag(tag_impls);
- for (trait_, trait_impls) in visitor.impls {
- rbml_w.start_tag(tag_impls_trait);
- encode_def_id(rbml_w, trait_);
- for impl_ in trait_impls {
- rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_));
- }
- rbml_w.end_tag();
- }
- rbml_w.end_tag();
-}
-
-fn encode_misc_info(ecx: &EncodeContext,
- krate: &hir::Crate,
- rbml_w: &mut Encoder) {
- rbml_w.start_tag(tag_misc_info);
- rbml_w.start_tag(tag_misc_info_crate_items);
- for item_id in &krate.module.item_ids {
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-
- let item = ecx.tcx.map.expect_item(item_id.id);
- each_auxiliary_node_id(item, |auxiliary_node_id| {
- rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
- true
- });
- }
-
- // Encode reexports for the root module.
- encode_reexports(ecx, rbml_w, 0);
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ /// Encodes an index, mapping each trait to its (local) implementations.
+ fn encode_impls(&mut self) -> LazySeq<TraitImpls> {
+ let mut visitor = ImplVisitor {
+ tcx: self.tcx,
+ impls: FnvHashMap()
+ };
+ self.tcx.map.krate().visit_all_items(&mut visitor);
- rbml_w.end_tag();
- rbml_w.end_tag();
-}
+ let all_impls: Vec<_> = visitor.impls.into_iter().map(|(trait_def_id, impls)| {
+ TraitImpls {
+ trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
+ impls: self.lazy_seq(impls)
+ }
+ }).collect();
-// Encodes all reachable symbols in this crate into the metadata.
-//
-// This pass is seeded off the reachability list calculated in the
-// middle::reachable module but filters out items that either don't have a
-// symbol associated with them (they weren't translated) or if they're an FFI
-// definition (as that's not defined in this crate).
-fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
- rbml_w.start_tag(tag_reachable_ids);
- for &id in ecx.reachable {
- let def_id = ecx.tcx.map.local_def_id(id);
- rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
+ self.lazy_seq(all_impls)
}
- rbml_w.end_tag();
-}
-
-fn encode_crate_dep(rbml_w: &mut Encoder,
- dep: &cstore::CrateMetadata) {
- rbml_w.start_tag(tag_crate_dep);
- rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
- let hash = decoder::get_crate_hash(dep.data());
- rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
- rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
- dep.explicitly_linked.get() as u8);
- rbml_w.end_tag();
-}
-
-fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
- rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
-}
-
-fn encode_rustc_version(rbml_w: &mut Encoder) {
- rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version());
-}
-
-fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
- rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
-}
-fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) {
- rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator);
-}
-
-fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
- rbml_w.wr_tagged_str(tag_crate_triple, triple);
-}
-
-fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
- let tag = tag_dylib_dependency_formats;
- match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
- Some(arr) => {
- let s = arr.iter().enumerate().filter_map(|(i, slot)| {
- let kind = match *slot {
- Linkage::NotLinked |
- Linkage::IncludedFromDylib => return None,
- Linkage::Dynamic => "d",
- Linkage::Static => "s",
- };
- Some(format!("{}:{}", i + 1, kind))
- }).collect::<Vec<String>>();
- rbml_w.wr_tagged_str(tag, &s.join(","));
- }
- None => {
- rbml_w.wr_tagged_str(tag, "");
- }
+ // Encodes all reachable symbols in this crate into the metadata.
+ //
+ // This pass is seeded off the reachability list calculated in the
+ // middle::reachable module but filters out items that either don't have a
+ // symbol associated with them (they weren't translated) or if they're an FFI
+ // definition (as that's not defined in this crate).
+ fn encode_reachable(&mut self) -> LazySeq<DefIndex> {
+ let reachable = self.reachable;
+ let tcx = self.tcx;
+ self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index))
}
-}
-fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
- match ecx.tcx.sess.opts.cg.panic {
- PanicStrategy::Unwind => {
- rbml_w.wr_tagged_u8(tag_panic_strategy, b'U');
- }
- PanicStrategy::Abort => {
- rbml_w.wr_tagged_u8(tag_panic_strategy, b'A');
+ fn encode_dylib_dependency_formats(&mut self) -> LazySeq<Option<LinkagePreference>> {
+ match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
+ Some(arr) => {
+ self.lazy_seq(arr.iter().map(|slot| {
+ match *slot {
+ Linkage::NotLinked |
+ Linkage::IncludedFromDylib => None,
+
+ Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
+ Linkage::Static => Some(LinkagePreference::RequireStatic),
+ }
+ }))
+ }
+ None => LazySeq::empty()
}
}
-}
-pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> {
- let mut wr = Cursor::new(Vec::new());
+ fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
+ let mut i = self.position();
+ let crate_deps = self.encode_crate_deps();
+ let dylib_dependency_formats = self.encode_dylib_dependency_formats();
+ let dep_bytes = self.position() - i;
+
+ // Encode the language items.
+ i = self.position();
+ let (lang_items, lang_items_missing) = self.encode_lang_items();
+ let lang_item_bytes = self.position() - i;
+
+ // Encode the native libraries used
+ i = self.position();
+ let native_libraries = self.encode_native_libraries();
+ let native_lib_bytes = self.position() - i;
+
+ // Encode codemap
+ i = self.position();
+ let codemap = self.encode_codemap();
+ let codemap_bytes = self.position() - i;
+
+ // Encode macro definitions
+ i = self.position();
+ let macro_defs = self.encode_macro_defs();
+ let macro_defs_bytes = self.position() - i;
+
+ // Encode the def IDs of impls, for coherence checking.
+ i = self.position();
+ let impls = self.encode_impls();
+ let impl_bytes = self.position() - i;
+
+ // Encode reachability info.
+ i = self.position();
+ let reachable_ids = self.encode_reachable();
+ let reachable_bytes = self.position() - i;
+
+ // Encode and index the items.
+ i = self.position();
+ let items = self.encode_info_for_items();
+ let item_bytes = self.position() - i;
+
+ i = self.position();
+ let index = items.write_index(&mut self.opaque.cursor);
+ let index_bytes = self.position() - i;
+
+ let tcx = self.tcx;
+ let link_meta = self.link_meta;
+ let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro);
+ let root = self.lazy(&CrateRoot {
+ rustc_version: RUSTC_VERSION.to_string(),
+ name: link_meta.crate_name.clone(),
+ triple: tcx.sess.opts.target_triple.clone(),
+ hash: link_meta.crate_hash,
+ disambiguator: tcx.sess.local_crate_disambiguator().to_string(),
+ panic_strategy: tcx.sess.opts.cg.panic.clone(),
+ plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| {
+ tcx.map.local_def_id(id).index
+ }),
+ macro_derive_registrar: if is_rustc_macro {
+ let id = tcx.sess.derive_registrar_fn.get().unwrap();
+ Some(tcx.map.local_def_id(id).index)
+ } else {
+ None
+ },
+
+ crate_deps: crate_deps,
+ dylib_dependency_formats: dylib_dependency_formats,
+ lang_items: lang_items,
+ lang_items_missing: lang_items_missing,
+ native_libraries: native_libraries,
+ codemap: codemap,
+ macro_defs: macro_defs,
+ impls: impls,
+ reachable_ids: reachable_ids,
+ index: index,
+ });
- {
- let mut rbml_w = Encoder::new(&mut wr);
- encode_metadata_inner(&mut rbml_w, &ecx, krate)
- }
+ let total_bytes = self.position();
- // RBML compacts the encoded bytes whenever appropriate,
- // so there are some garbages left after the end of the data.
- let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize;
- let mut v = wr.into_inner();
- v.truncate(metalen);
- assert_eq!(v.len(), metalen);
-
- // And here we run into yet another obscure archive bug: in which metadata
- // loaded from archives may have trailing garbage bytes. Awhile back one of
- // our tests was failing sporadically on the OSX 64-bit builders (both nopt
- // and opt) by having rbml generate an out-of-bounds panic when looking at
- // metadata.
- //
- // Upon investigation it turned out that the metadata file inside of an rlib
- // (and ar archive) was being corrupted. Some compilations would generate a
- // metadata file which would end in a few extra bytes, while other
- // compilations would not have these extra bytes appended to the end. These
- // extra bytes were interpreted by rbml as an extra tag, so they ended up
- // being interpreted causing the out-of-bounds.
- //
- // The root cause of why these extra bytes were appearing was never
- // discovered, and in the meantime the solution we're employing is to insert
- // the length of the metadata to the start of the metadata. Later on this
- // will allow us to slice the metadata to the precise length that we just
- // generated regardless of trailing bytes that end up in it.
- //
- // We also need to store the metadata encoding version here, because
- // rlibs don't have it. To get older versions of rustc to ignore
- // this metadata, there are 4 zero bytes at the start, which are
- // treated as a length of 0 by old compilers.
-
- let len = v.len();
- let mut result = vec![];
- result.push(0);
- result.push(0);
- result.push(0);
- result.push(0);
- result.extend(metadata_encoding_version.iter().cloned());
- result.push((len >> 24) as u8);
- result.push((len >> 16) as u8);
- result.push((len >> 8) as u8);
- result.push((len >> 0) as u8);
- result.extend(v);
- result
-}
-
-fn encode_metadata_inner(rbml_w: &mut Encoder,
- ecx: &EncodeContext,
- krate: &hir::Crate) {
- struct Stats {
- attr_bytes: u64,
- dep_bytes: u64,
- lang_item_bytes: u64,
- native_lib_bytes: u64,
- plugin_registrar_fn_bytes: u64,
- codemap_bytes: u64,
- macro_defs_bytes: u64,
- impl_bytes: u64,
- misc_bytes: u64,
- item_bytes: u64,
- index_bytes: u64,
- xref_bytes: u64,
- zero_bytes: u64,
- total_bytes: u64,
- }
- let mut stats = Stats {
- attr_bytes: 0,
- dep_bytes: 0,
- lang_item_bytes: 0,
- native_lib_bytes: 0,
- plugin_registrar_fn_bytes: 0,
- codemap_bytes: 0,
- macro_defs_bytes: 0,
- impl_bytes: 0,
- misc_bytes: 0,
- item_bytes: 0,
- index_bytes: 0,
- xref_bytes: 0,
- zero_bytes: 0,
- total_bytes: 0,
- };
-
- encode_rustc_version(rbml_w);
- encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
- encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
- encode_hash(rbml_w, &ecx.link_meta.crate_hash);
- encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator());
- encode_dylib_dependency_formats(rbml_w, &ecx);
- encode_panic_strategy(rbml_w, &ecx);
-
- let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_attributes(rbml_w, &krate.attrs);
- stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_crate_deps(rbml_w, ecx.cstore);
- stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode the language items.
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_lang_items(&ecx, rbml_w);
- stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode the native libraries used
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_native_libraries(&ecx, rbml_w);
- stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode the plugin registrar function
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_plugin_registrar_fn(&ecx, rbml_w);
- stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode codemap
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_codemap(&ecx, rbml_w);
- stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode macro definitions
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_macro_defs(rbml_w, krate);
- stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode the def IDs of impls, for coherence checking.
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_impls(&ecx, krate, rbml_w);
- stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode miscellaneous info.
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_misc_info(&ecx, krate, rbml_w);
- encode_reachable(&ecx, rbml_w);
- stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- // Encode and index the items.
- rbml_w.start_tag(tag_items);
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- let index = encode_info_for_items(&ecx, rbml_w);
- stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
- rbml_w.end_tag();
-
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_item_index(rbml_w, index.items);
- stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_xrefs(&ecx, rbml_w, index.xrefs);
- stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
- encode_struct_field_attrs(&ecx, rbml_w, krate);
-
- stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-
- if ecx.tcx.sess.meta_stats() {
- for e in rbml_w.writer.get_ref() {
- if *e == 0 {
- stats.zero_bytes += 1;
+ if self.tcx.sess.meta_stats() {
+ let mut zero_bytes = 0;
+ for e in self.opaque.cursor.get_ref() {
+ if *e == 0 {
+ zero_bytes += 1;
+ }
}
+
+ println!("metadata stats:");
+ println!(" dep bytes: {}", dep_bytes);
+ println!(" lang item bytes: {}", lang_item_bytes);
+ println!(" native bytes: {}", native_lib_bytes);
+ println!(" codemap bytes: {}", codemap_bytes);
+ println!(" macro def bytes: {}", macro_defs_bytes);
+ println!(" impl bytes: {}", impl_bytes);
+ println!(" reachable bytes: {}", reachable_bytes);
+ println!(" item bytes: {}", item_bytes);
+ println!(" index bytes: {}", index_bytes);
+ println!(" zero bytes: {}", zero_bytes);
+ println!(" total bytes: {}", total_bytes);
}
- println!("metadata stats:");
- println!(" attribute bytes: {}", stats.attr_bytes);
- println!(" dep bytes: {}", stats.dep_bytes);
- println!(" lang item bytes: {}", stats.lang_item_bytes);
- println!(" native bytes: {}", stats.native_lib_bytes);
- println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
- println!(" codemap bytes: {}", stats.codemap_bytes);
- println!(" macro def bytes: {}", stats.macro_defs_bytes);
- println!(" impl bytes: {}", stats.impl_bytes);
- println!(" misc bytes: {}", stats.misc_bytes);
- println!(" item bytes: {}", stats.item_bytes);
- println!(" index bytes: {}", stats.index_bytes);
- println!(" xref bytes: {}", stats.xref_bytes);
- println!(" zero bytes: {}", stats.zero_bytes);
- println!(" total bytes: {}", stats.total_bytes);
+ root
}
}
-// Get the encoded string for a type
-pub fn encoded_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- t: Ty<'tcx>,
- def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
- -> Vec<u8> {
- let mut wr = Cursor::new(Vec::new());
- tyencode::enc_ty(&mut wr, &tyencode::ctxt {
- diag: tcx.sess.diagnostic(),
- ds: def_id_to_string,
+// NOTE(eddyb) The following comment was preserved for posterity, even
+// though it's no longer relevant as EBML (which uses nested & tagged
+// "documents") was replaced with a scheme that can't go out of bounds.
+//
+// And here we run into yet another obscure archive bug: in which metadata
+// loaded from archives may have trailing garbage bytes. Awhile back one of
+// our tests was failing sporadically on the OSX 64-bit builders (both nopt
+// and opt) by having ebml generate an out-of-bounds panic when looking at
+// metadata.
+//
+// Upon investigation it turned out that the metadata file inside of an rlib
+// (and ar archive) was being corrupted. Some compilations would generate a
+// metadata file which would end in a few extra bytes, while other
+// compilations would not have these extra bytes appended to the end. These
+// extra bytes were interpreted by ebml as an extra tag, so they ended up
+// being interpreted causing the out-of-bounds.
+//
+// The root cause of why these extra bytes were appearing was never
+// discovered, and in the meantime the solution we're employing is to insert
+// the length of the metadata to the start of the metadata. Later on this
+// will allow us to slice the metadata to the precise length that we just
+// generated regardless of trailing bytes that end up in it.
+
+pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ cstore: &cstore::CStore,
+ reexports: &def::ExportMap,
+ link_meta: &LinkMeta,
+ reachable: &NodeSet,
+ mir_map: &MirMap<'tcx>) -> Vec<u8> {
+ let mut cursor = Cursor::new(vec![]);
+ cursor.write_all(METADATA_HEADER).unwrap();
+
+ // Will be filed with the root position after encoding everything.
+ cursor.write_all(&[0, 0, 0, 0]).unwrap();
+
+ let root = EncodeContext {
+ opaque: opaque::Encoder::new(&mut cursor),
tcx: tcx,
- abbrevs: &RefCell::new(FnvHashMap())
- }, t);
- wr.into_inner()
+ reexports: reexports,
+ link_meta: link_meta,
+ cstore: cstore,
+ reachable: reachable,
+ mir_map: mir_map,
+ lazy_state: LazyState::NoNode,
+ type_shorthands: Default::default(),
+ predicate_shorthands: Default::default()
+ }.encode_crate_root();
+ let mut result = cursor.into_inner();
+
+ // Encode the root position.
+ let header = METADATA_HEADER.len();
+ let pos = root.position;
+ result[header + 0] = (pos >> 24) as u8;
+ result[header + 1] = (pos >> 16) as u8;
+ result[header + 2] = (pos >> 8) as u8;
+ result[header + 3] = (pos >> 0) as u8;
+
+ result
}