Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for Literal types with incremental and fine-grained mode #6075

Merged
9 changes: 7 additions & 2 deletions mypy/server/astmerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,12 @@ def replace_statements(self, nodes: List[Statement]) -> List[Statement]:


class TypeReplaceVisitor(SyntheticTypeVisitor[None]):
"""Similar to NodeReplaceVisitor, but for type objects."""
"""Similar to NodeReplaceVisitor, but for type objects.
Note: this visitor may sometimes visit unanalyzed types
such as 'UnboundType' and 'RawLiteralType' For example, see
NodeReplaceVisitor.process_base_func.
"""

def __init__(self, replacements: Dict[SymbolNode, SymbolNode]) -> None:
self.replacements = replacements
Expand Down Expand Up @@ -393,7 +398,7 @@ def visit_typeddict_type(self, typ: TypedDictType) -> None:
typ.fallback.accept(self)

def visit_raw_literal_type(self, t: RawLiteralType) -> None:
assert False, "Unexpected RawLiteralType after semantic analysis phase"
pass

def visit_literal_type(self, typ: LiteralType) -> None:
typ.fallback.accept(self)
Expand Down
1 change: 1 addition & 0 deletions mypy/test/testmerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
'contextlib',
'sys',
'mypy_extensions',
'typing_extensions',
'enum',
)

Expand Down
14 changes: 14 additions & 0 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -4890,3 +4890,17 @@ python_version=3.6
[out]
[out2]
tmp/a.py:2: error: Incompatible types in assignment (expression has type "int", variable has type "str")

[case testLiteralIncrementalTurningIntoLiteral]
import mod
reveal_type(mod.a)
[file mod.py]
from typing_extensions import Literal
a = 1
[file mod.py.2]
from typing_extensions import Literal
a: Literal[2] = 2
[out]
main:2: error: Revealed type is 'builtins.int'
[out2]
main:2: error: Revealed type is 'Literal[2]'
16 changes: 16 additions & 0 deletions test-data/unit/deps-expressions.test
Original file line number Diff line number Diff line change
Expand Up @@ -448,3 +448,19 @@ def g() -> None:
[out]
<m.f1> -> m.g
<m.f2> -> m.g

[case testLiteralDepsExpr]
from typing_extensions import Literal

Alias = Literal[1]

a: Alias
b = a
def f(x: Alias) -> None: pass
def g() -> Literal[1]:
return b
[out]
<m.Alias> -> m, m.f
<m.a> -> m
<m.b> -> m, m.g
<typing_extensions.Literal> -> m
299 changes: 299 additions & 0 deletions test-data/unit/diff.test
Original file line number Diff line number Diff line change
Expand Up @@ -1109,3 +1109,302 @@ plugins=<ROOT>/test-data/unit/plugins/dyn_class.py
[out]
__main__.Diff
__main__.Diff.x

[case testLiteralTriggersVar]
from typing_extensions import Literal

x: Literal[1] = 1
y = 1
z: Literal[1] = 1
same: Literal[1] = 1
class C:
x_class: Literal[1] = 1
y_class = 1
z_class: Literal[1] = 1
same_class: Literal[1] = 1
def __init__(self) -> None:
self.x_instance: Literal[1] = 1
self.y_instance = 1
self.z_instance: Literal[1] = 1
self.same_instance: Literal[1] = 1

[file next.py]
from typing_extensions import Literal

x = 1
y: Literal[1] = 1
z: Literal[2] = 2
same: Literal[1] = 1
class C:
x_class = 1
y_class: Literal[1] = 1
z_class: Literal[2] = 2
same_class: Literal[1] = 1
def __init__(self) -> None:
self.x_instance = 1
self.y_instance: Literal[1] = 1
self.z_instance: Literal[2] = 2
self.same_instance: Literal[1] = 1
[out]
__main__.C.x_class
__main__.C.x_instance
__main__.C.y_class
__main__.C.y_instance
__main__.C.z_class
__main__.C.z_instance
__main__.x
__main__.y
__main__.z

[case testLiteralTriggersFunctions]
from typing_extensions import Literal

def function_1() -> int: pass
def function_2() -> Literal[1]: pass
def function_3() -> Literal[1]: pass

def function_4(x: int) -> None: pass
def function_5(x: Literal[1]) -> None: pass
def function_6(x: Literal[1]) -> None: pass

def function_same_1() -> Literal[1]: pass
def function_same_2(x: Literal[1]) -> None: pass

class C:
def method_1(self) -> int: pass
def method_2(self) -> Literal[1]: pass
def method_3(self) -> Literal[1]: pass

def method_4(self, x: int) -> None: pass
def method_5(self, x: Literal[1]) -> None: pass
def method_6(self, x: Literal[1]) -> None: pass

def method_same_1(self) -> Literal[1]: pass
def method_same_2(self, x: Literal[1]) -> None: pass

@classmethod
def classmethod_1(cls) -> int: pass
@classmethod
def classmethod_2(cls) -> Literal[1]: pass
@classmethod
def classmethod_3(cls) -> Literal[1]: pass

@classmethod
def classmethod_4(cls, x: int) -> None: pass
@classmethod
def classmethod_5(cls, x: Literal[1]) -> None: pass
@classmethod
def classmethod_6(cls, x: Literal[1]) -> None: pass

