Skip to content

Commit 41e3e6b

Browse files
migeed-zmeta-codesync[bot]
authored andcommitted
Document another group of conformance gap involving callables and constructors
Reviewed By: grievejia Differential Revision: D91738737 fbshipit-source-id: f6c3258cb4432d3dcf0b28355a0acd4c18ed93c1
1 parent 5770cc6 commit 41e3e6b

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

pyrefly/lib/test/callable.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,3 +1261,73 @@ def g():
12611261
return wrap(lambda x: f(x))
12621262
"#,
12631263
);
1264+
1265+
testcase!(
1266+
bug = "conformance: Protocol with ParamSpec[...] should be compatible with Protocol using *args: Any, **kwargs: Any",
1267+
test_protocol_paramspec_ellipsis,
1268+
r#"
1269+
from typing import Any, Protocol, ParamSpec
1270+
1271+
P = ParamSpec("P")
1272+
1273+
class Proto3(Protocol):
1274+
def __call__(self, a: int, *args: Any, **kwargs: Any) -> None: ...
1275+
1276+
class Proto4(Protocol[P]):
1277+
def __call__(self, a: int, *args: P.args, **kwargs: P.kwargs) -> None: ...
1278+
1279+
class Proto6(Protocol):
1280+
# Note: conformance uses `*args: Any, *, k: str` which pyrefly incorrectly treats as parse error
1281+
def __call__(self, a: int, /, *args: Any, k: str, **kwargs: Any) -> None: ...
1282+
1283+
class Proto7(Protocol):
1284+
def __call__(self, a: float, /, b: int, *, k: str, m: str) -> None: ...
1285+
1286+
def test(p4: Proto4[...], p7: Proto7):
1287+
# Both should be OK per conformance spec - pyrefly incorrectly errors
1288+
ok10: Proto3 = p4 # E: `Proto4[Ellipsis]` is not assignable to `Proto3`
1289+
ok11: Proto6 = p7 # E: `Proto7` is not assignable to `Proto6`
1290+
"#,
1291+
);
1292+
1293+
testcase!(
1294+
bug = "conformance: Constructor to Callable conversion should work with __new__ and __init__ together",
1295+
test_constructor_callable_conversion,
1296+
r#"
1297+
from typing import Callable, ParamSpec, TypeVar, Self, assert_type, overload, Generic
1298+
1299+
P = ParamSpec("P")
1300+
R = TypeVar("R")
1301+
T = TypeVar("T")
1302+
1303+
def accepts_callable(cb: Callable[P, R]) -> Callable[P, R]:
1304+
return cb
1305+
1306+
class Class3:
1307+
def __new__(cls, *args, **kwargs) -> Self: ...
1308+
def __init__(self, x: int) -> None: ...
1309+
1310+
# pyrefly incorrectly errors on this line - should be OK
1311+
r3 = accepts_callable(Class3) # E: `type[Class3]` is not assignable to parameter `cb` with type `(*args: Unknown, **kwargs: Unknown) -> Class3`
1312+
1313+
class Class7(Generic[T]):
1314+
@overload
1315+
def __init__(self: "Class7[int]", x: int) -> None: ...
1316+
@overload
1317+
def __init__(self: "Class7[str]", x: str) -> None: ...
1318+
def __init__(self, x: int | str) -> None:
1319+
pass
1320+
1321+
r7 = accepts_callable(Class7)
1322+
# pyrefly incorrectly errors on these - should be OK
1323+
assert_type(r7(""), Class7[str]) # E: assert_type(Class7[int], Class7[str]) failed # E: Argument `Literal['']` is not assignable
1324+
1325+
class Class8(Generic[T]):
1326+
def __new__(cls, x: list[T], y: list[T]) -> Self:
1327+
return super().__new__(cls)
1328+
1329+
r8 = accepts_callable(Class8)
1330+
# pyrefly incorrectly errors on this - should be OK
1331+
assert_type(r8([""], [""]), Class8[str]) # E: assert_type(Class8[Any], Class8[str]) failed
1332+
"#,
1333+
);

pyrefly/lib/test/constructors.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,3 +686,18 @@ takes_Cstr(C)
686686
takes_Cstr_wrong(C) # E: Argument `type[C]` is not assignable to parameter `x` with type `(str) -> C[int]` in function `takes_Cstr_wrong`
687687
"#,
688688
);
689+
690+
testcase!(
691+
bug = "conformance: Should error when class-scoped type variables are used in self annotation of __init__",
692+
test_init_class_scoped_typevars_in_self,
693+
r#"
694+
from typing import Generic, TypeVar
695+
696+
T1 = TypeVar("T1")
697+
T2 = TypeVar("T2")
698+
699+
class Class8(Generic[T1, T2]):
700+
def __init__(self: "Class8[T2, T1]") -> None: # should error: class-scoped type vars used in self annotation
701+
pass
702+
"#,
703+
);

pyrefly/lib/test/generic_basic.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ use crate::test::util::TestEnv;
1111
use crate::testcase;
1212

1313
testcase!(
14-
bug =
15-
"We should use the bounds/constraints of the type var to determine the callable input type",
14+
bug = "conformance: Should use bounds/constraints of type var to determine callable input type for type[T] constructors",
1615
test_tyvar_constructor,
1716
r#"
1817
def test[T](cls: type[T]) -> T:
19-
cls(1) # Not OK, we should assume object constructor here
18+
cls(1) # should error: no args for object constructor
2019
return cls()
2120
class A:
2221
def __init__(self, x: int) -> None: pass
2322
def test2[T: A](cls: type[T]) -> T:
24-
a1: A = cls() # Not OK
23+
a1: A = cls() # should error: missing required arg x
2524
a2: A = cls(1)
2625
return cls()
2726
"#,

0 commit comments

Comments
 (0)