@@ -118,12 +118,12 @@ pub enum SymbolScope {
118
118
bitflags ! {
119
119
#[ derive( Copy , Clone , Debug , PartialEq ) ]
120
120
pub struct SymbolFlags : u16 {
121
- const REFERENCED = 0x001 ;
122
- const ASSIGNED = 0x002 ;
123
- const PARAMETER = 0x004 ;
124
- const ANNOTATED = 0x008 ;
125
- const IMPORTED = 0x010 ;
126
- const NONLOCAL = 0x020 ;
121
+ const REFERENCED = 0x001 ; // USE in CPython
122
+ const ASSIGNED = 0x002 ; // DEF_LOCAL in CPython
123
+ const PARAMETER = 0x004 ; // DEF_PARAM in CPython
124
+ const ANNOTATED = 0x008 ; // DEF_ANNOT in CPython
125
+ const IMPORTED = 0x010 ; // DEF_IMPORT in CPython
126
+ const NONLOCAL = 0x020 ; // DEF_NONLOCAL in CPython
127
127
// indicates if the symbol gets a value assigned by a named expression in a comprehension
128
128
// this is required to correct the scope in the analysis.
129
129
const ASSIGNED_IN_COMPREHENSION = 0x040 ;
@@ -138,8 +138,13 @@ bitflags! {
138
138
/// def method(self):
139
139
/// return x // is_free_class
140
140
/// ```
141
- const FREE_CLASS = 0x100 ;
142
- const BOUND = Self :: ASSIGNED . bits( ) | Self :: PARAMETER . bits( ) | Self :: IMPORTED . bits( ) | Self :: ITER . bits( ) ;
141
+ const FREE_CLASS = 0x100 ; // DEF_FREE_CLASS in CPython
142
+ const GLOBAL = 0x200 ; // DEF_GLOBAL in CPython
143
+ const COMP_ITER = 0x400 ; // DEF_COMP_ITER in CPython
144
+ const COMP_CELL = 0x800 ; // DEF_COMP_CELL in CPython
145
+ const TYPE_PARAM = 0x1000 ; // DEF_TYPE_PARAM in CPython
146
+
147
+ const BOUND = Self :: ASSIGNED . bits( ) | Self :: PARAMETER . bits( ) | Self :: IMPORTED . bits( ) | Self :: ITER . bits( ) | Self :: TYPE_PARAM . bits( ) ;
143
148
}
144
149
}
145
150
@@ -557,6 +562,7 @@ enum SymbolUsage {
557
562
AnnotationParameter ,
558
563
AssignedNamedExprInComprehension ,
559
564
Iter ,
565
+ TypeParam ,
560
566
}
561
567
562
568
struct SymbolTableBuilder < ' src > {
@@ -572,6 +578,7 @@ struct SymbolTableBuilder<'src> {
572
578
/// In cpython this is stored in the AST, but I think this
573
579
/// is not logical, since it is not context free.
574
580
#[ derive( Copy , Clone , PartialEq ) ]
581
+ #[ allow( dead_code) ] // IterDefinitionExp may be used in future
575
582
enum ExpressionContext {
576
583
Load ,
577
584
Store ,
@@ -641,6 +648,22 @@ impl SymbolTableBuilder<'_> {
641
648
} else {
642
649
SymbolUsage :: Parameter
643
650
} ;
651
+
652
+ // Check for duplicate parameter names
653
+ let table = self . tables . last ( ) . unwrap ( ) ;
654
+ if table. symbols . contains_key ( parameter. name . as_str ( ) ) {
655
+ return Err ( SymbolTableError {
656
+ error : format ! (
657
+ "duplicate parameter '{}' in function definition" ,
658
+ parameter. name
659
+ ) ,
660
+ location : Some (
661
+ self . source_code
662
+ . source_location ( parameter. name . range . start ( ) ) ,
663
+ ) ,
664
+ } ) ;
665
+ }
666
+
644
667
self . register_ident ( & parameter. name , usage)
645
668
}
646
669
@@ -796,6 +819,17 @@ impl SymbolTableBuilder<'_> {
796
819
if let Some ( alias) = & name. asname {
797
820
// `import my_module as my_alias`
798
821
self . register_ident ( alias, SymbolUsage :: Imported ) ?;
822
+ } else if name. name . id == "*" {
823
+ // Star imports are only allowed at module level
824
+ if self . tables . last ( ) . unwrap ( ) . typ != SymbolTableType :: Module {
825
+ return Err ( SymbolTableError {
826
+ error : "'import *' only allowed at module level" . to_string ( ) ,
827
+ location : Some (
828
+ self . source_code . source_location ( name. name . range . start ( ) ) ,
829
+ ) ,
830
+ } ) ;
831
+ }
832
+ // Don't register star imports as symbols
799
833
} else {
800
834
// `import module`
801
835
self . register_name (
@@ -1248,8 +1282,9 @@ impl SymbolTableBuilder<'_> {
1248
1282
self . scan_expression ( & generator. target , ExpressionContext :: Iter ) ?;
1249
1283
if is_first_generator {
1250
1284
is_first_generator = false ;
1285
+ // Don't scan the first iter here, it's handled outside the comprehension scope
1251
1286
} else {
1252
- self . scan_expression ( & generator. iter , ExpressionContext :: IterDefinitionExp ) ?;
1287
+ self . scan_expression ( & generator. iter , ExpressionContext :: Load ) ?;
1253
1288
}
1254
1289
1255
1290
for if_expr in & generator. ifs {
@@ -1261,7 +1296,7 @@ impl SymbolTableBuilder<'_> {
1261
1296
1262
1297
// The first iterable is passed as an argument into the created function:
1263
1298
assert ! ( !generators. is_empty( ) ) ;
1264
- self . scan_expression ( & generators[ 0 ] . iter , ExpressionContext :: IterDefinitionExp ) ?;
1299
+ self . scan_expression ( & generators[ 0 ] . iter , ExpressionContext :: Load ) ?;
1265
1300
1266
1301
Ok ( ( ) )
1267
1302
}
@@ -1275,7 +1310,7 @@ impl SymbolTableBuilder<'_> {
1275
1310
range : type_var_range,
1276
1311
..
1277
1312
} ) => {
1278
- self . register_name ( name. as_str ( ) , SymbolUsage :: Assigned , * type_var_range) ?;
1313
+ self . register_name ( name. as_str ( ) , SymbolUsage :: TypeParam , * type_var_range) ?;
1279
1314
if let Some ( binding) = bound {
1280
1315
self . scan_expression ( binding, ExpressionContext :: Load ) ?;
1281
1316
}
@@ -1285,14 +1320,14 @@ impl SymbolTableBuilder<'_> {
1285
1320
range : param_spec_range,
1286
1321
..
1287
1322
} ) => {
1288
- self . register_name ( name, SymbolUsage :: Assigned , * param_spec_range) ?;
1323
+ self . register_name ( name, SymbolUsage :: TypeParam , * param_spec_range) ?;
1289
1324
}
1290
1325
TypeParam :: TypeVarTuple ( TypeParamTypeVarTuple {
1291
1326
name,
1292
1327
range : type_var_tuple_range,
1293
1328
..
1294
1329
} ) => {
1295
- self . register_name ( name, SymbolUsage :: Assigned , * type_var_tuple_range) ?;
1330
+ self . register_name ( name, SymbolUsage :: TypeParam , * type_var_tuple_range) ?;
1296
1331
}
1297
1332
}
1298
1333
}
@@ -1496,7 +1531,7 @@ impl SymbolTableBuilder<'_> {
1496
1531
match role {
1497
1532
SymbolUsage :: Nonlocal if scope_depth < 2 => {
1498
1533
return Err ( SymbolTableError {
1499
- error : format ! ( "cannot define nonlocal '{name}' at top level." ) ,
1534
+ error : "nonlocal declaration not allowed at module level" . to_string ( ) ,
1500
1535
location,
1501
1536
} ) ;
1502
1537
}
@@ -1536,24 +1571,29 @@ impl SymbolTableBuilder<'_> {
1536
1571
}
1537
1572
SymbolUsage :: Global => {
1538
1573
symbol. scope = SymbolScope :: GlobalExplicit ;
1574
+ flags. insert ( SymbolFlags :: GLOBAL ) ;
1539
1575
}
1540
1576
SymbolUsage :: Used => {
1541
1577
flags. insert ( SymbolFlags :: REFERENCED ) ;
1542
1578
}
1543
1579
SymbolUsage :: Iter => {
1544
1580
flags. insert ( SymbolFlags :: ITER ) ;
1545
1581
}
1582
+ SymbolUsage :: TypeParam => {
1583
+ flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: TYPE_PARAM ) ;
1584
+ }
1546
1585
}
1547
1586
1548
1587
// and even more checking
1549
1588
// it is not allowed to assign to iterator variables (by named expressions)
1550
- if flags. contains ( SymbolFlags :: ITER | SymbolFlags :: ASSIGNED )
1551
- /* && symbol.is_assign_named_expr_in_comprehension*/
1589
+ if flags. contains ( SymbolFlags :: ITER )
1590
+ && flags . contains ( SymbolFlags :: ASSIGNED_IN_COMPREHENSION )
1552
1591
{
1553
1592
return Err ( SymbolTableError {
1554
- error :
1555
- "assignment expression cannot be used in a comprehension iterable expression"
1556
- . to_string ( ) ,
1593
+ error : format ! (
1594
+ "assignment expression cannot rebind comprehension iteration variable '{}'" ,
1595
+ symbol. name
1596
+ ) ,
1557
1597
location,
1558
1598
} ) ;
1559
1599
}
0 commit comments