Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-39235: Fix end location for genexp in call args #17925

Merged
merged 2 commits into from Jan 9, 2020

Conversation

@gvanrossum
Copy link
Member

gvanrossum commented Jan 9, 2020

The fix changes copy_location() to require an extra node from which to extract the end location, and fixing all 5 call sites.

https://bugs.python.org/issue39235

Automerge-Triggered-By: @gvanrossum

@@ -3146,7 +3146,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func,
}
else if (TYPE(CHILD(ch, 1)) == comp_for) {
/* the lone generator expression */
e = copy_location(ast_for_genexp(c, ch), maybegenbeg);
e = copy_location(ast_for_genexp(c, ch), maybegenbeg, closepar);

This comment has been minimized.

Copy link
@lysnikolaou

lysnikolaou Jan 9, 2020

Contributor

Note that if maybegenbeg and closepar are passed here and used as start and end line/col info we will need to work around this in pegen, since the parser there does not consider the parentheses part of the generator expression and uses its first and last character for the node metadata.

This comment has been minimized.

Copy link
@gvanrossum

gvanrossum Jan 9, 2020

Author Member

Clearly this is the intention of the original code -- it started out pointing the start location to the open parenthesis. This is apparently so that the location for a genexp node always includes the surrounding parentheses -- which are considered part of the syntax (just like for a list comprehension the [...] are considered part of the syntax).

There is some discussion of this in bpo-31241 (though not for function calls).

We can probably handle this in pegen by writing a separate bit of function call syntax, e.g.

    | ...
    | primary lone_genexp
    | primary '(' [arguments] ')'
    | ...
lone_genexp:
    | '(' expression for_if_clauses ')'

(We'll need a similar thing for call_tail in the targets section.)

@pablogsal

This comment has been minimized.

Copy link
Member

pablogsal commented Jan 9, 2020

Could you add some tests to Lib/test_ast.py? Something like:

index 55b91cfa23..e72df9b64d 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -235,7 +235,8 @@ eval_tests = [
   "()",
   # Combination
   "a.b.c.d(a.b[1:2])",
-
+  # Function call with generator expr
+  "f(x for x in y)",
 ]

 # TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension
@@ -879,6 +880,13 @@ Module(
         self.assertEqual(elif_stmt.lineno, 3)
         self.assertEqual(elif_stmt.col_offset, 0)

+    def test_generatorexp_inside_call_col_offsets(self):
+        expression = 'func(x for x in y)'
+        node = ast.parse(expression)
+        genexp = node.body[0].value.args[0]
+        genexp_str = expression[genexp.col_offset:genexp.end_col_offset]
+        self.assertEqual(genexp_str, '(x for x in y)')
+
     def test_starred_expr_end_position_within_call(self):
         node = ast.parse('f(*[0, 1])')
         starred_expr = node.body[0].value.args[0]
@@ -1952,5 +1960,6 @@ eval_results = [
 ('Expression', ('Tuple', (1, 0), [('Constant', (1, 1), 1, None), ('Constant', (1, 3), 2, None), ('Constant', (1, 5), 3, None)], ('Load',))),
 ('Expression', ('Tuple', (1, 0), [], ('Load',))),
 ('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Constant', (1, 12), 1, None), ('Constant', (1, 14), 2, None), None), ('Load',))], [])),
+('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('GeneratorExp', (1, 1), ('Name', (1, 2), 'x', ('Load',)), [('comprehension', ('Name', (1, 8), 'x', ('Store',)), ('Name', (1, 13), 'y', ('Load',)), [], 0)])], [])),
 ]
 main()
Copy link
Member

serhiy-storchaka left a comment

LGTM.

As for tests, I can change existing tests to catch this error in separate PR.

@serhiy-storchaka

This comment has been minimized.

Copy link
Member

serhiy-storchaka commented Jan 9, 2020

I propose to merge this PR without tests and backport it to 3.8. Then merge tests in #17926 without backporting them, because I am not sure that all other end positions are calculated correctly and do not want to break alternate implementations which do it correctly.

@gvanrossum

This comment has been minimized.

Copy link
Member Author

gvanrossum commented Jan 9, 2020

@pablogsal Given GH-17926 should I still add the test you suggested?

@lysnikolaou

This comment has been minimized.

Copy link
Contributor

lysnikolaou commented Jan 9, 2020

Yes, backporting this is the only way since we need it for pegen, but there is a strong need to document these changes somewhere, because they could break code, like @asottile mentions in #17582.

I'm not sure if just the news entry is enough.

@miss-islington miss-islington merged commit a796d8e into master Jan 9, 2020
9 checks passed
9 checks passed
Docs
Details
Windows (x86)
Details
Windows (x64)
Details
macOS
Details
Ubuntu
Details
Azure Pipelines PR #20200109.29 succeeded
Details
bedevere/issue-number Issue number 39235 found
Details
bedevere/news News entry found in Misc/NEWS.d
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@miss-islington miss-islington deleted the bpo-39235-genexp-endloc branch Jan 9, 2020
@miss-islington

This comment has been minimized.

Copy link

miss-islington commented Jan 9, 2020

Thanks @gvanrossum for the PR 🌮🎉.. I'm working now to backport this PR to: 3.8.
🐍🍒🤖

miss-islington added a commit to miss-islington/cpython that referenced this pull request Jan 9, 2020
The fix changes copy_location() to require an extra node from which to extract the end location, and fixing all 5 call sites.

https://bugs.python.org/issue39235
(cherry picked from commit a796d8e)

Co-authored-by: Guido van Rossum <guido@python.org>
@bedevere-bot

This comment has been minimized.

Copy link

bedevere-bot commented Jan 9, 2020

GH-17927 is a backport of this pull request to the 3.8 branch.

miss-islington added a commit that referenced this pull request Jan 9, 2020
The fix changes copy_location() to require an extra node from which to extract the end location, and fixing all 5 call sites.

https://bugs.python.org/issue39235
(cherry picked from commit a796d8e)

Co-authored-by: Guido van Rossum <guido@python.org>
@pablogsal

This comment has been minimized.

Copy link
Member

pablogsal commented Jan 9, 2020

@pablogsal Given GH-17926 should I still add the test you suggested?

I am fine as with GH-17926 we will be able to detect if a future change breaks/changes what this PR is fixing.

sthagen added a commit to sthagen/cpython that referenced this pull request Jan 10, 2020
bpo-39235: Fix end location for genexp in call args (pythonGH-17925)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.