-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Expand file tree
/
Copy pathmaptype.py
More file actions
107 lines (84 loc) · 3.73 KB
/
maptype.py
File metadata and controls
107 lines (84 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
from typing import Dict, List, cast
from mypy.expandtype import expand_type
from mypy.nodes import TypeInfo
from mypy.types import Type, Instance, AnyType
def map_instance_to_supertype(instance: Instance,
superclass: TypeInfo) -> Instance:
"""Produce a supertype of `instance` that is an Instance
of `superclass`, mapping type arguments up the chain of bases.
`superclass` is required to be a superclass of `instance.type`.
"""
if instance.type == superclass:
# Fast path: `instance` already belongs to `superclass`.
return instance
if not superclass.type_vars:
# Fast path: `superclass` has no type variables to map to.
return Instance(superclass, [])
return map_instance_to_supertypes(instance, superclass)[0]
def map_instance_to_direct_supertype(instance: Instance,
supertype: TypeInfo) -> Instance:
typ = instance.type
for base in typ.bases:
if base.type == supertype:
map = type_var_map(typ, instance.args)
return cast(Instance, expand_type(base, map))
# Relationship with the supertype not specified explicitly. Use AnyType
# type arguments implicitly.
# TODO Should this be an error instead?
return Instance(supertype, [AnyType()] * len(supertype.type_vars))
def type_var_map(typ: TypeInfo, args: List[Type]) -> Dict[int, Type]:
if not args:
return None
else:
tvars = {} # type: Dict[int, Type]
for i in range(len(args)):
tvars[i + 1] = args[i]
return tvars
def map_instance_to_supertypes(instance: Instance,
supertype: TypeInfo) -> List[Instance]:
# FIX: Currently we should only have one supertype per interface, so no
# need to return an array
result = [] # type: List[Instance]
for path in class_derivation_paths(instance.type, supertype):
types = [instance]
for sup in path:
a = [] # type: List[Instance]
for t in types:
a.extend(map_instance_to_direct_supertypes(t, sup))
types = a
result.extend(types)
return result
def class_derivation_paths(typ: TypeInfo,
supertype: TypeInfo) -> List[List[TypeInfo]]:
"""Return an array of non-empty paths of direct base classes from
type to supertype. Return [] if no such path could be found.
InterfaceImplementationPaths(A, B) == [[B]] if A inherits B
InterfaceImplementationPaths(A, C) == [[B, C]] if A inherits B and
B inherits C
"""
# FIX: Currently we might only ever have a single path, so this could be
# simplified
result = [] # type: List[List[TypeInfo]]
for base in typ.bases:
if base.type == supertype:
result.append([base.type])
else:
# Try constructing a longer path via the base class.
for path in class_derivation_paths(base.type, supertype):
result.append([base.type] + path)
return result
def map_instance_to_direct_supertypes(instance: Instance,
supertype: TypeInfo) -> List[Instance]:
# FIX: There should only be one supertypes, always.
typ = instance.type
result = [] # type: List[Instance]
for b in typ.bases:
if b.type == supertype:
map = type_var_map(typ, instance.args)
result.append(cast(Instance, expand_type(b, map)))
if result:
return result
else:
# Relationship with the supertype not specified explicitly. Use dynamic
# type arguments implicitly.
return [Instance(supertype, [AnyType()] * len(supertype.type_vars))]