Skip to content

Commit a99b2f9

Browse files
committed
Closes #224
1 parent 8fd434e commit a99b2f9

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

classes/contrib/mypy/validation/validate_associated_type.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from mypy.plugin import MethodContext
2-
from mypy.types import Instance
2+
from mypy.types import CallableType, Instance
33
from typing_extensions import Final
44

55
#: Fullname of the `AssociatedType` class.
@@ -14,6 +14,11 @@
1414
'AssociatedType "{0}" must not be reused, originally associated with "{1}"'
1515
)
1616

17+
_GENERIC_MISSMATCH_MSG: Final = (
18+
'Generic type "{0}" with "{1}" type arguments does not match ' +
19+
'generic instance declaration "{2}" with "{3}" type arguments'
20+
)
21+
1722

1823
def check_type(
1924
associated_type: Instance,
@@ -30,8 +35,8 @@ def check_type(
3035
return all([
3136
_check_base_class(associated_type, ctx),
3237
_check_type_reuse(associated_type, typeclass, ctx),
38+
_check_generics(associated_type, typeclass, ctx),
3339
# TODO: check_body
34-
# TODO: check_generics_match_definition
3540
# TODO: we also need to check type vars used on definition:
3641
# no values, no bounds (?)
3742
])
@@ -78,3 +83,27 @@ def _check_type_reuse(
7883

7984
metadata['typeclass'] = fullname
8085
return has_reuse
86+
87+
88+
def _check_generics(
89+
associated_type: Instance,
90+
typeclass: Instance,
91+
ctx: MethodContext,
92+
) -> bool:
93+
assert isinstance(typeclass.args[1], CallableType)
94+
instance_decl = typeclass.args[1].arg_types[0]
95+
if not isinstance(instance_decl, Instance):
96+
return True
97+
98+
if len(instance_decl.args) != len(associated_type.type.type_vars):
99+
ctx.api.fail(
100+
_GENERIC_MISSMATCH_MSG.format(
101+
associated_type.type.fullname,
102+
len(associated_type.type.type_vars),
103+
instance_decl,
104+
len(instance_decl.args),
105+
),
106+
ctx.context,
107+
)
108+
return False
109+
return True
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
- case: typeclass_definied_by_wrong_type
2+
disable_cache: false
3+
main: |
4+
from typing import List, TypeVar
5+
6+
from classes import AssociatedType, Supports, typeclass
7+
8+
X = TypeVar('X')
9+
10+
class Compare(AssociatedType):
11+
...
12+
13+
@typeclass(Compare)
14+
def compare(instance: List[X]) -> X:
15+
...
16+
out: |
17+
main:10: error: Generic type "main.Compare" with "0" type arguments does not match generic instance declaration "builtins.list[X`-1]" with "1" type arguments

0 commit comments

Comments
 (0)