Skip to content

Commit bc8cb90

Browse files
authored
Merge branch 'master' into experiments/typecheck-unreachable
2 parents f7f8915 + 12aa642 commit bc8cb90

File tree

92 files changed

+3939
-951
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3939
-951
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ jobs:
167167
echo debug build; python -c 'import sysconfig; print(bool(sysconfig.get_config_var("Py_DEBUG")))'
168168
echo os.cpu_count; python -c 'import os; print(os.cpu_count())'
169169
echo os.sched_getaffinity; python -c 'import os; print(len(getattr(os, "sched_getaffinity", lambda *args: [])(0)))'
170-
pip install setuptools==75.1.0 tox==4.21.2
170+
pip install tox==4.21.2
171171
172172
- name: Compiled with mypyc
173173
if: ${{ matrix.test_mypyc }}
@@ -230,7 +230,7 @@ jobs:
230230
default: 3.11.1
231231
command: python -c "import platform; print(f'{platform.architecture()=} {platform.machine()=}');"
232232
- name: Install tox
233-
run: pip install setuptools==75.1.0 tox==4.21.2
233+
run: pip install tox==4.21.2
234234
- name: Setup tox environment
235235
run: tox run -e py --notest
236236
- name: Test

docs/source/config_file.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ Platform configuration
432432

433433
Specifies the Python version used to parse and check the target
434434
program. The string should be in the format ``MAJOR.MINOR`` --
435-
for example ``2.7``. The default is the version of the Python
435+
for example ``3.9``. The default is the version of the Python
436436
interpreter used to run mypy.
437437

438438
This option may only be set in the global section (``[mypy]``).
@@ -1196,7 +1196,7 @@ of your repo (or append it to the end of an existing ``pyproject.toml`` file) an
11961196
# mypy global options:
11971197
11981198
[tool.mypy]
1199-
python_version = "2.7"
1199+
python_version = "3.9"
12001200
warn_return_any = true
12011201
warn_unused_configs = true
12021202
exclude = [

mypy/argmap.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,8 @@ def expand_actual_type(
249249
formal_name = (set(actual_type.items.keys()) - self.kwargs_used).pop()
250250
self.kwargs_used.add(formal_name)
251251
return actual_type.items[formal_name]
252-
elif (
253-
isinstance(actual_type, Instance)
254-
and len(actual_type.args) > 1
255-
and is_subtype(actual_type, self.context.mapping_type)
252+
elif isinstance(actual_type, Instance) and is_subtype(
253+
actual_type, self.context.mapping_type
256254
):
257255
# Only `Mapping` type can be unpacked with `**`.
258256
# Other types will produce an error somewhere else.

mypy/binder.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
from typing_extensions import TypeAlias as _TypeAlias
88

99
from mypy.erasetype import remove_instance_last_known_values
10-
from mypy.literals import Key, literal, literal_hash, subkeys
10+
from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash, subkeys
1111
from mypy.nodes import Expression, IndexExpr, MemberExpr, NameExpr, RefExpr, TypeInfo, Var
12+
from mypy.options import Options
1213
from mypy.subtypes import is_same_type, is_subtype
1314
from mypy.typeops import make_simplified_union
1415
from mypy.types import (
@@ -40,6 +41,7 @@ class CurrentType(NamedTuple):
4041

4142
class Frame:
4243
"""A Frame represents a specific point in the execution of a program.
44+
4345
It carries information about the current types of expressions at
4446
that point, arising either from assignments to those expressions
4547
or the result of isinstance checks and other type narrowing
@@ -99,7 +101,7 @@ class A:
99101
# This maps an expression to a list of bound types for every item in the union type.
100102
type_assignments: Assigns | None = None
101103

102-
def __init__(self) -> None:
104+
def __init__(self, options: Options) -> None:
103105
# Each frame gets an increasing, distinct id.
104106
self.next_id = 1
105107

@@ -133,6 +135,11 @@ def __init__(self) -> None:
133135
self.break_frames: list[int] = []
134136
self.continue_frames: list[int] = []
135137

138+
# If True, initial assignment to a simple variable (e.g. "x", but not "x.y")
139+
# is added to the binder. This allows more precise narrowing and more
140+
# flexible inference of variable types (--allow-redefinition-new).
141+
self.bind_all = options.allow_redefinition_new
142+
136143
def _get_id(self) -> int:
137144
self.next_id += 1
138145
return self.next_id
@@ -238,12 +245,20 @@ def update_from_options(self, frames: list[Frame]) -> bool:
238245
for key in keys:
239246
current_value = self._get(key)
240247
resulting_values = [f.types.get(key, current_value) for f in frames]
241-
if any(x is None for x in resulting_values):
248+
# Keys can be narrowed using two different semantics. The new semantics
249+
# is enabled for plain variables when bind_all is true, and it allows
250+
# variable types to be widened using subsequent assignments. This is
251+
# tricky to support for instance attributes (primarily due to deferrals),
252+
# so we don't use it for them.
253+
old_semantics = not self.bind_all or extract_var_from_literal_hash(key) is None
254+
if old_semantics and any(x is None for x in resulting_values):
242255
# We didn't know anything about key before
243256
# (current_value must be None), and we still don't
244257
# know anything about key in at least one possible frame.
245258
continue
246259

260+
resulting_values = [x for x in resulting_values if x is not None]
261+
247262
if all_reachable and all(
248263
x is not None and not x.from_assignment for x in resulting_values
249264
):
@@ -290,7 +305,11 @@ def update_from_options(self, frames: list[Frame]) -> bool:
290305
# still equivalent to such type).
291306
if isinstance(type, UnionType):
292307
type = collapse_variadic_union(type)
293-
if isinstance(type, ProperType) and isinstance(type, UnionType):
308+
if (
309+
old_semantics
310+
and isinstance(type, ProperType)
311+
and isinstance(type, UnionType)
312+
):
294313
# Simplify away any extra Any's that were added to the declared
295314
# type when popping a frame.
296315
simplified = UnionType.make_union(

mypy/build.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,8 +2240,10 @@ def semantic_analysis_pass1(self) -> None:
22402240
# TODO: Do this while constructing the AST?
22412241
self.tree.names = SymbolTable()
22422242
if not self.tree.is_stub:
2243-
# Always perform some low-key variable renaming
2244-
self.tree.accept(LimitedVariableRenameVisitor())
2243+
if not self.options.allow_redefinition_new:
2244+
# Perform some low-key variable renaming when assignments can't
2245+
# widen inferred types
2246+
self.tree.accept(LimitedVariableRenameVisitor())
22452247
if options.allow_redefinition:
22462248
# Perform more renaming across the AST to allow variable redefinitions
22472249
self.tree.accept(VariableRenameVisitor())

0 commit comments

Comments
 (0)