diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 14650b1b5242..1cd40d474966 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -6012,6 +6012,9 @@ def visit_dictionary_comprehension(self, e: DictionaryComprehension) -> Type: name="", variables=[ktdef, vtdef], ) + if e.key is None: + self.chk.fail("PEP 798 is not supported yet", e) + return AnyType(TypeOfAny.from_error) return self.check_call( constructor, [e.key, e.value], [nodes.ARG_POS, nodes.ARG_POS], e )[0] diff --git a/mypy/nativeparse.py b/mypy/nativeparse.py index cd74f81b1d91..093f50f59e31 100644 --- a/mypy/nativeparse.py +++ b/mypy/nativeparse.py @@ -295,7 +295,7 @@ def parse_to_binary_ast( platform=options.platform, always_true=options.always_true, always_false=options.always_false, - cache_version=3, + cache_version=4, ) return ( ast_bytes, @@ -1564,7 +1564,11 @@ def read_expression(state: State, data: ReadBuffer) -> Expression: expect_end_tag(data) return expr elif tag == nodes.DICT_COMPREHENSION: - key = read_expression(state, data) + has_key = read_bool(data) + if has_key: + key = read_expression(state, data) + else: + key = None value = read_expression(state, data) n_generators = read_int(data) indices = [read_expression(state, data) for _ in range(n_generators)] @@ -1573,6 +1577,9 @@ def read_expression(state: State, data: ReadBuffer) -> Expression: is_async = [read_bool(data) for _ in range(n_generators)] expr = DictionaryComprehension(key, value, indices, sequences, condlists, is_async) read_loc(data, expr) + if key is None: + # TODO: add similar check to other kinds of comprehensions. + state.check_min_version("Unpacking in comprehensions", (3, 15), expr.line, expr.column) expect_end_tag(data) return expr elif tag == nodes.SET_COMPREHENSION: diff --git a/mypy/nodes.py b/mypy/nodes.py index cbeda29ec74a..53efc1fbc86b 100644 --- a/mypy/nodes.py +++ b/mypy/nodes.py @@ -3066,7 +3066,7 @@ class DictionaryComprehension(Expression): __match_args__ = ("key", "value", "indices", "sequences", "condlists") - key: Expression + key: Expression | None value: Expression sequences: list[Expression] condlists: list[list[Expression]] @@ -3075,7 +3075,7 @@ class DictionaryComprehension(Expression): def __init__( self, - key: Expression, + key: Expression | None, value: Expression, indices: list[Lvalue], sequences: list[Expression], diff --git a/mypy/semanal.py b/mypy/semanal.py index cd1b0a738974..bceade1b1ac1 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -6461,7 +6461,8 @@ def visit_dictionary_comprehension(self, expr: DictionaryComprehension) -> None: with self.enter(expr): self.analyze_comp_for(expr) - expr.key.accept(self) + if expr.key is not None: + expr.key.accept(self) expr.value.accept(self) self.analyze_comp_for_2(expr) diff --git a/mypy/traverser.py b/mypy/traverser.py index 6fdb54298f85..224d3b3460eb 100644 --- a/mypy/traverser.py +++ b/mypy/traverser.py @@ -363,7 +363,8 @@ def visit_dictionary_comprehension(self, o: DictionaryComprehension, /) -> None: index.accept(self) for cond in conditions: cond.accept(self) - o.key.accept(self) + if o.key is not None: + o.key.accept(self) o.value.accept(self) def visit_list_comprehension(self, o: ListComprehension, /) -> None: diff --git a/mypy/treetransform.py b/mypy/treetransform.py index 25092de66a14..c5e1ad44ea4c 100644 --- a/mypy/treetransform.py +++ b/mypy/treetransform.py @@ -628,7 +628,7 @@ def visit_dictionary_comprehension( self, node: DictionaryComprehension ) -> DictionaryComprehension: return DictionaryComprehension( - self.expr(node.key), + self.optional_expr(node.key), self.expr(node.value), [self.expr(index) for index in node.indices], [self.expr(s) for s in node.sequences], diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py index 91e1e55d8da2..6681fcd0825a 100644 --- a/mypyc/irbuild/expression.py +++ b/mypyc/irbuild/expression.py @@ -1419,7 +1419,11 @@ def _dict_comp_body(builder: IRBuilder, o: DictionaryComprehension) -> Value: loop_params = list(zip(o.indices, o.sequences, o.condlists, o.is_async)) def gen_inner_stmts() -> None: - k = builder.accept(o.key) + if o.key is not None: + k = builder.accept(o.key) + else: + builder.error("PEP 798 is not supported yet", o.line) + k = builder.none() v = builder.accept(o.value) builder.call_c(exact_dict_set_item_op, [builder.read(d, o.line), k, v], o.line) diff --git a/mypyc/irbuild/prebuildvisitor.py b/mypyc/irbuild/prebuildvisitor.py index b99a588c34d2..0f2aa7c1c91e 100644 --- a/mypyc/irbuild/prebuildvisitor.py +++ b/mypyc/irbuild/prebuildvisitor.py @@ -43,7 +43,8 @@ def _comprehension_has_lambda(node: GeneratorExpr | DictionaryComprehension) -> if isinstance(node, GeneratorExpr): node.left_expr.accept(checker) else: - node.key.accept(checker) + if node.key is not None: + node.key.accept(checker) node.value.accept(checker) for conds in node.condlists: for cond in conds: