提交 a15dfca5 编写于 作者: J Jeffrey Seyfried

Instead of renaming, treat differently marked identifiers as unequal

上级 ca924047
......@@ -53,7 +53,6 @@
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
use syntax::ext::mtwt;
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
use syntax::parse::token::{self, keywords};
......@@ -462,7 +461,7 @@ struct BindingInfo {
}
// Map from the name in a pattern to its binding mode.
type BindingMap = HashMap<Name, BindingInfo>;
type BindingMap = HashMap<ast::Ident, BindingInfo>;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum PatternSource {
......@@ -668,7 +667,7 @@ enum ModulePrefixResult<'a> {
/// One local scope.
#[derive(Debug)]
struct Rib<'a> {
bindings: HashMap<Name, Def>,
bindings: HashMap<ast::Ident, Def>,
kind: RibKind<'a>,
}
......@@ -1385,15 +1384,17 @@ fn resolve_module_path(&mut self,
/// Invariant: This must only be called during main resolution, not during
/// import resolution.
fn resolve_ident_in_lexical_scope(&mut self,
ident: ast::Ident,
mut ident: ast::Ident,
ns: Namespace,
record_used: bool)
-> Option<LexicalScopeBinding<'a>> {
let name = match ns { ValueNS => mtwt::resolve(ident), TypeNS => ident.name };
if ns == TypeNS {
ident = ast::Ident::with_empty_ctxt(ident.name);
}
// Walk backwards up the ribs in scope.
for i in (0 .. self.get_ribs(ns).len()).rev() {
if let Some(def) = self.get_ribs(ns)[i].bindings.get(&name).cloned() {
if let Some(def) = self.get_ribs(ns)[i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::LocalDef(LocalDef {
ribs: Some((ns, i)),
......@@ -1556,7 +1557,7 @@ fn with_scope<F>(&mut self, id: NodeId, f: F)
/// Searches the current set of local scopes for labels.
/// Stops after meeting a closure.
fn search_label(&self, name: Name) -> Option<Def> {
fn search_label(&self, ident: ast::Ident) -> Option<Def> {
for rib in self.label_ribs.iter().rev() {
match rib.kind {
NormalRibKind => {
......@@ -1567,7 +1568,7 @@ fn search_label(&self, name: Name) -> Option<Def> {
return None;
}
}
let result = rib.bindings.get(&name).cloned();
let result = rib.bindings.get(&ident).cloned();
if result.is_some() {
return result;
}
......@@ -1716,7 +1717,7 @@ fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<
// plain insert (no renaming)
let def_id = self.definitions.local_def_id(type_parameter.id);
let def = Def::TyParam(space, index as u32, def_id, name);
function_type_rib.bindings.insert(name, def);
function_type_rib.bindings.insert(ast::Ident::with_empty_ctxt(name), def);
}
self.type_ribs.push(function_type_rib);
}
......@@ -1887,7 +1888,7 @@ fn with_self_rib<F>(&mut self, self_def: Def, f: F)
let mut self_type_rib = Rib::new(NormalRibKind);
// plain insert (no renaming, types are not currently hygienic....)
self_type_rib.bindings.insert(keywords::SelfType.name(), self_def);
self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def);
self.type_ribs.push(self_type_rib);
f(self);
self.type_ribs.pop();
......@@ -1998,7 +1999,7 @@ fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
_ => false,
} {
let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
binding_map.insert(mtwt::resolve(ident.node), binding_info);
binding_map.insert(ident.node, binding_info);
}
}
true
......@@ -2020,15 +2021,14 @@ fn check_consistent_bindings(&mut self, arm: &Arm) {
for (&key, &binding_0) in &map_0 {
match map_i.get(&key) {
None => {
resolve_error(self,
p.span,
ResolutionError::VariableNotBoundInPattern(key, 1, i + 1));
let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1);
resolve_error(self, p.span, error);
}
Some(binding_i) => {
if binding_0.binding_mode != binding_i.binding_mode {
resolve_error(self,
binding_i.span,
ResolutionError::VariableBoundWithDifferentMode(key,
ResolutionError::VariableBoundWithDifferentMode(key.name,
i + 1));
}
}
......@@ -2039,7 +2039,7 @@ fn check_consistent_bindings(&mut self, arm: &Arm) {
if !map_0.contains_key(&key) {
resolve_error(self,
binding.span,
ResolutionError::VariableNotBoundInPattern(key, i + 1, 1));
ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1));
}
}
}
......@@ -2173,16 +2173,15 @@ fn fresh_binding(&mut self,
pat_id: NodeId,
outer_pat_id: NodeId,
pat_src: PatternSource,
bindings: &mut HashMap<Name, NodeId>)
bindings: &mut HashMap<ast::Ident, NodeId>)
-> PathResolution {
// Add the binding to the local ribs, if it
// doesn't already exist in the bindings map. (We
// must not add it if it's in the bindings map
// because that breaks the assumptions later
// passes make about or-patterns.)
let renamed = mtwt::resolve(ident.node);
let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
match bindings.get(&renamed).cloned() {
match bindings.get(&ident.node).cloned() {
Some(id) if id == outer_pat_id => {
// `Variant(a, a)`, error
resolve_error(
......@@ -2204,7 +2203,7 @@ fn fresh_binding(&mut self,
Some(..) if pat_src == PatternSource::Match => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
def = self.value_ribs.last_mut().unwrap().bindings[&renamed];
def = self.value_ribs.last_mut().unwrap().bindings[&ident.node];
}
Some(..) => {
span_bug!(ident.span, "two bindings with the same name from \
......@@ -2213,8 +2212,8 @@ fn fresh_binding(&mut self,
None => {
// A completely fresh binding, add to the lists if it's valid.
if ident.node.name != keywords::Invalid.name() {
bindings.insert(renamed, outer_pat_id);
self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def);
bindings.insert(ident.node, outer_pat_id);
self.value_ribs.last_mut().unwrap().bindings.insert(ident.node, def);
}
}
}
......@@ -2275,7 +2274,7 @@ fn resolve_pattern(&mut self,
pat_src: PatternSource,
// Maps idents to the node ID for the
// outermost pattern that binds them.
bindings: &mut HashMap<Name, NodeId>) {
bindings: &mut HashMap<ast::Ident, NodeId>) {
// Visit all direct subpatterns of this pattern.
let outer_pat_id = pat.id;
pat.walk(&mut |pat| {
......@@ -2748,7 +2747,7 @@ fn find_best_match(&mut self, name: &str) -> SuggestionType {
let names = self.value_ribs
.iter()
.rev()
.flat_map(|rib| rib.bindings.keys());
.flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name));
if let Some(found) = find_best_match_for_name(names, name, None) {
if name != found {
......@@ -2759,7 +2758,7 @@ fn find_best_match(&mut self, name: &str) -> SuggestionType {
fn resolve_labeled_block(&mut self, label: Option<ast::Ident>, id: NodeId, block: &Block) {
if let Some(label) = label {
let (label, def) = (mtwt::resolve(label), Def::Label(id));
let def = Def::Label(id);
self.with_label_rib(|this| {
this.label_ribs.last_mut().unwrap().bindings.insert(label, def);
this.visit_block(block);
......@@ -2966,7 +2965,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
{
let rib = this.label_ribs.last_mut().unwrap();
rib.bindings.insert(mtwt::resolve(label.node), def);
rib.bindings.insert(label.node, def);
}
visit::walk_expr(this, expr);
......@@ -2974,7 +2973,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
}
ExprKind::Break(Some(label)) | ExprKind::Continue(Some(label)) => {
match self.search_label(mtwt::resolve(label.node)) {
match self.search_label(label.node) {
None => {
self.record_def(expr.id, err_path_resolution());
resolve_error(self,
......
......@@ -26,7 +26,6 @@
use std::fmt;
use std::rc::Rc;
use std::hash::{Hash, Hasher};
use serialize::{Encodable, Decodable, Encoder, Decoder};
/// A name is a part of an identifier, representing a string or gensym. It's
......@@ -46,7 +45,7 @@
/// An identifier contains a Name (index into the interner
/// table) and a SyntaxContext to track renaming and
/// macro expansion per Flatt et al., "Macros That Work Together"
#[derive(Clone, Copy, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Ident {
pub name: Name,
pub ctxt: SyntaxContext
......@@ -93,40 +92,6 @@ pub const fn with_empty_ctxt(name: Name) -> Ident {
}
}
impl PartialEq for Ident {
fn eq(&self, other: &Ident) -> bool {
if self.ctxt != other.ctxt {
// There's no one true way to compare Idents. They can be compared
// non-hygienically `id1.name == id2.name`, hygienically
// `mtwt::resolve(id1) == mtwt::resolve(id2)`, or even member-wise
// `(id1.name, id1.ctxt) == (id2.name, id2.ctxt)` depending on the situation.
// Ideally, PartialEq should not be implemented for Ident at all, but that
// would be too impractical, because many larger structures (Token, in particular)
// including Idents as their parts derive PartialEq and use it for non-hygienic
// comparisons. That's why PartialEq is implemented and defaults to non-hygienic
// comparison. Hash is implemented too and is consistent with PartialEq, i.e. only
// the name of Ident is hashed. Still try to avoid comparing idents in your code
// (especially as keys in hash maps), use one of the three methods listed above
// explicitly.
//
// If you see this panic, then some idents from different contexts were compared
// non-hygienically. It's likely a bug. Use one of the three comparison methods
// listed above explicitly.
panic!("idents with different contexts are compared with operator `==`: \
{:?}, {:?}.", self, other);
}
self.name == other.name
}
}
impl Hash for Ident {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state)
}
}
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}#{}", self.name, self.ctxt.0)
......
......@@ -26,7 +26,6 @@
use ptr::P;
use util::small_vector::SmallVector;
use util::lev_distance::find_best_match_for_name;
use ext::mtwt;
use fold::Folder;
use std::collections::{HashMap, HashSet};
......@@ -483,15 +482,12 @@ pub enum SyntaxExtension {
pub struct BlockInfo {
/// Should macros escape from this scope?
pub macros_escape: bool,
/// What are the pending renames?
pub pending_renames: mtwt::RenameList,
}
impl BlockInfo {
pub fn new() -> BlockInfo {
BlockInfo {
macros_escape: false,
pending_renames: Vec::new(),
}
}
}
......
此差异已折叠。
......@@ -17,7 +17,7 @@
pub use self::SyntaxContext_::*;
use ast::{Ident, Mrk, Name, SyntaxContext};
use ast::{Mrk, SyntaxContext};
use std::cell::RefCell;
use std::collections::HashMap;
......@@ -25,27 +25,19 @@
/// The SCTable contains a table of SyntaxContext_'s. It
/// represents a flattened tree structure, to avoid having
/// managed pointers everywhere (that caused an ICE).
/// the `marks` and `renames` fields are side-tables
/// that ensure that adding the same mark to the same context
/// gives you back the same context as before. This should cut
/// down on memory use *a lot*; applying a mark to a tree containing
/// 50 identifiers would otherwise generate 50 new contexts.
/// The `marks` ensures that adding the same mark to the
/// same context gives you back the same context as before.
pub struct SCTable {
table: RefCell<Vec<SyntaxContext_>>,
marks: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
renames: RefCell<HashMap<Name,SyntaxContext>>,
}
#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
pub enum SyntaxContext_ {
EmptyCtxt,
Mark (Mrk,SyntaxContext),
Rename (Name),
}
/// A list of ident->name renamings
pub type RenameList = Vec<(Ident, Name)>;
/// Extend a syntax context with a given mark
pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
with_sctable(|table| apply_mark_internal(m, ctxt, table))
......@@ -63,32 +55,6 @@ fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxCo
}
}
/// Extend a syntax context with a given rename
pub fn apply_rename(from: Ident, to: Name, ident: Ident) -> Ident {
with_sctable(|table| apply_rename_internal(from, to, ident, table))
}
/// Extend a syntax context with a given rename and sctable (explicit memoization)
fn apply_rename_internal(from: Ident, to: Name, ident: Ident, table: &SCTable) -> Ident {
if (ident.name, ident.ctxt) != (from.name, from.ctxt) {
return ident;
}
let ctxt = *table.renames.borrow_mut().entry(to).or_insert_with(|| {
SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(to)))
});
Ident { ctxt: ctxt, ..ident }
}
/// Apply a list of renamings to a context
// if these rename lists get long, it would make sense
// to consider memoizing this fold. This may come up
// when we add hygiene to item names.
pub fn apply_renames(renames: &RenameList, ident: Ident) -> Ident {
renames.iter().fold(ident, |ident, &(from, to)| {
apply_rename(from, to, ident)
})
}
/// Fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn with_sctable<T, F>(op: F) -> T where
F: FnOnce(&SCTable) -> T,
......@@ -102,7 +68,6 @@ fn new_sctable_internal() -> SCTable {
SCTable {
table: RefCell::new(vec![EmptyCtxt]),
marks: RefCell::new(HashMap::new()),
renames: RefCell::new(HashMap::new()),
}
}
......@@ -119,7 +84,6 @@ pub fn clear_tables() {
with_sctable(|table| {
*table.table.borrow_mut() = Vec::new();
*table.marks.borrow_mut() = HashMap::new();
*table.renames.borrow_mut() = HashMap::new();
});
}
......@@ -128,7 +92,6 @@ pub fn reset_tables() {
with_sctable(|table| {
*table.table.borrow_mut() = vec![EmptyCtxt];
*table.marks.borrow_mut() = HashMap::new();
*table.renames.borrow_mut() = HashMap::new();
});
}
......@@ -138,24 +101,6 @@ fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
(vec.len() - 1) as u32
}
/// Resolve a syntax object to a name, per MTWT.
pub fn resolve(id: Ident) -> Name {
with_sctable(|sctable| {
resolve_internal(id, sctable)
})
}
/// Resolve a syntax object to a name, per MTWT.
/// adding memoization to resolve 500+ seconds in resolve for librustc (!)
fn resolve_internal(id: Ident, table: &SCTable) -> Name {
match table.table.borrow()[id.ctxt.0 as usize] {
EmptyCtxt => id.name,
// ignore marks here:
Mark(_, subctxt) => resolve_internal(Ident::new(id.name, subctxt), table),
Rename(name) => name,
}
}
/// Return the outer mark for a context with a mark at the outside.
/// FAILS when outside is not a mark.
pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
......
......@@ -15,7 +15,6 @@
pub use self::Token::*;
use ast::{self, BinOpKind};
use ext::mtwt;
use ptr::P;
use util::interner::{RcStr, StrInterner};
use util::interner;
......@@ -313,17 +312,6 @@ pub fn is_reserved_keyword(&self) -> bool {
_ => false,
}
}
/// Hygienic identifier equality comparison.
///
/// See `styntax::ext::mtwt`.
pub fn mtwt_eq(&self, other : &Token) -> bool {
match (self, other) {
(&Ident(id1), &Ident(id2)) | (&Lifetime(id1), &Lifetime(id2)) =>
mtwt::resolve(id1) == mtwt::resolve(id2),
_ => *self == *other
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册