Improve intercrate hygiene.

This commit is contained in:
Jeffrey Seyfried 2017-03-27 00:46:00 +00:00
parent dde8dc61dd
commit 3eb235b45e
11 changed files with 112 additions and 74 deletions

View File

@ -117,7 +117,7 @@ pub type ExportMap = NodeMap<Vec<Export>>;
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Export {
pub name: ast::Name, // The name of the target.
pub ident: ast::Ident, // The name of the target.
pub def: Def, // The definition of the target.
pub span: Span, // The span of the target definition.
}

View File

@ -2662,7 +2662,7 @@ impl<'a> LoweringContext<'a> {
let parent_def = self.parent_def.unwrap();
let def_id = {
let defs = self.resolver.definitions();
let def_path_data = DefPathData::Binding(name.as_str());
let def_path_data = DefPathData::Binding(Ident::with_empty_ctxt(name));
let def_index = defs
.create_def_with_parent(parent_def, id, def_path_data, REGULAR_SPACE, Mark::root());
DefId::local(def_index)

View File

@ -14,7 +14,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace};
use syntax::ast::*;
use syntax::ext::hygiene::Mark;
use syntax::visit;
use syntax::symbol::{Symbol, keywords};
use syntax::symbol::keywords;
use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE};
@ -103,14 +103,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
DefPathData::Impl,
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
DefPathData::TypeNs(i.ident.name.as_str()),
DefPathData::TypeNs(i.ident.modern()),
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
return visit::walk_item(self, i);
}
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()),
ItemKind::Mod(..) => DefPathData::Module(i.ident.modern()),
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
DefPathData::ValueNs(i.ident.name.as_str()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()),
DefPathData::ValueNs(i.ident.modern()),
ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.modern()),
ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false),
ItemKind::GlobalAsm(..) => DefPathData::Misc,
ItemKind::Use(ref view_path) => {
@ -138,15 +138,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
for v in &enum_definition.variants {
let variant_def_index =
this.create_def(v.node.data.id(),
DefPathData::EnumVariant(v.node.name.name.as_str()),
DefPathData::EnumVariant(v.node.name.modern()),
REGULAR_SPACE);
this.with_parent(variant_def_index, |this| {
for (index, field) in v.node.data.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name)
.unwrap_or_else(|| Symbol::intern(&index.to_string()));
this.create_def(field.id,
DefPathData::Field(name.as_str()),
REGULAR_SPACE);
let ident = field.ident.map(Ident::modern)
.unwrap_or_else(|| Ident::from_str(&index.to_string()));
this.create_def(field.id, DefPathData::Field(ident), REGULAR_SPACE);
}
if let Some(ref expr) = v.node.disr_expr {
@ -164,9 +162,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}
for (index, field) in struct_def.fields().iter().enumerate() {
let name = field.ident.map(|ident| ident.name.as_str())
.unwrap_or(Symbol::intern(&index.to_string()).as_str());
this.create_def(field.id, DefPathData::Field(name), REGULAR_SPACE);
let ident = field.ident.map(Ident::modern)
.unwrap_or_else(|| Ident::from_str(&index.to_string()));
this.create_def(field.id, DefPathData::Field(ident), REGULAR_SPACE);
}
}
_ => {}
@ -177,7 +175,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
let def = self.create_def(foreign_item.id,
DefPathData::ValueNs(foreign_item.ident.name.as_str()),
DefPathData::ValueNs(foreign_item.ident.modern()),
REGULAR_SPACE);
self.with_parent(def, |this| {
@ -188,7 +186,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_generics(&mut self, generics: &'a Generics) {
for ty_param in generics.ty_params.iter() {
self.create_def(ty_param.id,
DefPathData::TypeParam(ty_param.ident.name.as_str()),
DefPathData::TypeParam(ty_param.ident.modern()),
REGULAR_SPACE);
}
@ -198,8 +196,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_trait_item(&mut self, ti: &'a TraitItem) {
let def_data = match ti.node {
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
DefPathData::ValueNs(ti.ident.name.as_str()),
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()),
DefPathData::ValueNs(ti.ident.modern()),
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.modern()),
TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false),
};
@ -216,8 +214,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_impl_item(&mut self, ii: &'a ImplItem) {
let def_data = match ii.node {
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
DefPathData::ValueNs(ii.ident.name.as_str()),
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()),
DefPathData::ValueNs(ii.ident.modern()),
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.modern()),
ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false),
};
@ -238,7 +236,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false),
PatKind::Ident(_, id, _) => {
let def = self.create_def(pat.id,
DefPathData::Binding(id.node.name.as_str()),
DefPathData::Binding(id.node.modern()),
REGULAR_SPACE);
self.parent_def = Some(def);
}
@ -283,7 +281,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) {
self.create_def(def.lifetime.id,
DefPathData::LifetimeDef(def.lifetime.ident.name.as_str()),
DefPathData::LifetimeDef(def.lifetime.ident.modern()),
REGULAR_SPACE);
}

View File

