Skip to content

Commit 0cd6193

Browse files
committed
symboltable updates
1 parent 07a04ac commit 0cd6193

File tree

1 file changed

+59
-19
lines changed

1 file changed

+59
-19
lines changed

compiler/codegen/src/symboltable.rs

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ pub enum SymbolScope {
118118
bitflags! {
119119
#[derive(Copy, Clone, Debug, PartialEq)]
120120
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
127127
// indicates if the symbol gets a value assigned by a named expression in a comprehension
128128
// this is required to correct the scope in the analysis.
129129
const ASSIGNED_IN_COMPREHENSION = 0x040;
@@ -138,8 +138,13 @@ bitflags! {
138138
/// def method(self):
139139
/// return x // is_free_class
140140
/// ```
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();
143148
}
144149
}
145150

@@ -557,6 +562,7 @@ enum SymbolUsage {
557562
AnnotationParameter,
558563
AssignedNamedExprInComprehension,
559564
Iter,
565+
TypeParam,
560566
}
561567

562568
struct SymbolTableBuilder<'src> {
@@ -572,6 +578,7 @@ struct SymbolTableBuilder<'src> {
572578
/// In cpython this is stored in the AST, but I think this
573579
/// is not logical, since it is not context free.
574580
#[derive(Copy, Clone, PartialEq)]
581+
#[allow(dead_code)] // IterDefinitionExp may be used in future
575582
enum ExpressionContext {
576583
Load,
577584
Store,
@@ -641,6 +648,22 @@ impl SymbolTableBuilder<'_> {
641648
} else {
642649
SymbolUsage::Parameter
643650
};
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+
644667
self.register_ident(&parameter.name, usage)
645668
}
646669

@@ -796,6 +819,17 @@ impl SymbolTableBuilder<'_> {
796819
if let Some(alias) = &name.asname {
797820
// `import my_module as my_alias`
798821
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
799833
} else {
800834
// `import module`
801835
self.register_name(
@@ -1248,8 +1282,9 @@ impl SymbolTableBuilder<'_> {
12481282
self.scan_expression(&generator.target, ExpressionContext::Iter)?;
12491283
if is_first_generator {
12501284
is_first_generator = false;
1285+
// Don't scan the first iter here, it's handled outside the comprehension scope
12511286
} else {
1252-
self.scan_expression(&generator.iter, ExpressionContext::IterDefinitionExp)?;
1287+
self.scan_expression(&generator.iter, ExpressionContext::Load)?;
12531288
}
12541289

12551290
for if_expr in &generator.ifs {
@@ -1261,7 +1296,7 @@ impl SymbolTableBuilder<'_> {
12611296

12621297
// The first iterable is passed as an argument into the created function:
12631298
assert!(!generators.is_empty());
1264-
self.scan_expression(&generators[0].iter, ExpressionContext::IterDefinitionExp)?;
1299+
self.scan_expression(&generators[0].iter, ExpressionContext::Load)?;
12651300

12661301
Ok(())
12671302
}
@@ -1275,7 +1310,7 @@ impl SymbolTableBuilder<'_> {
12751310
range: type_var_range,
12761311
..
12771312
}) => {
1278-
self.register_name(name.as_str(), SymbolUsage::Assigned, *type_var_range)?;
1313+
self.register_name(name.as_str(), SymbolUsage::TypeParam, *type_var_range)?;
12791314
if let Some(binding) = bound {
12801315
self.scan_expression(binding, ExpressionContext::Load)?;
12811316
}
@@ -1285,14 +1320,14 @@ impl SymbolTableBuilder<'_> {
12851320
range: param_spec_range,
12861321
..
12871322
}) => {
1288-
self.register_name(name, SymbolUsage::Assigned, *param_spec_range)?;
1323+
self.register_name(name, SymbolUsage::TypeParam, *param_spec_range)?;
12891324
}
12901325
TypeParam::TypeVarTuple(TypeParamTypeVarTuple {
12911326
name,
12921327
range: type_var_tuple_range,
12931328
..
12941329
}) => {
1295-
self.register_name(name, SymbolUsage::Assigned, *type_var_tuple_range)?;
1330+
self.register_name(name, SymbolUsage::TypeParam, *type_var_tuple_range)?;
12961331
}
12971332
}
12981333
}
@@ -1496,7 +1531,7 @@ impl SymbolTableBuilder<'_> {
14961531
match role {
14971532
SymbolUsage::Nonlocal if scope_depth < 2 => {
14981533
return Err(SymbolTableError {
1499-
error: format!("cannot define nonlocal '{name}' at top level."),
1534+
error: "nonlocal declaration not allowed at module level".to_string(),
15001535
location,
15011536
});
15021537
}
@@ -1536,24 +1571,29 @@ impl SymbolTableBuilder<'_> {
15361571
}
15371572
SymbolUsage::Global => {
15381573
symbol.scope = SymbolScope::GlobalExplicit;
1574+
flags.insert(SymbolFlags::GLOBAL);
15391575
}
15401576
SymbolUsage::Used => {
15411577
flags.insert(SymbolFlags::REFERENCED);
15421578
}
15431579
SymbolUsage::Iter => {
15441580
flags.insert(SymbolFlags::ITER);
15451581
}
1582+
SymbolUsage::TypeParam => {
1583+
flags.insert(SymbolFlags::ASSIGNED | SymbolFlags::TYPE_PARAM);
1584+
}
15461585
}
15471586

15481587
// and even more checking
15491588
// 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)
15521591
{
15531592
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+
),
15571597
location,
15581598
});
15591599
}

0 commit comments

Comments
 (0)