Skip to content

Commit 438a3e9

Browse files
authored
New semantic analyzer: fix crash on broken overload at class scope (#7181)
Fixes #7044 The crash is caused by the fact that `.type` for broken overloads can be `None`. There is another example where we deal with this in `analyze_ref_expr()`. The crash doesn't happen on the old analyzer because it doesn't add the broken overload to the symbol table. I solve the crash by generating a dummy `Overloaded()` type in this case. An alternative solution would be to re-analyze a broken overload as independent (re-)definitions, but I think this is more error-prone to keep an overload in AST, but a bunch of functions in symbol table. Using this opportunity I also remove a redundant `add_symbol()` call (we always add the overload before even processing it). Note that the behavior of the new analyzer is still different from the old one, but IMO it is more consistent in some sense.
1 parent dc58be0 commit 438a3e9

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

mypy/checkexpr.py

+2
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
174174
elif isinstance(node, OverloadedFuncDef) and node.type is not None:
175175
# node.type is None when there are multiple definitions of a function
176176
# and it's decorated by something that is not typing.overload
177+
# TODO: use a dummy Overloaded instead of AnyType in this case
178+
# like we do in mypy.types.function_type()?
177179
result = node.type
178180
elif isinstance(node, TypeInfo):
179181
# Reference to a type object.

mypy/newsemanal/semanal.py

-2
Original file line numberDiff line numberDiff line change
@@ -701,8 +701,6 @@ def analyze_overloaded_func_def(self, defn: OverloadedFuncDef) -> None:
701701
self.process_final_in_overload(defn)
702702
self.process_static_or_class_method_in_overload(defn)
703703

704-
self.add_symbol(defn.name(), defn, defn)
705-
706704
def analyze_overload_sigs_and_impl(
707705
self,
708706
defn: OverloadedFuncDef) -> Tuple[List[CallableType],

mypy/types.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -2177,9 +2177,21 @@ def function_type(func: mypy.nodes.FuncBase, fallback: Instance) -> FunctionLike
21772177
return func.type
21782178
else:
21792179
# Implicit type signature with dynamic types.
2180-
# Overloaded functions always have a signature, so func must be an ordinary function.
2181-
assert isinstance(func, mypy.nodes.FuncItem), str(func)
2182-
return callable_type(func, fallback)
2180+
if isinstance(func, mypy.nodes.FuncItem):
2181+
return callable_type(func, fallback)
2182+
else:
2183+
# Broken overloads can have self.type set to None.
2184+
# TODO: should we instead always set the type in semantic analyzer?
2185+
assert isinstance(func, mypy.nodes.OverloadedFuncDef)
2186+
any_type = AnyType(TypeOfAny.from_error)
2187+
dummy = CallableType([any_type, any_type],
2188+
[ARG_STAR, ARG_STAR2],
2189+
[None, None], any_type,
2190+
fallback,
2191+
line=func.line, is_ellipsis_args=True)
2192+
# Return an Overloaded, because some callers may expect that
2193+
# an OverloadedFuncDef has an Overloaded type.
2194+
return Overloaded([dummy])
21832195

21842196

21852197
def callable_type(fdef: mypy.nodes.FuncItem, fallback: Instance,

test-data/unit/check-newsemanal.test

+19
Original file line numberDiff line numberDiff line change
@@ -3113,3 +3113,22 @@ class A: pass
31133113
def f() -> None: pass
31143114

31153115
[targets m, m.f, __main__]
3116+
3117+
[case testNewAnalyzerNoCrashOnCustomProperty]
3118+
# flags: --ignore-missing-imports
3119+
from unimported import custom
3120+
3121+
class User:
3122+
first_name: str
3123+
3124+
@custom
3125+
def name(self) -> str:
3126+
return self.first_name
3127+
3128+
@name.setter # type: ignore
3129+
def name(self, value: str) -> None:
3130+
self.first_name = value
3131+
3132+
def __init__(self, name: str) -> None:
3133+
self.name = name # E: Cannot assign to a method \
3134+
# E: Incompatible types in assignment (expression has type "str", variable has type overloaded function)

0 commit comments

Comments
 (0)