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

Generator expression has wrong line/col info when inside a Call object #83416

Closed
lysnikolaou opened this issue Jan 6, 2020 · 9 comments
Closed
Labels
3.8 only security fixes 3.9 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error

Comments

@lysnikolaou
Copy link
Contributor

BPO 39235
Nosy @gvanrossum, @serhiy-storchaka, @lysnikolaou, @pablogsal, @miss-islington
PRs
  • bpo-39235: Fix end location for genexp in call args #17925
  • bpo-39235: Check end_lineno and end_col_offset of AST nodes. #17926
  • [3.8] bpo-39235: Fix end location for genexp in call args (GH-17925) #17927
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2020-01-10.08:15:16.778>
    created_at = <Date 2020-01-06.19:27:27.233>
    labels = ['interpreter-core', 'type-bug', '3.8', '3.9']
    title = 'Generator expression has wrong line/col info when inside a Call object'
    updated_at = <Date 2020-01-10.08:15:16.776>
    user = 'https://github.com/lysnikolaou'

    bugs.python.org fields:

    activity = <Date 2020-01-10.08:15:16.776>
    actor = 'serhiy.storchaka'
    assignee = 'none'
    closed = True
    closed_date = <Date 2020-01-10.08:15:16.778>
    closer = 'serhiy.storchaka'
    components = ['Interpreter Core']
    creation = <Date 2020-01-06.19:27:27.233>
    creator = 'lys.nikolaou'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 39235
    keywords = ['patch']
    message_count = 9.0
    messages = ['359454', '359455', '359456', '359458', '359690', '359692', '359693', '359708', '359709']
    nosy_count = 5.0
    nosy_names = ['gvanrossum', 'serhiy.storchaka', 'lys.nikolaou', 'pablogsal', 'miss-islington']
    pr_nums = ['17925', '17926', '17927']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue39235'
    versions = ['Python 3.8', 'Python 3.9']

    @lysnikolaou
    Copy link
    Contributor Author

    A normal generator expression like (i for i in a) produces the following AST:

    Module(
    body=[
    Expr(
    value=GeneratorExp(
    elt=Name(
    id="i", ctx=Load(), lineno=1, col_offset=1, end_lineno=1, end_col_offset=2
    ),
    generators=[
    comprehension(
    target=Name(
    id="i",
    ctx=Store(),
    lineno=1,
    col_offset=7,
    end_lineno=1,
    end_col_offset=8,
    ),
    iter=Name(
    id="a",
    ctx=Load(),
    lineno=1,
    col_offset=12,
    end_lineno=1,
    end_col_offset=13,
    ),
    ifs=[],
    is_async=0,
    )
    ],
    lineno=1,
    *col_offset=0,*
    end_lineno=1,
    *end_col_offset=14,*
    ),
    lineno=1,
    col_offset=0,
    end_lineno=1,
    end_col_offset=14,
    )
    ],
    type_ignores=[],
    )

    But when calling a function with a generator expression as an argument, something is off:

    Module(
    body=[
    Expr(
    value=Call(
    func=Name(
    id="f", ctx=Load(), lineno=1, col_offset=0, end_lineno=1, end_col_offset=1
    ),
    args=[
    GeneratorExp(
    elt=Name(
    id="i",
    ctx=Load(),
    lineno=1,
    col_offset=2,
    end_lineno=1,
    end_col_offset=3,
    ),
    generators=[
    comprehension(
    target=Name(
    id="i",
    ctx=Store(),
    lineno=1,
    col_offset=8,
    end_lineno=1,
    end_col_offset=9,
    ),
    iter=Name(
    id="a",
    ctx=Load(),
    lineno=1,
    col_offset=13,
    end_lineno=1,
    end_col_offset=14,
    ),
    ifs=[],
    is_async=0,
    )
    ],
    lineno=1,
    *col_offset=1,*
    end_lineno=1,
    *end_col_offset=2,*
    )
    ],
    keywords=[],
    lineno=1,
    col_offset=0,
    end_lineno=1,
    end_col_offset=15,
    ),
    lineno=1,
    col_offset=0,
    end_lineno=1,
    end_col_offset=15,
    )
    ],
    type_ignores=[],
    )

    I'm not sure if this is intentional or not, because there is a call to copy_location in Python/ast.c:3149. If this call to copy_location is removed, the inconsistency goes away.

    @lysnikolaou lysnikolaou added 3.7 (EOL) end of life 3.8 only security fixes 3.9 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error labels Jan 6, 2020
    @pablogsal
    Copy link
    Member

    I think that was introduced in https://bugs.python.org/issue31241

    @lysnikolaou
    Copy link
    Contributor Author

    Do you think it is okay to just remove the call to copy_location?

    @pablogsal
    Copy link
    Member

    Do you think it is okay to just remove the call to copy_location?

    I think that because in that case the parenthesis is collapsed with function call parenthesis, the position of the AST node for the generator expression should point to the left parenthesis.

    But I would suggest asking Serhiy (I added him to the noisy list) as he was the author of the PR.

    @gvanrossum
    Copy link
    Member

    OK, so I looked into this (sine we can't wait for Serhiy).

    The problem was probably introduced when Ivan added end lineno/column attributes to parse tree nodes. The offending copy_location() call copies the begin and end locations from the given node (maybegenbeg). But in the problematic case, maybegenbeg is just the left paren in the function call, not the node representing the surrounding () group.

    But there's a separate argument to ast_for_call(), closepar, that should be used for the end lineno/offset.

    Looking at the various calls to ast_for_call() in Python/ast.c, we find these:

    • ast_for_decorator -- passes the open and close parentheses- ast_for_trailer -- passes the open and close parentheses
    • ast_for_classdef -- passes NULL (because no genexpr allowed here)

    So instead of calling copy_location() we should manually set the begin and end positions.

    An alternative would be to add a second node* argument to copy_location(). That would require us to modify all 5 calls to it, but it still feels the better way to go. I'll see if I can produce a PR for that.

    @miss-islington
    Copy link
    Contributor

    New changeset a796d8e by Miss Islington (bot) (Guido van Rossum) in branch 'master':
    bpo-39235: Fix end location for genexp in call args (GH-17925)
    a796d8e

    @miss-islington
    Copy link
    Contributor

    New changeset 33e033d by Miss Islington (bot) in branch '3.8':
    bpo-39235: Fix end location for genexp in call args (GH-17925)
    33e033d

    @serhiy-storchaka
    Copy link
    Member

    New changeset 850a885 by Serhiy Storchaka in branch 'master':
    bpo-39235: Check end_lineno and end_col_offset of AST nodes. (GH-17926)
    850a885

    @serhiy-storchaka
    Copy link
    Member

    If somebody want to backport tests to 3.8, he must check manually all end positions.

    @serhiy-storchaka serhiy-storchaka removed the 3.7 (EOL) end of life label Jan 10, 2020
    @serhiy-storchaka serhiy-storchaka removed the 3.7 (EOL) end of life label Jan 10, 2020
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.8 only security fixes 3.9 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants