Skip to content

Commit 0d8a372

Browse files
committed
symboltable takes responsibility of __debug__
1 parent d8acea3 commit 0d8a372

File tree

4 files changed

+66
-61
lines changed

4 files changed

+66
-61
lines changed

Lib/test/test_future_stmt/test_future.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,6 @@ def test_infinity_numbers(self):
459459
self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})")
460460
self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))")
461461

462-
# TODO: RUSTPYTHON
463-
# AssertionError: SyntaxError not raised
464-
@unittest.expectedFailure
465462
def test_annotation_with_complex_target(self):
466463
with self.assertRaises(SyntaxError):
467464
exec(

crates/codegen/src/compile.rs

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,6 @@ enum NameUsage {
110110
Store,
111111
Delete,
112112
}
113-
114-
fn is_forbidden_name(name: &str) -> bool {
115-
// See https://docs.python.org/3/library/constants.html#built-in-constants
116-
const BUILTIN_CONSTANTS: &[&str] = &["__debug__"];
117-
118-
BUILTIN_CONSTANTS.contains(&name)
119-
}
120-
121113
/// Main structure holding the state of compilation.
122114
struct Compiler {
123115
code_stack: Vec<ir::CodeInfo>,
@@ -1523,11 +1515,7 @@ impl Compiler {
15231515
self._name_inner(name, |i| &mut i.metadata.names)
15241516
}
15251517
fn varname(&mut self, name: &str) -> CompileResult<bytecode::NameIdx> {
1526-
if Self::is_forbidden_arg_name(name) {
1527-
return Err(self.error(CodegenErrorType::SyntaxError(format!(
1528-
"cannot assign to {name}",
1529-
))));
1530-
}
1518+
// Note: __debug__ checks are now handled in symboltable phase
15311519
Ok(self._name_inner(name, |i| &mut i.metadata.varnames))
15321520
}
15331521
fn _name_inner(
@@ -1812,15 +1800,6 @@ impl Compiler {
18121800
symboltable::mangle_name(private, name)
18131801
}
18141802

1815-
fn check_forbidden_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
1816-
let msg = match usage {
1817-
NameUsage::Store if is_forbidden_name(name) => "cannot assign to",
1818-
NameUsage::Delete if is_forbidden_name(name) => "cannot delete",
1819-
_ => return Ok(()),
1820-
};
1821-
Err(self.error(CodegenErrorType::SyntaxError(format!("{msg} {name}"))))
1822-
}
1823-
18241803
// = compiler_nameop
18251804
fn compile_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
18261805
enum NameOp {
@@ -1832,7 +1811,6 @@ impl Compiler {
18321811
}
18331812

18341813
let name = self.mangle(name);
1835-
self.check_forbidden_name(&name, usage)?;
18361814

18371815
// Special handling for __debug__
18381816
if NameUsage::Load == usage && name == "__debug__" {
@@ -2434,7 +2412,6 @@ impl Compiler {
24342412
match &expression {
24352413
Expr::Name(ExprName { id, .. }) => self.compile_name(id.as_str(), NameUsage::Delete)?,
24362414
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
2437-
self.check_forbidden_name(attr.as_str(), NameUsage::Delete)?;
24382415
self.compile_expression(value)?;
24392416
let idx = self.name(attr.as_str());
24402417
emit!(self, Instruction::DeleteAttr { idx });
@@ -3453,10 +3430,6 @@ impl Compiler {
34533430
Ok(())
34543431
}
34553432

3456-
fn is_forbidden_arg_name(name: &str) -> bool {
3457-
is_forbidden_name(name)
3458-
}
3459-
34603433
/// Compile default arguments
34613434
// = compiler_default_arguments
34623435
fn compile_default_arguments(
@@ -6000,7 +5973,6 @@ impl Compiler {
60005973
self.compile_subscript(value, slice, *ctx)?;
60015974
}
60025975
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
6003-
self.check_forbidden_name(attr.as_str(), NameUsage::Store)?;
60045976
self.compile_expression(value)?;
60055977
let idx = self.name(attr.as_str());
60065978
emit!(self, Instruction::StoreAttr { idx });
@@ -6095,7 +6067,6 @@ impl Compiler {
60956067
}
60966068
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
60976069
let attr = attr.as_str();
6098-
self.check_forbidden_name(attr, NameUsage::Store)?;
60996070
self.compile_expression(value)?;
61006071
emit!(self, Instruction::Copy { index: 1_u32 });
61016072
let idx = self.name(attr);
@@ -6923,12 +6894,6 @@ impl Compiler {
69236894
let (size, unpack) = self.gather_elements(additional_positional, &arguments.args)?;
69246895
let has_double_star = arguments.keywords.iter().any(|k| k.arg.is_none());
69256896

6926-
for keyword in &arguments.keywords {
6927-
if let Some(name) = &keyword.arg {
6928-
self.check_forbidden_name(name.as_str(), NameUsage::Store)?;
6929-
}
6930-
}
6931-
69326897
if unpack || has_double_star {
69336898
// Create a tuple with positional args:
69346899
if unpack {

crates/codegen/src/symboltable.rs

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,12 @@ impl SymbolTableBuilder {
988988
}
989989

990990
fn scan_parameter(&mut self, parameter: &Parameter) -> SymbolTableResult {
991+
self.check_name(
992+
parameter.name.as_str(),
993+
ExpressionContext::Store,
994+
parameter.name.range,
995+
)?;
996+
991997
let usage = if parameter.annotation.is_some() {
992998
SymbolUsage::AnnotationParameter
993999
} else {
@@ -1250,6 +1256,7 @@ impl SymbolTableBuilder {
12501256
for name in names {
12511257
if let Some(alias) = &name.asname {
12521258
// `import my_module as my_alias`
1259+
self.check_name(alias.as_str(), ExpressionContext::Store, alias.range)?;
12531260
self.register_ident(alias, SymbolUsage::Imported)?;
12541261
} else if name.name.as_str() == "*" {
12551262
// Star imports are only allowed at module level
@@ -1264,12 +1271,10 @@ impl SymbolTableBuilder {
12641271
}
12651272
// Don't register star imports as symbols
12661273
} else {
1267-
// `import module`
1268-
self.register_name(
1269-
name.name.split('.').next().unwrap(),
1270-
SymbolUsage::Imported,
1271-
name.name.range,
1272-
)?;
1274+
// `import module` or `from x import name`
1275+
let imported_name = name.name.split('.').next().unwrap();
1276+
self.check_name(imported_name, ExpressionContext::Store, name.name.range)?;
1277+
self.register_name(imported_name, SymbolUsage::Imported, name.name.range)?;
12731278
}
12741279
}
12751280
}
@@ -1306,7 +1311,11 @@ impl SymbolTableBuilder {
13061311
// https://github.com/python/cpython/blob/main/Python/symtable.c#L1233
13071312
match &**target {
13081313
Expr::Name(ast::ExprName { id, .. }) if *simple => {
1309-
self.register_name(id.as_str(), SymbolUsage::AnnotationAssigned, *range)?;
1314+
let id_str = id.as_str();
1315+
1316+
self.check_name(id_str, ExpressionContext::Store, *range)?;
1317+
1318+
self.register_name(id_str, SymbolUsage::AnnotationAssigned, *range)?;
13101319
// PEP 649: Register annotate function in module/class scope
13111320
let current_scope = self.tables.last().map(|t| t.typ);
13121321
match current_scope {
@@ -1523,8 +1532,9 @@ impl SymbolTableBuilder {
15231532
self.scan_expression(slice, ExpressionContext::Load)?;
15241533
}
15251534
Expr::Attribute(ExprAttribute {
1526-
value, range: _, ..
1535+
value, attr, range, ..
15271536
}) => {
1537+
self.check_name(attr.as_str(), context, *range)?;
15281538
self.scan_expression(value, ExpressionContext::Load)?;
15291539
}
15301540
Expr::Dict(ExprDict {
@@ -1668,11 +1678,17 @@ impl SymbolTableBuilder {
16681678

16691679
self.scan_expressions(&arguments.args, ExpressionContext::Load)?;
16701680
for keyword in &arguments.keywords {
1681+
if let Some(arg) = &keyword.arg {
1682+
self.check_name(arg.as_str(), ExpressionContext::Store, keyword.range)?;
1683+
}
16711684
self.scan_expression(&keyword.value, ExpressionContext::Load)?;
16721685
}
16731686
}
16741687
Expr::Name(ExprName { id, range, .. }) => {
16751688
let id = id.as_str();
1689+
1690+
self.check_name(id, context, *range)?;
1691+
16761692
// Determine the contextual usage of this symbol:
16771693
match context {
16781694
ExpressionContext::Delete => {
@@ -1796,6 +1812,7 @@ impl SymbolTableBuilder {
17961812
// propagate inner names.
17971813
if let Expr::Name(ExprName { id, .. }) = &**target {
17981814
let id = id.as_str();
1815+
self.check_name(id, ExpressionContext::Store, *range)?;
17991816
let table = self.tables.last().unwrap();
18001817
if table.typ == CompilerScope::Comprehension {
18011818
self.register_name(
@@ -2161,6 +2178,37 @@ impl SymbolTableBuilder {
21612178
self.register_name(ident.as_str(), role, ident.range)
21622179
}
21632180

2181+
fn check_name(
2182+
&self,
2183+
name: &str,
2184+
context: ExpressionContext,
2185+
range: TextRange,
2186+
) -> SymbolTableResult {
2187+
if name == "__debug__" {
2188+
let location = Some(
2189+
self.source_file
2190+
.to_source_code()
2191+
.source_location(range.start(), PositionEncoding::Utf8),
2192+
);
2193+
match context {
2194+
ExpressionContext::Store | ExpressionContext::Iter => {
2195+
return Err(SymbolTableError {
2196+
error: "cannot assign to __debug__".to_owned(),
2197+
location,
2198+
});
2199+
}
2200+
ExpressionContext::Delete => {
2201+
return Err(SymbolTableError {
2202+
error: "cannot delete __debug__".to_owned(),
2203+
location,
2204+
});
2205+
}
2206+
_ => {}
2207+
}
2208+
}
2209+
Ok(())
2210+
}
2211+
21642212
fn register_name(
21652213
&mut self,
21662214
name: &str,
@@ -2173,18 +2221,7 @@ impl SymbolTableBuilder {
21732221
.source_location(range.start(), PositionEncoding::Utf8);
21742222
let location = Some(location);
21752223

2176-
// Check for forbidden names like __debug__
2177-
if name == "__debug__"
2178-
&& matches!(
2179-
role,
2180-
SymbolUsage::Parameter | SymbolUsage::AnnotationParameter | SymbolUsage::Assigned
2181-
)
2182-
{
2183-
return Err(SymbolTableError {
2184-
error: "cannot assign to __debug__".to_owned(),
2185-
location,
2186-
});
2187-
}
2224+
// Note: __debug__ checks are handled by check_name function, so no check needed here.
21882225

21892226
let scope_depth = self.tables.len();
21902227
let table = self.tables.last_mut().unwrap();

extra_tests/snippets/syntax_forbidden_name.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ def raisesSyntaxError(parse_stmt, exec_stmt=None):
2121
raisesSyntaxError("", "del __debug__")
2222
raisesSyntaxError("", "(a, __debug__, c) = (1, 2, 3)")
2323
raisesSyntaxError("", "(a, *__debug__, c) = (1, 2, 3)")
24+
raisesSyntaxError("", "__debug__ : int")
25+
raisesSyntaxError("", "__debug__ : int = 1")
2426

25-
# TODO:
26-
# raisesSyntaxError("", "__debug__ : int")
27+
# Import statements
28+
raisesSyntaxError("import sys as __debug__")
29+
raisesSyntaxError("from sys import path as __debug__")
30+
31+
# Comprehension iteration targets
32+
raisesSyntaxError("[x for __debug__ in range(5)]")

0 commit comments

Comments
 (0)