Skip to content

Commit f13e07c

Browse files
committed
Clean up _ast conversion glue and compiler warning escalation
Rename the Node conversion parameter `ctx` to `vm` throughout the _ast module. Remove the unused compile_program, compile_program_single, compile_block_expression, and compile_expression forwarders; compile_top stays as the entry point. Stash an escalated compiler SyntaxWarning so a non-SyntaxWarning category propagates unchanged instead of being rewritten to SyntaxError, matching PyErr_ExceptionMatches(SyntaxWarning) in compiler_warn. Drop the now-unused CompileWarningError::into_codegen_error. Replace the PositionalArguments two-variant enum with a struct holding a shared range and a PositionalArgumentsKind enum. Assisted-by: Claude
1 parent 0f38041 commit f13e07c

19 files changed

Lines changed: 1177 additions & 1287 deletions

crates/codegen/src/compile.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,7 +2057,7 @@ impl<'warnings> Compiler<'warnings> {
20572057

20582058
// compiler_exit_scope
20592059
fn exit_scope(&mut self) -> CodeObject {
2060-
let _table = self.pop_symbol_table();
2060+
self.pop_symbol_table();
20612061
// Various scopes can have sub_tables:
20622062
// - ast::TypeParams scope can have sub_tables (the function body's symbol table)
20632063
// - Module scope can have sub_tables (for TypeAlias scopes, nested functions, classes)
@@ -9920,7 +9920,7 @@ impl<'warnings> Compiler<'warnings> {
99209920
{
99219921
let _ = self.push_symbol_table()?;
99229922
}
9923-
let _ = self.pop_symbol_table();
9923+
self.pop_symbol_table();
99249924
Ok(())
99259925
}
99269926

@@ -13887,7 +13887,7 @@ mod tests {
1388713887
source_path: "source_path".to_owned(),
1388813888
})
1388913889
};
13890-
let _ = compile_top_with_syntax_warning_handler(
13890+
compile_top_with_syntax_warning_handler(
1389113891
parsed,
1389213892
source_file,
1389313893
Mode::Eval,
@@ -13916,7 +13916,7 @@ mod tests {
1391613916
source_path: "source_path".to_owned(),
1391713917
})
1391813918
};
13919-
let _ = compile_top_with_syntax_warning_handler(
13919+
compile_top_with_syntax_warning_handler(
1392013920
parsed,
1392113921
source_file,
1392213922
Mode::Exec,
@@ -14643,7 +14643,7 @@ def f(x, y, z):
1464314643
let mut compiler =
1464414644
Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
1464514645
compiler.compile_program(&ast, symbol_table).unwrap();
14646-
let _table = compiler.pop_symbol_table();
14646+
compiler.pop_symbol_table();
1464714647
let stack_top = compiler.code_stack.pop().unwrap();
1464814648
stack_top.debug_late_cfg_trace().unwrap()
1464914649
}
@@ -14709,7 +14709,7 @@ def f(x, y, z):
1470914709
in_async_scope: is_async,
1471014710
};
1471114711
compiler.set_qualname();
14712-
let (_doc_str, body) = split_doc(body, &compiler.opts);
14712+
let (_, body) = split_doc(body, &compiler.opts);
1471314713
let start_label = compiler.use_cpython_function_start_label();
1471414714
let is_gen = is_async || compiler.current_symbol_table().is_generator;
1471514715
let stop_iteration_block = if is_gen {
@@ -14749,7 +14749,7 @@ def f(x, y, z):
1474914749
compiler.set_no_location();
1475014750
}
1475114751

14752-
let _table = compiler.pop_symbol_table();
14752+
compiler.pop_symbol_table();
1475314753
let stack_top = compiler.code_stack.pop().unwrap();
1475414754
stack_top.debug_late_cfg_trace().unwrap()
1475514755
}

crates/vm/src/stdlib/_ast.rs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -98,33 +98,33 @@ fn get_node_field_required(
9898
}
9999

