@@ -203,23 +203,37 @@ class EvalExprScopeInfo : public ScopeInfo {
203
203
InternedString internString (llvm::StringRef s) override { abort (); }
204
204
};
205
205
206
+ struct ScopeNameUsageEntry {
207
+ // Properties determined from crawling the scope:
208
+ unsigned char read : 1 ;
209
+ unsigned char written : 1 ;
210
+ unsigned char forced_globals : 1 ;
211
+ unsigned char params : 1 ;
212
+
213
+ // Properties determined by looking at other scopes as well:
214
+ unsigned char referenced_from_nested : 1 ;
215
+ unsigned char got_from_closure : 1 ;
216
+ unsigned char passthrough_accesses : 1 ; // what names a child scope accesses a name from a parent scope
217
+
218
+ ScopeNameUsageEntry ()
219
+ : read(0 ),
220
+ written (0 ),
221
+ forced_globals(0 ),
222
+ params(0 ),
223
+ referenced_from_nested(0 ),
224
+ got_from_closure(0 ),
225
+ passthrough_accesses(0 ) {}
226
+ };
227
+
206
228
struct ScopingAnalysis ::ScopeNameUsage {
207
229
AST* node;
208
230
ScopeNameUsage* parent;
209
231
llvm::StringRef private_name;
210
232
ScopingAnalysis* scoping;
211
233
212
- // Properties determined from crawling the scope:
213
- StrSet read;
214
- StrSet written;
215
- StrSet forced_globals;
216
- StrSet params;
217
- std::vector<AST_Name*> del_name_nodes;
234
+ std::unordered_map<InternedString, ScopeNameUsageEntry> results;
218
235
219
- // Properties determined by looking at other scopes as well:
220
- StrSet referenced_from_nested;
221
- StrSet got_from_closure;
222
- StrSet passthrough_accesses; // what names a child scope accesses a name from a parent scope
236
+ std::vector<AST_Name*> del_name_nodes;
223
237
224
238
// `import *` and `exec` both force the scope to use the NAME lookup
225
239
// However, this is not allowed to happen (a SyntaxError) if the scope has
@@ -251,12 +265,12 @@ struct ScopingAnalysis::ScopeNameUsage {
251
265
AST_ClassDef* classdef = ast_cast<AST_ClassDef>(node);
252
266
253
267
// classes have an implicit write to "__module__"
254
- written. insert ( scoping->getInternedStrings ().get (" __module__" )) ;
268
+ results[ scoping->getInternedStrings ().get (" __module__" )]. written = 1 ;
255
269
256
270
if (classdef->body .size () && classdef->body [0 ]->type == AST_TYPE::Expr) {
257
271
AST_Expr* first_expr = ast_cast<AST_Expr>(classdef->body [0 ]);
258
272
if (first_expr->value ->type == AST_TYPE::Str) {
259
- written. insert ( scoping->getInternedStrings ().get (" __doc__" )) ;
273
+ results[ scoping->getInternedStrings ().get (" __doc__" )]. written = 1 ;
260
274
}
261
275
}
262
276
}
@@ -273,8 +287,10 @@ struct ScopingAnalysis::ScopeNameUsage {
273
287
void dump () {
274
288
#define DUMP (n ) \
275
289
printf (STRINGIFY (n) " :\n " ); \
276
- for (auto s : n) { \
277
- printf (" %s\n " , s.c_str ()); \
290
+ for (auto s : results) { \
291
+ if (!s.second .n ) \
292
+ continue ; \
293
+ printf (" %s\n " , s.first .c_str ()); \
278
294
}
279
295
280
296
DUMP (read);
@@ -300,6 +316,8 @@ class ScopeInfoBase : public ScopeInfo {
300
316
bool allDerefVarsAndInfoCached;
301
317
302
318
bool globals_from_module;
319
+ bool takes_closure = false ;
320
+ bool passthrough_accesses = false ;
303
321
304
322
public:
305
323
ScopeInfoBase (ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast, bool usesNameLookup,
@@ -313,45 +331,54 @@ class ScopeInfoBase : public ScopeInfo {
313
331
assert (usage);
314
332
assert (ast);
315
333
334
+ bool got_from_closure = false ;
335
+ std::vector<InternedString> referenced_from_nested_sorted;
336
+ for (auto && r : usage->results ) {
337
+ if (r.second .referenced_from_nested )
338
+ referenced_from_nested_sorted.push_back (r.first );
339
+ got_from_closure = got_from_closure || r.second .got_from_closure ;
340
+ passthrough_accesses = passthrough_accesses || r.second .passthrough_accesses ;
341
+ }
342
+
316
343
// Sort the entries by name to make the order deterministic.
317
- std::vector<InternedString> referenced_from_nested_sorted (usage->referenced_from_nested .begin (),
318
- usage->referenced_from_nested .end ());
319
344
std::sort (referenced_from_nested_sorted.begin (), referenced_from_nested_sorted.end ());
320
345
int i = 0 ;
321
346
for (auto & p : referenced_from_nested_sorted) {
322
347
closure_offsets[p] = i;
323
348
i++;
324
349
}
350
+
351
+ takes_closure = got_from_closure || passthrough_accesses;
325
352
}
326
353
327
354
~ScopeInfoBase () override { delete this ->usage ; }
328
355
329
356
ScopeInfo* getParent () override { return parent; }
330
357
331
- bool createsClosure () override { return usage-> referenced_from_nested .size () > 0 ; }
358
+ bool createsClosure () override { return closure_offsets .size () > 0 ; }
332
359
333
- bool takesClosure () override {
334
- return usage->got_from_closure .size () > 0 || usage->passthrough_accesses .size () > 0 ;
335
- }
360
+ bool takesClosure () override { return takes_closure; }
336
361
337
- bool passesThroughClosure () override { return usage-> passthrough_accesses . size () > 0 && !createsClosure (); }
362
+ bool passesThroughClosure () override { return passthrough_accesses && !createsClosure (); }
338
363
339
364
VarScopeType getScopeTypeOfName (InternedString name) override {
340
365
if (name.isCompilerCreatedName ())
341
366
return VarScopeType::FAST;
342
367
343
- if (usage->forced_globals .count (name) > 0 )
368
+ auto it = usage->results .find (name);
369
+ bool found_name = it != usage->results .end ();
370
+ if (found_name && it->second .forced_globals )
344
371
return VarScopeType::GLOBAL;
345
372
346
- if (usage-> got_from_closure . count (name) > 0 )
373
+ if (found_name && it-> second . got_from_closure )
347
374
return VarScopeType::DEREF;
348
375
349
376
if (usesNameLookup_) {
350
377
return VarScopeType::NAME;
351
378
} else {
352
- if (usage-> written . count (name) == 0 )
379
+ if (!found_name || !it-> second . written )
353
380
return VarScopeType::GLOBAL;
354
- else if (usage-> referenced_from_nested . count (name) > 0 )
381
+ else if (found_name && it-> second . referenced_from_nested )
355
382
return VarScopeType::CLOSURE;
356
383
else
357
384
return VarScopeType::FAST;
@@ -409,16 +436,14 @@ class ScopeInfoBase : public ScopeInfo {
409
436
410
437
// Get all the variables that we need to return: any variable from the
411
438
// passed-in closure that is accessed in this scope or in a child scope.
412
- StrSet allDerefs = usage->got_from_closure ;
413
- for (InternedString name : usage->passthrough_accesses ) {
414
- if (allDerefs.find (name) != allDerefs.end ()) {
415
- allDerefs.insert (name);
416
- }
417
- }
418
-
419
- // Call `getDerefInfo` on all of these variables and put the results in
420
- // `allDerefVarsAndInfo`
421
- for (InternedString name : allDerefs) {
439
+ for (auto && r : usage->results ) {
440
+ bool is_deref = r.second .got_from_closure || r.second .passthrough_accesses ;
441
+ if (!is_deref)
442
+ continue ;
443
+
444
+ auto && name = r.first ;
445
+ // Call `getDerefInfo` on all of these variables and put the results in
446
+ // `allDerefVarsAndInfo`
422
447
allDerefVarsAndInfo.push_back ({ name, getDerefInfo (name) });
423
448
}
424
449
@@ -459,16 +484,17 @@ class NameCollectorVisitor : public ASTVisitor {
459
484
public:
460
485
void doWrite (InternedString name) {
461
486
assert (name == mangleName (name, cur->private_name , scoping->getInternedStrings ()));
462
- cur->read .insert (name);
463
- cur->written .insert (name);
487
+ auto & r = cur->results [name];
488
+ r.read = 1 ;
489
+ r.written = 1 ;
464
490
if (this ->currently_visiting_functiondef_args ) {
465
- cur-> params . insert (name) ;
491
+ r. params = 1 ;
466
492
}
467
493
}
468
494
469
495
void doRead (InternedString name) {
470
496
assert (name == mangleName (name, cur->private_name , scoping->getInternedStrings ()));
471
- cur->read . insert ( name) ;
497
+ cur->results [ name]. read = 1 ;
472
498
}
473
499
474
500
void doDel (AST_Name* node) { cur->del_name_nodes .push_back (node); }
@@ -557,11 +583,12 @@ class NameCollectorVisitor : public ASTVisitor {
557
583
bool visit_global (AST_Global* node) override {
558
584
for (int i = 0 ; i < node->names .size (); i++) {
559
585
mangleNameInPlace (node->names [i], cur->private_name , scoping->getInternedStrings ());
560
- if (cur->params .find (node->names [i]) != cur->params .end ()) {
586
+ auto & r = cur->results [node->names [i]];
587
+ if (r.params ) {
561
588
// Throw an exception if a name is both declared global and a parameter
562
589
raiseGlobalAndLocalException (node->names [i], this ->orig_node );
563
590
}
564
- cur-> forced_globals . insert (node-> names [i]) ;
591
+ r. forced_globals = 1 ;
565
592
}
566
593
return true ;
567
594
}
@@ -788,30 +815,35 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
788
815
789
816
bool is_any_name_free = false ;
790
817
791
- for (const auto & name : usage->read ) {
792
- if (usage-> forced_globals . count (name) )
818
+ for (auto && r : usage->results ) {
819
+ if (!r. second . read )
793
820
continue ;
794
- if (usage-> written . count (name) )
821
+ if (r. second . forced_globals )
795
822
continue ;
823
+ if (r.second .written )
824
+ continue ;
825
+
826
+ auto && name = r.first ;
796
827
797
828
bool is_name_free = true ;
798
829
799
830
std::vector<ScopeNameUsage*> intermediate_parents;
800
831
801
832
ScopeNameUsage* parent = usage->parent ;
802
833
while (parent) {
834
+ auto parent_result = parent->results .find (name);
803
835
if (parent->node ->type == AST_TYPE::ClassDef) {
804
836
intermediate_parents.push_back (parent);
805
837
parent = parent->parent ;
806
- } else if (parent->forced_globals . count (name) ) {
838
+ } else if (parent_result != parent->results . end () && parent_result-> second . forced_globals ) {
807
839
is_name_free = false ;
808
840
break ;
809
- } else if (parent->written . count (name) ) {
810
- usage-> got_from_closure . insert (name) ;
811
- parent-> referenced_from_nested . insert (name) ;
841
+ } else if (parent_result != parent->results . end () && parent_result-> second . written ) {
842
+ r. second . got_from_closure = 1 ;
843
+ parent_result-> second . referenced_from_nested = 1 ;
812
844
813
845
for (ScopeNameUsage* iparent : intermediate_parents) {
814
- iparent->passthrough_accesses . insert ( name) ;
846
+ iparent->results [ name]. passthrough_accesses = 1 ;
815
847
}
816
848
817
849
break ;
@@ -853,7 +885,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
853
885
// `del` for closure variables. But it is, so, there you go:
854
886
for (AST_Name* name_node : usage->del_name_nodes ) {
855
887
InternedString name = name_node->id ;
856
- if (usage->referenced_from_nested .count (name) > 0 ) {
888
+ if (usage->results .count (name) && usage-> results [name]. referenced_from_nested ) {
857
889
char buf[1024 ];
858
890
snprintf (buf, sizeof (buf), " can not delete variable '%s' referenced in nested scope" , name.c_str ());
859
891
assert (usage->node ->type == AST_TYPE::FunctionDef);
0 commit comments