Make `Parameters` an optional field on `ExprLambda` (#6669)

## Summary

If a lambda doesn't contain any parameters, or any parameter _tokens_
(like `*`), we can use `None` for the parameters. This feels like a
better representation to me, since, e.g., what should the `TextRange` be
for a non-existent set of parameters? It also allows us to remove
several sites where we check if the `Parameters` is empty by seeing if
it contains any arguments, so semantically, we're already trying to
detect and model around this elsewhere.

Changing this also fixes a number of issues with dangling comments in
parameter-less lambdas, since those comments are now automatically
marked as dangling on the lambda. (As-is, we were also doing something
not-great whereby the lambda was responsible for formatting dangling
comments on the parameters, which has been removed.)

Closes https://github.com/astral-sh/ruff/issues/6646.

Closes https://github.com/astral-sh/ruff/issues/6647.

## Test Plan

`cargo test`
This commit is contained in:
Charlie Marsh 2023-08-18 11:34:54 -04:00 committed by GitHub
parent ea72d5feba
commit 6a5acde226
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 517 additions and 412 deletions

View File

@ -874,18 +874,20 @@ where
}, },
) => { ) => {
// Visit the default arguments, but avoid the body, which will be deferred. // Visit the default arguments, but avoid the body, which will be deferred.
for ParameterWithDefault { if let Some(parameters) = parameters {
default, for ParameterWithDefault {
parameter: _, default,
range: _, parameter: _,
} in parameters range: _,
.posonlyargs } in parameters
.iter() .posonlyargs
.chain(&parameters.args) .iter()
.chain(&parameters.kwonlyargs) .chain(&parameters.args)
{ .chain(&parameters.kwonlyargs)
if let Some(expr) = &default { {
self.visit_expr(expr); if let Some(expr) = &default {
self.visit_expr(expr);
}
} }
} }
@ -1834,7 +1836,9 @@ impl<'a> Checker<'a> {
range: _, range: _,
}) = expr }) = expr
{ {
self.visit_parameters(parameters); if let Some(parameters) = parameters {
self.visit_parameters(parameters);
}
self.visit_expr(body); self.visit_expr(body);
} else { } else {
unreachable!("Expected Expr::Lambda"); unreachable!("Expected Expr::Lambda");

View File

@ -184,7 +184,10 @@ impl<'a> Visitor<'a> for SuspiciousVariablesVisitor<'a> {
return false; return false;
} }
if parameters.includes(&loaded.id) { if parameters
.as_ref()
.is_some_and(|parameters| parameters.includes(&loaded.id))
{
return false; return false;
} }

View File

@ -76,17 +76,20 @@ where
range: _, range: _,
}) => { }) => {
visitor::walk_expr(self, body); visitor::walk_expr(self, body);
for ParameterWithDefault {
parameter, if let Some(parameters) = parameters {
default: _, for ParameterWithDefault {
range: _, parameter,
} in parameters default: _,
.posonlyargs range: _,
.iter() } in parameters
.chain(&parameters.args) .posonlyargs
.chain(&parameters.kwonlyargs) .iter()
{ .chain(&parameters.args)
self.names.remove(parameter.name.as_str()); .chain(&parameters.kwonlyargs)
{
self.names.remove(parameter.name.as_str());
}
} }
} }
_ => visitor::walk_expr(self, expr), _ => visitor::walk_expr(self, expr),

View File

