-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Protocols #3132
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
Protocols #3132
Changes from 1 commit
884481d
c19b6d4
83c1579
b01f5b0
16901fc
c8c1247
f430c65
beea7d2
260237a
5414eaf
7f8a514
92b71a2
83085c7
27b8570
41179c2
5171844
db123a3
31bf16c
03b5d72
65a8546
2768d76
93beb75
5135fd9
fdeb89b
1fbcb4a
d012e38
801770d
a625f37
fb6b1ad
adb68eb
b9a0b2d
969f76f
2e5de3e
1daaf8d
2b6d198
937c629
e8e6661
8e6306f
3f2d707
a82413d
957c76d
8cf08ec
e0083d9
c9629da
affec0c
01948dd
78a62eb
0ae409a
cb27279
5452227
798954a
9db4e51
7d2327a
88d4fed
d9187e2
3ee1c53
85082d5
2733e1a
232428f
4c04e0b
e81a3f9
b4ca6f0
b063767
79d8e30
480b977
483f163
70c3ae0
509113a
0cb0985
9f554b6
70463a5
78f2011
473a2d2
8dfe8ea
f7e55fa
06a1680
204ec82
985d1f7
8d2e199
f0471c1
4dfa3e1
6d05060
759409f
83501ff
166b6da
d25bcfc
d652a69
addac40
803ce1e
1c9f6f9
3c0411c
491b31f
98f0180
0f55718
513c759
36f3d6d
05b70ab
561856e
228f621
0716b59
9cd4e29
eb06c55
59aeed2
73d2d69
ee18dde
34d1cd1
fbbd169
3acd19e
22ad771
4f2391e
359a43b
eacff5f
afe1291
1858ed9
057a871
28c1b9d
ad2bcaa
8af7248
9ca98b2
0cb13b7
fd06408
969a64b
e9cbba8
e93f839
9292971
4c3f4e2
e71dff0
d195964
318bb70
3d8782f
6e1100c
5bfa3b2
82f01b7
c7304bd
58e6b36
eefe881
96a04ae
b1c4d37
8b6006c
f76349b
c3bfe2b
e2f4f5d
91fe9fd
aaea344
27c3e36
cfa539d
713db0c
40d635f
19073e5
50d98c0
9411255
f1c915e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,7 +69,7 @@ def is_subtype(left: Type, right: Type, | |
else: | ||
result = left.accept(SubtypeVisitor(right, type_parameter_checker, | ||
ignore_pos_arg_names=ignore_pos_arg_names)) | ||
# Useful for debugging | ||
# Useful for debugging: | ||
# print(left, right, result) | ||
return result | ||
|
||
|
@@ -145,18 +145,17 @@ def visit_instance(self, left: Instance) -> bool: | |
rname = right.type.fullname() | ||
# Always try a nominal check if possible, | ||
# there might be errors that a user wants to silence *once*. | ||
# Also, nominal checks are faster. | ||
if not left.type.has_base(rname) and rname != 'builtins.object': | ||
if right.type.is_protocol: | ||
return is_protocol_implementation(left, right) | ||
return False | ||
|
||
# Map left type to corresponding right instances. | ||
t = map_instance_to_supertype(left, right.type) | ||
|
||
return all(self.check_type_parameter(lefta, righta, tvar.variance) | ||
for lefta, righta, tvar in | ||
zip(t.args, right.args, right.type.defn.type_vars)) | ||
if left.type.has_base(rname) or rname == 'builtins.object': | ||
# Map left type to corresponding right instances. | ||
t = map_instance_to_supertype(left, right.type) | ||
nominal = all(self.check_type_parameter(lefta, righta, tvar.variance) | ||
for lefta, righta, tvar in | ||
zip(t.args, right.args, right.type.defn.type_vars)) | ||
if nominal: | ||
return True | ||
if right.type.is_protocol and is_protocol_implementation(left, right): | ||
return True | ||
return False | ||
if isinstance(right, TypeType): | ||
item = right.item | ||
if isinstance(item, TupleType): | ||
|
@@ -170,7 +169,7 @@ def visit_instance(self, left: Instance) -> bool: | |
else: | ||
return False | ||
if isinstance(right, CallableType): | ||
# Special case: Instance can by a subtype of Callable. | ||
# Special case: Instance can be a subtype of Callable. | ||
call = find_member('__call__', left, left) | ||
if call: | ||
return is_subtype(call, right) | ||
|
@@ -311,10 +310,8 @@ def pop_on_exit(stack: List[Tuple[Instance, Instance]], | |
|
||
def is_protocol_implementation(left: Instance, right: Instance, allow_any: bool = True) -> bool: | ||
"""Check whether 'left' implements the protocol 'right'. If 'allow_any' is False, then | ||
check for a proper subtype. Treat recursive protocols by using a global 'assuming' | ||
structural subtype matrix (in sparse representation). If concurrent type checking | ||
will be implemented, then every thread/process should use its own matrix | ||
(see comment in nodes.TypeInfo). | ||
check for a proper subtype. Treat recursive protocols by using the 'assuming' | ||
structural subtype matrix (in sparse representation), see comment in nodes.TypeInfo. | ||
""" | ||
assert right.type.is_protocol | ||
assuming = right.type.assuming if allow_any else right.type.assuming_proper | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment here explaining how |
||
|
@@ -334,7 +331,7 @@ def is_protocol_implementation(left: Instance, right: Instance, allow_any: bool | |
if not subtype: | ||
return False | ||
if allow_any: | ||
# nominal check currently ignore arg names | ||
# nominal check currently ignores arg names | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use capitalized 'nominal'. |
||
is_compat = is_subtype(subtype, supertype, ignore_pos_arg_names=True) | ||
else: | ||
is_compat = is_proper_subtype(subtype, supertype) | ||
|
@@ -350,6 +347,9 @@ def is_protocol_implementation(left: Instance, right: Instance, allow_any: bool | |
# this rule is copied from nominal check in checker.py | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use capitalized 'this'. |
||
if IS_CLASS_OR_STATIC in superflags and IS_CLASS_OR_STATIC not in subflags: | ||
return False | ||
# This additional push serves as poor man's subtype cache. | ||
# (This already gives a decent speed-up.) | ||
# TODO: Implement a general fast subtype cache? | ||
assuming.append((left, right)) | ||
return True | ||
|
||
|
@@ -452,7 +452,7 @@ def map_method(method: FuncBase, itype: Instance, subtype: Instance) -> Type: | |
by 'find_var_type'. | ||
""" | ||
from mypy.checkmember import bind_self | ||
signature = function_type(method, Instance(itype.type.mro[-1], [])) | ||
signature = function_type(method, fallback=Instance(itype.type.mro[-1], [])) | ||
signature = bind_self(signature, subtype) | ||
itype = map_instance_to_supertype(itype, method.info) | ||
return expand_type_by_instance(signature, itype) | ||
|
@@ -715,24 +715,23 @@ def is_proper_subtype(t: Type, s: Type) -> bool: | |
|
||
if isinstance(t, Instance): | ||
if isinstance(s, Instance): | ||
if s.type.is_protocol: | ||
return is_protocol_implementation(t, s, allow_any=False) | ||
if not t.type.has_base(s.type.fullname()): | ||
return False | ||
|
||
def check_argument(left: Type, right: Type, variance: int) -> bool: | ||
if variance == COVARIANT: | ||
return is_proper_subtype(left, right) | ||
elif variance == CONTRAVARIANT: | ||
return is_proper_subtype(right, left) | ||
else: | ||
return sametypes.is_same_type(left, right) | ||
|
||
# Map left type to corresponding right instances. | ||
t = map_instance_to_supertype(t, s.type) | ||
|
||
return all(check_argument(ta, ra, tvar.variance) for ta, ra, tvar in | ||
zip(t.args, s.args, s.type.defn.type_vars)) | ||
if t.type.has_base(s.type.fullname()): | ||
def check_argument(left: Type, right: Type, variance: int) -> bool: | ||
if variance == COVARIANT: | ||
return is_proper_subtype(left, right) | ||
elif variance == CONTRAVARIANT: | ||
return is_proper_subtype(right, left) | ||
else: | ||
return sametypes.is_same_type(left, right) | ||
# Map left type to corresponding right instances. | ||
t = map_instance_to_supertype(t, s.type) | ||
nominal = all(check_argument(ta, ra, tvar.variance) for ta, ra, tvar in | ||
zip(t.args, s.args, s.type.defn.type_vars)) | ||
if nominal: | ||
return True | ||
if s.type.is_protocol and is_protocol_implementation(t, s, allow_any=False): | ||
return True | ||
return False | ||
if isinstance(s, CallableType): | ||
call = find_member('__call__', t, t) | ||
if call: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about changing
allow_any
toproper_subtype
(and negate the value) or similar for consistency?