@classmethod
def classmethod_same_1(cls) -> Literal[1]: pass
@classmethod
def classmethod_same_2(cls, x: Literal[1]) -> None: pass

@staticmethod
def staticmethod_1() -> int: pass
@staticmethod
def staticmethod_2() -> Literal[1]: pass
@staticmethod
def staticmethod_3() -> Literal[1]: pass

@staticmethod
def staticmethod_4(x: int) -> None: pass
@staticmethod
def staticmethod_5(x: Literal[1]) -> None: pass
@staticmethod
def staticmethod_6(x: Literal[1]) -> None: pass

@staticmethod
def staticmethod_same_1() -> Literal[1]: pass
@staticmethod
def staticmethod_same_2(x: Literal[1]) -> None: pass

[file next.py]
from typing_extensions import Literal

def function_1() -> Literal[1]: pass
def function_2() -> int: pass
def function_3() -> Literal[2]: pass

def function_4(x: Literal[1]) -> None: pass
def function_5(x: int) -> None: pass
def function_6(x: Literal[2]) -> None: pass

def function_same_1() -> Literal[1]: pass
def function_same_2(x: Literal[1]) -> None: pass

class C:
def method_1(self) -> Literal[1]: pass
def method_2(self) -> int: pass
def method_3(self) -> Literal[2]: pass

def method_4(self, x: Literal[1]) -> None: pass
def method_5(self, x: int) -> None: pass
def method_6(self, x: Literal[2]) -> None: pass

def method_same_1(self) -> Literal[1]: pass
def method_same_2(self, x: Literal[1]) -> None: pass

@classmethod
def classmethod_1(cls) -> Literal[1]: pass
@classmethod
def classmethod_2(cls) -> int: pass
@classmethod
def classmethod_3(cls) -> Literal[2]: pass

@classmethod
def classmethod_4(cls, x: Literal[1]) -> None: pass
@classmethod
def classmethod_5(cls, x: int) -> None: pass
@classmethod
def classmethod_6(cls, x: Literal[2]) -> None: pass

@classmethod
def classmethod_same_1(cls) -> Literal[1]: pass
@classmethod
def classmethod_same_2(cls, x: Literal[1]) -> None: pass

@staticmethod
def staticmethod_1() -> Literal[1]: pass
@staticmethod
def staticmethod_2() -> int: pass
@staticmethod
def staticmethod_3() -> Literal[2]: pass

@staticmethod
def staticmethod_4(x: Literal[1]) -> None: pass
@staticmethod
def staticmethod_5(x: int) -> None: pass
@staticmethod
def staticmethod_6(x: Literal[2]) -> None: pass

@staticmethod
def staticmethod_same_1() -> Literal[1]: pass
@staticmethod
def staticmethod_same_2(x: Literal[1]) -> None: pass
[builtins fixtures/classmethod.pyi]
[out]
__main__.C.classmethod_1
__main__.C.classmethod_2
__main__.C.classmethod_3
__main__.C.classmethod_4
__main__.C.classmethod_5
__main__.C.classmethod_6
__main__.C.method_1
__main__.C.method_2
__main__.C.method_3
__main__.C.method_4
__main__.C.method_5
__main__.C.method_6
__main__.C.staticmethod_1
__main__.C.staticmethod_2
__main__.C.staticmethod_3
__main__.C.staticmethod_4
__main__.C.staticmethod_5
__main__.C.staticmethod_6
__main__.function_1
__main__.function_2
__main__.function_3
__main__.function_4
__main__.function_5
__main__.function_6

[case testLiteralTriggersProperty]
from typing_extensions import Literal

class C:
@property
def p1(self) -> Literal[1]: pass

@property
def p2(self) -> int: pass

@property
def same(self) -> Literal[1]: pass

[file next.py]
from typing_extensions import Literal

class C:
@property
def p1(self) -> int: pass

@property
def p2(self) -> Literal[1]: pass

@property
def same(self) -> Literal[1]: pass
[builtins fixtures/property.pyi]
[out]
__main__.C.p1
__main__.C.p2

[case testLiteralsTriggersOverload]
from typing import overload
from typing_extensions import Literal

@overload
def func(x: str) -> str: ...
@overload
def func(x: Literal[1]) -> int: ...
def func(x):
pass

@overload
def func_same(x: str) -> str: ...
@overload
def func_same(x: Literal[1]) -> int: ...
def func_same(x):
pass

class C:
@overload
def method(self, x: str) -> str: ...
@overload
def method(self, x: Literal[1]) -> int: ...
def method(self, x):
pass

@overload
def method_same(self, x: str) -> str: ...
@overload
def method_same(self, x: Literal[1]) -> int: ...
def method_same(self, x):
pass

[file next.py]
from typing import overload
from typing_extensions import Literal

@overload
def func(x: str) -> str: ...
@overload
def func(x: Literal[2]) -> int: ...
def func(x):
pass

@overload
def func_same(x: str) -> str: ...
@overload
def func_same(x: Literal[1]) -> int: ...
def func_same(x):
pass

class C:
@overload
def method(self, x: str) -> str: ...
@overload
def method(self, x: Literal[2]) -> int: ...
def method(self, x):
pass

@overload
def method_same(self, x: str) -> str: ...
@overload
def method_same(self, x: Literal[1]) -> int: ...
def method_same(self, x):
pass
[out]
__main__.C.method
__main__.func
Loading