@ -103,7 +103,10 @@ pub(crate) fn unnecessary_map(
return; return;
}; };
if late_binding(parameters, body) { if parameters
.as_ref()
.is_some_and(|parameters| late_binding(parameters, body))
{
return; return;
} }
} }
@ -134,7 +137,10 @@ pub(crate) fn unnecessary_map(
return; return;
}; };
if late_binding(parameters, body) { if parameters
.as_ref()
.is_some_and(|parameters| late_binding(parameters, body))
{
return; return;
} }
} }
@ -171,7 +177,10 @@ pub(crate) fn unnecessary_map(
return; return;
} }
if late_binding(parameters, body) { if parameters
.as_ref()
.is_some_and(|parameters| late_binding(parameters, body))
{
return; return;
} }
} }
@ -240,7 +249,7 @@ struct LateBindingVisitor<'a> {
/// The arguments to the current lambda. /// The arguments to the current lambda.
parameters: &'a Parameters, parameters: &'a Parameters,
/// The arguments to any lambdas within the current lambda body. /// The arguments to any lambdas within the current lambda body.
lambdas: Vec<&'a Parameters>, lambdas: Vec<Option<&'a Parameters>>,
/// Whether any names within the current lambda body are late-bound within nested lambdas. /// Whether any names within the current lambda body are late-bound within nested lambdas.
late_bound: bool, late_bound: bool,
} }
@ -261,7 +270,7 @@ impl<'a> Visitor<'a> for LateBindingVisitor<'a> {
fn visit_expr(&mut self, expr: &'a Expr) { fn visit_expr(&mut self, expr: &'a Expr) {
match expr { match expr {
Expr::Lambda(ast::ExprLambda { parameters, .. }) => { Expr::Lambda(ast::ExprLambda { parameters, .. }) => {
self.lambdas.push(parameters); self.lambdas.push(parameters.as_deref());
visitor::walk_expr(self, expr); visitor::walk_expr(self, expr);
self.lambdas.pop(); self.lambdas.pop();
} }
@ -275,11 +284,11 @@ impl<'a> Visitor<'a> for LateBindingVisitor<'a> {
// If the name is defined in the current lambda... // If the name is defined in the current lambda...
if self.parameters.includes(id) { if self.parameters.includes(id) {
// And isn't overridden by any nested lambdas... // And isn't overridden by any nested lambdas...
if !self if !self.lambdas.iter().any(|parameters| {
.lambdas parameters
.iter() .as_ref()
.any(|parameters| parameters.includes(id)) .is_some_and(|parameters| parameters.includes(id))
{ }) {
// Then it's late-bound. // Then it's late-bound.
self.late_bound = true; self.late_bound = true;
} }

View File

@ -59,12 +59,7 @@ pub(crate) fn reimplemented_list_builtin(checker: &mut Checker, expr: &ExprLambd
range: _, range: _,
} = expr; } = expr;
if parameters.args.is_empty() if parameters.is_none() {
&& parameters.kwonlyargs.is_empty()
&& parameters.posonlyargs.is_empty()
&& parameters.vararg.is_none()
&& parameters.kwarg.is_none()
{
if let Expr::List(ast::ExprList { elts, .. }) = body.as_ref() { if let Expr::List(ast::ExprList { elts, .. }) = body.as_ref() {
if elts.is_empty() { if elts.is_empty() {
let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range()); let mut diagnostic = Diagnostic::new(ReimplementedListBuiltin, expr.range());

View File

@ -89,18 +89,19 @@ fn check_patch_call(call: &ast::ExprCall, index: usize) -> Option<Diagnostic> {
.find_argument("new", index)? .find_argument("new", index)?
.as_lambda_expr()?; .as_lambda_expr()?;
// Walk the lambda body. // Walk the lambda body. If the lambda uses the arguments, then it's valid.
let mut visitor = LambdaBodyVisitor { if let Some(parameters) = parameters {
parameters, let mut visitor = LambdaBodyVisitor {
uses_args: false, parameters,
}; uses_args: false,
visitor.visit_expr(body); };
visitor.visit_expr(body);
if visitor.uses_args { if visitor.uses_args {
None return None;
} else { }
Some(Diagnostic::new(PytestPatchWithLambda, call.func.range()))
} }
Some(Diagnostic::new(PytestPatchWithLambda, call.func.range()))
} }
/// PT008 /// PT008

View File

@ -436,7 +436,10 @@ pub(crate) fn unused_arguments(
} }
} }
} }
ScopeKind::Lambda(ast::ExprLambda { parameters, .. }) => { ScopeKind::Lambda(ast::ExprLambda {
parameters: Some(parameters),
..
}) => {
if checker.enabled(Argumentable::Lambda.rule_code()) { if checker.enabled(Argumentable::Lambda.rule_code()) {
function( function(
Argumentable::Lambda, Argumentable::Lambda,

View File

@ -91,7 +91,7 @@ pub(crate) fn lambda_assignment(
let mut indented = String::new(); let mut indented = String::new();
for (idx, line) in function( for (idx, line) in function(
id, id,
parameters, parameters.as_deref(),
body, body,
annotation, annotation,
checker.semantic(), checker.semantic(),
@ -180,7 +180,7 @@ fn extract_types(annotation: &Expr, semantic: &SemanticModel) -> Option<(Vec<Exp
fn function( fn function(
name: &str, name: &str,
parameters: &Parameters, parameters: Option<&Parameters>,
body: &Expr, body: &Expr,
annotation: Option<&Expr>, annotation: Option<&Expr>,
semantic: &SemanticModel, semantic: &SemanticModel,
@ -190,6 +190,9 @@ fn function(
value: Some(Box::new(body.clone())), value: Some(Box::new(body.clone())),
range: TextRange::default(), range: TextRange::default(),
}); });
let parameters = parameters
.cloned()
.unwrap_or_else(|| Parameters::empty(TextRange::default()));
if let Some(annotation) = annotation { if let Some(annotation) = annotation {
if let Some((arg_types, return_type)) = extract_types(annotation, semantic) { if let Some((arg_types, return_type)) = extract_types(annotation, semantic) {
// A `lambda` expression can only have positional and positional-only // A `lambda` expression can only have positional and positional-only
@ -228,7 +231,7 @@ fn function(
parameters: Box::new(Parameters { parameters: Box::new(Parameters {
posonlyargs: new_posonlyargs, posonlyargs: new_posonlyargs,
args: new_args, args: new_args,
..parameters.clone() ..parameters
}), }),
body: vec![body], body: vec![body],
decorator_list: vec![], decorator_list: vec![],
@ -242,7 +245,7 @@ fn function(
let func = Stmt::FunctionDef(ast::StmtFunctionDef { let func = Stmt::FunctionDef(ast::StmtFunctionDef {
is_async: false, is_async: false,
name: Identifier::new(name.to_string(), TextRange::default()), name: Identifier::new(name.to_string(), TextRange::default()),
parameters: Box::new(parameters.clone()), parameters: Box::new(parameters),
body: vec![body], body: vec![body],
decorator_list: vec![], decorator_list: vec![],
returns: None, returns: None,

View File

@ -542,7 +542,7 @@ pub struct ExprUnaryOp<'a> {
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct ExprLambda<'a> { pub struct ExprLambda<'a> {
parameters: ComparableParameters<'a>, parameters: Option<ComparableParameters<'a>>,
body: Box<ComparableExpr<'a>>, body: Box<ComparableExpr<'a>>,
} }
@ -773,7 +773,7 @@ impl<'a> From<&'a ast::Expr> for ComparableExpr<'a> {
body, body,
range: _, range: _,
}) => Self::Lambda(ExprLambda { }) => Self::Lambda(ExprLambda {
parameters: (parameters.as_ref()).into(), parameters: parameters.as_ref().map(Into::into),
body: body.into(), body: body.into(),
}), }),
ast::Expr::IfExp(ast::ExprIfExp { ast::Expr::IfExp(ast::ExprIfExp {

View File

@ -2038,7 +2038,9 @@ impl AstNode for ast::ExprLambda {
range: _, range: _,
} = self; } = self;
visitor.visit_parameters(parameters); if let Some(parameters) = parameters {
visitor.visit_parameters(parameters);
}
visitor.visit_expr(body); visitor.visit_expr(body);
} }
} }

View File

@ -632,7 +632,7 @@ impl From<ExprUnaryOp> for Expr {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ExprLambda { pub struct ExprLambda {
pub range: TextRange, pub range: TextRange,
pub parameters: Box<Parameters>, pub parameters: Option<Box<Parameters>>,
pub body: Box<Expr>, pub body: Box<Expr>,
} }

View File

@ -354,7 +354,9 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
body, body,
range: _, range: _,
}) => { }) => {
visitor.visit_parameters(parameters); if let Some(parameters) = parameters {
visitor.visit_parameters(parameters);
}
visitor.visit_expr(body); visitor.visit_expr(body);
} }
Expr::IfExp(ast::ExprIfExp { Expr::IfExp(ast::ExprIfExp {

View File

@ -878,9 +878,11 @@ impl<'a> Generator<'a> {
range: _, range: _,
}) => { }) => {
group_if!(precedence::LAMBDA, { group_if!(precedence::LAMBDA, {
let npos = parameters.args.len() + parameters.posonlyargs.len(); self.p("lambda");
self.p(if npos > 0 { "lambda " } else { "lambda" }); if let Some(parameters) = parameters {
self.unparse_parameters(parameters); self.p(" ");
self.unparse_parameters(parameters);
}
self.p(": "); self.p(": ");
self.unparse_expr(body, precedence::LAMBDA); self.unparse_expr(body, precedence::LAMBDA);
}); });

View File

@ -56,12 +56,16 @@ lambda x: lambda y: lambda z: (
z) # Trailing z) # Trailing
# Trailing # Trailing
a = ( a = (
lambda # Dangling lambda # Dangling
: 1 : 1
) )
a = (
lambda x # Dangling
, y: 1
)
# Regression test: lambda empty arguments ranges were too long, leading to unstable # Regression test: lambda empty arguments ranges were too long, leading to unstable
# formatting # formatting
(lambda:(# (lambda:(#
@ -93,3 +97,24 @@ lambda a, *args, b, **kwds,: 0
lambda a, *, b, **kwds,: 0 lambda a, *, b, **kwds,: 0
lambda a, /: a lambda a, /: a
lambda a, /, c: a lambda a, /, c: a
# Dangling comments without parameters.
(
lambda
: # 3
None
)
(
lambda
# 3
: None
)
(
lambda # 1
# 2
: # 3
# 4
None # 5
)

View File

@ -162,9 +162,14 @@ fn handle_enclosed_comment<'a>(
locator: &Locator, locator: &Locator,
) -> CommentPlacement<'a> { ) -> CommentPlacement<'a> {
match comment.enclosing_node() { match comment.enclosing_node() {
AnyNodeRef::Parameters(arguments) => { AnyNodeRef::Parameters(parameters) => {
handle_parameters_separator_comment(comment, arguments, locator) handle_parameters_separator_comment(comment, parameters, locator).or_else(|comment| {
.or_else(|comment| handle_bracketed_end_of_line_comment(comment, locator)) if are_parameters_parenthesized(parameters, locator.contents()) {
handle_bracketed_end_of_line_comment(comment, locator)
} else {
CommentPlacement::Default(comment)
}
})
} }
AnyNodeRef::Arguments(_) | AnyNodeRef::TypeParams(_) => { AnyNodeRef::Arguments(_) | AnyNodeRef::TypeParams(_) => {
handle_bracketed_end_of_line_comment(comment, locator) handle_bracketed_end_of_line_comment(comment, locator)
@ -1544,6 +1549,13 @@ fn is_first_statement_in_alternate_body(statement: AnyNodeRef, has_body: AnyNode
} }
} }
/// Returns `true` if the parameters are parenthesized (as in a function definition), or `false` if
/// not (as in a lambda).
fn are_parameters_parenthesized(parameters: &Parameters, contents: &str) -> bool {
// A lambda never has parentheses around its parameters, but a function definition always does.
contents[parameters.range()].starts_with('(')
}
/// Counts the number of empty lines in `contents`. /// Counts the number of empty lines in `contents`.
fn max_empty_lines(contents: &str) -> u32 { fn max_empty_lines(contents: &str) -> u32 {
let mut newlines = 0u32; let mut newlines = 0u32;

View File

@ -1,13 +1,14 @@
use crate::comments::{dangling_node_comments, SourceComment}; use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprLambda;
use crate::comments::{dangling_comments, SourceComment};
use crate::context::PyFormatContext; use crate::context::PyFormatContext;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::other::parameters::ParametersParentheses; use crate::other::parameters::ParametersParentheses;
use crate::AsFormat; use crate::AsFormat;
use crate::{FormatNodeRule, PyFormatter}; use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{space, text};
use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::ExprLambda;
#[derive(Default)] #[derive(Default)]
pub struct FormatExprLambda; pub struct FormatExprLambda;
@ -20,13 +21,12 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
body, body,
} = item; } = item;
let comments = f.context().comments().clone();
let dangling = comments.dangling(item);
write!(f, [text("lambda")])?; write!(f, [text("lambda")])?;
if !parameters.args.is_empty() if let Some(parameters) = parameters {
|| !parameters.posonlyargs.is_empty()
|| parameters.vararg.is_some()
|| parameters.kwarg.is_some()
{
write!( write!(
f, f,
[ [
@ -38,21 +38,15 @@ impl FormatNodeRule<ExprLambda> for FormatExprLambda {
)?; )?;
} }
write!( write!(f, [text(":")])?;
f,
[ if dangling.is_empty() {
text(":"), write!(f, [space()])?;
space(), } else {
body.format(), write!(f, [dangling_comments(dangling)])?;
// It's possible for some `Arguments` of `lambda`s to be assigned dangling comments. }
//
// a = ( write!(f, [body.format()])
// lambda # Dangling
// : 1
// )
dangling_node_comments(parameters.as_ref())
]
)
} }
fn fmt_dangling_comments( fn fmt_dangling_comments(

View File

@ -7,8 +7,8 @@ use ruff_python_trivia::{SimpleToken, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use crate::comments::{ use crate::comments::{
dangling_open_parenthesis_comments, leading_comments, leading_node_comments, trailing_comments, dangling_comments, dangling_open_parenthesis_comments, leading_comments, leading_node_comments,
CommentLinePosition, SourceComment, trailing_comments, CommentLinePosition, SourceComment,
}; };
use crate::context::{NodeLevel, WithNodeLevel}; use crate::context::{NodeLevel, WithNodeLevel};
use crate::expression::parentheses::empty_parenthesized; use crate::expression::parentheses::empty_parenthesized;
@ -242,7 +242,7 @@ impl FormatNodeRule<Parameters> for FormatParameters {
+ usize::from(kwarg.is_some()); + usize::from(kwarg.is_some());
if self.parentheses == ParametersParentheses::Never { if self.parentheses == ParametersParentheses::Never {
write!(f, [group(&format_inner)]) write!(f, [group(&format_inner), dangling_comments(dangling)])
} else if num_parameters == 0 { } else if num_parameters == 0 {
// No parameters, format any dangling comments between `()` // No parameters, format any dangling comments between `()`
write!(f, [empty_parenthesized("(", dangling, ")")]) write!(f, [empty_parenthesized("(", dangling, ")")])

View File

@ -62,12 +62,16 @@ lambda x: lambda y: lambda z: (
z) # Trailing z) # Trailing
# Trailing # Trailing
a = ( a = (
lambda # Dangling lambda # Dangling
: 1 : 1
) )
a = (
lambda x # Dangling
, y: 1
)
# Regression test: lambda empty arguments ranges were too long, leading to unstable # Regression test: lambda empty arguments ranges were too long, leading to unstable
# formatting # formatting
(lambda:(# (lambda:(#
@ -99,6 +103,27 @@ lambda a, *args, b, **kwds,: 0
lambda a, *, b, **kwds,: 0 lambda a, *, b, **kwds,: 0
lambda a, /: a lambda a, /: a
lambda a, /, c: a lambda a, /, c: a
# Dangling comments without parameters.
(
lambda
: # 3
None
)
(
lambda
# 3
: None
)
(
lambda # 1
# 2
: # 3
# 4
None # 5
)
``` ```
## Output ## Output
@ -159,9 +184,14 @@ lambda x: lambda y: lambda z: (
) # Trailing ) # Trailing
# Trailing # Trailing
a = (
lambda: # Dangling
1
)
a = ( a = (
lambda: 1 # Dangling lambda x, # Dangling
y: 1
) )
# Regression test: lambda empty arguments ranges were too long, leading to unstable # Regression test: lambda empty arguments ranges were too long, leading to unstable
@ -188,7 +218,7 @@ lambda **kwds,: 0
lambda a, *args,: 0 lambda a, *args,: 0
lambda a, **kwds,: 0 lambda a, **kwds,: 0
lambda *args, b,: 0 lambda *args, b,: 0
lambda: 0 lambda *, b,: 0
lambda *args, **kwds,: 0 lambda *args, **kwds,: 0
lambda a, *args, b,: 0 lambda a, *args, b,: 0
lambda a, *, b,: 0 lambda a, *, b,: 0
@ -199,6 +229,25 @@ lambda a, *args, b, **kwds,: 0
lambda a, *, b, **kwds,: 0 lambda a, *, b, **kwds,: 0
lambda a, /: a lambda a, /: a
lambda a, /, c: a lambda a, /, c: a
# Dangling comments without parameters.
(
lambda: # 3
None
)
(
lambda: # 3
None
)
(
lambda: # 1
# 2
# 3
# 4
None # 5
)
``` ```

View File

@ -1354,14 +1354,12 @@ NamedExpression: ast::Expr = {
}; };
LambdaDef: ast::Expr = { LambdaDef: ast::Expr = {
<location:@L> "lambda" <location_args:@L> <p:ParameterList<UntypedParameter, StarUntypedParameter, StarUntypedParameter>?> <end_location_args:@R> ":" <body:Test<"all">> <end_location:@R> =>? { <location:@L> "lambda" <location_args:@L> <parameters:ParameterList<UntypedParameter, StarUntypedParameter, StarUntypedParameter>?> <end_location_args:@R> ":" <body:Test<"all">> <end_location:@R> =>? {
p.as_ref().map(validate_arguments).transpose()?; parameters.as_ref().map(validate_arguments).transpose()?;
let p = p
.unwrap_or_else(|| ast::Parameters::empty((location_args..end_location_args).into()));
Ok(ast::Expr::Lambda( Ok(ast::Expr::Lambda(
ast::ExprLambda { ast::ExprLambda {
parameters: Box::new(p), parameters: parameters.map(Box::new),
body: Box::new(body), body: Box::new(body),
range: (location..end_location).into() range: (location..end_location).into()
} }

View File

@ -1,5 +1,5 @@
// auto-generated: "lalrpop 0.20.0" // auto-generated: "lalrpop 0.20.0"
// sha3: e2b75c2709648429269934006c032842f6800678baccab09dedfb746463c30b4 // sha3: 6ec03d3255ad27917601bff9ad0b1df5f8702124139879a78e7dca689ca1b113
use num_bigint::BigInt; use num_bigint::BigInt;
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
use ruff_python_ast::{self as ast, Ranged, IpyEscapeKind}; use ruff_python_ast::{self as ast, Ranged, IpyEscapeKind};
@ -35817,7 +35817,7 @@ fn __action184<
(_, location, _): (TextSize, TextSize, TextSize), (_, location, _): (TextSize, TextSize, TextSize),
(_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize),
(_, location_args, _): (TextSize, TextSize, TextSize), (_, location_args, _): (TextSize, TextSize, TextSize),
(_, p, _): (TextSize, core::option::Option<ast::Parameters>, TextSize), (_, parameters, _): (TextSize, core::option::Option<ast::Parameters>, TextSize),
(_, end_location_args, _): (TextSize, TextSize, TextSize), (_, end_location_args, _): (TextSize, TextSize, TextSize),
(_, _, _): (TextSize, token::Tok, TextSize), (_, _, _): (TextSize, token::Tok, TextSize),
(_, body, _): (TextSize, ast::Expr, TextSize), (_, body, _): (TextSize, ast::Expr, TextSize),
@ -35825,13 +35825,11 @@ fn __action184<
) -> Result<ast::Expr,__lalrpop_util::ParseError<TextSize,token::Tok,LexicalError>> ) -> Result<ast::Expr,__lalrpop_util::ParseError<TextSize,token::Tok,LexicalError>>
{ {
{ {
p.as_ref().map(validate_arguments).transpose()?; parameters.as_ref().map(validate_arguments).transpose()?;
let p = p
.unwrap_or_else(|| ast::Parameters::empty((location_args..end_location_args).into()));
Ok(ast::Expr::Lambda( Ok(ast::Expr::Lambda(
ast::ExprLambda { ast::ExprLambda {
parameters: Box::new(p), parameters: parameters.map(Box::new),
body: Box::new(body), body: Box::new(body),
range: (location..end_location).into() range: (location..end_location).into()
} }

View File

@ -10,51 +10,53 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..20, range: 0..20,
parameters: Parameters { parameters: Some(
range: 7..17, Parameters {
posonlyargs: [], range: 7..17,
args: [], posonlyargs: [],
vararg: None, args: [],
kwonlyargs: [ vararg: None,
ParameterWithDefault { kwonlyargs: [
range: 10..11, ParameterWithDefault {
parameter: Parameter {
range: 10..11, range: 10..11,
name: Identifier { parameter: Parameter {
id: "a",
range: 10..11, range: 10..11,
name: Identifier {
id: "a",
range: 10..11,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14, range: 13..14,
name: Identifier { parameter: Parameter {
id: "b",
range: 13..14, range: 13..14,
name: Identifier {
id: "b",
range: 13..14,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 16..17,
parameter: Parameter {
range: 16..17, range: 16..17,
name: Identifier { parameter: Parameter {
id: "c",
range: 16..17, range: 16..17,
name: Identifier {
id: "c",
range: 16..17,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, kwarg: None,
], },
kwarg: None, ),
},
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 19..20, range: 19..20,

View File

@ -10,71 +10,73 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..26, range: 0..26,
parameters: Parameters { parameters: Some(
range: 7..23, Parameters {
posonlyargs: [], range: 7..23,
args: [], posonlyargs: [],
vararg: None, args: [],
kwonlyargs: [ vararg: None,
ParameterWithDefault { kwonlyargs: [
range: 10..11, ParameterWithDefault {
parameter: Parameter {
range: 10..11, range: 10..11,
name: Identifier { parameter: Parameter {
id: "a",
range: 10..11, range: 10..11,
name: Identifier {
id: "a",
range: 10..11,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
}, range: 13..17,
ParameterWithDefault { parameter: Parameter {
range: 13..17,
parameter: Parameter {
range: 13..14,
name: Identifier {
id: "b",
range: 13..14, range: 13..14,
}, name: Identifier {
annotation: None, id: "b",
}, range: 13..14,
default: Some(
Constant(
ExprConstant {
range: 15..17,
value: Int(
20,
),
kind: None,
}, },
annotation: None,
},
default: Some(
Constant(
ExprConstant {
range: 15..17,
value: Int(
20,
),
kind: None,
},
),
), ),
), },
}, ParameterWithDefault {
ParameterWithDefault { range: 19..23,
range: 19..23, parameter: Parameter {
parameter: Parameter {
range: 19..20,
name: Identifier {
id: "c",
range: 19..20, range: 19..20,
}, name: Identifier {
annotation: None, id: "c",
}, range: 19..20,
default: Some(
Constant(
ExprConstant {
range: 21..23,
value: Int(
30,
),
kind: None,
}, },
annotation: None,
},
default: Some(
Constant(
ExprConstant {
range: 21..23,
value: Int(
30,
),
kind: None,
},
),
), ),
), },
}, ],
], kwarg: None,
kwarg: None, },
}, ),
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 25..26, range: 25..26,

View File

@ -10,14 +10,7 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..9, range: 0..9,
parameters: Parameters { parameters: None,
range: 6..6,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 8..9, range: 8..9,

View File

@ -10,76 +10,78 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..26, range: 0..26,
parameters: Parameters { parameters: Some(
range: 7..23, Parameters {
posonlyargs: [], range: 7..23,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 7..8, ParameterWithDefault {
parameter: Parameter {
range: 7..8, range: 7..8,
name: Identifier { parameter: Parameter {
id: "a",
range: 7..8, range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11, range: 10..11,
name: Identifier { parameter: Parameter {
id: "b",
range: 10..11, range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14, range: 13..14,
name: Identifier { parameter: Parameter {
id: "c",
range: 13..14, range: 13..14,
name: Identifier {
id: "c",
range: 13..14,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, vararg: None,
], kwonlyargs: [
vararg: None, ParameterWithDefault {
kwonlyargs: [
ParameterWithDefault {
range: 19..20,
parameter: Parameter {
range: 19..20, range: 19..20,
name: Identifier { parameter: Parameter {
id: "d",
range: 19..20, range: 19..20,
name: Identifier {
id: "d",
range: 19..20,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 22..23,
parameter: Parameter {
range: 22..23, range: 22..23,
name: Identifier { parameter: Parameter {
id: "e",
range: 22..23, range: 22..23,
name: Identifier {
id: "e",
range: 22..23,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, kwarg: None,
], },
kwarg: None, ),
},
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 25..26, range: 25..26,

View File

@ -10,51 +10,53 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..17, range: 0..17,
parameters: Parameters { parameters: Some(
range: 7..14, Parameters {
posonlyargs: [], range: 7..14,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 7..8, ParameterWithDefault {
parameter: Parameter {
range: 7..8, range: 7..8,
name: Identifier { parameter: Parameter {
id: "a",
range: 7..8, range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11, range: 10..11,
name: Identifier { parameter: Parameter {
id: "b",
range: 10..11, range: 10..11,
name: Identifier {
id: "b",
range: 10..11,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 13..14,
parameter: Parameter {
range: 13..14, range: 13..14,
name: Identifier { parameter: Parameter {
id: "c",
range: 13..14, range: 13..14,
name: Identifier {
id: "c",
range: 13..14,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, vararg: None,
], kwonlyargs: [],
vararg: None, kwarg: None,
kwonlyargs: [], },
kwarg: None, ),
},
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 16..17, range: 16..17,

View File

@ -10,71 +10,73 @@ Ok(
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..23, range: 0..23,
parameters: Parameters { parameters: Some(
range: 7..20, Parameters {
posonlyargs: [], range: 7..20,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 7..8, ParameterWithDefault {
parameter: Parameter {
range: 7..8, range: 7..8,
name: Identifier { parameter: Parameter {
id: "a",
range: 7..8, range: 7..8,
name: Identifier {
id: "a",
range: 7..8,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
}, range: 10..14,
ParameterWithDefault { parameter: Parameter {
range: 10..14,
parameter: Parameter {
range: 10..11,
name: Identifier {
id: "b",
range: 10..11, range: 10..11,
}, name: Identifier {
annotation: None, id: "b",
}, range: 10..11,
default: Some(
Constant(
ExprConstant {
range: 12..14,
value: Int(
20,
),
kind: None,
}, },
annotation: None,
},
default: Some(
Constant(
ExprConstant {
range: 12..14,
value: Int(
20,
),
kind: None,
},
),
), ),
), },
}, ParameterWithDefault {
ParameterWithDefault { range: 16..20,
range: 16..20, parameter: Parameter {
parameter: Parameter {
range: 16..17,
name: Identifier {
id: "c",
range: 16..17, range: 16..17,
}, name: Identifier {
annotation: None, id: "c",
}, range: 16..17,
default: Some(
Constant(
ExprConstant {
range: 18..20,
value: Int(
30,
),
kind: None,
}, },
annotation: None,
},
default: Some(
Constant(
ExprConstant {
range: 18..20,
value: Int(
30,
),
kind: None,
},
),
), ),
), },
}, ],
], vararg: None,
vararg: None, kwonlyargs: [],
kwonlyargs: [], kwarg: None,
kwarg: None, },
}, ),
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 22..23, range: 22..23,

View File

@ -727,27 +727,29 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 591..619, range: 591..619,
parameters: Parameters { parameters: Some(
range: 598..603, Parameters {
posonlyargs: [], range: 598..603,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 598..603, ParameterWithDefault {
parameter: Parameter {
range: 598..603, range: 598..603,
name: Identifier { parameter: Parameter {
id: "query",
range: 598..603, range: 598..603,
name: Identifier {
id: "query",
range: 598..603,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, vararg: None,
], kwonlyargs: [],
vararg: None, kwarg: None,
kwonlyargs: [], },
kwarg: None, ),
},
body: Compare( body: Compare(
ExprCompare { ExprCompare {
range: 605..619, range: 605..619,

View File

@ -9,39 +9,41 @@ expression: parse_ast
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..18, range: 0..18,
parameters: Parameters { parameters: Some(
range: 7..11, Parameters {
posonlyargs: [], range: 7..11,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 7..8, ParameterWithDefault {
parameter: Parameter {
range: 7..8, range: 7..8,
name: Identifier { parameter: Parameter {
id: "x",
range: 7..8, range: 7..8,
name: Identifier {
id: "x",
range: 7..8,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ParameterWithDefault {
},
ParameterWithDefault {
range: 10..11,
parameter: Parameter {
range: 10..11, range: 10..11,
name: Identifier { parameter: Parameter {
id: "y",
range: 10..11, range: 10..11,
name: Identifier {
id: "y",
range: 10..11,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, vararg: None,
], kwonlyargs: [],
vararg: None, kwarg: None,
kwonlyargs: [], },
kwarg: None, ),
},
body: BinOp( body: BinOp(
ExprBinOp { ExprBinOp {
range: 13..18, range: 13..18,

View File

@ -9,14 +9,7 @@ expression: parse_ast
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 0..9, range: 0..9,
parameters: Parameters { parameters: None,
range: 6..6,
posonlyargs: [],
args: [],
vararg: None,
kwonlyargs: [],
kwarg: None,
},
body: Constant( body: Constant(
ExprConstant { ExprConstant {
range: 8..9, range: 8..9,

View File

@ -663,27 +663,29 @@ expression: "parse_suite(source, \"<test>\").unwrap()"
value: Lambda( value: Lambda(
ExprLambda { ExprLambda {
range: 507..535, range: 507..535,
parameters: Parameters { parameters: Some(
range: 514..519, Parameters {
posonlyargs: [], range: 514..519,
args: [ posonlyargs: [],
ParameterWithDefault { args: [
range: 514..519, ParameterWithDefault {
parameter: Parameter {
range: 514..519, range: 514..519,
name: Identifier { parameter: Parameter {
id: "query",
range: 514..519, range: 514..519,
name: Identifier {
id: "query",
range: 514..519,
},
annotation: None,
}, },
annotation: None, default: None,
}, },
default: None, ],
}, vararg: None,
], kwonlyargs: [],
vararg: None, kwarg: None,
kwonlyargs: [], },
kwarg: None, ),
},
body: Compare( body: Compare(
ExprCompare { ExprCompare {
range: 521..535, range: 521..535,