Py 3.14 changes fix (#6755)

* marshal v5

* conditional blclk

* fix jit don't use lossy string

* add varname

* symboltable takes responsibility of __debug__
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-01-18 01:02:40 +09:00
1 parent 892116c009
commit 6df3753229
9 files changed
+197 -89

No files matched your search

Generated
+1
View File
@@ -3104,6 +3104,7 @@ dependencies = [
"num-traits",
"rustpython-compiler-core",
"rustpython-derive",
"rustpython-wtf8",
"thiserror 2.0.17",
]
-3
View File
@@ -459,9 +459,6 @@ class AnnotationsFutureTestCase(unittest.TestCase):
self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})")
self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))")
# TODO: RUSTPYTHON
# AssertionError: SyntaxError not raised
@unittest.expectedFailure
def test_annotation_with_complex_target(self):
with self.assertRaises(SyntaxError):
exec(
+47 -49
View File
@@ -110,14 +110,6 @@ enum NameUsage {
Store,
Delete,
}
fn is_forbidden_name(name: &str) -> bool {
// See https://docs.python.org/3/library/constants.html#built-in-constants
const BUILTIN_CONSTANTS: &[&str] = &["__debug__"];
BUILTIN_CONSTANTS.contains(&name)
}
/// Main structure holding the state of compilation.
struct Compiler {
code_stack: Vec<ir::CodeInfo>,
@@ -130,10 +122,6 @@ struct Compiler {
ctx: CompileContext,
opts: CompileOpts,
in_annotation: bool,
// PEP 649: Track if we're inside a conditional block (if/for/while/etc.)
in_conditional_block: bool,
// PEP 649: Next index for conditional annotation tracking
next_conditional_annotation_index: u32,
}
enum DoneWithFuture {
@@ -424,6 +412,8 @@ impl Compiler {
in_inlined_comp: false,
fblock: Vec::with_capacity(MAXBLOCKS),
symbol_table_index: 0, // Module is always the first symbol table
in_conditional_block: 0,
next_conditional_annotation_index: 0,
};
Self {
code_stack: vec![module_code],
@@ -441,8 +431,6 @@ impl Compiler {
},
opts,
in_annotation: false,
in_conditional_block: false,
next_conditional_annotation_index: 0,
}
}
@@ -1045,6 +1033,8 @@ impl Compiler {
in_inlined_comp: false,
fblock: Vec::with_capacity(MAXBLOCKS),
symbol_table_index: key,
in_conditional_block: 0,
next_conditional_annotation_index: 0,
};
// Push the old compiler unit on the stack (like PyCapsule)
@@ -1525,11 +1515,7 @@ impl Compiler {
self._name_inner(name, |i| &mut i.metadata.names)
}
fn varname(&mut self, name: &str) -> CompileResult<bytecode::NameIdx> {
if Self::is_forbidden_arg_name(name) {
return Err(self.error(CodegenErrorType::SyntaxError(format!(
"cannot assign to {name}",
))));
}
// Note: __debug__ checks are now handled in symboltable phase
Ok(self._name_inner(name, |i| &mut i.metadata.varnames))
}
fn _name_inner(
@@ -1814,15 +1800,6 @@ impl Compiler {
symboltable::mangle_name(private, name)
}
fn check_forbidden_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
let msg = match usage {
NameUsage::Store if is_forbidden_name(name) => "cannot assign to",
NameUsage::Delete if is_forbidden_name(name) => "cannot delete",
_ => return Ok(()),
};
Err(self.error(CodegenErrorType::SyntaxError(format!("{msg} {name}"))))
}
// = compiler_nameop
fn compile_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
enum NameOp {
@@ -1834,7 +1811,6 @@ impl Compiler {
}
let name = self.mangle(name);
self.check_forbidden_name(&name, usage)?;
// Special handling for __debug__
if NameUsage::Load == usage && name == "__debug__" {
@@ -2135,6 +2111,7 @@ impl Compiler {
elif_else_clauses,
..
}) => {
self.enter_conditional_block();
match elif_else_clauses.as_slice() {
// Only if
[] => {
@@ -2182,6 +2159,7 @@ impl Compiler {
self.switch_to_block(after_block);
}
}
self.leave_conditional_block();
}
Stmt::While(StmtWhile {
test, body, orelse, ..
@@ -2228,11 +2206,13 @@ impl Compiler {
is_star,
..
}) => {
self.enter_conditional_block();
if *is_star {
self.compile_try_star_except(body, handlers, orelse, finalbody)?
} else {
self.compile_try_statement(body, handlers, orelse, finalbody)?
}
self.leave_conditional_block();
}
Stmt::FunctionDef(StmtFunctionDef {
name,
@@ -2432,7 +2412,6 @@ impl Compiler {
match &expression {
Expr::Name(ExprName { id, .. }) => self.compile_name(id.as_str(), NameUsage::Delete)?,
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
self.check_forbidden_name(attr.as_str(), NameUsage::Delete)?;
self.compile_expression(value)?;
let idx = self.name(attr.as_str());
emit!(self, Instruction::DeleteAttr { idx });
@@ -3451,10 +3430,6 @@ impl Compiler {
Ok(())
}
fn is_forbidden_arg_name(name: &str) -> bool {
is_forbidden_name(name)
}
/// Compile default arguments
// = compiler_default_arguments
fn compile_default_arguments(
@@ -4485,6 +4460,8 @@ impl Compiler {
}
fn compile_while(&mut self, test: &Expr, body: &[Stmt], orelse: &[Stmt]) -> CompileResult<()> {
self.enter_conditional_block();
let while_block = self.new_block();
let else_block = self.new_block();
let after_block = self.new_block();
@@ -4513,6 +4490,8 @@ impl Compiler {
// Note: PopBlock is no longer emitted for loops
self.compile_statements(orelse)?;
self.switch_to_block(after_block);
self.leave_conditional_block();
Ok(())
}
@@ -4522,6 +4501,8 @@ impl Compiler {
body: &[Stmt],
is_async: bool,
) -> CompileResult<()> {
self.enter_conditional_block();
// Python 3.12+ style with statement:
//
// BEFORE_WITH # TOS: ctx_mgr -> [__exit__, __enter__ result]
@@ -4734,6 +4715,7 @@ impl Compiler {
// ===== After block =====
self.switch_to_block(after_block);
self.leave_conditional_block();
Ok(())
}
@@ -4745,6 +4727,8 @@ impl Compiler {
orelse: &[Stmt],
is_async: bool,
) -> CompileResult<()> {
self.enter_conditional_block();
// Start loop
let for_block = self.new_block();
let else_block = self.new_block();
@@ -4812,6 +4796,7 @@ impl Compiler {
self.switch_to_block(after_block);
self.leave_conditional_block();
Ok(())
}
@@ -5784,8 +5769,10 @@ impl Compiler {
}
fn compile_match(&mut self, subject: &Expr, cases: &[MatchCase]) -> CompileResult<()> {
self.enter_conditional_block();
let mut pattern_context = PatternContext::new();
self.compile_match_inner(subject, cases, &mut pattern_context)?;
self.leave_conditional_block();
Ok(())
}
@@ -5946,16 +5933,22 @@ impl Compiler {
} else {
// PEP 649: Handle conditional annotations
if self.current_symbol_table().has_conditional_annotations {
// Allocate an index for every annotation when has_conditional_annotations
// This keeps indices aligned with compile_module_annotate's enumeration
let code_info = self.current_code_info();
let annotation_index = code_info.next_conditional_annotation_index;
code_info.next_conditional_annotation_index += 1;
// Determine if this annotation is conditional
let is_module = self.current_symbol_table().typ == CompilerScope::Module;
let is_conditional = is_module || self.in_conditional_block;
// Module and Class scopes both need all annotations tracked
let scope_type = self.current_symbol_table().typ;
let in_conditional_block = self.current_code_info().in_conditional_block > 0;
let is_conditional =
matches!(scope_type, CompilerScope::Module | CompilerScope::Class)
|| in_conditional_block;
// Only add to __conditional_annotations__ set if actually conditional
if is_conditional {
// Get the current annotation index and increment
let annotation_index = self.next_conditional_annotation_index;
self.next_conditional_annotation_index += 1;
// Add index to __conditional_annotations__ set
let cond_annotations_name = self.name("__conditional_annotations__");
emit!(self, Instruction::LoadName(cond_annotations_name));
self.emit_load_const(ConstantData::Integer {
@@ -5980,7 +5973,6 @@ impl Compiler {
self.compile_subscript(value, slice, *ctx)?;
}
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
self.check_forbidden_name(attr.as_str(), NameUsage::Store)?;
self.compile_expression(value)?;
let idx = self.name(attr.as_str());
emit!(self, Instruction::StoreAttr { idx });
@@ -6075,7 +6067,6 @@ impl Compiler {
}
Expr::Attribute(ExprAttribute { value, attr, .. }) => {
let attr = attr.as_str();
self.check_forbidden_name(attr, NameUsage::Store)?;
self.compile_expression(value)?;
emit!(self, Instruction::Copy { index: 1_u32 });
let idx = self.name(attr);
@@ -6903,12 +6894,6 @@ impl Compiler {
let (size, unpack) = self.gather_elements(additional_positional, &arguments.args)?;
let has_double_star = arguments.keywords.iter().any(|k| k.arg.is_none());
for keyword in &arguments.keywords {
if let Some(name) = &keyword.arg {
self.check_forbidden_name(name.as_str(), NameUsage::Store)?;
}
}
if unpack || has_double_star {
// Create a tuple with positional args:
if unpack {
@@ -7511,6 +7496,19 @@ impl Compiler {
self.code_stack.last_mut().expect("no code on stack")
}
/// Enter a conditional block (if/for/while/match/try/with)
/// PEP 649: Track conditional annotation context
fn enter_conditional_block(&mut self) {
self.current_code_info().in_conditional_block += 1;
}
/// Leave a conditional block
fn leave_conditional_block(&mut self) {
let code_info = self.current_code_info();
debug_assert!(code_info.in_conditional_block > 0);
code_info.in_conditional_block -= 1;
}
/// Compile break or continue statement with proper fblock cleanup.
/// compiler_break, compiler_continue
/// This handles unwinding through With blocks and exception handlers.
+10
View File
@@ -145,6 +145,14 @@ pub struct CodeInfo {
// Reference to the symbol table for this scope
pub symbol_table_index: usize,
// PEP 649: Track nesting depth inside conditional blocks (if/for/while/etc.)
// u_in_conditional_block
pub in_conditional_block: u32,
// PEP 649: Next index for conditional annotation tracking
// u_next_conditional_annotation_index
pub next_conditional_annotation_index: u32,
}
impl CodeInfo {
@@ -171,6 +179,8 @@ impl CodeInfo {
in_inlined_comp: _,
fblock: _,
symbol_table_index: _,
in_conditional_block: _,
next_conditional_annotation_index: _,
} = self;
let CodeUnitMetadata {
+71 -23
View File
@@ -780,6 +780,8 @@ struct SymbolTableBuilder {
source_file: SourceFile,
// Current scope's varnames being collected (temporary storage)
current_varnames: Vec<String>,
// Stack to preserve parent varnames when entering nested scopes
varnames_stack: Vec<Vec<String>>,
// Track if we're inside an iterable definition expression (for nested comprehensions)
in_iter_def_exp: bool,
// Track if we're inside an annotation (yield/await/named expr not allowed)
@@ -815,6 +817,7 @@ impl SymbolTableBuilder {
future_annotations: false,
source_file,
current_varnames: Vec::new(),
varnames_stack: Vec::new(),
in_iter_def_exp: false,
in_annotation: false,
in_type_alias: false,
@@ -845,8 +848,9 @@ impl SymbolTableBuilder {
.unwrap_or(false);
let table = SymbolTable::new(name.to_owned(), typ, line_number, is_nested);
self.tables.push(table);
// Clear current_varnames for the new scope
self.current_varnames.clear();
// Save parent's varnames and start fresh for the new scope
self.varnames_stack
.push(core::mem::take(&mut self.current_varnames));
}
fn enter_type_param_block(&mut self, name: &str, line_number: u32) -> SymbolTableResult {
@@ -880,6 +884,8 @@ impl SymbolTableBuilder {
// Save the collected varnames to the symbol table
table.varnames = core::mem::take(&mut self.current_varnames);
self.tables.last_mut().unwrap().sub_tables.push(table);
// Restore parent's varnames
self.current_varnames = self.varnames_stack.pop().unwrap_or_default();
}
/// Enter annotation scope (PEP 649)
@@ -907,7 +913,10 @@ impl SymbolTableBuilder {
// Take the annotation block and push to stack for processing
let annotation_table = current.annotation_block.take().unwrap();
self.tables.push(*annotation_table);
self.current_varnames.clear();
// Save parent's varnames and seed with existing annotation varnames (e.g., "format")
self.varnames_stack
.push(core::mem::take(&mut self.current_varnames));
self.current_varnames = self.tables.last().unwrap().varnames.clone();
if can_see_class_scope && !self.future_annotations {
self.add_classdict_freevar();
@@ -927,6 +936,8 @@ impl SymbolTableBuilder {
// Store back to parent's annotation_block (not sub_tables)
let parent = self.tables.last_mut().unwrap();
parent.annotation_block = Some(Box::new(table));
// Restore parent's varnames
self.current_varnames = self.varnames_stack.pop().unwrap_or_default();
}
fn add_classdict_freevar(&mut self) {
@@ -977,6 +988,12 @@ impl SymbolTableBuilder {
}
fn scan_parameter(&mut self, parameter: &Parameter) -> SymbolTableResult {
self.check_name(
parameter.name.as_str(),
ExpressionContext::Store,
parameter.name.range,
)?;
let usage = if parameter.annotation.is_some() {
SymbolUsage::AnnotationParameter
} else {
@@ -1239,6 +1256,7 @@ impl SymbolTableBuilder {
for name in names {
if let Some(alias) = &name.asname {
// `import my_module as my_alias`
self.check_name(alias.as_str(), ExpressionContext::Store, alias.range)?;
self.register_ident(alias, SymbolUsage::Imported)?;
} else if name.name.as_str() == "*" {
// Star imports are only allowed at module level
@@ -1253,12 +1271,10 @@ impl SymbolTableBuilder {
}
// Don't register star imports as symbols
} else {
// `import module`
self.register_name(
name.name.split('.').next().unwrap(),
SymbolUsage::Imported,
name.name.range,
)?;
// `import module` or `from x import name`
let imported_name = name.name.split('.').next().unwrap();
self.check_name(imported_name, ExpressionContext::Store, name.name.range)?;
self.register_name(imported_name, SymbolUsage::Imported, name.name.range)?;
}
}
}
@@ -1295,7 +1311,11 @@ impl SymbolTableBuilder {
// https://github.com/python/cpython/blob/main/Python/symtable.c#L1233
match &**target {
Expr::Name(ast::ExprName { id, .. }) if *simple => {
self.register_name(id.as_str(), SymbolUsage::AnnotationAssigned, *range)?;
let id_str = id.as_str();
self.check_name(id_str, ExpressionContext::Store, *range)?;
self.register_name(id_str, SymbolUsage::AnnotationAssigned, *range)?;
// PEP 649: Register annotate function in module/class scope
let current_scope = self.tables.last().map(|t| t.typ);
match current_scope {
@@ -1512,8 +1532,9 @@ impl SymbolTableBuilder {
self.scan_expression(slice, ExpressionContext::Load)?;
}
Expr::Attribute(ExprAttribute {
value, range: _, ..
value, attr, range, ..
}) => {
self.check_name(attr.as_str(), context, *range)?;
self.scan_expression(value, ExpressionContext::Load)?;
}
Expr::Dict(ExprDict {
@@ -1657,11 +1678,17 @@ impl SymbolTableBuilder {
self.scan_expressions(&arguments.args, ExpressionContext::Load)?;
for keyword in &arguments.keywords {
if let Some(arg) = &keyword.arg {
self.check_name(arg.as_str(), ExpressionContext::Store, keyword.range)?;
}
self.scan_expression(&keyword.value, ExpressionContext::Load)?;
}
}
Expr::Name(ExprName { id, range, .. }) => {
let id = id.as_str();
self.check_name(id, context, *range)?;
// Determine the contextual usage of this symbol:
match context {
ExpressionContext::Delete => {
@@ -1785,6 +1812,7 @@ impl SymbolTableBuilder {
// propagate inner names.
if let Expr::Name(ExprName { id, .. }) = &**target {
let id = id.as_str();
self.check_name(id, ExpressionContext::Store, *range)?;
let table = self.tables.last().unwrap();
if table.typ == CompilerScope::Comprehension {
self.register_name(
@@ -2150,6 +2178,37 @@ impl SymbolTableBuilder {
self.register_name(ident.as_str(), role, ident.range)
}
fn check_name(
&self,
name: &str,
context: ExpressionContext,
range: TextRange,
) -> SymbolTableResult {
if name == "__debug__" {
let location = Some(
self.source_file
.to_source_code()
.source_location(range.start(), PositionEncoding::Utf8),
);
match context {
ExpressionContext::Store | ExpressionContext::Iter => {
return Err(SymbolTableError {
error: "cannot assign to __debug__".to_owned(),
location,
});
}
ExpressionContext::Delete => {
return Err(SymbolTableError {
error: "cannot delete __debug__".to_owned(),
location,
});
}
_ => {}
}
}
Ok(())
}
fn register_name(
&mut self,
name: &str,
@@ -2162,18 +2221,7 @@ impl SymbolTableBuilder {
.source_location(range.start(), PositionEncoding::Utf8);
let location = Some(location);
// Check for forbidden names like __debug__
if name == "__debug__"
&& matches!(
role,
SymbolUsage::Parameter | SymbolUsage::AnnotationParameter | SymbolUsage::Assigned
)
{
return Err(SymbolTableError {
error: "cannot assign to __debug__".to_owned(),
location,
});
}
// Note: __debug__ checks are handled by check_name function, so no check needed here.
let scope_depth = self.tables.len();
let table = self.tables.last_mut().unwrap();
+9 -1
View File
@@ -4,7 +4,7 @@ use malachite_bigint::{BigInt, Sign};
use num_complex::Complex64;
use rustpython_wtf8::Wtf8;
pub const FORMAT_VERSION: u32 = 4;
pub const FORMAT_VERSION: u32 = 5;
#[derive(Debug)]
pub enum MarshalError {
@@ -65,6 +65,7 @@ enum Type {
// Unknown = b'?',
Set = b'<',
FrozenSet = b'>',
Slice = b':', // Added in version 5
Ascii = b'a',
// AsciiInterned = b'A',
// SmallTuple = b')',
@@ -101,6 +102,7 @@ impl TryFrom<u8> for Type {
// b'?' => Unknown,
b'<' => Set,
b'>' => FrozenSet,
b':' => Slice,
b'a' => Ascii,
// b'A' => AsciiInterned,
// b')' => SmallTuple,
@@ -466,6 +468,12 @@ pub fn deserialize_value<R: Read, Bag: MarshalBag>(rdr: &mut R, bag: Bag) -> Res
bag.make_bytes(value)
}
Type::Code => bag.make_code(deserialize_code(rdr, bag.constant_bag())?),
Type::Slice => {
// Slice constants are not yet supported in RustPython
// This would require adding a Slice variant to ConstantData enum
// For now, return an error if we encounter a slice in marshal data
return Err(MarshalError::BadType);
}
};
Ok(value)
}
+1
View File
@@ -23,6 +23,7 @@ cranelift-module = "0.127"
[dev-dependencies]
rustpython-derive = { workspace = true }
rustpython-wtf8 = { workspace = true }
approx = "0.5.1"
+50 -11
View File
@@ -3,19 +3,20 @@ use rustpython_compiler_core::bytecode::{
CodeObject, ConstantData, Instruction, OpArg, OpArgState,
};
use rustpython_jit::{CompiledCode, JitType};
use rustpython_wtf8::{Wtf8, Wtf8Buf};
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Function {
code: Box<CodeObject>,
annotations: HashMap<String, StackValue>,
annotations: HashMap<Wtf8Buf, StackValue>,
}
impl Function {
pub fn compile(self) -> CompiledCode {
let mut arg_types = Vec::new();
for arg in self.code.arg_names().args {
let arg_type = match self.annotations.get(arg) {
let arg_type = match self.annotations.get(AsRef::<Wtf8>::as_ref(arg.as_str())) {
Some(StackValue::String(annotation)) => match annotation.as_str() {
"int" => JitType::Int,
"float" => JitType::Float,
@@ -27,7 +28,7 @@ impl Function {
arg_types.push(arg_type);
}
let ret_type = match self.annotations.get("return") {
let ret_type = match self.annotations.get(AsRef::<Wtf8>::as_ref("return")) {
Some(StackValue::String(annotation)) => match annotation.as_str() {
"int" => Some(JitType::Int),
"float" => Some(JitType::Float),
@@ -45,7 +46,7 @@ impl Function {
enum StackValue {
String(String),
None,
Map(HashMap<String, StackValue>),
Map(HashMap<Wtf8Buf, StackValue>),
Code(Box<CodeObject>),
Function(Function),
}
@@ -66,7 +67,7 @@ impl From<ConstantData> for StackValue {
/// Extract annotations from an annotate function's bytecode.
/// The annotate function uses BUILD_MAP with key-value pairs loaded before it.
/// Keys are parameter names (from LOAD_CONST), values are type names (from LOAD_NAME/LOAD_GLOBAL).
fn extract_annotations_from_annotate_code(code: &CodeObject) -> HashMap<String, StackValue> {
fn extract_annotations_from_annotate_code(code: &CodeObject) -> HashMap<Wtf8Buf, StackValue> {
let mut annotations = HashMap::new();
let mut stack: Vec<(bool, usize)> = Vec::new(); // (is_const, index)
let mut op_arg_state = OpArgState::default();
@@ -91,17 +92,55 @@ fn extract_annotations_from_annotate_code(code: &CodeObject) -> HashMap<String,
for chunk in pairs.chunks(2) {
if chunk.len() == 2 {
let (key_is_const, key_idx) = chunk[0];
let (_val_is_const, val_idx) = chunk[1];
let (val_is_const, val_idx) = chunk[1];
// Key should be a const string (parameter name)
if key_is_const
&& let ConstantData::Str { value } = &code.constants[key_idx]
{
let param_name = value.to_string_lossy().into_owned();
// Value should be a name (type name)
if let Some(type_name) = code.names.get(val_idx) {
let param_name = value;
// Value can be a name (type ref) or a const string (forward ref)
let type_name = if val_is_const {
match code.constants.get(val_idx) {
Some(ConstantData::Str { value }) => {
Some(value.as_str().map(|s| s.to_owned()).unwrap_or_else(
|_| value.to_string_lossy().into_owned(),
))
}
Some(other) => {
eprintln!(
"Warning: Malformed annotation for '{:?}': expected string constant at index {}, got {:?}",
param_name, val_idx, other
);
None
}
None => {
eprintln!(
"Warning: Malformed annotation for '{:?}': constant index {} out of bounds (len={})",
param_name,
val_idx,
code.constants.len()
);
None
}
}
} else {
match code.names.get(val_idx) {
Some(name) => Some(name.clone()),
None => {
eprintln!(
"Warning: Malformed annotation for '{}': name index {} out of bounds (len={})",
param_name,
val_idx,
code.names.len()
);
None
}
}
};
if let Some(type_name) = type_name {
annotations
.insert(param_name, StackValue::String(type_name.clone()));
.insert(param_name.clone(), StackValue::String(type_name));
}
}
}
@@ -183,7 +222,7 @@ impl StackMachine {
for _ in 0..size.get(arg) {
let value = self.stack.pop().unwrap();
let name = if let Some(StackValue::String(name)) = self.stack.pop() {
name
Wtf8Buf::from(name)
} else {
unimplemented!("no string keys isn't yet supported in py_function!")
};
@@ -21,6 +21,12 @@ raisesSyntaxError("", "__debug__ := 1")
raisesSyntaxError("", "del __debug__")
raisesSyntaxError("", "(a, __debug__, c) = (1, 2, 3)")
raisesSyntaxError("", "(a, *__debug__, c) = (1, 2, 3)")
raisesSyntaxError("", "__debug__ : int")
raisesSyntaxError("", "__debug__ : int = 1")
# TODO:
# raisesSyntaxError("", "__debug__ : int")
# Import statements
raisesSyntaxError("import sys as __debug__")
raisesSyntaxError("from sys import path as __debug__")
# Comprehension iteration targets
raisesSyntaxError("[x for __debug__ in range(5)]")