@ -23,8 +23,8 @@ use rustc_data_structures::stable_hasher::StableHasher;
use serialize::{Encodable, Decodable, Encoder, Decoder};
use std::fmt::Write;
use std::hash::Hash;
use syntax::ast;
use syntax::ext::hygiene::Mark;
use syntax::ast::{self, Ident};
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::symbol::{Symbol, InternedString};
use ty::TyCtxt;
use util::nodemap::NodeMap;
@ -327,7 +327,7 @@ impl DefPath {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
// they are treated specially by the `def_path` function.
@ -341,31 +341,31 @@ pub enum DefPathData {
/// An impl
Impl,
/// Something in the type NS
TypeNs(InternedString),
TypeNs(Ident),
/// Something in the value NS
ValueNs(InternedString),
ValueNs(Ident),
/// A module declaration
Module(InternedString),
Module(Ident),
/// A macro rule
MacroDef(InternedString),
MacroDef(Ident),
/// A closure expression
ClosureExpr,
// Subportions of items
/// A type parameter (generic parameter)
TypeParam(InternedString),
TypeParam(Ident),
/// A lifetime definition
LifetimeDef(InternedString),
LifetimeDef(Ident),
/// A variant of a enum
EnumVariant(InternedString),
EnumVariant(Ident),
/// A struct field
Field(InternedString),
Field(Ident),
/// Implicit ctor for a tuple-like struct
StructCtor,
/// Initializer for a const
Initializer,
/// Pattern binding
Binding(InternedString),
Binding(Ident),
/// An `impl Trait` type node.
ImplTrait,
/// A `typeof` type node.
@ -551,18 +551,18 @@ impl Definitions {
}
impl DefPathData {
pub fn get_opt_name(&self) -> Option<ast::Name> {
pub fn get_opt_ident(&self) -> Option<Ident> {
use self::DefPathData::*;
match *self {
TypeNs(ref name) |
ValueNs(ref name) |
Module(ref name) |
MacroDef(ref name) |
TypeParam(ref name) |
LifetimeDef(ref name) |
EnumVariant(ref name) |
Binding(ref name) |
Field(ref name) => Some(Symbol::intern(name)),
TypeNs(ident) |
ValueNs(ident) |
Module(ident) |
MacroDef(ident) |
TypeParam(ident) |
LifetimeDef(ident) |
EnumVariant(ident) |
Binding(ident) |
Field(ident) => Some(ident),
Impl |
CrateRoot |
@ -575,19 +575,23 @@ impl DefPathData {
}
}
pub fn get_opt_name(&self) -> Option<ast::Name> {
self.get_opt_ident().map(|ident| ident.name)
}
pub fn as_interned_str(&self) -> InternedString {
use self::DefPathData::*;
let s = match *self {
TypeNs(ref name) |
ValueNs(ref name) |
Module(ref name) |
MacroDef(ref name) |
TypeParam(ref name) |
LifetimeDef(ref name) |
EnumVariant(ref name) |
Binding(ref name) |
Field(ref name) => {
return name.clone();
TypeNs(ident) |
ValueNs(ident) |
Module(ident) |
MacroDef(ident) |
TypeParam(ident) |
LifetimeDef(ident) |
EnumVariant(ident) |
Binding(ident) |
Field(ident) => {
return ident.name.as_str();
}
// note that this does not show up in user printouts
@ -609,3 +613,25 @@ impl DefPathData {
self.as_interned_str().to_string()
}
}
impl Eq for DefPathData {}
impl PartialEq for DefPathData {
fn eq(&self, other: &DefPathData) -> bool {
::std::mem::discriminant(self) == ::std::mem::discriminant(other) &&
self.get_opt_ident() == other.get_opt_ident()
}
}
impl ::std::hash::Hash for DefPathData {
fn hash<H: ::std::hash::Hasher>(&self, hasher: &mut H) {
::std::mem::discriminant(self).hash(hasher);
if let Some(ident) = self.get_opt_ident() {
if ident.ctxt == SyntaxContext::empty() && ident.name == ident.name.interned() {
ident.name.as_str().hash(hasher)
} else {
// FIXME(jseyfried) implement stable hashing for idents with macros 2.0 hygiene info
ident.hash(hasher)
}
}
}
}

View File

@ -1118,7 +1118,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::def_id::DefIn
}
impl_stable_hash_for!(struct hir::def::Export {
name,
ident,
def,
span
});

View File

@ -28,6 +28,7 @@
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(discriminant_value)]
#![feature(i128_type)]
#![feature(libc)]
#![feature(never_type)]

View File

@ -39,7 +39,7 @@ use std::u32;
use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
use syntax::attr;
use syntax::ast;
use syntax::ast::{self, Ident};
use syntax::codemap;
use syntax::ext::base::MacroKind;
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION};
@ -667,7 +667,8 @@ impl<'a, 'tcx> CrateMetadata {
},
ext.kind()
);
callback(def::Export { name: name, def: def, span: DUMMY_SP });
let ident = Ident::with_empty_ctxt(name);
callback(def::Export { ident: ident, def: def, span: DUMMY_SP });
}
}
return
@ -703,7 +704,7 @@ impl<'a, 'tcx> CrateMetadata {
if let Some(def) = self.get_def(child_index) {
callback(def::Export {
def: def,
name: self.item_name(child_index),
ident: Ident::with_empty_ctxt(self.item_name(child_index)),
span: self.entry(child_index).span.decode(self),
});
}
@ -720,7 +721,8 @@ impl<'a, 'tcx> CrateMetadata {
let span = child.span.decode(self);
if let (Some(def), Some(name)) =
(self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) {
callback(def::Export { def: def, name: name, span: span });
let ident = Ident::with_empty_ctxt(name);
callback(def::Export { def: def, ident: ident, span: span });
// For non-reexport structs and variants add their constructors to children.
// Reexport lists automatically contain constructors when necessary.
match def {
@ -728,7 +730,7 @@ impl<'a, 'tcx> CrateMetadata {
if let Some(ctor_def_id) = self.get_struct_ctor_def_id(child_index) {
let ctor_kind = self.get_ctor_kind(child_index);
let ctor_def = Def::StructCtor(ctor_def_id, ctor_kind);
callback(def::Export { def: ctor_def, name: name, span: span });
callback(def::Export { def: ctor_def, ident: ident, span: span });
}
}
Def::Variant(def_id) => {
@ -736,7 +738,7 @@ impl<'a, 'tcx> CrateMetadata {
// value namespace, they are reserved for possible future use.
let ctor_kind = self.get_ctor_kind(child_index);
let ctor_def = Def::VariantCtor(def_id, ctor_kind);
callback(def::Export { def: ctor_def, name: name, span: span });
callback(def::Export { def: ctor_def, ident: ident, span: span });
}
_ => {}
}

View File

@ -439,7 +439,7 @@ impl<'a> Resolver<'a> {
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, child: Export) {
let ident = Ident::with_empty_ctxt(child.name);
let ident = child.ident;
let def = child.def;
let def_id = def.def_id();
let vis = self.session.cstore.visibility(def_id);
@ -480,9 +480,8 @@ impl<'a> Resolver<'a> {
for child in self.session.cstore.item_children(def_id) {
let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
let ident = Ident::with_empty_ctxt(child.name);
self.define(module, ident, ns, (child.def, ty::Visibility::Public,
DUMMY_SP, expansion));
self.define(module, child.ident, ns,
(child.def, ty::Visibility::Public, DUMMY_SP, expansion));
if self.session.cstore.associated_item_cloned(child.def.def_id())
.method_has_self_argument {
@ -643,7 +642,7 @@ impl<'a> Resolver<'a> {
let ident = Ident::with_empty_ctxt(name);
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, false, span);
if let Ok(binding) = result {
self.macro_exports.push(Export { name: name, def: binding.def(), span: span });
self.macro_exports.push(Export { ident: ident, def: binding.def(), span: span });
} else {
span_err!(self.session, span, E0470, "reexported macro not found");
}

View File

@ -726,7 +726,8 @@ impl<'a> Resolver<'a> {
}));
if attr::contains_name(&item.attrs, "macro_export") {
let def = Def::Macro(def_id, MacroKind::Bang);
self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
self.macro_exports
.push(Export { ident: ident.modern(), def: def, span: item.span });
} else {
self.unused_macros.insert(def_id);
}

View File

@ -803,7 +803,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
if module as *const _ == self.graph_root as *const _ {
let macro_exports = mem::replace(&mut self.macro_exports, Vec::new());
for export in macro_exports.into_iter().rev() {
if exported_macro_names.insert(export.name, export.span).is_none() {
if exported_macro_names.insert(export.ident.modern(), export.span).is_none() {
reexports.push(export);
}
}
@ -824,7 +824,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
self.session.cstore.export_macros(def.def_id().krate);
}
if let Def::Macro(..) = def {
if let Some(&span) = exported_macro_names.get(&ident.name) {
if let Some(&span) = exported_macro_names.get(&ident.modern()) {
let msg =
format!("a macro named `{}` has already been exported", ident);
self.session.struct_span_err(span, &msg)
@ -833,7 +833,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
.emit();
}
}
reexports.push(Export { name: ident.name, def: def, span: binding.span });
reexports.push(Export { ident: ident.modern(), def: def, span: binding.span });
}
}

View File

@ -54,13 +54,24 @@ impl fmt::Display for Ident {
impl Encodable for Ident {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.name.encode(s)
if self.ctxt.modern() == SyntaxContext::empty() {
s.emit_str(&self.name.as_str())
} else { // FIXME(jseyfried) intercrate hygiene
let mut string = "#".to_owned();
string.push_str(&self.name.as_str());
s.emit_str(&string)
}
}
}
impl Decodable for Ident {
fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
Ok(Ident::with_empty_ctxt(Symbol::decode(d)?))
let string = d.read_str()?;
Ok(if !string.starts_with('#') {
Ident::from_str(&string)
} else { // FIXME(jseyfried) intercrate hygiene
Ident::with_empty_ctxt(Symbol::gensym(&string[1..]))
})
}
}