10000 __type_params__ in __build_class__ (#5883) · RustPython/RustPython@8a2a6af · GitHub
[go: up one dir, main page]

Skip to content

Commit 8a2a6af

Browse files
authored
__type_params__ in __build_class__ (#5883)
* remove future __classs_getitem__ * __type_params__ in __build_class__
1 parent c529c24 commit 8a2a6af

File tree

9 files changed

+76
-24
lines changed

9 files changed

+76
-24
lines changed

Lib/test/test_typing.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -656,8 +656,6 @@ class A(Generic[P]): ...
656656
P_default = ParamSpec('P_default', default=...)
657657
self.assertIs(P_default.__default__, ...)
658658

659-
# TODO: RUSTPYTHON
660-
@unittest.expectedFailure
661659
def test_paramspec_none(self):
662660
U = ParamSpec('U')
663661
U_None = ParamSpec('U_None', default=None)
@@ -756,8 +754,6 @@ class A(Generic[T, P, U]): ...
756754
self.assertEqual(A[float, [range]].__args__, (float, (range,), float))
757755
self.assertEqual(A[float, [range], int].__args__, (float, (range,), int))
758756

759-
# TODO: RUSTPYTHON
760-
@unittest.expectedFailure
761757
def test_typevartuple_none(self):
762758
U = TypeVarTuple('U')
763759
U_None = TypeVarTuple('U_None', default=None)
@@ -3893,8 +3889,6 @@ def f(x: X): ...
38933889
{'x': list[list[ForwardRef('X')]]}
38943890
)
38953891

3896-
# TODO: RUSTPYTHON
3897-
@unittest.expectedFailure
38983892
def test_pep695_generic_class_with_future_annotations(self):
38993893
original_globals = dict(ann_module695.__dict__)
39003894

@@ -3913,8 +3907,6 @@ def test_pep695_generic_class_with_future_annotations_and_local_shadowing(self):
39133907
hints_for_B = get_type_hints(ann_module695.B)
39143908
self.assertEqual(hints_for_B, {"x": int, "y": str, "z": bytes})
39153909

3916-
# TODO: RUSTPYTHON
3917-
@unittest.expectedFailure
39183910
def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self):
39193911
hints_for_C = get_type_hints(ann_module695.C)
39203912
self.assertEqual(

compiler/codegen/src/compile.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,7 @@ impl Compiler<'_> {
12121212
/// Store each type parameter so it is accessible to the current scope, and leave a tuple of
12131213
/// all the type parameters on the stack.
12141214
fn compile_type_params(&mut self, type_params: &TypeParams) -> CompileResult<()> {
1215+
// First, compile each type parameter and store it
12151216
for type_param in &type_params.type_params {
12161217
match type_param {
12171218
TypeParam::TypeVar(TypeParamTypeVar { name, bound, .. }) => {
@@ -1664,8 +1665,12 @@ impl Compiler<'_> {
16641665
let qualified_name = self.qualified_path.join(".");
16651666

16661667
// If there are type params, we need to push a special symbol table just for them
1667-
if type_params.is_some() {
1668+
if let Some(type_params) = type_params {
16681669
self.push_symbol_table();
1670+
// Compile type parameters and store as .type_params
1671+
self.compile_type_params(type_params)?;
1672+
let dot_type_params = self.name(".type_params");
1673+
emit!(self, Instruction::StoreLocal(dot_type_params));
16691674
}
16701675

16711676
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
@@ -1688,6 +1693,18 @@ impl Compiler<'_> {
16881693
if Self::find_ann(body) {
16891694
emit!(self, Instruction::SetupAnnotation);
16901695
}
1696+
1697+
// Set __type_params__ from .type_params if we have type parameters (PEP 695)
1698+
if type_params.is_some() {
1699+
// Load .type_params from enclosing scope
1700+
let dot_type_params = self.name(".type_params");
1701+
emit!(self, Instruction::LoadNameAny(dot_type_params));
1702+
1703+
// Store as __type_params__
1704+
let dunder_type_params = self.name("__type_params__");
1705+
emit!(self, Instruction::StoreLocal(dunder_type_params));
1706+
}
1707+
16911708
self.compile_statements(body)?;
16921709

16931710
let classcell_idx = self
@@ -1721,8 +1738,10 @@ impl Compiler<'_> {
17211738
let mut func_flags = bytecode::MakeFunctionFlags::empty();
17221739

17231740
// Prepare generic type parameters:
1724-
if let Some(type_params) = type_params {
1725-
self.compile_type_params(type_params)?;
1741+
if type_params.is_some() {
1742+
// Load .type_params from the type params scope
1743+
let dot_type_params = self.name(".type_params");
1744+
emit!(self, Instruction::LoadNameAny(dot_type_params));
17261745
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
17271746
}
17281747

compiler/codegen/src/symboltable.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,7 @@ impl SymbolTableBuilder<'_> {
12671267
}
12681268

12691269
fn scan_type_params(&mut self, type_params: &TypeParams) -> SymbolTableResult {
1270+
// First register all type parameters
12701271
for type_param in &type_params.type_params {
12711272
match type_param {
12721273
TypeParam::TypeVar(TypeParamTypeVar {

vm/src/builtins/bytearray.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,8 @@ impl PyByteArray {
568568
self.borrow_buf_mut().reverse();
569569
}
570570

571-
#[pyclassmethod]
571+
// TODO: Uncomment when Python adds __class_getitem__ to bytearray
572+
// #[pyclassmethod]
572573
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
573574
PyGenericAlias::from_args(cls, args, vm)
574575
}

vm/src/builtins/bytes.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,8 @@ impl PyBytes {
483483
PyTuple::new_ref(param, &vm.ctx)
484484
}
485485

486-
#[pyclassmethod]
486+
// TODO: Uncomment when Python adds __class_getitem__ to bytes
487+
// #[pyclassmethod]
487488
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
488489
PyGenericAlias::from_args(cls, args, vm)
489490
}

vm/src/builtins/memory.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,8 @@ impl Py<PyMemoryView> {
550550
Representable
551551
))]
552552
impl PyMemoryView {
553-
#[pyclassmethod]
553+
// TODO: Uncomment when Python adds __class_getitem__ to memoryview
554+
// #[pyclassmethod]
554555
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
555556
PyGenericAlias::from_args(cls, args, vm)
556557
}

vm/src/builtins/range.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,6 @@ pub fn init(context: &Context) {
184184
Representable
185185
))]
186186
impl PyRange {
187-
#[pyclassmethod]
188-
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
189-
PyGenericAlias::from_args(cls, args, vm)
190-
}
191-
192187
fn new(cls: PyTypeRef, stop: ArgIndex, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
193188
PyRange {
194189
start: vm.ctx.new_pyref(0),
@@ -328,6 +323,12 @@ impl PyRange {
328323

329324
Ok(range.into())
330325
}
326+
327+
// TODO: Uncomment when Python adds __class_getitem__ to range
328+
// #[pyclassmethod]
329+
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
330+
PyGenericAlias::from_args(cls, args, vm)
331+
}
331332
}
332333

333334
#[pyclass]

vm/src/builtins/slice.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ impl PyPayload for PySlice {
3030

3131
#[pyclass(with(Comparable, Representable, Hashable))]
3232
impl PySlice {
33-
#[pyclassmethod]
34-
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
35-
PyGenericAlias::from_args(cls, args, vm)
36-
}
37-
3833
#[pygetset]
3934
fn start(&self, vm: &VirtualMachine) -> PyObjectRef {
4035
self.start.clone().to_pyobject(vm)
@@ -200,6 +195,12 @@ impl PySlice {
200195
(zelf.start.clone(), zelf.stop.clone(), zelf.step.clone()),
201196
))
202197
}
198+
199+
// TODO: Uncomment when Python adds __class_getitem__ to slice
200+
// #[pyclassmethod]
201+
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
202+
PyGenericAlias::from_args(cls, args, vm)
203+
}
203204
}
204205

205206
impl Hashable for PySlice {

vm/src/stdlib/builtins.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,23 @@ mod builtins {
932932
))
933933
})?;
934934

935+
// For PEP 695 classes, set .type_params in namespace before calling the function
936+
if let Ok(type_params) = function
937+
.as_object()
938+
.get_attr(identifier!(vm, __type_params__), vm)
939+
{
940+
if let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>() {
941+
if !type_params_tuple.is_empty() {
942+
// Set .type_params in namespace so the compiler-generated code can use it
943+
namespace.as_object().set_item(
944+
vm.ctx.intern_str(".type_params"),
945+
type_params,
946+
vm,
947+
)?;
948+
}
949+
}
950+
}
951+
935952
let classcell = function.invoke_with_locals(().into(), Some(namespace.clone()), vm)?;
936953
let classcell = <Option<PyCellRef>>::try_from_object(vm, classcell)?;
937954

@@ -943,9 +960,27 @@ mod builtins {
943960
)?;
944961
}
945962

963+
// Remove .type_params from namespace before creating the class
964+
namespace
965+
.as_object()
966+
.del_item(vm.ctx.intern_str(".type_params"), vm)
967+
.ok();
968+
946969
let args = FuncArgs::new(vec![name_obj.into(), bases, namespace.into()], kwargs);
947970
let class = metaclass.call(args, vm)?;
948971

972+
// For PEP 695 classes, set __type_params__ on the class from the function
973+
if let Ok(type_params) = function
974+
.as_object()
975+
.get_attr(identifier!(vm, __type_params__), vm)
976+
{
977+
if let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>() {
978+
if !type_params_tuple.is_empty() {
979+
class.set_attr(identifier!(vm, __type_params__), type_params, vm)?;
980+
}
981+
}
982+
}
983+
949984
if let Some(ref classcell) = classcell {
950985
let classcell = classcell.get().ok_or_else(|| {
951986
vm.new_type_error(format!(

0 commit comments

Comments
 (0)
0