Skip to content

Commit 6bda874

Browse files
committed
Use checkmember.py to check variable overrides
1 parent de3bec4 commit 6bda874

File tree

6 files changed

+143
-114
lines changed

6 files changed

+143
-114
lines changed

mypy/checker.py

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,18 @@
1212
import mypy.checkexpr
1313
from mypy import errorcodes as codes, join, message_registry, nodes, operators
1414
from mypy.binder import ConditionalTypeBinder, Frame, get_declaration
15-
from mypy.checkmember import analyze_member_access
15+
from mypy.checkmember import (
16+
MemberContext,
17+
analyze_descriptor_access,
18+
analyze_instance_member_access,
19+
analyze_member_access,
20+
)
1621
from mypy.checkpattern import PatternChecker
1722
from mypy.constraints import SUPERTYPE_OF
1823
from mypy.erasetype import erase_type, erase_typevars, remove_instance_last_known_values
1924
from mypy.errorcodes import TYPE_VAR, UNUSED_AWAITABLE, UNUSED_COROUTINE, ErrorCode
2025
from mypy.errors import Errors, ErrorWatcher, report_internal_error
21-
from mypy.expandtype import expand_self_type, expand_type, expand_type_by_instance
26+
from mypy.expandtype import expand_self_type, expand_type
2227
from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash
2328
from mypy.maptype import map_instance_to_supertype
2429
from mypy.meet import is_overlapping_erased_types, is_overlapping_types, meet_types
@@ -3583,31 +3588,39 @@ def check_compatibility_super(
35833588
base_type = get_proper_type(base_type)
35843589
compare_type = get_proper_type(compare_type)
35853590
if compare_type:
3586-
if isinstance(base_type, CallableType) and isinstance(compare_type, CallableType):
3587-
base_static = is_node_static(base_node)
3591+
# Unlike for base_type, where we use the full analyze_member_access(), we know
3592+
# that subclass node is an assignment, so we use a much simpler logic: just bind
3593+
# self or invoke descriptors. Although this may not cover some niche corner
3594+
# cases, it is faster, and works with current logic where we check overrides
3595+
# before storing inferred variable type.
3596+
if isinstance(compare_type, CallableType):
35883597
compare_static = is_node_static(compare_node)
3589-
3590-
# In case compare_static is unknown, also check
3591-
# if 'definition' is set. The most common case for
3592-
# this is with TempNode(), where we lose all
3593-
# information about the real rvalue node (but only get
3594-
# the rvalue type)
3598+
# Since this method may be called before storing inferred type,
3599+
# fall back to rvalue to obtain the static method flag.
35953600
if compare_static is None and compare_type.definition:
35963601
compare_static = is_node_static(compare_type.definition)
3597-
35983602
# Compare against False, as is_node_static can return None
3599-
if base_static is False and compare_static is False:
3600-
# Class-level function objects and classmethods become bound
3601-
# methods: the former to the instance, the latter to the
3602-
# class
3603-
base_type = bind_self(base_type, self.scope.active_self_type())
3603+
if compare_static is False:
3604+
# TODO: handle aliases to class methods (similarly).
36043605
compare_type = bind_self(compare_type, self.scope.active_self_type())
36053606

3606-
# If we are a static method, ensure to also tell the
3607-
# lvalue it now contains a static method
3608-
if base_static and compare_static:
3609-
lvalue_node.is_staticmethod = True
3607+
elif isinstance(compare_type, Instance):
3608+
self_type = self.scope.active_self_type()
3609+
assert self_type is not None, "Internal error: base lookup outside class"
3610+
mx = MemberContext(
3611+
is_lvalue=False,
3612+
is_super=False,
3613+
is_operator=False,
3614+
original_type=self_type,
3615+
context=lvalue,
3616+
chk=self,
3617+
suppress_errors=True,
3618+
)
3619+
with self.msg.filter_errors():
3620+
compare_type = analyze_descriptor_access(compare_type, mx)
36103621

3622+
# TODO: check __set__() type override for custom descriptors.
3623+
# TODO: for descriptors check also class object access override.
36113624
ok = self.check_subtype(
36123625
compare_type,
36133626
base_type,
@@ -3647,49 +3660,30 @@ def lvalue_type_from_base(
36473660
expr_name = expr_node.name
36483661
base_var = base.names.get(expr_name)
36493662

3650-
if not base_var:
3651-
return None, None
3652-
base_node = base_var.node
3653-
base_type = base_var.type
3654-
if isinstance(base_node, Var) and base_type is not None:
3655-
base_type = expand_self_type(base_node, base_type, fill_typevars(expr_node.info))
3656-
if isinstance(base_node, Decorator):
3657-
base_node = base_node.func
3658-
base_type = base_node.type
3659-
3660-
if not base_type:
3663+
# TODO: defer current node if the superclass node is not ready.
3664+
if not base_var or not base_var.type:
36613665
return None, None
3662-
if not has_no_typevars(base_type):
3663-
self_type = self.scope.active_self_type()
3664-
assert self_type is not None, "Internal error: base lookup outside class"
3665-
if isinstance(self_type, TupleType):
3666-
instance = tuple_fallback(self_type)
3667-
else:
3668-
instance = self_type
3669-
itype = map_instance_to_supertype(instance, base)
3670-
base_type = expand_type_by_instance(base_type, itype)
3671-
3672-
base_type = get_proper_type(base_type)
3673-
if isinstance(base_type, CallableType) and isinstance(base_node, FuncDef):
3674-
# If we are a property, return the Type of the return
3675-
# value, not the Callable
3676-
if base_node.is_property:
3677-
base_type = get_proper_type(base_type.ret_type)
3678-
if isinstance(base_type, FunctionLike) and isinstance(base_node, OverloadedFuncDef):
3679-
# Same for properties with setter
3680-
if base_node.is_property:
3681-
if setter_type:
3682-
assert isinstance(base_node.items[0], Decorator)
3683-
base_type = base_node.items[0].var.setter_type
3684-
# This flag is True only for custom properties, so it is safe to assert.
3685-
assert base_type is not None
3686-
base_type = self.bind_and_map_method(base_var, base_type, expr_node.info, base)
3687-
assert isinstance(base_type, CallableType)
3688-
base_type = get_proper_type(base_type.arg_types[0])
3689-
else:
3690-
base_type = base_type.items[0].ret_type
36913666

3692-
return base_type, base_node
3667+
self_type = self.scope.active_self_type()
3668+
assert self_type is not None, "Internal error: base lookup outside class"
3669+
if isinstance(self_type, TupleType):
3670+
instance = tuple_fallback(self_type)
3671+
else:
3672+
instance = self_type
3673+
3674+
mx = MemberContext(
3675+
is_lvalue=setter_type,
3676+
is_super=False,
3677+
is_operator=False,
3678+
original_type=self_type,
3679+
context=expr_node,
3680+
chk=self,
3681+
suppress_errors=True,
3682+
)
3683+
# TODO: we should not filter "cannot determine type" errors here.
3684+
with self.msg.filter_errors():
3685+
base_type = analyze_instance_member_access(expr_name, instance, mx, base)
3686+
return base_type, base_var.node
36933687

36943688
def check_compatibility_classvar_super(
36953689
self, node: Var, base: TypeInfo, base_node: Node | None
@@ -4515,6 +4509,7 @@ def set_inferred_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
45154509
refers to the variable (lvalue). If var is None, do nothing.
45164510
"""
45174511
if var and not self.current_node_deferred:
4512+
# TODO: should we also set 'is_ready = True' here?
45184513
var.type = type
45194514
var.is_inferred = True
45204515
if var not in self.var_decl_frames:
@@ -4525,12 +4520,15 @@ def set_inferred_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
45254520
if lvalue.def_var is not None:
45264521
self.inferred_attribute_types[lvalue.def_var] = type
45274522
self.store_type(lvalue, type)
4523+
p_type = get_proper_type(type)
4524+
if isinstance(p_type, CallableType) and is_node_static(p_type.definition):
4525+
var.is_staticmethod = True
45284526

45294527
def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type) -> None:
45304528
"""Store best known type for variable if type inference failed.
45314529
45324530
If a program ignores error on type inference error, the variable should get some
4533-
inferred type so that if can used later on in the program. Example:
4531+
inferred type so that it can used later on in the program. Example:
45344532
45354533
x = [] # type: ignore
45364534
x.append(1) # Should be ok!

0 commit comments

Comments
 (0)