diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 575fa3205..050a1635b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1224,15 +1224,15 @@ class UnpackTests(BaseTestCase): PartOld = Old[int, *Ts] self.assertEqual(PartOld[str].__args__, (int, str)) - # self.assertEqual(PartOld[*tuple[str]].__args__, (int, str)) - # self.assertEqual(PartOld[*Tuple[str]].__args__, (int, str)) + self.assertEqual(PartOld[*tuple[str]].__args__, (int, str)) + self.assertEqual(PartOld[*Tuple[str]].__args__, (int, str)) self.assertEqual(PartOld[Unpack[tuple[str]]].__args__, (int, str)) self.assertEqual(PartOld[Unpack[Tuple[str]]].__args__, (int, str)) PartNew = New[int, *Ts] self.assertEqual(PartNew[str].__args__, (int, str)) - # self.assertEqual(PartNew[*tuple[str]].__args__, (int, str)) - # self.assertEqual(PartNew[*Tuple[str]].__args__, (int, str)) + self.assertEqual(PartNew[*tuple[str]].__args__, (int, str)) + self.assertEqual(PartNew[*Tuple[str]].__args__, (int, str)) self.assertEqual(PartNew[Unpack[tuple[str]]].__args__, (int, str)) self.assertEqual(PartNew[Unpack[Tuple[str]]].__args__, (int, str)) @@ -1241,7 +1241,7 @@ class UnpackTests(BaseTestCase): def test_unpack_wrong_type(self): Ts = TypeVarTuple("Ts") class Gen[*Ts]: ... - # PartGen = Gen[int, *Ts] + PartGen = Gen[int, *Ts] bad_unpack_param = re.escape("Unpack[...] must be used with a tuple type") with self.assertRaisesRegex(TypeError, bad_unpack_param): @@ -1291,7 +1291,7 @@ class TypeVarTupleTests(BaseTestCase): def test_parameterised_tuple_is_equal_to_itself(self): Ts = TypeVarTuple('Ts') - # self.assertEqual(tuple[*Ts], tuple[*Ts]) + self.assertEqual(tuple[*Ts], tuple[*Ts]) self.assertEqual(Tuple[Unpack[Ts]], Tuple[Unpack[Ts]]) def tests_tuple_arg_ordering_matters(self): @@ -1306,28 +1306,24 @@ class TypeVarTupleTests(BaseTestCase): Tuple[Unpack[Ts2], Unpack[Ts1]], ) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_tuple_args_and_parameters_are_correct(self): Ts = TypeVarTuple('Ts') - # t1 = tuple[*Ts] + t1 = tuple[*Ts] self.assertEqual(t1.__args__, (*Ts,)) self.assertEqual(t1.__parameters__, (Ts,)) t2 = Tuple[Unpack[Ts]] self.assertEqual(t2.__args__, (Unpack[Ts],)) self.assertEqual(t2.__parameters__, (Ts,)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - # class G1(Generic[*Ts]): pass + class G1(Generic[*Ts]): pass class G2(Generic[Unpack[Ts]]): pass for A in G1, G2, Tuple, tuple: - # B = A[*Ts] + B = A[*Ts] self.assertEqual(B[()], A[()]) self.assertEqual(B[float], A[float]) self.assertEqual(B[float, str], A[float, str]) @@ -1337,7 +1333,7 @@ class TypeVarTupleTests(BaseTestCase): self.assertEqual(C[float], A[float]) self.assertEqual(C[float, str], A[float, str]) - # D = list[A[*Ts]] + D = list[A[*Ts]] self.assertEqual(D[()], list[A[()]]) self.assertEqual(D[float], list[A[float]]) self.assertEqual(D[float, str], list[A[float, str]]) @@ -1365,7 +1361,7 @@ class TypeVarTupleTests(BaseTestCase): self.assertEqual(G[float, str, int], A[float, str, int]) self.assertEqual(G[float, str, int, bytes], A[float, str, int, bytes]) - # H = tuple[list[T], A[*Ts], list[T2]] + H = tuple[list[T], A[*Ts], list[T2]] with self.assertRaises(TypeError): H[()] with self.assertRaises(TypeError): @@ -1391,13 +1387,11 @@ class TypeVarTupleTests(BaseTestCase): self.assertEqual(I[float, str, int, bytes], Tuple[List[float], A[str, int], List[bytes]]) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_bad_var_substitution(self): Ts = TypeVarTuple('Ts') T = TypeVar('T') T2 = TypeVar('T2') - # class G1(Generic[*Ts]): pass + class G1(Generic[*Ts]): pass class G2(Generic[Unpack[Ts]]): pass for A in G1, G2, Tuple, tuple: @@ -1407,8 +1401,7 @@ class TypeVarTupleTests(BaseTestCase): C = A[T, T2] with self.assertRaises(TypeError): - # C[*Ts] - pass + C[*Ts] with self.assertRaises(TypeError): C[Unpack[Ts]] @@ -1427,7 +1420,7 @@ class TypeVarTupleTests(BaseTestCase): def test_repr_is_correct(self): Ts = TypeVarTuple('Ts') - # class G1(Generic[*Ts]): pass + class G1(Generic[*Ts]): pass class G2(Generic[Unpack[Ts]]): pass self.assertEqual(repr(Ts), 'Ts') @@ -1435,17 +1428,15 @@ class TypeVarTupleTests(BaseTestCase): self.assertEqual(repr((*Ts,)[0]), 'typing.Unpack[Ts]') self.assertEqual(repr(Unpack[Ts]), 'typing.Unpack[Ts]') - # self.assertEqual(repr(tuple[*Ts]), 'tuple[typing.Unpack[Ts]]') + self.assertEqual(repr(tuple[*Ts]), 'tuple[typing.Unpack[Ts]]') self.assertEqual(repr(Tuple[Unpack[Ts]]), 'typing.Tuple[typing.Unpack[Ts]]') - # self.assertEqual(repr(*tuple[*Ts]), '*tuple[typing.Unpack[Ts]]') + self.assertEqual(repr(*tuple[*Ts]), '*tuple[typing.Unpack[Ts]]') self.assertEqual(repr(Unpack[Tuple[Unpack[Ts]]]), 'typing.Unpack[typing.Tuple[typing.Unpack[Ts]]]') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_variadic_class_repr_is_correct(self): Ts = TypeVarTuple('Ts') - # class A(Generic[*Ts]): pass + class A(Generic[*Ts]): pass class B(Generic[Unpack[Ts]]): pass self.assertEndsWith(repr(A[()]), 'A[()]') @@ -1455,8 +1446,8 @@ class TypeVarTupleTests(BaseTestCase): self.assertEndsWith(repr(A[float, str]), 'A[float, str]') self.assertEndsWith(repr(B[float, str]), 'B[float, str]') - # self.assertEndsWith(repr(A[*tuple[int, ...]]), - # 'A[*tuple[int, ...]]') + self.assertEndsWith(repr(A[*tuple[int, ...]]), + 'A[*tuple[int, ...]]') self.assertEndsWith(repr(B[Unpack[Tuple[int, ...]]]), 'B[typing.Unpack[typing.Tuple[int, ...]]]') @@ -1475,17 +1466,15 @@ class TypeVarTupleTests(BaseTestCase): self.assertEndsWith(repr(B[float, Unpack[Tuple[int, ...]], str]), 'B[float, typing.Unpack[typing.Tuple[int, ...]], str]') - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_variadic_class_alias_repr_is_correct(self): Ts = TypeVarTuple('Ts') class A(Generic[Unpack[Ts]]): pass - # B = A[*Ts] - # self.assertEndsWith(repr(B), 'A[typing.Unpack[Ts]]') - # self.assertEndsWith(repr(B[()]), 'A[()]') - # self.assertEndsWith(repr(B[float]), 'A[float]') - # self.assertEndsWith(repr(B[float, str]), 'A[float, str]') + B = A[*Ts] + self.assertEndsWith(repr(B), 'A[typing.Unpack[Ts]]') + self.assertEndsWith(repr(B[()]), 'A[()]') + self.assertEndsWith(repr(B[float]), 'A[float]') + self.assertEndsWith(repr(B[float, str]), 'A[float, str]') C = A[Unpack[Ts]] self.assertEndsWith(repr(C), 'A[typing.Unpack[Ts]]') @@ -1562,12 +1551,10 @@ class TypeVarTupleTests(BaseTestCase): with self.assertRaisesRegex(TypeError, r'Cannot subclass typing.Unpack\[Ts\]'): class J(Unpack[Ts]): pass - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_variadic_class_args_are_correct(self): T = TypeVar('T') Ts = TypeVarTuple('Ts') - # class A(Generic[*Ts]): pass + class A(Generic[*Ts]): pass class B(Generic[Unpack[Ts]]): pass C = A[()] @@ -1590,10 +1577,10 @@ class TypeVarTupleTests(BaseTestCase): self.assertEqual(I.__args__, (T,)) self.assertEqual(J.__args__, (T,)) - # K = A[*Ts] - # L = B[Unpack[Ts]] - # self.assertEqual(K.__args__, (*Ts,)) - # self.assertEqual(L.__args__, (Unpack[Ts],)) + K = A[*Ts] + L = B[Unpack[Ts]] + self.assertEqual(K.__args__, (*Ts,)) + self.assertEqual(L.__args__, (Unpack[Ts],)) M = A[T, *Ts] N = B[T, Unpack[Ts]] @@ -1618,19 +1605,21 @@ class TypeVarTupleTests(BaseTestCase): self.assertIs(D[T].__origin__, D) self.assertIs(D[Unpack[Ts]].__origin__, D) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_get_type_hints_on_unpack_args(self): Ts = TypeVarTuple('Ts') - # def func1(*args: *Ts): pass - # self.assertEqual(gth(func1), {'args': Unpack[Ts]}) + def func1(*args: *Ts): pass + self.assertEqual(gth(func1), {'args': Unpack[Ts]}) - # def func2(*args: *tuple[int, str]): pass - # self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]}) + def func2(*args: *tuple[int, str]): pass + self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]}) - # class CustomVariadic(Generic[*Ts]): pass + class CustomVariadic(Generic[*Ts]): pass - # def func3(*args: *CustomVariadic[int, str]): pass - # self.assertEqual(gth(func3), {'args': Unpack[CustomVariadic[int, str]]}) + def func3(*args: *CustomVariadic[int, str]): pass + self.assertEqual(gth(func3), {'args': Unpack[CustomVariadic[int, str]]}) def test_get_type_hints_on_unpack_args_string(self): Ts = TypeVarTuple('Ts') @@ -1642,17 +1631,17 @@ class TypeVarTupleTests(BaseTestCase): def func2(*args: '*tuple[int, str]'): pass self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]}) - # class CustomVariadic(Generic[*Ts]): pass + class CustomVariadic(Generic[*Ts]): pass - # def func3(*args: '*CustomVariadic[int, str]'): pass - # self.assertEqual(gth(func3, localns={'CustomVariadic': CustomVariadic}), - # {'args': Unpack[CustomVariadic[int, str]]}) + def func3(*args: '*CustomVariadic[int, str]'): pass + self.assertEqual(gth(func3, localns={'CustomVariadic': CustomVariadic}), + {'args': Unpack[CustomVariadic[int, str]]}) def test_tuple_args_are_correct(self): Ts = TypeVarTuple('Ts') - # self.assertEqual(tuple[*Ts].__args__, (*Ts,)) + self.assertEqual(tuple[*Ts].__args__, (*Ts,)) self.assertEqual(Tuple[Unpack[Ts]].__args__, (Unpack[Ts],)) self.assertEqual(tuple[*Ts, int].__args__, (*Ts, int)) @@ -1820,20 +1809,21 @@ class TypeVarTupleTests(BaseTestCase): F[int, str, float] F[int, str, float, bool] - + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_variadic_args_annotations_are_correct(self): Ts = TypeVarTuple('Ts') def f(*args: Unpack[Ts]): pass - # def g(*args: *Ts): pass + def g(*args: *Ts): pass self.assertEqual(f.__annotations__, {'args': Unpack[Ts]}) - # self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) + self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) def test_variadic_args_with_ellipsis_annotations_are_correct(self): - # def a(*args: *tuple[int, ...]): pass - # self.assertEqual(a.__annotations__, - # {'args': (*tuple[int, ...],)[0]}) + def a(*args: *tuple[int, ...]): pass + self.assertEqual(a.__annotations__, + {'args': (*tuple[int, ...],)[0]}) def b(*args: Unpack[Tuple[int, ...]]): pass self.assertEqual(b.__annotations__, @@ -1845,29 +1835,29 @@ class TypeVarTupleTests(BaseTestCase): # Unpacking using `*`, native `tuple` type - # def a(*args: *tuple[int, *Ts]): pass - # self.assertEqual( - # a.__annotations__, - # {'args': (*tuple[int, *Ts],)[0]}, - # ) + def a(*args: *tuple[int, *Ts]): pass + self.assertEqual( + a.__annotations__, + {'args': (*tuple[int, *Ts],)[0]}, + ) - # def b(*args: *tuple[*Ts, int]): pass - # self.assertEqual( - # b.__annotations__, - # {'args': (*tuple[*Ts, int],)[0]}, - # ) + def b(*args: *tuple[*Ts, int]): pass + self.assertEqual( + b.__annotations__, + {'args': (*tuple[*Ts, int],)[0]}, + ) - # def c(*args: *tuple[str, *Ts, int]): pass - # self.assertEqual( - # c.__annotations__, - # {'args': (*tuple[str, *Ts, int],)[0]}, - # ) + def c(*args: *tuple[str, *Ts, int]): pass + self.assertEqual( + c.__annotations__, + {'args': (*tuple[str, *Ts, int],)[0]}, + ) - # def d(*args: *tuple[int, bool, *Ts, float, str]): pass - # self.assertEqual( - # d.__annotations__, - # {'args': (*tuple[int, bool, *Ts, float, str],)[0]}, - # ) + def d(*args: *tuple[int, bool, *Ts, float, str]): pass + self.assertEqual( + d.__annotations__, + {'args': (*tuple[int, bool, *Ts, float, str],)[0]}, + ) # Unpacking using `Unpack`, `Tuple` type from typing.py @@ -1895,11 +1885,9 @@ class TypeVarTupleTests(BaseTestCase): {'args': Unpack[Tuple[int, bool, Unpack[Ts], float, str]]}, ) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_variadic_class_same_args_results_in_equalty(self): Ts = TypeVarTuple('Ts') - # class C(Generic[*Ts]): pass + class C(Generic[*Ts]): pass class D(Generic[Unpack[Ts]]): pass self.assertEqual(C[int], C[int]) @@ -1909,8 +1897,8 @@ class TypeVarTupleTests(BaseTestCase): Ts2 = TypeVarTuple('Ts2') self.assertEqual( - # C[*Ts1], - # C[*Ts1], + C[*Ts1], + C[*Ts1], ) self.assertEqual( D[Unpack[Ts1]], @@ -1935,11 +1923,9 @@ class TypeVarTupleTests(BaseTestCase): D[int, Unpack[Ts1], Unpack[Ts2]], ) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_variadic_class_arg_ordering_matters(self): Ts = TypeVarTuple('Ts') - # class C(Generic[*Ts]): pass + class C(Generic[*Ts]): pass class D(Generic[Unpack[Ts]]): pass self.assertNotEqual( @@ -1968,10 +1954,10 @@ class TypeVarTupleTests(BaseTestCase): Ts1 = TypeVarTuple('Ts1') Ts2 = TypeVarTuple('Ts2') - # class C(Generic[*Ts]): pass + class C(Generic[*Ts]): pass class D(Generic[Unpack[Ts]]): pass - # self.assertNotEqual(C[*Ts1], C[*Ts2]) + self.assertNotEqual(C[*Ts1], C[*Ts2]) self.assertNotEqual(D[Unpack[Ts1]], D[Unpack[Ts2]]) class TypeVarTuplePicklingTests(BaseTestCase): @@ -2010,8 +1996,7 @@ class TypeVarTuplePicklingTests(BaseTestCase): global_Ts = TypeVarTuple('global_Ts') tuples = [ - # TODO: RUSTPYTHON - # tuple[*global_Ts], + tuple[*global_Ts], Tuple[Unpack[global_Ts]], tuple[T, *global_Ts], @@ -6153,7 +6138,7 @@ class GetUtilitiesTestCase(TestCase): self.assertIs(get_origin(NotRequired[int]), NotRequired) self.assertIs(get_origin((*Ts,)[0]), Unpack) self.assertIs(get_origin(Unpack[Ts]), Unpack) - # self.assertIs(get_origin((*tuple[*Ts],)[0]), tuple) + self.assertIs(get_origin((*tuple[*Ts],)[0]), tuple) self.assertIs(get_origin(Unpack[Tuple[Unpack[Ts]]]), Unpack) # TODO: RUSTPYTHON @@ -6221,9 +6206,9 @@ class GetUtilitiesTestCase(TestCase): self.assertEqual(get_args(Ts), ()) self.assertEqual(get_args((*Ts,)[0]), (Ts,)) self.assertEqual(get_args(Unpack[Ts]), (Ts,)) - # self.assertEqual(get_args(tuple[*Ts]), (*Ts,)) + self.assertEqual(get_args(tuple[*Ts]), (*Ts,)) self.assertEqual(get_args(tuple[Unpack[Ts]]), (Unpack[Ts],)) - # self.assertEqual(get_args((*tuple[*Ts],)[0]), (*Ts,)) + self.assertEqual(get_args((*tuple[*Ts],)[0]), (*Ts,)) self.assertEqual(get_args(Unpack[tuple[Unpack[Ts]]]), (tuple[Unpack[Ts]],)) @@ -8405,8 +8390,6 @@ class AnnotatedTests(BaseTestCase): with self.assertRaises(TypeError): LI[None] - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_typevar_subst(self): dec = "a decoration" Ts = TypeVarTuple('Ts') @@ -8414,7 +8397,7 @@ class AnnotatedTests(BaseTestCase): T1 = TypeVar('T1') T2 = TypeVar('T2') - # A = Annotated[tuple[*Ts], dec] + A = Annotated[tuple[*Ts], dec] self.assertEqual(A[int], Annotated[tuple[int], dec]) self.assertEqual(A[str, int], Annotated[tuple[str, int], dec]) with self.assertRaises(TypeError): @@ -8751,15 +8734,13 @@ class ParamSpecTests(BaseTestCase): self.assertEqual(G1.__args__, ((int, str), (bytes,))) self.assertEqual(G2.__args__, ((int,), (str, bytes))) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_typevartuple_and_paramspecs_in_user_generics(self): Ts = TypeVarTuple("Ts") P = ParamSpec("P") - # class X(Generic[*Ts, P]): - # f: Callable[P, int] - # g: Tuple[*Ts] + class X(Generic[*Ts, P]): + f: Callable[P, int] + g: Tuple[*Ts] G1 = X[int, [bytes]] self.assertEqual(G1.__args__, (int, (bytes,))) @@ -8772,9 +8753,9 @@ class ParamSpecTests(BaseTestCase): with self.assertRaises(TypeError): X[()] - # class Y(Generic[P, *Ts]): - # f: Callable[P, int] - # g: Tuple[*Ts] + class Y(Generic[P, *Ts]): + f: Callable[P, int] + g: Tuple[*Ts] G1 = Y[[bytes], int] self.assertEqual(G1.__args__, ((bytes,), int)) @@ -8787,8 +8768,6 @@ class ParamSpecTests(BaseTestCase): with self.assertRaises(TypeError): Y[()] - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_typevartuple_and_paramspecs_in_generic_aliases(self): P = ParamSpec('P') T = TypeVar('T') @@ -8796,21 +8775,21 @@ class ParamSpecTests(BaseTestCase): for C in Callable, collections.abc.Callable: with self.subTest(generic=C): - # A = C[P, Tuple[*Ts]] + A = C[P, Tuple[*Ts]] B = A[[int, str], bytes, float] self.assertEqual(B.__args__, (int, str, Tuple[bytes, float])) class X(Generic[T, P]): pass - # A = X[Tuple[*Ts], P] + A = X[Tuple[*Ts], P] B = A[bytes, float, [int, str]] self.assertEqual(B.__args__, (Tuple[bytes, float], (int, str,))) class Y(Generic[P, T]): pass - # A = Y[P, Tuple[*Ts]] + A = Y[P, Tuple[*Ts]] B = A[[int, str], bytes, float] self.assertEqual(B.__args__, ((int, str,), Tuple[bytes, float])) @@ -8892,10 +8871,10 @@ class ParamSpecTests(BaseTestCase): self.assertEqual(A8.__args__, ((T, list[T]),)) self.assertEqual(A8[int], Base[[int, list[int]]]) - # A9 = Base[[Tuple[*Ts], *Ts]] - # self.assertEqual(A9.__parameters__, (Ts,)) - # self.assertEqual(A9.__args__, ((Tuple[*Ts], *Ts),)) - # self.assertEqual(A9[int, str], Base[Tuple[int, str], int, str]) + A9 = Base[[Tuple[*Ts], *Ts]] + self.assertEqual(A9.__parameters__, (Ts,)) + self.assertEqual(A9.__args__, ((Tuple[*Ts], *Ts),)) + self.assertEqual(A9[int, str], Base[Tuple[int, str], int, str]) A10 = Base[P2] self.assertEqual(A10.__parameters__, (P2,)) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index 71b94cdb9..10c1c84d9 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -80,6 +80,7 @@ struct Compiler<'src> { ctx: CompileContext, class_name: Option, opts: CompileOpts, + in_annotation: bool, } enum DoneWithFuture { @@ -335,6 +336,7 @@ impl<'src> Compiler<'src> { }, class_name: None, opts, + in_annotation: false, } } } @@ -2897,7 +2899,11 @@ impl Compiler<'_> { .into(), }); } else { - self.compile_expression(annotation)?; + let was_in_annotation = self.in_annotation; + self.in_annotation = true; + let result = self.compile_expression(annotation); + self.in_annotation = was_in_annotation; + result?; } Ok(()) } @@ -3504,8 +3510,15 @@ impl Compiler<'_> { Self::contains_await(elt), )?; } - Expr::Starred(_) => { - return Err(self.error(CodegenErrorType::InvalidStarExpr)); + Expr::Starred(ExprStarred { value, .. }) => { + if self.in_annotation { + // In annotation context, starred expressions are allowed (PEP 646) + // For now, just compile the inner value without wrapping with Unpack + // This is a temporary solution until we figure out how to properly import typing + self.compile_expression(value)?; + } else { + return Err(self.error(CodegenErrorType::InvalidStarExpr)); + } } Expr::If(ExprIf { test, body, orelse, .. diff --git a/vm/src/builtins/asyncgenerator.rs b/vm/src/builtins/asyncgenerator.rs index bdfdd7b27..a280495fd 100644 --- a/vm/src/builtins/asyncgenerator.rs +++ b/vm/src/builtins/asyncgenerator.rs @@ -69,7 +69,7 @@ impl PyAsyncGen { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 3d9b8e245..1130fec60 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -322,7 +322,7 @@ impl PyDict { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/enumerate.rs b/vm/src/builtins/enumerate.rs index 84944ad1d..f0287a619 100644 --- a/vm/src/builtins/enumerate.rs +++ b/vm/src/builtins/enumerate.rs @@ -57,7 +57,7 @@ impl Constructor for PyEnumerate { impl PyEnumerate { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/genericalias.rs b/vm/src/builtins/genericalias.rs index 6191d652f..86797241f 100644 --- a/vm/src/builtins/genericalias.rs +++ b/vm/src/builtins/genericalias.rs @@ -63,7 +63,12 @@ impl Constructor for PyGenericAlias { return Err(vm.new_type_error("GenericAlias() takes no keyword arguments")); } let (origin, arguments): (_, PyObjectRef) = args.bind(vm)?; - PyGenericAlias::new(origin, arguments, vm) + let args = if let Ok(tuple) = arguments.try_to_ref::(vm) { + tuple.to_owned() + } else { + PyTuple::new_ref(vec![arguments], &vm.ctx) + }; + PyGenericAlias::new(origin, args, false, vm) .into_ref_with_type(vm, cls) .map(Into::into) } @@ -84,28 +89,7 @@ impl Constructor for PyGenericAlias { flags(BASETYPE) )] impl PyGenericAlias { - pub fn new(origin: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> Self { - let args = if let Ok(tuple) = args.try_to_ref::(vm) { - tuple.to_owned() - } else { - PyTuple::new_ref(vec![args], &vm.ctx) - }; - - let parameters = make_parameters(&args, vm); - Self { - origin, - args, - parameters, - starred: false, // default to false - } - } - - fn with_tuple_args( - origin: PyTypeRef, - args: PyTupleRef, - starred: bool, - vm: &VirtualMachine, - ) -> Self { + pub fn new(origin: PyTypeRef, args: PyTupleRef, starred: bool, vm: &VirtualMachine) -> Self { let parameters = make_parameters(&args, vm); Self { origin, @@ -115,6 +99,16 @@ impl PyGenericAlias { } } + /// Create a GenericAlias from an origin and PyObjectRef arguments (helper for compatibility) + pub fn from_args(origin: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> Self { + let args = if let Ok(tuple) = args.try_to_ref::(vm) { + tuple.to_owned() + } else { + PyTuple::new_ref(vec![args], &vm.ctx) + }; + Self::new(origin, args, false, vm) + } + fn repr(&self, vm: &VirtualMachine) -> PyResult { fn repr_item(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult { if obj.is(&vm.ctx.ellipsis) { @@ -146,7 +140,7 @@ impl PyGenericAlias { } } - Ok(format!( + let repr_str = format!( "{}[{}]", repr_item(self.origin.clone().into(), vm)?, if self.args.is_empty() { @@ -158,7 +152,14 @@ impl PyGenericAlias { .collect::>>()? .join(", ") } - )) + ); + + // Add * prefix if this is a starred GenericAlias + Ok(if self.starred { + format!("*{repr_str}") + } else { + repr_str + }) } #[pygetset] @@ -200,10 +201,7 @@ impl PyGenericAlias { vm, )?; - Ok( - PyGenericAlias::new(zelf.origin.clone(), new_args.to_pyobject(vm), vm) - .into_pyobject(vm), - ) + Ok(PyGenericAlias::new(zelf.origin.clone(), new_args, false, vm).into_pyobject(vm)) } #[pymethod] @@ -598,7 +596,7 @@ impl Iterable for PyGenericAlias { // CPython's ga_iter creates an iterator that yields one starred GenericAlias // we don't have gaiterobject yet - let starred_alias = PyGenericAlias::with_tuple_args( + let starred_alias = PyGenericAlias::new( zelf.origin.clone(), zelf.args.clone(), true, // starred diff --git a/vm/src/builtins/list.rs b/vm/src/builtins/list.rs index 5895ce37e..fe867ebd7 100644 --- a/vm/src/builtins/list.rs +++ b/vm/src/builtins/list.rs @@ -337,7 +337,7 @@ impl PyList { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/mappingproxy.rs b/vm/src/builtins/mappingproxy.rs index 24aca1e27..8942a0a22 100644 --- a/vm/src/builtins/mappingproxy.rs +++ b/vm/src/builtins/mappingproxy.rs @@ -176,7 +176,7 @@ impl PyMappingProxy { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } #[pymethod] diff --git a/vm/src/builtins/set.rs b/vm/src/builtins/set.rs index 8a71378f4..4ff5bed7b 100644 --- a/vm/src/builtins/set.rs +++ b/vm/src/builtins/set.rs @@ -790,7 +790,7 @@ impl PySet { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } @@ -1134,7 +1134,7 @@ impl PyFrozenSet { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 7f3855c52..029417f43 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -343,7 +343,7 @@ impl PyTuple { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/builtins/weakref.rs b/vm/src/builtins/weakref.rs index 62c541ebf..441cac9b3 100644 --- a/vm/src/builtins/weakref.rs +++ b/vm/src/builtins/weakref.rs @@ -55,7 +55,7 @@ impl Constructor for PyWeak { impl PyWeak { #[pyclassmethod] fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/protocol/object.rs b/vm/src/protocol/object.rs index da0abdf1c..dc3bb3d7b 100644 --- a/vm/src/protocol/object.rs +++ b/vm/src/protocol/object.rs @@ -693,7 +693,7 @@ impl PyObject { } else { if self.class().fast_issubclass(vm.ctx.types.type_type) { if self.is(vm.ctx.types.type_type) { - return PyGenericAlias::new(self.class().to_owned(), needle, vm) + return PyGenericAlias::from_args(self.class().to_owned(), needle, vm) .to_pyresult(vm); } diff --git a/vm/src/stdlib/collections.rs b/vm/src/stdlib/collections.rs index 57e3335ac..f24d3fb4e 100644 --- a/vm/src/stdlib/collections.rs +++ b/vm/src/stdlib/collections.rs @@ -415,7 +415,7 @@ mod _collections { args: PyObjectRef, vm: &VirtualMachine, ) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/stdlib/itertools.rs b/vm/src/stdlib/itertools.rs index ac106fe16..efe336812 100644 --- a/vm/src/stdlib/itertools.rs +++ b/vm/src/stdlib/itertools.rs @@ -68,7 +68,7 @@ mod decl { args: PyObjectRef, vm: &VirtualMachine, ) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } #[pymethod] diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 35a9aa1b3..8b13b77fb 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -592,7 +592,7 @@ pub(super) mod _os { args: PyObjectRef, vm: &VirtualMachine, ) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 39d3ebaf6..28d9a89a1 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -502,7 +502,7 @@ mod _sre { args: PyObjectRef, vm: &VirtualMachine, ) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } } @@ -816,7 +816,7 @@ mod _sre { args: PyObjectRef, vm: &VirtualMachine, ) -> PyGenericAlias { - PyGenericAlias::new(cls, args, vm) + PyGenericAlias::from_args(cls, args, vm) } }