diff --git a/Lib/test/_typed_dict_helper.py b/Lib/test/_typed_dict_helper.py deleted file mode 100644 index d333db1931..0000000000 --- a/Lib/test/_typed_dict_helper.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Used to test `get_type_hints()` on a cross-module inherited `TypedDict` class - -This script uses future annotations to postpone a type that won't be available -on the module inheriting from to `Foo`. The subclass in the other module should -look something like this: - - class Bar(_typed_dict_helper.Foo, total=False): - b: int -""" - -from __future__ import annotations - -from typing import Optional, TypedDict - -OptionalIntType = Optional[int] - -class Foo(TypedDict): - a: OptionalIntType diff --git a/Lib/test/ann_module.py b/Lib/test/ann_module.py deleted file mode 100644 index 5081e6b583..0000000000 --- a/Lib/test/ann_module.py +++ /dev/null @@ -1,62 +0,0 @@ - - -""" -The module for testing variable annotations. -Empty lines above are for good reason (testing for correct line numbers) -""" - -from typing import Optional -from functools import wraps - -__annotations__[1] = 2 - -class C: - - x = 5; y: Optional['C'] = None - -from typing import Tuple -x: int = 5; y: str = x; f: Tuple[int, int] - -class M(type): - - __annotations__['123'] = 123 - o: type = object - -(pars): bool = True - -class D(C): - j: str = 'hi'; k: str= 'bye' - -from types import new_class -h_class = new_class('H', (C,)) -j_class = new_class('J') - -class F(): - z: int = 5 - def __init__(self, x): - pass - -class Y(F): - def __init__(self): - super(F, self).__init__(123) - -class Meta(type): - def __new__(meta, name, bases, namespace): - return super().__new__(meta, name, bases, namespace) - -class S(metaclass = Meta): - x: str = 'something' - y: str = 'something else' - -def foo(x: int = 10): - def bar(y: List[str]): - x: str = 'yes' - bar() - -def dec(func): - @wraps(func) - def wrapper(*args, **kwargs): - return func(*args, **kwargs) - return wrapper - -u: int | float diff --git a/Lib/test/ann_module2.py b/Lib/test/ann_module2.py deleted file mode 100644 index 76cf5b3ad9..0000000000 --- a/Lib/test/ann_module2.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Some correct syntax for variable annotation here. -More examples are in test_grammar and test_parser. -""" - -from typing import no_type_check, ClassVar - -i: int = 1 -j: int -x: float = i/10 - -def f(): - class C: ... - return C() - -f().new_attr: object = object() - -class C: - def __init__(self, x: int) -> None: - self.x = x - -c = C(5) -c.new_attr: int = 10 - -__annotations__ = {} - - -@no_type_check -class NTC: - def meth(self, param: complex) -> None: - ... - -class CV: - var: ClassVar['CV'] - -CV.var = CV() diff --git a/Lib/test/ann_module3.py b/Lib/test/ann_module3.py deleted file mode 100644 index eccd7be22d..0000000000 --- a/Lib/test/ann_module3.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -Correct syntax for variable annotation that should fail at runtime -in a certain manner. More examples are in test_grammar and test_parser. -""" - -def f_bad_ann(): - __annotations__[1] = 2 - -class C_OK: - def __init__(self, x: int) -> None: - self.x: no_such_name = x # This one is OK as proposed by Guido - -class D_bad_ann: - def __init__(self, x: int) -> None: - sfel.y: int = 0 - -def g_bad_ann(): - no_such_name.attr: int = 0 diff --git a/Lib/test/ann_module4.py b/Lib/test/ann_module4.py deleted file mode 100644 index 13e9aee54c..0000000000 --- a/Lib/test/ann_module4.py +++ /dev/null @@ -1,5 +0,0 @@ -# This ann_module isn't for test_typing, -# it's for test_module - -a:int=3 -b:str=4 diff --git a/Lib/test/ann_module5.py b/Lib/test/ann_module5.py deleted file mode 100644 index 837041e121..0000000000 --- a/Lib/test/ann_module5.py +++ /dev/null @@ -1,10 +0,0 @@ -# Used by test_typing to verify that Final wrapped in ForwardRef works. - -from __future__ import annotations - -from typing import Final - -name: Final[str] = "final" - -class MyClass: - value: Final = 3000 diff --git a/Lib/test/ann_module6.py b/Lib/test/ann_module6.py deleted file mode 100644 index 679175669b..0000000000 --- a/Lib/test/ann_module6.py +++ /dev/null @@ -1,7 +0,0 @@ -# Tests that top-level ClassVar is not allowed - -from __future__ import annotations - -from typing import ClassVar - -wrong: ClassVar[int] = 1 diff --git a/Lib/test/ann_module7.py b/Lib/test/ann_module7.py deleted file mode 100644 index 8f890cd280..0000000000 --- a/Lib/test/ann_module7.py +++ /dev/null @@ -1,11 +0,0 @@ -# Tests class have ``__text_signature__`` - -from __future__ import annotations - -DEFAULT_BUFFER_SIZE = 8192 - -class BufferedReader(object): - """BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n--\n\n - Create a new buffered reader using the given readable raw IO object. - """ - pass diff --git a/Lib/test/mod_generics_cache.py b/Lib/test/mod_generics_cache.py deleted file mode 100644 index 6d35c58396..0000000000 --- a/Lib/test/mod_generics_cache.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Module for testing the behavior of generics across different modules.""" - -import sys -from textwrap import dedent -from typing import TypeVar, Generic, Optional - - -if sys.version_info[:2] >= (3, 6): - exec(dedent(""" - default_a: Optional['A'] = None - default_b: Optional['B'] = None - - T = TypeVar('T') - - - class A(Generic[T]): - some_b: 'B' - - - class B(Generic[T]): - class A(Generic[T]): - pass - - my_inner_a1: 'B.A' - my_inner_a2: A - my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ - """)) -else: # This should stay in sync with the syntax above. - __annotations__ = dict( - default_a=Optional['A'], - default_b=Optional['B'], - ) - default_a = None - default_b = None - - T = TypeVar('T') - - - class A(Generic[T]): - __annotations__ = dict( - some_b='B' - ) - - - class B(Generic[T]): - class A(Generic[T]): - pass - - __annotations__ = dict( - my_inner_a1='B.A', - my_inner_a2=A, - my_outer_a='A' # unless somebody calls get_type_hints with localns=B.__dict__ - ) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index d5c9250ab0..e40f569d2c 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -400,7 +400,7 @@ def test_var_annot_module_semantics(self): def test_var_annot_in_module(self): # check that functions fail the same way when executed # outside of module where they were defined - from test.ann_module3 import f_bad_ann, g_bad_ann, D_bad_ann + from test.typinganndata.ann_module3 import f_bad_ann, g_bad_ann, D_bad_ann with self.assertRaises(NameError): f_bad_ann() with self.assertRaises(NameError): diff --git a/Lib/test/test_module/__init__.py b/Lib/test/test_module/__init__.py index d8a0ba0803..b599c6d8c8 100644 --- a/Lib/test/test_module/__init__.py +++ b/Lib/test/test_module/__init__.py @@ -334,7 +334,7 @@ def test_annotations_getset_raises(self): del foo.__annotations__ def test_annotations_are_created_correctly(self): - ann_module4 = import_helper.import_fresh_module('test.ann_module4') + ann_module4 = import_helper.import_fresh_module('test.typinganndata.ann_module4') self.assertTrue("__annotations__" in ann_module4.__dict__) del ann_module4.__annotations__ self.assertFalse("__annotations__" in ann_module4.__dict__) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a4f2e897b1..a048c39cc9 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -629,8 +629,6 @@ def test_typevar(self): class A(Generic[T]): ... Alias = Optional[T] - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_typevar_none(self): U = TypeVar('U') U_None = TypeVar('U_None', default=None) @@ -1210,8 +1208,6 @@ def foo(**kwargs: Unpack[Movie]): ... self.assertEqual(repr(foo.__annotations__['kwargs']), f"typing.Unpack[{__name__}.Movie]") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_builtin_tuple(self): Ts = TypeVarTuple("Ts") @@ -2636,11 +2632,6 @@ def test_consistency(self): class CollectionsCallableTests(BaseCallableTests, BaseTestCase): Callable = collections.abc.Callable - # TODO: RUSTPYTHON - @unittest.expectedFailure - def test_errors(self): - super().test_errors() - class LiteralTests(BaseTestCase): def test_basics(self): @@ -3608,8 +3599,6 @@ class C(B[int]): c.bar = 'abc' self.assertEqual(c.__dict__, {'bar': 'abc'}) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_setattr_exceptions(self): class Immutable[T]: def __setattr__(self, key, value): @@ -3753,8 +3742,6 @@ class Meta(type): ... self.assertEqual(Union[T, int][Meta], Union[Meta, int]) self.assertEqual(Callable[..., Meta].__args__, (Ellipsis, Meta)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generic_hashes(self): class A(Generic[T]): ... @@ -4302,8 +4289,6 @@ class B(Generic[T]): self.assertEqual(A[T], A[T]) self.assertNotEqual(A[T], B[T]) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_multiple_inheritance(self): class A(Generic[T, VT]): @@ -6106,8 +6091,6 @@ class C(Generic[T]): pass self.assertIs(get_origin((*tuple[*Ts],)[0]), tuple) self.assertIs(get_origin(Unpack[Tuple[Unpack[Ts]]]), Unpack) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_get_args(self): T = TypeVar('T') class C(Generic[T]): pass @@ -7599,8 +7582,6 @@ class A[T](TypedDict): self.assertEqual(A[str].__parameters__, ()) self.assertEqual(A[str].__args__, (str,)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generic_inheritance(self): class A(TypedDict, Generic[T]): a: T diff --git a/Lib/test/typinganndata/mod_generics_cache.py b/Lib/test/typinganndata/mod_generics_cache.py index 62deea9859..6c1ee2fec8 100644 --- a/Lib/test/typinganndata/mod_generics_cache.py +++ b/Lib/test/typinganndata/mod_generics_cache.py @@ -2,25 +2,23 @@ from typing import TypeVar, Generic, Optional, TypeAliasType -# TODO: RUSTPYTHON +default_a: Optional['A'] = None +default_b: Optional['B'] = None -# default_a: Optional['A'] = None -# default_b: Optional['B'] = None +T = TypeVar('T') -# T = TypeVar('T') +class A(Generic[T]): + some_b: 'B' -# class A(Generic[T]): -# some_b: 'B' +class B(Generic[T]): + class A(Generic[T]): + pass -# class B(Generic[T]): -# class A(Generic[T]): -# pass + my_inner_a1: 'B.A' + my_inner_a2: A + my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ -# my_inner_a1: 'B.A' -# my_inner_a2: A -# my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__ - -# type Alias = int -# OldStyle = TypeAliasType("OldStyle", int) +type Alias = int +OldStyle = TypeAliasType("OldStyle", int) diff --git a/compiler/codegen/src/compile.rs b/compiler/codegen/src/compile.rs index bf12e13296..4180b79712 100644 --- a/compiler/codegen/src/compile.rs +++ b/compiler/codegen/src/compile.rs @@ -1215,38 +1215,83 @@ impl Compiler<'_> { // First, compile each type parameter and store it for type_param in &type_params.type_params { match type_param { - TypeParam::TypeVar(TypeParamTypeVar { name, bound, .. }) => { + TypeParam::TypeVar(TypeParamTypeVar { + name, + bound, + default, + .. + }) => { if let Some(expr) = &bound { self.compile_expression(expr)?; self.emit_load_const(ConstantData::Str { value: name.as_str().into(), }); emit!(self, Instruction::TypeVarWithBound); - emit!(self, Instruction::Duplicate); - self.store_name(name.as_ref())?; } else { - // self.store_name(type_name.as_str())?; self.emit_load_const(ConstantData::Str { value: name.as_str().into(), }); emit!(self, Instruction::TypeVar); - emit!(self, Instruction::Duplicate); - self.store_name(name.as_ref())?; } + + // Handle default value if present (PEP 695) + if let Some(default_expr) = default { + // Compile the default expression + self.compile_expression(default_expr)?; + + emit!( + self, + Instruction::CallIntrinsic2 { + func: bytecode::IntrinsicFunction2::SetTypeparamDefault + } + ); + } + + emit!(self, Instruction::Duplicate); + self.store_name(name.as_ref())?; } - TypeParam::ParamSpec(TypeParamParamSpec { name, .. }) => { + TypeParam::ParamSpec(TypeParamParamSpec { name, default, .. }) => { self.emit_load_const(ConstantData::Str { value: name.as_str().into(), }); emit!(self, Instruction::ParamSpec); + + // Handle default value if present (PEP 695) + if let Some(default_expr) = default { + // Compile the default expression + self.compile_expression(default_expr)?; + + emit!( + self, + Instruction::CallIntrinsic2 { + func: bytecode::IntrinsicFunction2::SetTypeparamDefault + } + ); + } + emit!(self, Instruction::Duplicate); self.store_name(name.as_ref())?; } - TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, .. }) => { + TypeParam::TypeVarTuple(TypeParamTypeVarTuple { name, default, .. }) => { self.emit_load_const(ConstantData::Str { value: name.as_str().into(), }); emit!(self, Instruction::TypeVarTuple); + + // Handle default value if present (PEP 695) + if let Some(default_expr) = default { + // Compile the default expression + self.compile_expression(default_expr)?; + + // Handle starred expression (*default) + emit!( + self, + Instruction::CallIntrinsic2 { + func: bytecode::IntrinsicFunction2::SetTypeparamDefault + } + ); + } + emit!(self, Instruction::Duplicate); self.store_name(name.as_ref())?; } @@ -1759,13 +1804,41 @@ impl Compiler<'_> { self.emit_load_const(ConstantData::Str { value: name.into() }); - // Call the __build_class__ builtin - let call = if let Some(arguments) = arguments { - self.compile_call_inner(2, arguments)? + // For PEP 695 classes: handle Generic base creation + if type_params.is_some() { + if let Some(arguments) = arguments { + // Has explicit bases - use them as is, don't add Generic + // CPython doesn't add Generic when explicit bases are present + let call = self.compile_call_inner(2, arguments)?; + self.compile_normal_call(call); + } else { + // No explicit bases, add Generic[*type_params] as the only base + // Stack currently: [function, class_name] + + // Load .type_params for creating Generic base + let dot_type_params = self.name(".type_params"); + emit!(self, Instruction::LoadNameAny(dot_type_params)); + + // Call INTRINSIC_SUBSCRIPT_GENERIC to create Generic[*type_params] + emit!( + self, + Instruction::CallIntrinsic1 { + func: bytecode::IntrinsicFunction1::SubscriptGeneric + } + ); + + // Call __build_class__ with 3 positional args: function, class_name, Generic[T] + emit!(self, Instruction::CallFunctionPositional { nargs: 3 }); + } } else { - CallType::Positional { nargs: 2 } - }; - self.compile_normal_call(call); + // No type params, normal compilation + let call = if let Some(arguments) = arguments { + self.compile_call_inner(2, arguments)? + } else { + CallType::Positional { nargs: 2 } + }; + self.compile_normal_call(call); + } // Pop the special type params symbol table if type_params.is_some() { diff --git a/compiler/core/src/bytecode.rs b/compiler/core/src/bytecode.rs index 2ad0e97969..be55fe3502 100644 --- a/compiler/core/src/bytecode.rs +++ b/compiler/core/src/bytecode.rs @@ -375,6 +375,49 @@ op_arg_enum!( } ); +op_arg_enum!( + /// Intrinsic function for CALL_INTRINSIC_1 + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[repr(u8)] + pub enum IntrinsicFunction1 { + /// Import * special case + // ImportStar = 0, + /// Set stop iteration value + // StopAsyncIteration = 1, + /// Unary operators + // UnaryPositive = 2, + // UnaryNegative = 3, + // UnaryNot = 4, + // UnaryInvert = 5, + /// Exit init subclass + // ExitInitCheck = 6, + /// Create a new list from an iterator + // ListToTupleForCall = 7, + /// Type parameter related + // TypeVar = 8, + // TypeVarTuple = 9, + // ParamSpec = 10, + /// Generic subscript for PEP 695 + SubscriptGeneric = 10, + // TypeAlias = 12, + // TypeParams = 13, + } +); + +op_arg_enum!( + /// Intrinsic function for CALL_INTRINSIC_2 + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[repr(u8)] + pub enum IntrinsicFunction2 { + // PrepReraiseS tar = 1, + // TypeVarWithBound = 2, + // TypeVarWithConstraints = 3, + // SetFunctionTypeParams = 4, + /// Set default value for type parameter (PEP 695) + SetTypeparamDefault = 5, + } +); + pub type NameIdx = u32; /// A Single bytecode instruction. @@ -454,6 +497,12 @@ pub enum Instruction { Duplicate2, GetIter, GetLen, + CallIntrinsic1 { + func: Arg, + }, + CallIntrinsic2 { + func: Arg, + }, Continue { target: Arg