Skip to content

Commit b10d781

Browse files
authored
Fix re-processing cross-reference when node kind changes (#17883)
This is quite a bad bug. Currently we rely on `SymbolNode` being updated in-place for all indirect references, but this is not the case when node kind (`FuncDef`, `Decorator`, etc.) changes, in this case a _new_ `SymbolNode` is created. I fix this by forcing reprocessing if the node kind changes. This currently blocks support for PEP 702, see #17476, so I will not wait for long before merging.
1 parent dfb7be1 commit b10d781

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed

mypy/server/astdiff.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ def snapshot_symbol_table(name_prefix: str, table: SymbolTable) -> dict[str, Sym
219219
assert symbol.kind != UNBOUND_IMPORTED
220220
if node and get_prefix(node.fullname) != name_prefix:
221221
# This is a cross-reference to a node defined in another module.
222-
result[name] = ("CrossRef", common)
222+
# Include the node kind (FuncDef, Decorator, TypeInfo, ...), so that we will
223+
# reprocess when a *new* node is created instead of merging an existing one.
224+
result[name] = ("CrossRef", common, type(node).__name__)
223225
else:
224226
result[name] = snapshot_definition(node, common)
225227
return result

test-data/unit/fine-grained.test

+98
Original file line numberDiff line numberDiff line change
@@ -10573,3 +10573,101 @@ m.py:9: error: Argument 1 to "foo" has incompatible type "int"; expected "str"
1057310573
m.py:9: error: Argument 2 to "foo" has incompatible type "str"; expected "int"
1057410574
m.py:10: error: Unexpected keyword argument "a" for "foo"
1057510575
partial.py:4: note: "foo" defined here
10576+
10577+
[case testReplaceFunctionWithDecoratedFunctionIndirect]
10578+
from b import f
10579+
x: int = f()
10580+
import b
10581+
y: int = b.f()
10582+
10583+
[file b.py]
10584+
from a import f
10585+
10586+
[file a.py]
10587+
def f() -> int: ...
10588+
10589+
[file a.py.2]
10590+
from typing import Callable
10591+
def d(t: Callable[[], str]) -> Callable[[], str]: ...
10592+
10593+
@d
10594+
def f() -> str: ...
10595+
10596+
[builtins fixtures/tuple.pyi]
10597+
[out]
10598+
==
10599+
main:2: error: Incompatible types in assignment (expression has type "str", variable has type "int")
10600+
main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int")
10601+
10602+
[case testReplaceFunctionWithDecoratedFunctionIndirect2]
10603+
from c import f
10604+
x: int = f()
10605+
import c
10606+
y: int = c.f()
10607+
10608+
[file c.py]
10609+
from b import f
10610+
10611+
[file b.py]
10612+
from a import f
10613+
10614+
[file a.py]
10615+
def f() -> int: ...
10616+
10617+
[file a.py.2]
10618+
from typing import Callable
10619+
def d(t: Callable[[], str]) -> Callable[[], str]: ...
10620+
10621+
@d
10622+
def f() -> str: ...
10623+
10624+
[builtins fixtures/tuple.pyi]
10625+
[out]
10626+
==
10627+
main:2: error: Incompatible types in assignment (expression has type "str", variable has type "int")
10628+
main:4: error: Incompatible types in assignment (expression has type "str", variable has type "int")
10629+
10630+
[case testReplaceFunctionWithClassIndirect]
10631+
from b import f
10632+
x: int = f()
10633+
import b
10634+
y: int = b.f()
10635+
10636+
[file b.py]
10637+
from a import f
10638+
10639+
[file a.py]
10640+
def f() -> int: ...
10641+
10642+
[file a.py.2]
10643+
class f: ...
10644+
10645+
[builtins fixtures/tuple.pyi]
10646+
[out]
10647+
==
10648+
main:2: error: Incompatible types in assignment (expression has type "f", variable has type "int")
10649+
main:4: error: Incompatible types in assignment (expression has type "f", variable has type "int")
10650+
10651+
[case testReplaceFunctionWithClassIndirect2]
10652+
from c import f
10653+
x: int = f()
10654+
import c
10655+
y: int = c.f()
10656+
10657+
[file c.py]
10658+
from b import f
10659+
10660+
[file b.py]
10661+
from a import f
10662+
10663+
[file a.py]
10664+
def f() -> int: ...
10665+
10666+
[file a.py.2]
10667+
class f: ...
10668+
10669+
[builtins fixtures/tuple.pyi]
10670+
[out]
10671+
==
10672+
main:2: error: Incompatible types in assignment (expression has type "f", variable has type "int")
10673+
main:4: error: Incompatible types in assignment (expression has type "f", variable has type "int")

0 commit comments

Comments
 (0)