@@ -915,30 +915,63 @@ fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
915
915
916
916
/// Resolve a syntax object to a name, per MTWT.
917
917
pub fn mtwt_resolve(id : Ident) -> Name {
918
- resolve_internal(id, get_sctable())
918
+ resolve_internal(id, get_sctable(), get_resolve_table())
919
+ }
920
+
921
+ // FIXME #4536: must be pub for testing
922
+ pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
923
+
924
+ // okay, I admit, putting this in TLS is not so nice:
925
+ // fetch the SCTable from TLS, create one if it doesn't yet exist.
926
+ pub fn get_resolve_table() -> @mut ResolveTable {
927
+ static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
928
+ match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
929
+ None => {
930
+ let new_table = @@mut HashMap::new();
931
+ local_data::set(resolve_table_key,new_table);
932
+ *new_table
933
+ },
934
+ Some(intr) => *intr
935
+ }
919
936
}
920
937
921
938
// Resolve a syntax object to a name, per MTWT.
939
+ // adding memoization to possibly resolve 500+ seconds in resolve for librustc (!)
922
940
// FIXME #4536 : currently pub to allow testing
923
- pub fn resolve_internal(id : Ident, table : &mut SCTable) -> Name {
924
- match table.table[id.ctxt] {
925
- EmptyCtxt => id.name,
926
- // ignore marks here:
927
- Mark(_,subctxt) => resolve_internal(Ident{name:id.name, ctxt: subctxt},table),
928
- // do the rename if necessary:
929
- Rename(Ident{name,ctxt},toname,subctxt) => {
930
- // this could be cached or computed eagerly:
931
- let resolvedfrom = resolve_internal(Ident{name:name,ctxt:ctxt},table);
932
- let resolvedthis = resolve_internal(Ident{name:id.name,ctxt:subctxt},table);
933
- if ((resolvedthis == resolvedfrom)
934
- && (marksof(ctxt,resolvedthis,table)
935
- == marksof(subctxt,resolvedthis,table))) {
936
- toname
937
- } else {
938
- resolvedthis
939
- }
941
+ pub fn resolve_internal(id : Ident,
942
+ table : &mut SCTable,
943
+ resolve_table : &mut ResolveTable) -> Name {
944
+ let key = (id.name,id.ctxt);
945
+ match resolve_table.contains_key(&key) {
946
+ false => {
947
+ let resolved = {
948
+ match table.table[id.ctxt] {
949
+ EmptyCtxt => id.name,
950
+ // ignore marks here:
951
+ Mark(_,subctxt) => resolve_internal(Ident{name:id.name, ctxt: subctxt},table,resolve_table),
952
+ // do the rename if necessary:
953
+ Rename(Ident{name,ctxt},toname,subctxt) => {
954
+ let resolvedfrom = resolve_internal(Ident{name:name,ctxt:ctxt},table,resolve_table);
955
+ let resolvedthis = resolve_internal(Ident{name:id.name,ctxt:subctxt},table,resolve_table);
956
+ if ((resolvedthis == resolvedfrom)
957
+ && (marksof(ctxt,resolvedthis,table)
958
+ == marksof(subctxt,resolvedthis,table))) {
959
+ toname
960
+ } else {
961
+ resolvedthis
962
+ }
963
+ }
964
+ IllegalCtxt() => fail!(~" expected resolvable context, got IllegalCtxt ")
965
+ }
966
+ };
967
+ resolve_table.insert(key,resolved);
968
+ resolved
969
+ }
970
+ true => {
971
+ // it's guaranteed to be there, because we just checked that it was
972
+ // there and we never remove anything from the table:
973
+ *(resolve_table.find(&key).unwrap())
940
974
}
941
- IllegalCtxt() => fail!(~" expected resolvable context, got IllegalCtxt ")
942
975
}
943
976
}
944
977
@@ -1017,20 +1050,21 @@ mod test {
1017
1050
use super::*;
1018
1051
use std::io;
1019
1052
use opt_vec;
1053
+ use std::hash::HashMap;
1020
1054
1021
- fn ident_to_segment(id : &ident ) -> PathSegment {
1055
+ fn ident_to_segment(id : &Ident ) -> PathSegment {
1022
1056
PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty}
1023
1057
}
1024
1058
1025
1059
#[test] fn idents_name_eq_test() {
1026
- assert!(segments_name_eq([ident {name:3,ctxt:4},
1027
- ident {name:78,ctxt:82}].map(ident_to_segment),
1028
- [ident {name:3,ctxt:104},
1029
- ident {name:78,ctxt:182}].map(ident_to_segment)));
1030
- assert!(!segments_name_eq([ident {name:3,ctxt:4},
1031
- ident {name:78,ctxt:82}].map(ident_to_segment),
1032
- [ident {name:3,ctxt:104},
1033
- ident {name:77,ctxt:182}].map(ident_to_segment)));
1060
+ assert!(segments_name_eq([Ident {name:3,ctxt:4},
1061
+ Ident {name:78,ctxt:82}].map(ident_to_segment),
1062
+ [Ident {name:3,ctxt:104},
1063
+ Ident {name:78,ctxt:182}].map(ident_to_segment)));
1064
+ assert!(!segments_name_eq([Ident {name:3,ctxt:4},
1065
+ Ident {name:78,ctxt:82}].map(ident_to_segment),
1066
+ [Ident {name:3,ctxt:104},
1067
+ Ident {name:77,ctxt:182}].map(ident_to_segment)));
1034
1068
}
1035
1069
1036
1070
#[test] fn xorpush_test () {
@@ -1162,52 +1196,59 @@ mod test {
1162
1196
#[test] fn resolve_tests () {
1163
1197
let a = 40;
1164
1198
let mut t = new_sctable_internal();
1199
+ let mut rt = HashMap::new();
1165
1200
// - ctxt is MT
1166
- assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t),a);
1201
+ assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt ),a);
1167
1202
// - simple ignored marks
1168
1203
{ let sc = unfold_marks(~[1,2,3],EMPTY_CTXT,&mut t);
1169
- assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
1204
+ assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt ),a);}
1170
1205
// - orthogonal rename where names don't match
1171
1206
{ let sc = unfold_test_sc(~[R(id(50,EMPTY_CTXT),51),M(12)],EMPTY_CTXT,&mut t);
1172
- assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
1207
+ assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt ),a);}
1173
1208
// - rename where names do match, but marks don't
1174
1209
{ let sc1 = new_mark_internal(1,EMPTY_CTXT,&mut t);
1175
1210
let sc = unfold_test_sc(~[R(id(a,sc1),50),
1176
1211
M(1),
1177
1212
M(2)],
1178
1213
EMPTY_CTXT,&mut t);
1179
- assert_eq!(resolve_internal(id(a,sc),&mut t), a);}
1214
+ assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt ), a);}
1180
1215
// - rename where names and marks match
1181
1216
{ let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
1182
1217
let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],EMPTY_CTXT,&mut t);
1183
- assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
1218
+ assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt ), 50); }
1184
1219
// - rename where names and marks match by literal sharing
1185
1220
{ let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
1186
1221
let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
1187
- assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
1222
+ assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt ), 50); }
1188
1223
// - two renames of the same var.. can only happen if you use
1189
1224
// local-expand to prevent the inner binding from being renamed
1190
1225
// during the rename-pass caused by the first:
1191
1226
io::println(" about to run bad test") ;
1192
1227
{ let sc = unfold_test_sc( ~[ R ( id( a, EMPTY_CTXT ) , 50 ) ,
1193
1228
R ( id( a, EMPTY_CTXT ) , 51 ) ] ,
1194
1229
EMPTY_CTXT , & mut t) ;
1195
- assert_eq!( resolve_internal( id( a, sc) , & mut t) , 51 ) ; }
1230
+ assert_eq!( resolve_internal( id( a, sc) , & mut t, & mut rt ) , 51 ) ; }
1196
1231
// the simplest double-rename:
1197
1232
{ let a_to_a50 = new_rename_internal( id( a, EMPTY_CTXT ) , 50 , EMPTY_CTXT , & mut t) ;
1198
1233
let a50_to_a51 = new_rename_internal( id( a, a_to_a50) , 51 , a_to_a50, & mut t) ;
1199
- assert_eq!( resolve_internal( id( a, a50_to_a51) , & mut t) , 51 ) ;
1234
+ assert_eq!( resolve_internal( id( a, a50_to_a51) , & mut t, & mut rt ) , 51 ) ;
1200
1235
// mark on the outside doesn't stop rename:
1201
1236
let sc = new_mark_internal( 9 , a50_to_a51, & mut t) ;
1202
- assert_eq!( resolve_internal( id( a, sc) , & mut t) , 51 ) ;
1237
+ assert_eq!( resolve_internal( id( a, sc) , & mut t, & mut rt ) , 51 ) ;
1203
1238
// but mark on the inside does:
1204
1239
let a50_to_a51_b = unfold_test_sc( ~[ R ( id( a, a_to_a50) , 51 ) ,
1205
1240
M ( 9 ) ] ,
1206
1241
a_to_a50,
1207
1242
& mut t) ;
1208
- assert_eq!( resolve_internal( id( a, a50_to_a51_b) , & mut t) , 50 ) ; }
1243
+ assert_eq!( resolve_internal( id( a, a50_to_a51_b) , & mut t, & mut rt) , 50 ) ; }
1244
+ }
1245
+
1246
+ #[ test] fn mtwt_resolve_test( ) {
1247
+ let a = 40 ;
1248
+ assert_eq!( mtwt_resolve( id( a, EMPTY_CTXT ) ) , a) ;
1209
1249
}
1210
1250
1251
+
1211
1252
#[ test] fn hashing_tests ( ) {
1212
1253
let mut t = new_sctable_internal( ) ;
1213
1254
assert_eq!( new_mark_internal( 12 , EMPTY_CTXT , & mut t) , 2 ) ;
@@ -1217,4 +1258,16 @@ mod test {
1217
1258
// I'm assuming that the rename table will behave the same....
1218
1259
}
1219
1260
1261
+ #[ test] fn resolve_table_hashing_tests( ) {
1262
+ let mut t = new_sctable_internal( ) ;
1263
+ let mut rt = HashMap :: new( ) ;
1264
+ assert_eq!( rt. len( ) , 0 ) ;
1265
+ resolve_internal( id( 30 , EMPTY_CTXT ) , & mut t, & mut rt) ;
1266
+ assert_eq!( rt. len( ) , 1 ) ;
1267
+ resolve_internal( id( 39 , EMPTY_CTXT ) , & mut t, & mut rt) ;
1268
+ assert_eq!( rt. len( ) , 2 ) ;
1269
+ resolve_internal( id( 30 , EMPTY_CTXT ) , & mut t, & mut rt) ;
1270
+ assert_eq!( rt. len( ) , 2 ) ;
1271
+ }
1272
+
1220
1273
}
0 commit comments