100100
fn get_required_identifier_field<T: Node>(
101-
ctx: &VirtualMachine,
101+
vm: &VirtualMachine,
102102
source_file: &SourceFile,
103103
obj: &PyObject,
104104
field: &'static str,
105105
typ: &str,
106106
) -> PyResult<T> {
107-
let value = get_node_field_required(ctx, obj, field, typ)?;
108-
if ctx.is_none(&value) {
109-
return Err(ctx.new_value_error(format!("field '{field}' is required for {typ}")));
107+
let value = get_node_field_required(vm, obj, field, typ)?;
108+
if vm.is_none(&value) {
109+
return Err(vm.new_value_error(format!("field '{field}' is required for {typ}")));
110110
}
111-
Node::ast_from_object(ctx, source_file, value)
111+
Node::ast_from_object(vm, source_file, value)
112112
}
113113

114114
fn get_required_node_field<T: Node>(
115-
ctx: &VirtualMachine,
115+
vm: &VirtualMachine,
116116
source_file: &SourceFile,
117117
obj: &PyObject,
118118
field: &'static str,
119119
typ: &str,
120120
) -> PyResult<T> {
121-
let value = get_node_field_required(ctx, obj, field, typ)?;
122-
if ctx.is_none(&value) {
123-
return Err(ctx.new_value_error(format!("field '{field}' is required for {typ}")));
121+
let value = get_node_field_required(vm, obj, field, typ)?;
122+
if vm.is_none(&value) {
123+
return Err(vm.new_value_error(format!("field '{field}' is required for {typ}")));
124124
}
125125
let recursion_context = format!(" while traversing '{typ}' node");
126-
ctx.with_recursion(&recursion_context, || {
127-
Node::ast_from_object(ctx, source_file, value)
126+
vm.with_recursion(&recursion_context, || {
127+
Node::ast_from_object(vm, source_file, value)
128128
})
129129
}
130130

@@ -139,15 +139,15 @@ fn get_node_field_opt(
139139
}
140140

141141
fn get_node_list_field<T: Node>(
142-
ctx: &VirtualMachine,
142+
vm: &VirtualMachine,
143143
source_file: &SourceFile,
144144
obj: &PyObject,
145145
field: &'static str,
146146
typ: &str,
147147
) -> PyResult<Vec<T>> {
148-
let value = get_node_list_field_object(ctx, obj, field, typ)?;
148+
let value = get_node_list_field_object(vm, obj, field, typ)?;
149149
let list = value.downcast_ref::<PyList>().unwrap();
150-
convert_node_list_field(ctx, source_file, list, field, typ)
150+
convert_node_list_field(vm, source_file, list, field, typ)
151151
}
152152

153153
fn get_node_list_field_object(
@@ -169,7 +169,7 @@ fn get_node_list_field_object(
169169
}
170170

171171
fn convert_node_list_field<T: Node>(
172-
ctx: &VirtualMachine,
172+
vm: &VirtualMachine,
173173
source_file: &SourceFile,
174174
list: &PyList,
175175
field: &'static str,
@@ -182,17 +182,17 @@ fn convert_node_list_field<T: Node>(
182182
let item = {
183183
let items = list.borrow_vec();
184184
if items.len() != len {
185-
return Err(ctx.new_runtime_error(format!(
185+
return Err(vm.new_runtime_error(format!(
186186
r#"{typ} field "{field}" changed size during iteration"#
187187
)));
188188
}
189189
items[i].clone()
190190
};
191-
result.push(ctx.with_recursion(&recursion_context, || {
192-
Node::ast_from_object(ctx, source_file, item)
191+
result.push(vm.with_recursion(&recursion_context, || {
192+
Node::ast_from_object(vm, source_file, item)
193193
})?);
194194
if list.borrow_vec().len() != len {
195-
return Err(ctx.new_runtime_error(format!(
195+
return Err(vm.new_runtime_error(format!(
196196
r#"{typ} field "{field}" changed size during iteration"#
197197
)));
198198
}
@@ -201,13 +201,13 @@ fn convert_node_list_field<T: Node>(
201201
}
202202

203203
fn get_node_boxed_slice_field<T: Node>(
204-
ctx: &VirtualMachine,
204+
vm: &VirtualMachine,
205205
source_file: &SourceFile,
206206
obj: &PyObject,
207207
field: &'static str,
208208
typ: &str,
209209
) -> PyResult<Box<[T]>> {
210-
Ok(get_node_list_field(ctx, source_file, obj, field, typ)?.into_boxed_slice())
210+
Ok(get_node_list_field(vm, source_file, obj, field, typ)?.into_boxed_slice())
211211
}
212212

213213
fn runtime_expr_list_from_values(
@@ -2068,7 +2068,6 @@ pub(crate) fn parse_func_type(
20682068
let func_type = ModFunctionType {
20692069
argtypes: argtypes.into_boxed_slice(),
20702070
returns,
2071-
range: TextRange::default(),
20722071
runtime_argtypes: None,
20732072
};
20742073
let source_file = SourceFileBuilder::new("".to_owned(), source.to_owned()).finish();
@@ -2436,6 +2435,11 @@ pub(crate) fn compile(
24362435
#[cfg(feature = "parser")]
24372436
let code = {
24382437
let source_path = filename.to_owned();
2438+
// A warning the filter escalates to an exception is stashed here so a
2439+
// non-SyntaxWarning category propagates unchanged, matching
2440+
// PyErr_ExceptionMatches(SyntaxWarning) in compiler_warn.
2441+
let escalated: core::cell::Cell<Option<crate::builtins::PyBaseExceptionRef>> =
2442+
core::cell::Cell::new(None);
24392443
let mut syntax_warning_handler = |location: SourceLocation, message: String| {
24402444
let fname = vm.ctx.new_str(source_path.as_str());
24412445
let message = vm.ctx.new_str(message);
@@ -2455,20 +2459,28 @@ pub(crate) fn compile(
24552459
|_| "compiler warning raised as an exception".to_owned(),
24562460
|message| message.as_wtf8().to_string(),
24572461
);
2458-
codegen::error::CodegenError {
2462+
let marker = codegen::error::CodegenError {
24592463
location: Some(location),
24602464
error: codegen::error::CodegenErrorType::SyntaxError(message),
24612465
source_path: source_path.clone(),
2462-
}
2466+
};
2467+
escalated.set(Some(exception));
2468+
marker
24632469
})
24642470
};
2465-
codegen::compile::compile_top_with_syntax_warning_handler(
2471+
let result = codegen::compile::compile_top_with_syntax_warning_handler(
24662472
ast,
24672473
source_file,
24682474
mode,
24692475
opts,
24702476
Some(&mut syntax_warning_handler),
2471-
)
2477+
);
2478+
match escalated.take() {
2479+
Some(exception) if !exception.fast_isinstance(vm.ctx.exceptions.syntax_warning) => {
2480+
return Err(exception);
2481+
}
2482+
_ => result,
2483+
}
24722484
};
24732485
#[cfg(not(feature = "parser"))]
24742486
let code = codegen::compile::compile_top(ast, source_file, mode, opts);

crates/vm/src/stdlib/_ast/argument.rs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,41 @@
11
use super::*;
22
use rustpython_compiler_core::SourceFile;
33

4-
pub(super) enum PositionalArguments {
5-
Args {
6-
range: TextRange,
7-
args: Box<[ast::Expr]>,
8-
},
9-
RuntimeValues {
10-
range: TextRange,
11-
values: Vec<Option<ast::Expr>>,
12-
},
4+
pub(super) struct PositionalArguments {
5+
range: TextRange,
6+
kind: PositionalArgumentsKind,
7+
}
8+
9+
enum PositionalArgumentsKind {
10+
Args(Box<[ast::Expr]>),
11+
RuntimeValues(Vec<Option<ast::Expr>>),
1312
}
1413

1514
impl PositionalArguments {
1615
pub(super) fn ast_from_field(
17-
ctx: &VirtualMachine,
16+
vm: &VirtualMachine,
1817
source_file: &SourceFile,
1918
object: &PyObject,
2019
field: &'static str,
2120
typ: &str,
2221
) -> PyResult<Self> {
2322
let values: Vec<Option<ast::Expr>> =
24-
get_node_list_field(ctx, source_file, object, field, typ)?;
23+
get_node_list_field(vm, source_file, object, field, typ)?;
2524
Ok(Self::from_values(TextRange::default(), values))
2625
}
2726

2827
fn from_args(range: TextRange, args: Box<[ast::Expr]>) -> Self {
29-
Self::Args { range, args }
28+
Self {
29+
range,
30+
kind: PositionalArgumentsKind::Args(args),
31+
}
3032
}
3133

3234
fn from_runtime_values(range: TextRange, values: Vec<Option<ast::Expr>>) -> Self {
33-
Self::RuntimeValues { range, values }
35+
Self {
36+
range,
37+
kind: PositionalArgumentsKind::RuntimeValues(values),
38+
}
3439
}
3540

3641
fn from_values(range: TextRange, values: Vec<Option<ast::Expr>>) -> Self {
@@ -49,15 +54,13 @@ impl PositionalArguments {
4954
}
5055

5156
fn range(&self) -> TextRange {
52-
match self {
53-
Self::Args { range, .. } | Self::RuntimeValues { range, .. } => *range,
54-
}
57+
self.range
5558
}
5659

5760
fn into_args_and_runtime_values(self) -> (Box<[ast::Expr]>, Option<Vec<Option<ast::Expr>>>) {
58-
match self {
59-
Self::Args { args, .. } => (args, None),
60-
Self::RuntimeValues { values, .. } => (
61+
match self.kind {
62+
PositionalArgumentsKind::Args(args) => (args, None),
63+
PositionalArgumentsKind::RuntimeValues(values) => (
6164
lower_runtime_expr_list(values.clone()).into_boxed_slice(),
6265
Some(values),
6366
),
@@ -67,18 +70,18 @@ impl PositionalArguments {
6770

6871
impl Node for PositionalArguments {
6972
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
70-
match self {
71-
Self::Args { args, .. } => BoxedSlice(args).ast_to_object(vm, source_file),
72-
Self::RuntimeValues { values, .. } => values.ast_to_object(vm, source_file),
73+
match self.kind {
74+
PositionalArgumentsKind::Args(args) => BoxedSlice(args).ast_to_object(vm, source_file),
75+
PositionalArgumentsKind::RuntimeValues(values) => values.ast_to_object(vm, source_file),
7376
}
7477
}
7578

7679
fn ast_from_object(
77-
ctx: &VirtualMachine,
80+
vm: &VirtualMachine,
7881
source_file: &SourceFile,
7982
object: PyObjectRef,
8083
) -> PyResult<Self> {
81-
let args: BoxedSlice<_> = Node::ast_from_object(ctx, source_file, object)?;
84+
let args: BoxedSlice<_> = Node::ast_from_object(vm, source_file, object)?;
8285
Ok(Self::from_args(TextRange::default(), args.0))
8386
}
8487
}
@@ -90,33 +93,32 @@ pub(super) struct KeywordArguments {
9093

9194
impl KeywordArguments {
9295
pub(super) fn ast_from_field(
93-
ctx: &VirtualMachine,
96+
vm: &VirtualMachine,
9497
source_file: &SourceFile,
9598
object: &PyObject,
9699
field: &'static str,
97100
typ: &str,
98101
) -> PyResult<Self> {
99102
Ok(Self {
100-
keywords: get_node_boxed_slice_field(ctx, source_file, object, field, typ)?,
103+
keywords: get_node_boxed_slice_field(vm, source_file, object, field, typ)?,
101104
range: TextRange::default(),
102105
})
103106
}
104107
}
105108

106109
impl Node for KeywordArguments {
107110
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
108-
let _source_file = source_file;
109111
let Self { keywords, range: _ } = self;
110112
// TODO: use range
111113
BoxedSlice(keywords).ast_to_object(vm, source_file)
112114
}
113115

114116
fn ast_from_object(
115-
ctx: &VirtualMachine,
117+
vm: &VirtualMachine,
116118
source_file: &SourceFile,
117119
object: PyObjectRef,
118120
) -> PyResult<Self> {
119-
let keywords: BoxedSlice<_> = Node::ast_from_object(ctx, source_file, object)?;
121+
let keywords: BoxedSlice<_> = Node::ast_from_object(vm, source_file, object)?;
120122
Ok(Self {
121123
keywords: keywords.0,
122124
range: TextRange::default(),

0 commit comments

Comments
 (0)