mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
ast: match CPython argument validation order (#8414)
Validate parameter annotations while converting ast.arguments, before merging positional and keyword-only defaults. This gives invalid annotation contexts precedence over default-list shape errors, as in CPython. Merge positional defaults before keyword-only defaults so an excess positional-default error also takes precedence over a keyword-only default length mismatch. Remove the expected-failure markers from the FunctionDef and Lambda AST validator tests that now pass. Assisted-by: Codex:gpt-5.6-sol
This commit is contained in:
3 files changed
+37
-4
No files matched your search
Vendored
-2
@@ -2055,7 +2055,6 @@ class ASTValidatorTests(unittest.TestCase):
|
||||
kw_defaults=[None, ast.Name("x", ast.Store())]),
|
||||
"must have Load context")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; ValueError not raised
|
||||
def test_funcdef(self):
|
||||
a = ast.arguments([], [], None, [], [], None, [])
|
||||
f = ast.FunctionDef("x", a, [], [], None, None, [])
|
||||
@@ -2267,7 +2266,6 @@ class ASTValidatorTests(unittest.TestCase):
|
||||
u = ast.UnaryOp(ast.Not(), ast.Name("x", ast.Store()))
|
||||
self.expr(u, "must have Load context")
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; ValueError not raised
|
||||
def test_lambda(self):
|
||||
a = ast.arguments([], [], None, [], [], None, [])
|
||||
self.expr(ast.Lambda(a, ast.Name("x", ast.Store())),
|
||||
|
||||
@@ -88,14 +88,23 @@ impl Node for ast::Parameters {
|
||||
"arguments",
|
||||
)?;
|
||||
|
||||
validate_parameter_annotations(
|
||||
vm,
|
||||
&posonlyargs,
|
||||
&args,
|
||||
vararg.as_deref(),
|
||||
&kwonlyargs,
|
||||
kwarg.as_deref(),
|
||||
)?;
|
||||
|
||||
let ParameterDefaults {
|
||||
runtime_defaults,
|
||||
defaults,
|
||||
_range: _,
|
||||
} = defaults;
|
||||
let kwonlyargs = merge_keyword_parameter_defaults(vm, kwonlyargs, kw_defaults)?;
|
||||
let (posonlyargs, args) =
|
||||
merge_positional_parameter_defaults(vm, posonlyargs, args, defaults)?;
|
||||
let kwonlyargs = merge_keyword_parameter_defaults(vm, kwonlyargs, kw_defaults)?;
|
||||
|
||||
Ok(Self {
|
||||
node_index: Default::default(),
|
||||
@@ -114,6 +123,29 @@ impl Node for ast::Parameters {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_parameter_annotations(
|
||||
vm: &VirtualMachine,
|
||||
posonlyargs: &PositionalParameters,
|
||||
args: &PositionalParameters,
|
||||
vararg: Option<&ast::Parameter>,
|
||||
kwonlyargs: &KeywordParameters,
|
||||
kwarg: Option<&ast::Parameter>,
|
||||
) -> PyResult<()> {
|
||||
for parameter in posonlyargs.args.iter().chain(&args.args) {
|
||||
super::validate::validate_parameter_annotation(vm, parameter)?;
|
||||
}
|
||||
if let Some(parameter) = vararg {
|
||||
super::validate::validate_parameter_annotation(vm, parameter)?;
|
||||
}
|
||||
for parameter in &kwonlyargs.keywords {
|
||||
super::validate::validate_parameter_annotation(vm, parameter)?;
|
||||
}
|
||||
if let Some(parameter) = kwarg {
|
||||
super::validate::validate_parameter_annotation(vm, parameter)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// product
|
||||
impl Node for ast::Parameter {
|
||||
fn ast_to_object(self, vm: &VirtualMachine, source_file: &SourceFile) -> PyObjectRef {
|
||||
|
||||
@@ -56,7 +56,10 @@ fn validate_keywords(vm: &VirtualMachine, keywords: &[ast::Keyword]) -> PyResult
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_parameter_annotation(vm: &VirtualMachine, parameter: &ast::Parameter) -> PyResult<()> {
|
||||
pub(super) fn validate_parameter_annotation(
|
||||
vm: &VirtualMachine,
|
||||
parameter: &ast::Parameter,
|
||||
) -> PyResult<()> {
|
||||
if let Some(annotation) = ¶meter.annotation {
|
||||
validate_expr(vm, annotation, ast::ExprContext::Load)?;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user