Skip to content

Commit 2da85ea

Browse files
committed
Merge remote-tracking branch 'upstream/master' into bugfix/st-synthetic-named-expr-in-match
2 parents b3ec408 + ee1f4c9 commit 2da85ea

File tree

9 files changed

+316
-97
lines changed

9 files changed

+316
-97
lines changed

CHANGELOG.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
### Performance improvements
66

7-
TODO
7+
Mypy may be 5-30% faster. This improvement comes largely from tuning the performance of the
8+
garbage collector.
9+
10+
Contributed by Jukka Lehtosalo (PR [18306](https://github.com/python/mypy/pull/18306)).
811

912
### Drop Support for Python 3.8
1013

@@ -33,13 +36,14 @@ Use this flag to disable this behavior. `--strict-bytes` will be enabled by defa
3336
Contributed by Ali Hamdan (PR [18137](https://github.com/python/mypy/pull/18263/)) and
3437
Shantanu Jain (PR [13952](https://github.com/python/mypy/pull/13952)).
3538

36-
### Improvements to partial type handling in loops
39+
### Improvements to reachability analysis and partial type handling in loops
3740

3841
This change results in mypy better modelling control flow within loops and hence detecting several
3942
issues it previously did not detect. In some cases, this change may require use of an additional
4043
explicit annotation of a variable.
4144

42-
Contributed by Christoph Tyralla (PR [18180](https://github.com/python/mypy/pull/18180)).
45+
Contributed by Christoph Tyralla (PR [18180](https://github.com/python/mypy/pull/18180),
46+
[PR](https://github.com/python/mypy/pull/18433)).
4347

4448
(Speaking of partial types, another reminder that mypy plans on enabling `--local-partial-types`
4549
by default in **mypy 2.0**).

docs/source/common_issues.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,8 @@ More specifically, mypy will understand the use of :py:data:`sys.version_info` a
427427
import sys
428428
429429
# Distinguishing between different versions of Python:
430-
if sys.version_info >= (3, 8):
431-
# Python 3.8+ specific definitions and imports
430+
if sys.version_info >= (3, 13):
431+
# Python 3.13+ specific definitions and imports
432432
else:
433433
# Other definitions and imports
434434

docs/source/runtime_troubles.rst

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -335,29 +335,25 @@ Using new additions to the typing module
335335
----------------------------------------
336336

337337
You may find yourself wanting to use features added to the :py:mod:`typing`
338-
module in earlier versions of Python than the addition, for example, using any
339-
of ``Literal``, ``Protocol``, ``TypedDict`` with Python 3.6.
338+
module in earlier versions of Python than the addition.
340339

341340
The easiest way to do this is to install and use the ``typing_extensions``
342341
package from PyPI for the relevant imports, for example:
343342

344343
.. code-block:: python
345344
346-
from typing_extensions import Literal
347-
x: Literal["open", "close"]
345+
from typing_extensions import TypeIs
348346
349347
If you don't want to rely on ``typing_extensions`` being installed on newer
350348
Pythons, you could alternatively use:
351349

352350
.. code-block:: python
353351
354352
import sys
355-
if sys.version_info >= (3, 8):
356-
from typing import Literal
353+
if sys.version_info >= (3, 13):
354+
from typing import TypeIs
357355
else:
358-
from typing_extensions import Literal
359-
360-
x: Literal["open", "close"]
356+
from typing_extensions import TypeIs
361357
362358
This plays nicely well with following :pep:`508` dependency specification:
363-
``typing_extensions; python_version<"3.8"``
359+
``typing_extensions; python_version<"3.13"``

mypy/checker.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -591,24 +591,43 @@ def accept_loop(
591591
*,
592592
exit_condition: Expression | None = None,
593593
) -> None:
594-
"""Repeatedly type check a loop body until the frame doesn't change.
595-
If exit_condition is set, assume it must be False on exit from the loop.
594+
"""Repeatedly type check a loop body until the frame doesn't change."""
596595

597-
Then check the else_body.
598-
"""
599-
# The outer frame accumulates the results of all iterations
596+
# The outer frame accumulates the results of all iterations:
600597
with self.binder.frame_context(can_skip=False, conditional_frame=True):
598+
599+
# Check for potential decreases in the number of partial types so as not to stop the
600+
# iteration too early:
601601
partials_old = sum(len(pts.map) for pts in self.partial_types)
602+
603+
# Disable error types that we cannot safely identify in intermediate iteration steps:
604+
warn_unreachable = self.options.warn_unreachable
605+
warn_redundant = codes.REDUNDANT_EXPR in self.options.enabled_error_codes
606+
self.options.warn_unreachable = False
607+
self.options.enabled_error_codes.discard(codes.REDUNDANT_EXPR)
608+
602609
while True:
603610
with self.binder.frame_context(can_skip=True, break_frame=2, continue_frame=1):
604611
self.accept(body)
605612
partials_new = sum(len(pts.map) for pts in self.partial_types)
606613
if (partials_new == partials_old) and not self.binder.last_pop_changed:
607614
break
608615
partials_old = partials_new
616+
617+
# If necessary, reset the modified options and make up for the postponed error checks:
618+
self.options.warn_unreachable = warn_unreachable
619+
if warn_redundant:
620+
self.options.enabled_error_codes.add(codes.REDUNDANT_EXPR)
621+
if warn_unreachable or warn_redundant:
622+
with self.binder.frame_context(can_skip=True, break_frame=2, continue_frame=1):
623+
self.accept(body)
624+
625+
# If exit_condition is set, assume it must be False on exit from the loop:
609626
if exit_condition:
610627
_, else_map = self.find_isinstance_check(exit_condition)
611628
self.push_type_map(else_map)
629+
630+
# Check the else body:
612631
if else_body:
613632
self.accept(else_body)
614633

@@ -2102,6 +2121,13 @@ def check_method_override_for_base_with_name(
21022121
if original_node and is_property(original_node):
21032122
original_type = get_property_type(original_type)
21042123

2124+
if isinstance(original_node, Var):
2125+
expanded_type = map_type_from_supertype(original_type, defn.info, base)
2126+
expanded_type = expand_self_type(
2127+
original_node, expanded_type, fill_typevars(defn.info)
2128+
)
2129+
original_type = get_proper_type(expanded_type)
2130+
21052131
if is_property(defn):
21062132
inner: FunctionLike | None
21072133
if isinstance(typ, FunctionLike):

mypy/checkpattern.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,8 @@ def should_self_match(self, typ: Type) -> bool:
713713
return False
714714

715715
def can_match_sequence(self, typ: ProperType) -> bool:
716+
if isinstance(typ, AnyType):
717+
return True
716718
if isinstance(typ, UnionType):
717719
return any(self.can_match_sequence(get_proper_type(item)) for item in typ.items)
718720
for other in self.non_sequence_match_types:
@@ -763,6 +765,8 @@ def construct_sequence_child(self, outer_type: Type, inner_type: Type) -> Type:
763765
or class T(Sequence[Tuple[T, T]]), there is no way any of those can map to Sequence[str].
764766
"""
765767
proper_type = get_proper_type(outer_type)
768+
if isinstance(proper_type, AnyType):
769+
return outer_type
766770
if isinstance(proper_type, UnionType):
767771
types = [
768772
self.construct_sequence_child(item, inner_type)
@@ -772,7 +776,6 @@ def construct_sequence_child(self, outer_type: Type, inner_type: Type) -> Type:
772776
return make_simplified_union(types)
773777
sequence = self.chk.named_generic_type("typing.Sequence", [inner_type])
774778
if is_subtype(outer_type, self.chk.named_type("typing.Sequence")):
775-
proper_type = get_proper_type(outer_type)
776779
if isinstance(proper_type, TupleType):
777780
proper_type = tuple_fallback(proper_type)
778781
assert isinstance(proper_type, Instance)

0 commit comments

Comments
 (0)