ruff/crates/ruff_python_parser/resources/inline/ok
Dhruv Manilawala 978909fcf4
Raise syntax error for unparenthesized generator expr in multi-argument call (#12445)
## Summary

This PR fixes a bug to raise a syntax error when an unparenthesized
generator expression is used as an argument to a call when there are
more than one argument.

For reference, the grammar is:
```
primary:
    | ...
    | primary genexp 
    | primary '(' [arguments] ')' 
    | ...

genexp:
    | '(' ( assignment_expression | expression !':=') for_if_clauses ')' 
```

The `genexp` requires the parenthesis as mentioned in the grammar. So,
the grammar for a call expression is either a name followed by a
generator expression or a name followed by a list of argument. In the
former case, the parenthesis are excluded because the generator
expression provides them while in the later case, the parenthesis are
explicitly provided for a list of arguments which means that the
generator expression requires it's own parenthesis.

This was discovered in https://github.com/astral-sh/ruff/issues/12420.

## Test Plan

Add test cases for valid and invalid syntax.

Make sure that the parser from CPython also raises this at the parsing
step:
```console
$ python3.13 -m ast parser/_.py
  File "parser/_.py", line 1
    total(1, 2, x for x in range(5), 6)
                ^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized

$ python3.13 -m ast parser/_.py
  File "parser/_.py", line 1
    sum(x for x in range(10), 10)
        ^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
```
2024-07-22 14:44:20 +05:30
..
ambiguous_lpar_with_items_binary_expr.py
ambiguous_lpar_with_items_if_expr.py
ann_assign_stmt_simple_target.py
args_unparenthesized_generator.py
assign_targets_terminator.py
async_for_statement.py
async_function_definition.py
async_with_statement.py
class_def_arguments.py
comma_separated_regular_list_terminator.py
decorator_async_function.py
del_targets_terminator.py
dotted_name_normalized_spaces.py
except_stmt_as_name_soft_keyword.py
for_in_target_valid_expr.py
from_import_no_space.py
from_import_soft_keyword_module_name.py
from_import_stmt_terminator.py
fstring_format_spec_terminator.py
function_def_parameter_range.py
function_def_parenthesized_return_types.py
function_def_valid_return_expr.py
global_stmt.py
import_as_name_soft_keyword.py
import_stmt_terminator.py
lambda_with_no_parameters.py
lambda_with_valid_body.py
match_as_pattern.py
match_as_pattern_soft_keyword.py
match_attr_pattern_soft_keyword.py
match_classify_as_identifier_1.py
match_classify_as_identifier_2.py
match_classify_as_keyword_1.py
match_classify_as_keyword_2.py
match_classify_as_keyword_or_identifier.py
match_sequence_pattern_parentheses_terminator.py
match_sequence_pattern_terminator.py
match_stmt_subject_expr.py
match_stmt_valid_guard_expr.py
nonlocal_stmt.py
param_with_annotation.py
param_with_default.py
param_with_star_annotation.py
params_non_default_after_star.py
params_seen_keyword_only_param_after_star.py
simple_stmts_in_block.py
simple_stmts_with_semicolons.py
type_param_param_spec.py
type_param_type_var.py
type_param_type_var_tuple.py