mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
ast: fix identifier interning (#8361)
* Fix AST identifier interning Ensure parsed name and function identifier fields use interned strings, matching CPython behavior. Assisted-by: Codex:gpt-5.6-sol * Apply PEP 8 import ordering
This commit is contained in:
4 files changed
+23
-5
No files matched your search
Vendored
-3
@@ -1331,7 +1331,6 @@ class CopyTests(unittest.TestCase):
|
||||
self.assertEqual(repl.x, 0)
|
||||
self.assertEqual(repl.y, y)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'x' is not 'x'
|
||||
def test_replace_ignore_known_custom_instance_fields(self):
|
||||
node = ast.parse('x').body[0].value
|
||||
node.extra = extra = object() # add instance 'extra' field
|
||||
@@ -1401,7 +1400,6 @@ class CopyTests(unittest.TestCase):
|
||||
self.assertIs(node2.returns, None)
|
||||
self.assertEqual(node2.decorator_list, [])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: "Name\.__replace__\ got\ an\ unexpected\ keyword\ argument\ 'extra'\." does not match "replace() does not support Name objects"
|
||||
def test_replace_reject_known_custom_instance_fields_commits(self):
|
||||
node = ast.parse('x').body[0].value
|
||||
node.extra = extra = object() # add instance 'extra' field
|
||||
@@ -1417,7 +1415,6 @@ class CopyTests(unittest.TestCase):
|
||||
self.assertIs(node.ctx, context)
|
||||
self.assertIs(node.extra, extra)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: "Name\.__replace__\ got\ an\ unexpected\ keyword\ argument\ 'unknown'\." does not match "replace() does not support Name objects"
|
||||
def test_replace_reject_unknown_instance_fields(self):
|
||||
node = ast.parse('x').body[0].value
|
||||
context = node.ctx
|
||||
|
||||
@@ -1376,7 +1376,8 @@ impl Node for ast::ExprName {
|
||||
.into_ref_with_type(vm, pyast::NodeExprName::static_type().to_owned())
|
||||
.unwrap();
|
||||
let dict = node.as_object().dict().unwrap();
|
||||
dict.set_item("id", id.to_pyobject(vm), vm).unwrap();
|
||||
dict.set_item("id", id.ast_to_object(vm, source_file), vm)
|
||||
.unwrap();
|
||||
dict.set_item("ctx", ctx.ast_to_object(vm, source_file), vm)
|
||||
.unwrap();
|
||||
node_add_location(&dict, range, vm, source_file);
|
||||
|
||||
@@ -409,7 +409,7 @@ impl Node for ast::StmtFunctionDef {
|
||||
|
||||
let node = NodeAst.into_ref_with_type(vm, cls).unwrap();
|
||||
let dict = node.as_object().dict().unwrap();
|
||||
dict.set_item("name", vm.ctx.new_str(name.as_str()).to_pyobject(vm), vm)
|
||||
dict.set_item("name", name.ast_to_object(vm, source_file), vm)
|
||||
.unwrap();
|
||||
dict.set_item("args", parameters.ast_to_object(vm, source_file), vm)
|
||||
.unwrap();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ast
|
||||
import copy
|
||||
|
||||
print(ast)
|
||||
|
||||
@@ -39,6 +40,25 @@ assert i.names[0].name == "a"
|
||||
assert i.names[0].asname is None
|
||||
|
||||
|
||||
# Regression: parsed AST identifier fields are interned, matching CPython.
|
||||
name_literal = "x"
|
||||
name = ast.parse("x").body[0].value
|
||||
assert name.id is name_literal
|
||||
|
||||
name.extra = object()
|
||||
replacement = copy.replace(name)
|
||||
assert replacement.id is name.id
|
||||
assert replacement.ctx is name.ctx
|
||||
assert not hasattr(replacement, "extra")
|
||||
|
||||
function_name = "f"
|
||||
function = ast.parse("def f(): pass").body[0]
|
||||
assert function.name is function_name
|
||||
|
||||
async_function = ast.parse("async def f(): pass").body[0]
|
||||
assert async_function.name is function_name
|
||||
|
||||
|
||||
# Regression test for issue #4862:
|
||||
# A cyclic AST fed to compile() used to overflow the Rust stack and SIGSEGV.
|
||||
# After the fix, the recursion guard in ast_from_object raises RecursionError,
|
||||
|
||||
Reference in new issue
Block a user