Skip to content

Conversation

@11happy
Copy link
Contributor

@11happy 11happy commented Dec 1, 2025

Summary

Parses ** Doublestar as power op without lhs, Part of #10653, referred discussion #10636 (comment)

Test Plan

test case :

{x: **y for x, y in data}

ruff-dev output before:

Error: Expected an expression at byte range 4..6

Caused by:
    Expected an expression

ruff-dev output ast after:

Module(
    ModModule {
        node_index: NodeIndex(None),
        range: 0..25,
        body: [
            Expr(
                StmtExpr {
                    node_index: NodeIndex(None),
                    range: 0..25,
                    value: DictComp(
                        ExprDictComp {
                            node_index: NodeIndex(None),
                            range: 0..25,
                            key: Name(
                                ExprName {
                                    node_index: NodeIndex(None),
                                    range: 1..2,
                                    id: Name("x"),
                                    ctx: Load,
                                },
                            ),
                            value: BinOp(
                                ExprBinOp {
                                    node_index: NodeIndex(None),
                                    range: 4..7,
                                    left: Name(
                                        ExprName {
                                            node_index: NodeIndex(None),
                                            range: 7..7,
                                            id: Name(""),
                                            ctx: Invalid,
                                        },
                                    ),
                                    op: Pow,
                                    right: Name(
                                        ExprName {
                                            node_index: NodeIndex(None),
                                            range: 6..7,
                                            id: Name("y"),
                                            ctx: Load,
                                        },
                                    ),
                                },
                            ),
                            generators: [
                                Comprehension {
                                    range: 8..24,
                                    node_index: NodeIndex(None),
                                    target: Tuple(
                                        ExprTuple {
                                            node_index: NodeIndex(None),
                                            range: 12..16,
                                            elts: [
                                                Name(
                                                    ExprName {
                                                        node_index: NodeIndex(None),
                                                        range: 12..13,
                                                        id: Name("x"),
                                                        ctx: Store,
                                                    },
                                                ),
                                                Name(
                                                    ExprName {
                                                        node_index: NodeIndex(None),
                                                        range: 15..16,
                                                        id: Name("y"),
                                                        ctx: Store,
                                                    },
                                                ),
                                            ],
                                            ctx: Store,
                                            parenthesized: false,
                                        },
                                    ),
                                    iter: Name(
                                        ExprName {
                                            node_index: NodeIndex(None),
                                            range: 20..24,
                                            id: Name("data"),
                                            ctx: Load,
                                        },
                                    ),
                                    ifs: [],
                                    is_async: false,
                                },
                            ],
                        },
                    ),
                },
            ),
        ],
    },
)


Signed-off-by: 11happy <[email protected]>
@astral-sh-bot
Copy link

astral-sh-bot bot commented Dec 1, 2025

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+1 -0 violations, +0 -0 fixes in 1 projects; 54 projects unchanged)

apache/superset (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --no-preview --select ALL

+ superset/config.py:262:1: ERA001 Found commented-out code

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
ERA001 1 1 0 0 0

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+1 -0 violations, +0 -0 fixes in 1 projects; 54 projects unchanged)

apache/superset (+1 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview --select ALL

+ superset/config.py:262:1: ERA001 Found commented-out code

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
ERA001 1 1 0 0 0

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding a few parser tests that demonstrate that the new recovery logic works as expected?

E.g., the ecosystem changes suggest that we:

a) Fail to emit a diagnostic in that case
b) or we now use this code path for **kwargs when we shouldn't

@MichaReiser MichaReiser added the parser Related to the parser label Dec 1, 2025
Signed-off-by: 11happy <[email protected]>
@11happy
Copy link
Contributor Author

11happy commented Dec 2, 2025

Would you mind adding a few parser tests that demonstrate that the new recovery logic works as expected?

E.g., the ecosystem changes suggest that we:

a) Fail to emit a diagnostic in that case
b) or we now use this code path for **kwargs when we shouldn't

I have added tests & I think its not the option b, I would appreciate any pointers to move forward

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind changing your PR to use the testing infrastructure described here

Can you also add an example where there's some content to the right, e.g. ** a + 3 * 2

Comment on lines +366 to +382
TokenKind::DoubleStar => {
self.bump(TokenKind::DoubleStar);
let right =
self.parse_binary_expression_or_higher(OperatorPrecedence::Exponent, context);
return Expr::BinOp(ast::ExprBinOp {
left: Box::new(Expr::Name(ast::ExprName {
range: self.missing_node_range(),
id: Name::empty(),
ctx: ExprContext::Invalid,
node_index: AtomicNodeIndex::NONE,
})),
op: Operator::Pow,
right: Box::new(right.expr),
range: self.node_range(start),
node_index: AtomicNodeIndex::NONE,
})
.into();
Copy link
Member

@MichaReiser MichaReiser Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is the right place for the fix. Would it be possible to add it to parse_binary_expression_or_higher or even in parse_binary_expression_or_higher_recursive? If not, can you explain why?

Moving it their would give you the diagnostic for free

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parser Related to the parser

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants