Skip to content

Commit 9a51738

Browse files
martindemellometa-codesync[bot]
authored andcommitted
Get rid of the CInstance check in the pyrefly type binder
Summary: We now get the static type as a "contextual type" from pyrefly, and do not need to fall back to the static python type binder. Using the contextual type, and looking up class types properly, fixes the type mismatch between our binder and pyrefly's type info. Also adds a type for `int64.__add__` so pyrefly can type it correctly. Reviewed By: DinoV Differential Revision: D97126935 fbshipit-source-id: 726fd5c2598bf63f096e34e48aa34f3e4d8d774e
1 parent 2e54db5 commit 9a51738

13 files changed

Lines changed: 403 additions & 337 deletions

File tree

cinderx/PythonLib/__static__/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
Literal,
1818
Protocol,
1919
Type,
20+
TYPE_CHECKING,
2021
TypeVar,
2122
Union,
2223
)
@@ -284,7 +285,10 @@ class int32(int):
284285
@set_type_final
285286
@type_code(TYPED_INT64)
286287
class int64(int):
287-
pass
288+
if TYPE_CHECKING:
289+
290+
def __add__(self, other) -> int64:
291+
return int64(0)
288292

289293

290294
@set_type_final

cinderx/PythonLib/cinderx/compiler/static/pyrefly_info.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,23 @@ def __init__(self, data: TypeInfo) -> None:
105105
self._locations: dict[LocationInfo, int] = {}
106106
for entry in data["locations"]:
107107
key = LocationInfo.from_location(entry["loc"])
108-
self._locations[key] = entry["type"]
108+
if "contextual_type" in entry:
109+
self._locations[key] = entry["contextual_type"]
110+
else:
111+
self._locations[key] = entry["type"]
109112

110113
def _lookup(self, node: AST) -> int | None:
111114
"""Look up the type_table index for an AST node by its source position."""
112115
key = LocationInfo.from_node(node)
113116
return self._locations.get(key)
114117

118+
def lookup_entry(self, node: AST) -> TypeTableEntry | None:
119+
"""Look up the raw type_table entry for an AST node (for debugging)."""
120+
type_index = self._lookup(node)
121+
if type_index is None:
122+
return None
123+
return self._type_table[type_index]
124+
115125
def lookup(
116126
self,
117127
node: AST,
@@ -175,6 +185,19 @@ def lookup_type(
175185
resolved = self.resolve_classname("builtins.None", modules, type_env)
176186
if resolved is not None:
177187
return resolved.instance
188+
elif entry["qname"] == "typing.Type":
189+
# pyre-ignore[27]: tagged union data layout
190+
args = entry.get("args", [])
191+
if args:
192+
inner_entry = self._type_table[args[0]]
193+
if inner_entry["kind"] == "class":
194+
qname = str(inner_entry["qname"])
195+
resolved = self.resolve_classname(qname, modules, type_env)
196+
if resolved is not None:
197+
# typing.Type[X] should resolve to the class X
198+
# itself; use exact_type since a bare name like
199+
# `C` refers to the exact class, not a subclass.
200+
return resolved.exact_type()
178201

179202
return None
180203

cinderx/PythonLib/cinderx/compiler/static/pyrefly_type_binder.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ def visit(self, node: AST, *args: object) -> NarrowingEffect | None:
6161
ret = super().generic_visit(node, *args)
6262
# pyre-fixme[16]: Optional type has no attribute `lookup`.
6363
declared_type = self._type_info.lookup(node, self.modules, self.type_env)
64-
6564
if declared_type is None:
6665
declared_type = self.type_env.dynamic.instance
6766
if isinstance(node, (ast.List, ast.ListComp)):

cinderx/PythonLib/test_cinderx/test_compiler/test_static/pyrefly_binder.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ def test_cases(self):
8383
basename = path.basename(filename)
8484
if basename == "__init__":
8585
continue
86-
modname = f"cinderx.PythonLib.test_cinderx.test_compiler.test_static.pyreflytests.{basename}"
86+
# Set qualified name relative to PythonLib/, to match pyrefly
87+
# (which goes off the sourcedb)
88+
modname = f"test_cinderx.test_compiler.test_static.pyreflytests.{basename}"
8789
with self.subTest(f), open(f) as f, open(jsonname) as jsonf:
8890
data = json.load(jsonf)
8991
code = self.compile_one(

cinderx/PythonLib/test_cinderx/test_compiler/test_static/pyreflytests/call.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"kind": "callable",
1111
"params": [],
1212
"return_type": 0,
13-
"defining_func": "cinderx.PythonLib.test_cinderx.test_compiler.test_static.pyreflytests.call.f",
14-
"hash": 14932184105665906002
13+
"defining_func": "test_cinderx.test_compiler.test_static.pyreflytests.call.f",
14+
"hash": 12738833633897673461
1515
}
1616
],
1717
"locations": [
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4+
PREFIX="test_cinderx.test_compiler.test_static.pyreflytests."
5+
FILTER="$1"
6+
7+
buck run fbcode//pyrefly/pyrefly:pyrefly -- check --report-cinderx tmp.trace "$SCRIPT_DIR"
8+
for f in tmp.trace/types/${PREFIX}*; do
9+
basename="${f#tmp.trace/types/${PREFIX}}"
10+
if [[ "$basename" == *.test.json ]]; then
11+
continue
12+
fi
13+
if [[ -n "$FILTER" && "$basename" != *"$FILTER"* ]]; then
14+
continue
15+
fi
16+
cp "$f" "$SCRIPT_DIR/$basename"
17+
done
18+
rm -rf tmp.trace/

cinderx/PythonLib/test_cinderx/test_compiler/test_static/pyreflytests/method_call.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,33 @@
88
},
99
{
1010
"kind": "class",
11-
"qname": "cinderx.PythonLib.test_cinderx.test_compiler.test_static.pyreflytests.method_call.C",
11+
"qname": "test_cinderx.test_compiler.test_static.pyreflytests.method_call.C",
1212
"args": [],
13-
"hash": 15166489944257147537
13+
"hash": 2273513381601418985
1414
},
1515
{
1616
"kind": "callable",
1717
"params": [
1818
1
1919
],
2020
"return_type": 0,
21-
"hash": 9850197048967803762
21+
"defining_func": "test_cinderx.test_compiler.test_static.pyreflytests.method_call.C.f",
22+
"hash": 17450959045071387878
2223
},
2324
{
2425
"kind": "bound_method",
2526
"self_type": 1,
2627
"func_type": 2,
27-
"defining_class": "cinderx.PythonLib.test_cinderx.test_compiler.test_static.pyreflytests.method_call.C",
28-
"hash": 170909769984178760
28+
"defining_class": "test_cinderx.test_compiler.test_static.pyreflytests.method_call.C",
29+
"hash": 280600409630062807
2930
},
3031
{
3132
"kind": "other_form",
3233
"qname": "typing.Type",
3334
"args": [
3435
1
3536
],
36-
"hash": 6809742840824427841
37+
"hash": 8453644861543316080
3738
}
3839
],
3940
"locations": [
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
{
2+
"type_table": [
3+
{
4+
"kind": "class",
5+
"qname": "__static__.int64",
6+
"args": [],
7+
"hash": 10862202650350632647
8+
},
9+
{
10+
"kind": "other_form",
11+
"qname": "typing.Type",
12+
"args": [
13+
0
14+
],
15+
"hash": 7033849792911641515
16+
},
17+
{
18+
"kind": "class",
19+
"qname": "builtins.int",
20+
"args": [],
21+
"hash": 7437843174258217660
22+
},
23+
{
24+
"kind": "literal",
25+
"value": "0",
26+
"promoted_type": 2,
27+
"hash": 6731702620203439994
28+
}
29+
],
30+
"locations": [
31+
{
32+
"loc": {
33+
"start_line": 5,
34+
"start_col": 11,
35+
"end_line": 5,
36+
"end_col": 16
37+
},
38+
"type": 1
39+
},
40+
{
41+
"loc": {
42+
"start_line": 6,
43+
"start_col": 4,
44+
"end_line": 6,
45+
"end_col": 5
46+
},
47+
"type": 0
48+
},
49+
{
50+
"loc": {
51+
"start_line": 6,
52+
"start_col": 7,
53+
"end_line": 6,
54+
"end_col": 12
55+
},
56+
"type": 1
57+
},
58+
{
59+
"loc": {
60+
"start_line": 6,
61+
"start_col": 15,
62+
"end_line": 6,
63+
"end_col": 16
64+
},
65+
"type": 3,
66+
"contextual_type": 0
67+
},
68+
{
69+
"loc": {
70+
"start_line": 7,
71+
"start_col": 4,
72+
"end_line": 7,
73+
"end_col": 5
74+
},
75+
"type": 0
76+
},
77+
{
78+
"loc": {
79+
"start_line": 7,
80+
"start_col": 7,
81+
"end_line": 7,
82+
"end_col": 12
83+
},
84+
"type": 1
85+
},
86+
{
87+
"loc": {
88+
"start_line": 7,
89+
"start_col": 15,
90+
"end_line": 7,
91+
"end_col": 23
92+
},
93+
"type": 0,
94+
"contextual_type": 0
95+
},
96+
{
97+
"loc": {
98+
"start_line": 7,
99+
"start_col": 15,
100+
"end_line": 7,
101+
"end_col": 20
102+
},
103+
"type": 1
104+
},
105+
{
106+
"loc": {
107+
"start_line": 7,
108+
"start_col": 21,
109+
"end_line": 7,
110+
"end_col": 22
111+
},
112+
"type": 3
113+
},
114+
{
115+
"loc": {
116+
"start_line": 8,
117+
"start_col": 11,
118+
"end_line": 8,
119+
"end_col": 16
120+
},
121+
"type": 0
122+
},
123+
{
124+
"loc": {
125+
"start_line": 8,
126+
"start_col": 11,
127+
"end_line": 8,
128+
"end_col": 12
129+
},
130+
"type": 0
131+
},
132+
{
133+
"loc": {
134+
"start_line": 8,
135+
"start_col": 15,
136+
"end_line": 8,
137+
"end_col": 16
138+
},
139+
"type": 0
140+
}
141+
]
142+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import __static__
2+
from __static__ import int64
3+
4+
5+
def f() -> int64:
6+
x: int64 = 0
7+
y: int64 = int64(0)
8+
return x + y
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from types import CodeType
2+
3+
from test_cinderx.test_compiler.test_static.pyrefly_binder import PyreBinderTests
4+
5+
6+
def verify(test: PyreBinderTests, code: CodeType) -> None:
7+
"""Verify that the compiled code includes PRIMITIVE_BINARY_OP."""
8+
9+
g = test.find_code(code, "f")
10+
test.assertInBytecode(g, "PRIMITIVE_BINARY_OP")

0 commit comments

Comments
 (0)