Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,26 @@ def _visit_func_def(self, defn: FuncDef) -> None:
if not self.set_original_def(symbol.node, defn):
# Report error.
self.check_no_global(defn.name(), defn, True)

# Analyze function signature and initializers in the first phase
# (at least this mirrors what happens at runtime).
with self.tvar_scope_frame(self.tvar_scope.method_frame()):
if defn.type:
self.check_classvar_in_signature(defn.type)
assert isinstance(defn.type, CallableType)
# Signature must be analyzed in the surrounding scope so that
# class-level imported names and type variables are in scope.
analyzer = self.type_analyzer()
defn.type = analyzer.visit_callable_type(defn.type, nested=False)
self.add_type_alias_deps(analyzer.aliases_used)
self.check_function_signature(defn)
if isinstance(defn, FuncDef):
assert isinstance(defn.type, CallableType)
defn.type = set_callable_name(defn.type, defn)
for arg in defn.arguments:
if arg.initializer:
arg.initializer.accept(self)

if phase_info == FUNCTION_FIRST_PHASE_POSTPONE_SECOND:
# Postpone this function (for the second phase).
self.postponed_functions_stack[-1].append(defn)
Expand Down Expand Up @@ -646,21 +666,6 @@ def analyze_property_with_multi_part_definition(self, defn: OverloadedFuncDef) -
def analyze_function(self, defn: FuncItem) -> None:
is_method = self.is_class_scope()
with self.tvar_scope_frame(self.tvar_scope.method_frame()):
if defn.type:
self.check_classvar_in_signature(defn.type)
assert isinstance(defn.type, CallableType)
# Signature must be analyzed in the surrounding scope so that
# class-level imported names and type variables are in scope.
analyzer = self.type_analyzer()
defn.type = analyzer.visit_callable_type(defn.type, nested=False)
self.add_type_alias_deps(analyzer.aliases_used)
self.check_function_signature(defn)
if isinstance(defn, FuncDef):
assert isinstance(defn.type, CallableType)
defn.type = set_callable_name(defn.type, defn)
for arg in defn.arguments:
if arg.initializer:
arg.initializer.accept(self)
# Bind the type variables again to visit the body.
if defn.type:
a = self.type_analyzer()
Expand Down
71 changes: 71 additions & 0 deletions test-data/unit/check-overloading.test
Original file line number Diff line number Diff line change
Expand Up @@ -4186,3 +4186,74 @@ def g(x: str) -> int: ...
[builtins fixtures/list.pyi]
[typing fixtures/typing-full.pyi]
[out]

[case testNestedOverloadsNoCrash]
from typing import overload

def f() -> None:
@overload
def g(x: str) -> str: ...
@overload
def g(x: int) -> int: ...
def g(x):
pass
g(str())
[out]

[case testNestedOverloadsTypeVar]
from typing import overload, TypeVar

T = TypeVar('T')

def f() -> None:
@overload
def g(x: str) -> str: ...
@overload
def g(x: T, y: int) -> T: ...
def g(x):
pass

g(str(), str()) # E: No overload variant of "g" matches argument types "str", "str" \
# N: Possible overload variant: \
# N: def [T] g(x: T, y: int) -> T \
# N: <1 more non-matching overload not shown>
reveal_type(g(str(), int())) # E: Revealed type is 'builtins.str*'
[out]

[case testNestedOverloadsTypeVarOverlap]
from typing import overload, TypeVar

T = TypeVar('T')

def f() -> None:
@overload
def g(x: str) -> int: ... # E: Overloaded function signatures 1 and 2 overlap with incompatible return types
@overload
def g(x: T) -> T: ...
def g(x):
pass
[out]

[case testNestedOverloadsMutuallyRecursive]
from typing import overload, TypeVar, Dict, Any

class C: ...
T = TypeVar('T')

def f() -> None:
@overload
def g() -> None: ...
@overload
def g(x: T) -> Dict[int, T]: ...
def g(*args, **kwargs) -> Any:
reveal_type(h(C())) # E: Revealed type is 'builtins.dict[builtins.str, __main__.C*]'

@overload
def h() -> None: ...
@overload
def h(x: T) -> Dict[str, T]: ...
def h(*args, **kwargs) -> Any:
reveal_type(g(C())) # E: Revealed type is 'builtins.dict[builtins.int, __main__.C*]'

[builtins fixtures/dict.pyi]
[out]