@@ -25,34 +25,22 @@ use std::collections::HashMap;
25
25
/// The SCTable contains a table of SyntaxContext_'s. It
26
26
/// represents a flattened tree structure, to avoid having
27
27
/// managed pointers everywhere (that caused an ICE).
28
- /// the mark_memo and rename_memo fields are side-tables
28
+ /// the `marks` and `renames` fields are side-tables
29
29
/// that ensure that adding the same mark to the same context
30
- /// gives you back the same context as before. This shouldn't
31
- /// change the semantics--everything here is immutable--but
32
- /// it should cut down on memory use *a lot*; applying a mark
33
- /// to a tree containing 50 identifiers would otherwise generate
34
- /// 50 new contexts
30
+ /// gives you back the same context as before. This should cut
31
+ /// down on memory use *a lot*; applying a mark to a tree containing
32
+ /// 50 identifiers would otherwise generate 50 new contexts.
35
33
pub struct SCTable {
36
34
table : RefCell < Vec < SyntaxContext_ > > ,
37
- mark_memo : RefCell < HashMap < ( SyntaxContext , Mrk ) , SyntaxContext > > ,
38
- // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and
39
- // compared as pair (name, ctxt) and not as an Ident
40
- rename_memo : RefCell < HashMap < ( SyntaxContext , ( Name , SyntaxContext ) , Name ) , SyntaxContext > > ,
35
+ marks : RefCell < HashMap < ( SyntaxContext , Mrk ) , SyntaxContext > > ,
36
+ renames : RefCell < HashMap < Name , SyntaxContext > > ,
41
37
}
42
38
43
39
#[ derive( PartialEq , RustcEncodable , RustcDecodable , Hash , Debug , Copy , Clone ) ]
44
40
pub enum SyntaxContext_ {
45
41
EmptyCtxt ,
46
42
Mark ( Mrk , SyntaxContext ) ,
47
- /// flattening the name and syntaxcontext into the rename...
48
- /// HIDDEN INVARIANTS:
49
- /// 1) the first name in a Rename node
50
- /// can only be a programmer-supplied name.
51
- /// 2) Every Rename node with a given Name in the
52
- /// "to" slot must have the same name and context
53
- /// in the "from" slot. In essence, they're all
54
- /// pointers to a single "rename" event node.
55
- Rename ( Ident , Name , SyntaxContext ) ,
43
+ Rename ( Name ) ,
56
44
/// actually, IllegalCtxt may not be necessary.
57
45
IllegalCtxt
58
46
}
@@ -67,37 +55,39 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
67
55
68
56
/// Extend a syntax context with a given mark and sctable (explicit memoization)
69
57
fn apply_mark_internal ( m : Mrk , ctxt : SyntaxContext , table : & SCTable ) -> SyntaxContext {
70
- let key = ( ctxt, m) ;
71
- * table. mark_memo . borrow_mut ( ) . entry ( key) . or_insert_with ( || {
72
- SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Mark ( m, ctxt) ) )
73
- } )
58
+ let ctxts = & mut * table. table . borrow_mut ( ) ;
59
+ match ctxts[ ctxt. 0 as usize ] {
60
+ // Applying the same mark twice is a no-op.
61
+ Mark ( outer_mark, prev_ctxt) if outer_mark == m => return prev_ctxt,
62
+ _ => * table. marks . borrow_mut ( ) . entry ( ( ctxt, m) ) . or_insert_with ( || {
63
+ SyntaxContext ( idx_push ( ctxts, Mark ( m, ctxt) ) )
64
+ } ) ,
65
+ }
74
66
}
75
67
76
68
/// Extend a syntax context with a given rename
77
- pub fn apply_rename ( id : Ident , to : Name ,
78
- ctxt : SyntaxContext ) -> SyntaxContext {
79
- with_sctable ( |table| apply_rename_internal ( id, to, ctxt, table) )
69
+ pub fn apply_rename ( from : Ident , to : Name , ident : Ident ) -> Ident {
70
+ with_sctable ( |table| apply_rename_internal ( from, to, ident, table) )
80
71
}
81
72
82
73
/// Extend a syntax context with a given rename and sctable (explicit memoization)
83
- fn apply_rename_internal ( id : Ident ,
84
- to : Name ,
85
- ctxt : SyntaxContext ,
86
- table : & SCTable ) -> SyntaxContext {
87
- let key = ( ctxt, ( id. name , id. ctxt ) , to) ;
88
-
89
- * table. rename_memo . borrow_mut ( ) . entry ( key) . or_insert_with ( || {
90
- SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Rename ( id, to, ctxt) ) )
91
- } )
74
+ fn apply_rename_internal ( from : Ident , to : Name , ident : Ident , table : & SCTable ) -> Ident {
75
+ if ( ident. name , ident. ctxt ) != ( from. name , from. ctxt ) {
76
+ return ident;
77
+ }
78
+ let ctxt = * table. renames . borrow_mut ( ) . entry ( to) . or_insert_with ( || {
79
+ SyntaxContext ( idx_push ( & mut * table. table . borrow_mut ( ) , Rename ( to) ) )
80
+ } ) ;
81
+ Ident { ctxt : ctxt, ..ident }
92
82
}
93
83
94
84
/// Apply a list of renamings to a context
95
85
// if these rename lists get long, it would make sense
96
86
// to consider memoizing this fold. This may come up
97
87
// when we add hygiene to item names.
98
- pub fn apply_renames ( renames : & RenameList , ctxt : SyntaxContext ) -> SyntaxContext {
99
- renames. iter ( ) . fold ( ctxt , |ctxt , & ( from, to) | {
100
- apply_rename ( from, to, ctxt )
88
+ pub fn apply_renames ( renames : & RenameList , ident : Ident ) -> Ident {
89
+ renames. iter ( ) . fold ( ident , |ident , & ( from, to) | {
90
+ apply_rename ( from, to, ident )
101
91
} )
102
92
}
103
93
@@ -114,8 +104,8 @@ pub fn with_sctable<T, F>(op: F) -> T where
114
104
fn new_sctable_internal ( ) -> SCTable {
115
105
SCTable {
116
106
table : RefCell :: new ( vec ! ( EmptyCtxt , IllegalCtxt ) ) ,
117
- mark_memo : RefCell :: new ( HashMap :: new ( ) ) ,
118
- rename_memo : RefCell :: new ( HashMap :: new ( ) ) ,
107
+ marks : RefCell :: new ( HashMap :: new ( ) ) ,
108
+ renames : RefCell :: new ( HashMap :: new ( ) ) ,
119
109
}
120
110
}
121
111
@@ -131,20 +121,18 @@ pub fn display_sctable(table: &SCTable) {
131
121
pub fn clear_tables ( ) {
132
122
with_sctable ( |table| {
133
123
* table. table . borrow_mut ( ) = Vec :: new ( ) ;
134
- * table. mark_memo . borrow_mut ( ) = HashMap :: new ( ) ;
135
- * table. rename_memo . borrow_mut ( ) = HashMap :: new ( ) ;
124
+ * table. marks . borrow_mut ( ) = HashMap :: new ( ) ;
125
+ * table. renames . borrow_mut ( ) = HashMap :: new ( ) ;
136
126
} ) ;
137
- with_resolve_table_mut ( |table| * table = HashMap :: new ( ) ) ;
138
127
}
139
128
140
129
/// Reset the tables to their initial state
141
130
pub fn reset_tables ( ) {
142
131
with_sctable ( |table| {
143
132
* table. table . borrow_mut ( ) = vec ! ( EmptyCtxt , IllegalCtxt ) ;
144
- * table. mark_memo . borrow_mut ( ) = HashMap :: new ( ) ;
145
- * table. rename_memo . borrow_mut ( ) = HashMap :: new ( ) ;
133
+ * table. marks . borrow_mut ( ) = HashMap :: new ( ) ;
134
+ * table. renames . borrow_mut ( ) = HashMap :: new ( ) ;
146
135
} ) ;
147
- with_resolve_table_mut ( |table| * table = HashMap :: new ( ) ) ;
148
136
}
149
137
150
138
/// Add a value to the end of a vec, return its index
@@ -156,103 +144,19 @@ fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
156
144
/// Resolve a syntax object to a name, per MTWT.
157
145
pub fn resolve ( id : Ident ) -> Name {
158
146
with_sctable ( |sctable| {
159
- with_resolve_table_mut ( |resolve_table| {
160
- resolve_internal ( id, sctable, resolve_table)
161
- } )
147
+ resolve_internal ( id, sctable)
162
148
} )
163
149
}
164
150
165
- type ResolveTable = HashMap < ( Name , SyntaxContext ) , Name > ;
166
-
167
- // okay, I admit, putting this in TLS is not so nice:
168
- // fetch the SCTable from TLS, create one if it doesn't yet exist.
169
- fn with_resolve_table_mut < T , F > ( op : F ) -> T where
170
- F : FnOnce ( & mut ResolveTable ) -> T ,
171
- {
172
- thread_local ! ( static RESOLVE_TABLE_KEY : RefCell <ResolveTable > = {
173
- RefCell :: new( HashMap :: new( ) )
174
- } ) ;
175
-
176
- RESOLVE_TABLE_KEY . with ( move |slot| op ( & mut * slot. borrow_mut ( ) ) )
177
- }
178
-
179
151
/// Resolve a syntax object to a name, per MTWT.
180
152
/// adding memoization to resolve 500+ seconds in resolve for librustc (!)
181
- fn resolve_internal ( id : Ident ,
182
- table : & SCTable ,
183
- resolve_table : & mut ResolveTable ) -> Name {
184
- let key = ( id. name , id. ctxt ) ;
185
-
186
- match resolve_table. get ( & key) {
187
- Some ( & name) => return name,
188
- None => { }
189
- }
190
-
191
- let resolved = {
192
- let result = ( * table. table . borrow ( ) ) [ id. ctxt . 0 as usize ] ;
193
- match result {
194
- EmptyCtxt => id. name ,
195
- // ignore marks here:
196
- Mark ( _, subctxt) =>
197
- resolve_internal ( Ident :: new ( id. name , subctxt) ,
198
- table, resolve_table) ,
199
- // do the rename if necessary:
200
- Rename ( Ident { name, ctxt} , toname, subctxt) => {
201
- let resolvedfrom =
202
- resolve_internal ( Ident :: new ( name, ctxt) ,
203
- table, resolve_table) ;
204
- let resolvedthis =
205
- resolve_internal ( Ident :: new ( id. name , subctxt) ,
206
- table, resolve_table) ;
207
- if ( resolvedthis == resolvedfrom)
208
- && ( marksof_internal ( ctxt, resolvedthis, table)
209
- == marksof_internal ( subctxt, resolvedthis, table) ) {
210
- toname
211
- } else {
212
- resolvedthis
213
- }
214
- }
215
- IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
216
- }
217
- } ;
218
- resolve_table. insert ( key, resolved) ;
219
- resolved
220
- }
221
-
222
- /// Compute the marks associated with a syntax context.
223
- pub fn marksof ( ctxt : SyntaxContext , stopname : Name ) -> Vec < Mrk > {
224
- with_sctable ( |table| marksof_internal ( ctxt, stopname, table) )
225
- }
226
-
227
- // the internal function for computing marks
228
- // it's not clear to me whether it's better to use a [] mutable
229
- // vector or a cons-list for this.
230
- fn marksof_internal ( ctxt : SyntaxContext ,
231
- stopname : Name ,
232
- table : & SCTable ) -> Vec < Mrk > {
233
- let mut result = Vec :: new ( ) ;
234
- let mut loopvar = ctxt;
235
- loop {
236
- let table_entry = ( * table. table . borrow ( ) ) [ loopvar. 0 as usize ] ;
237
- match table_entry {
238
- EmptyCtxt => {
239
- return result;
240
- } ,
241
- Mark ( mark, tl) => {
242
- xor_push ( & mut result, mark) ;
243
- loopvar = tl;
244
- } ,
245
- Rename ( _, name, tl) => {
246
- // see MTWT for details on the purpose of the stopname.
247
- // short version: it prevents duplication of effort.
248
- if name == stopname {
249
- return result;
250
- } else {
251
- loopvar = tl;
252
- }
253
- }
254
- IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
255
- }
153
+ fn resolve_internal ( id : Ident , table : & SCTable ) -> Name {
154
+ match table. table . borrow ( ) [ id. ctxt . 0 as usize ] {
155
+ EmptyCtxt => id. name ,
156
+ // ignore marks here:
157
+ Mark ( _, subctxt) => resolve_internal ( Ident :: new ( id. name , subctxt) , table) ,
158
+ Rename ( name) => name,
159
+ IllegalCtxt => panic ! ( "expected resolvable context, got IllegalCtxt" )
256
160
}
257
161
}
258
162
@@ -267,16 +171,6 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
267
171
} )
268
172
}
269
173
270
- /// Push a name... unless it matches the one on top, in which
271
- /// case pop and discard (so two of the same marks cancel)
272
- fn xor_push ( marks : & mut Vec < Mrk > , mark : Mrk ) {
273
- if ( !marks. is_empty ( ) ) && ( * marks. last ( ) . unwrap ( ) == mark) {
274
- marks. pop ( ) . unwrap ( ) ;
275
- } else {
276
- marks. push ( mark) ;
277
- }
278
- }
279
-
280
174
#[ cfg( test) ]
281
175
mod tests {
282
176
use self :: TestSC :: * ;
0 commit comments