fix ast fields including type_comments

This commit is contained in:
Jeong, YunWon committed 2026-02-03 14:16:10 +09:00
1 parent 1876ac88e0
commit 63bbb3c804
6 files changed
+95 -31

No files matched your search

+3 -2
View File
@@ -126,8 +126,9 @@ impl Node for ast::Parameter {
_vm,
)
.unwrap();
// dict.set_item("type_comment", type_comment.ast_to_object(_vm), _vm)
// .unwrap();
// Ruff AST doesn't track type_comment, so always set to None
dict.set_item("type_comment", _vm.ctx.none(), _vm)
.unwrap();
node_add_location(&dict, range, _vm, source_file);
node.into()
}
+9 -3
View File
@@ -37,6 +37,12 @@ macro_rules! impl_node {
),*
]).into(),
);
// Signal that this is a built-in AST node with field defaults
class.set_attr(
ctx.intern_str("_field_types"),
ctx.new_dict().into(),
);
}
}
};
@@ -902,21 +908,21 @@ impl_node!(
impl_node!(
#[pyclass(module = "_ast", name = "TypeVar", base = NodeTypeParam)]
pub(crate) struct NodeTypeParamTypeVar,
fields: ["name", "bound"],
fields: ["name", "bound", "default_value"],
attributes: ["lineno", "col_offset", "end_lineno", "end_col_offset"],
);
impl_node!(
#[pyclass(module = "_ast", name = "ParamSpec", base = NodeTypeParam)]
pub(crate) struct NodeTypeParamParamSpec,
fields: ["name"],
fields: ["name", "default_value"],
attributes: ["lineno", "col_offset", "end_lineno", "end_col_offset"],
);
impl_node!(
#[pyclass(module = "_ast", name = "TypeVarTuple", base = NodeTypeParam)]
pub(crate) struct NodeTypeParamTypeVarTuple,
fields: ["name"],
fields: ["name", "default_value"],
attributes: ["lineno", "col_offset", "end_lineno", "end_col_offset"],
);
+49 -17
View File
@@ -87,24 +87,56 @@ pub(crate) mod _ast {
zelf.set_attr(vm.ctx.intern_str(key), value, vm)?;
}
// Set default values for fields that weren't provided
let class_name = &*zelf.class().name();
if class_name == "Module" && !set_fields.contains("type_ignores") {
zelf.set_attr("type_ignores", vm.ctx.new_list(vec![]), vm)?;
}
if class_name == "ImportFrom" && !set_fields.contains("level") {
zelf.set_attr("level", vm.ctx.new_int(0), vm)?;
}
if class_name == "alias" && !set_fields.contains("asname") {
zelf.set_attr("asname", vm.ctx.none(), vm)?;
}
// Set type_comment to None for nodes that support it
if !set_fields.contains("type_comment") {
match class_name {
"FunctionDef" | "AsyncFunctionDef" | "For" | "AsyncFor" | "With" | "AsyncWith" | "arg" => {
zelf.set_attr("type_comment", vm.ctx.none(), vm)?;
// Set default values only for built-in AST nodes (_field_types present).
// Custom AST subclasses without _field_types do NOT get automatic defaults.
let has_field_types = zelf.class().get_attr(vm.ctx.intern_str("_field_types")).is_some();
if has_field_types {
// ASDL list fields (type*) default to empty list,
// optional fields (type?) default to None.
const LIST_FIELDS: &[&str] = &[
"args",
"argtypes",
"bases",
"body",
"cases",
"comparators",
"decorator_list",
"defaults",
"elts",
"finalbody",
"generators",
"handlers",
"ifs",
"items",
"keys",
"kw_defaults",
"keywords",
"kwonlyargs",
"names",
"orelse",
"ops",
"posonlyargs",
"targets",
"type_ignores",
"type_params",
"values",
];
for field in &fields {
if !set_fields.contains(field.as_str()) {
let default: PyObjectRef = if LIST_FIELDS.contains(&field.as_str()) {
vm.ctx.new_list(vec![]).into()
} else {
vm.ctx.none()
};
zelf.set_attr(vm.ctx.intern_str(field.as_str()), default, vm)?;
}
_ => {}
}
// Special defaults that are not None or empty list
let class_name = &*zelf.class().name();
if class_name == "ImportFrom" && !set_fields.contains("level") {
zelf.set_attr("level", vm.ctx.new_int(0), vm)?;
}
}
+9 -7
View File
@@ -182,9 +182,9 @@ impl Node for ast::StmtFunctionDef {
.unwrap();
dict.set_item("returns", returns.ast_to_object(vm, source_file), vm)
.unwrap();
// TODO: Ruff ignores type_comment during parsing
// dict.set_item("type_comment", type_comment.ast_to_object(_vm), _vm)
// .unwrap();
// Ruff AST doesn't track type_comment, so always set to None
dict.set_item("type_comment", vm.ctx.none(), vm)
.unwrap();
dict.set_item(
"type_params",
type_params
@@ -647,8 +647,9 @@ impl Node for ast::StmtFor {
.unwrap();
dict.set_item("orelse", orelse.ast_to_object(_vm, source_file), _vm)
.unwrap();
// dict.set_item("type_comment", type_comment.ast_to_object(_vm), _vm)
// .unwrap();
// Ruff AST doesn't track type_comment, so always set to None
dict.set_item("type_comment", _vm.ctx.none(), _vm)
.unwrap();
node_add_location(&dict, _range, _vm, source_file);
node.into()
}
@@ -799,8 +800,9 @@ impl Node for ast::StmtWith {
.unwrap();
dict.set_item("body", body.ast_to_object(_vm, source_file), _vm)
.unwrap();
// dict.set_item("type_comment", type_comment.ast_to_object(_vm), _vm)
// .unwrap();
// Ruff AST doesn't track type_comment, so always set to None
dict.set_item("type_comment", _vm.ctx.none(), _vm)
.unwrap();
node_add_location(&dict, _range, _vm, source_file);
node.into()
}
+7 -1
View File
@@ -78,7 +78,7 @@ impl Node for ast::TypeParamTypeVar {
name,
bound,
range: _range,
default: _,
default,
} = self;
let node = NodeAst
.into_ref_with_type(_vm, pyast::NodeTypeParamTypeVar::static_type().to_owned())
@@ -88,6 +88,12 @@ impl Node for ast::TypeParamTypeVar {
.unwrap();
dict.set_item("bound", bound.ast_to_object(_vm, source_file), _vm)
.unwrap();
dict.set_item(
"default_value",
default.ast_to_object(_vm, source_file),
_vm,
)
.unwrap();
node_add_location(&dict, _range, _vm, source_file);
node.into()
}
+18 -1
View File
@@ -141,10 +141,27 @@ mod builtins {
.source
.fast_isinstance(&ast::NodeAst::make_class(&vm.ctx))
{
// If PyCF_ONLY_AST is set, just return the AST node as-is
use num_traits::Zero;
let flags = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
// compile(ast_node, ..., PyCF_ONLY_AST) returns the AST after validation
if !(flags & ast::PY_COMPILE_FLAG_AST_ONLY).is_zero() {
let expected_type = match mode_str {
"exec" => "Module",
"eval" => "Expression",
"single" => "Interactive",
"func_type" => "FunctionType",
_ => {
return Err(vm.new_value_error(format!(
"compile() mode must be 'exec', 'eval', 'single' or 'func_type', got '{mode_str}'"
)));
}
};
let cls_name = args.source.class().name().to_string();
if cls_name != expected_type {
return Err(vm.new_type_error(format!(
"expected {expected_type} node, got {cls_name}"
)));
}
return Ok(args.source);
}