mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
__type_params__ in __build_class__ (#5883)
* remove future __classs_getitem__ * __type_params__ in __build_class__
This commit is contained in:
8
Lib/test/test_typing.py
vendored
8
Lib/test/test_typing.py
vendored
@@ -656,8 +656,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
P_default = ParamSpec('P_default', default=...)
|
||||
self.assertIs(P_default.__default__, ...)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_paramspec_none(self):
|
||||
U = ParamSpec('U')
|
||||
U_None = ParamSpec('U_None', default=None)
|
||||
@@ -756,8 +754,6 @@ class TypeParameterDefaultsTests(BaseTestCase):
|
||||
self.assertEqual(A[float, [range]].__args__, (float, (range,), float))
|
||||
self.assertEqual(A[float, [range], int].__args__, (float, (range,), int))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_typevartuple_none(self):
|
||||
U = TypeVarTuple('U')
|
||||
U_None = TypeVarTuple('U_None', default=None)
|
||||
@@ -3893,8 +3889,6 @@ class GenericTests(BaseTestCase):
|
||||
{'x': list[list[ForwardRef('X')]]}
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pep695_generic_class_with_future_annotations(self):
|
||||
original_globals = dict(ann_module695.__dict__)
|
||||
|
||||
@@ -3913,8 +3907,6 @@ class GenericTests(BaseTestCase):
|
||||
hints_for_B = get_type_hints(ann_module695.B)
|
||||
self.assertEqual(hints_for_B, {"x": int, "y": str, "z": bytes})
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pep695_generic_class_with_future_annotations_name_clash_with_global_vars(self):
|
||||
hints_for_C = get_type_hints(ann_module695.C)
|
||||
self.assertEqual(
|
||||
|
||||
@@ -1212,6 +1212,7 @@ impl Compiler<'_> {
|
||||
/// Store each type parameter so it is accessible to the current scope, and leave a tuple of
|
||||
/// all the type parameters on the stack.
|
||||
fn compile_type_params(&mut self, type_params: &TypeParams) -> CompileResult<()> {
|
||||
// First, compile each type parameter and store it
|
||||
for type_param in &type_params.type_params {
|
||||
match type_param {
|
||||
TypeParam::TypeVar(TypeParamTypeVar { name, bound, .. }) => {
|
||||
@@ -1664,8 +1665,12 @@ impl Compiler<'_> {
|
||||
let qualified_name = self.qualified_path.join(".");
|
||||
|
||||
// If there are type params, we need to push a special symbol table just for them
|
||||
if type_params.is_some() {
|
||||
if let Some(type_params) = type_params {
|
||||
self.push_symbol_table();
|
||||
// Compile type parameters and store as .type_params
|
||||
self.compile_type_params(type_params)?;
|
||||
let dot_type_params = self.name(".type_params");
|
||||
emit!(self, Instruction::StoreLocal(dot_type_params));
|
||||
}
|
||||
|
||||
self.push_output(bytecode::CodeFlags::empty(), 0, 0, 0, name.to_owned());
|
||||
@@ -1688,6 +1693,18 @@ impl Compiler<'_> {
|
||||
if Self::find_ann(body) {
|
||||
emit!(self, Instruction::SetupAnnotation);
|
||||
}
|
||||
|
||||
// Set __type_params__ from .type_params if we have type parameters (PEP 695)
|
||||
if type_params.is_some() {
|
||||
// Load .type_params from enclosing scope
|
||||
let dot_type_params = self.name(".type_params");
|
||||
emit!(self, Instruction::LoadNameAny(dot_type_params));
|
||||
|
||||
// Store as __type_params__
|
||||
let dunder_type_params = self.name("__type_params__");
|
||||
emit!(self, Instruction::StoreLocal(dunder_type_params));
|
||||
}
|
||||
|
||||
self.compile_statements(body)?;
|
||||
|
||||
let classcell_idx = self
|
||||
@@ -1721,8 +1738,10 @@ impl Compiler<'_> {
|
||||
let mut func_flags = bytecode::MakeFunctionFlags::empty();
|
||||
|
||||
// Prepare generic type parameters:
|
||||
if let Some(type_params) = type_params {
|
||||
self.compile_type_params(type_params)?;
|
||||
if type_params.is_some() {
|
||||
// Load .type_params from the type params scope
|
||||
let dot_type_params = self.name(".type_params");
|
||||
emit!(self, Instruction::LoadNameAny(dot_type_params));
|
||||
func_flags |= bytecode::MakeFunctionFlags::TYPE_PARAMS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1267,6 +1267,7 @@ impl SymbolTableBuilder<'_> {
|
||||
}
|
||||
|
||||
fn scan_type_params(&mut self, type_params: &TypeParams) -> SymbolTableResult {
|
||||
// First register all type parameters
|
||||
for type_param in &type_params.type_params {
|
||||
match type_param {
|
||||
TypeParam::TypeVar(TypeParamTypeVar {
|
||||
|
||||
@@ -568,7 +568,8 @@ impl PyByteArray {
|
||||
self.borrow_buf_mut().reverse();
|
||||
}
|
||||
|
||||
#[pyclassmethod]
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to bytearray
|
||||
// #[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
@@ -483,7 +483,8 @@ impl PyBytes {
|
||||
PyTuple::new_ref(param, &vm.ctx)
|
||||
}
|
||||
|
||||
#[pyclassmethod]
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to bytes
|
||||
// #[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
@@ -550,7 +550,8 @@ impl Py<PyMemoryView> {
|
||||
Representable
|
||||
))]
|
||||
impl PyMemoryView {
|
||||
#[pyclassmethod]
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to memoryview
|
||||
// #[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
@@ -184,11 +184,6 @@ pub fn init(context: &Context) {
|
||||
Representable
|
||||
))]
|
||||
impl PyRange {
|
||||
#[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
fn new(cls: PyTypeRef, stop: ArgIndex, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
PyRange {
|
||||
start: vm.ctx.new_pyref(0),
|
||||
@@ -328,6 +323,12 @@ impl PyRange {
|
||||
|
||||
Ok(range.into())
|
||||
}
|
||||
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to range
|
||||
// #[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
|
||||
@@ -30,11 +30,6 @@ impl PyPayload for PySlice {
|
||||
|
||||
#[pyclass(with(Comparable, Representable, Hashable))]
|
||||
impl PySlice {
|
||||
#[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn start(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.start.clone().to_pyobject(vm)
|
||||
@@ -200,6 +195,12 @@ impl PySlice {
|
||||
(zelf.start.clone(), zelf.stop.clone(), zelf.step.clone()),
|
||||
))
|
||||
}
|
||||
|
||||
// TODO: Uncomment when Python adds __class_getitem__ to slice
|
||||
// #[pyclassmethod]
|
||||
fn __class_getitem__(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
|
||||
PyGenericAlias::from_args(cls, args, vm)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for PySlice {
|
||||
|
||||
@@ -932,6 +932,23 @@ mod builtins {
|
||||
))
|
||||
})?;
|
||||
|
||||
// For PEP 695 classes, set .type_params in namespace before calling the function
|
||||
if let Ok(type_params) = function
|
||||
.as_object()
|
||||
.get_attr(identifier!(vm, __type_params__), vm)
|
||||
{
|
||||
if let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>() {
|
||||
if !type_params_tuple.is_empty() {
|
||||
// Set .type_params in namespace so the compiler-generated code can use it
|
||||
namespace.as_object().set_item(
|
||||
vm.ctx.intern_str(".type_params"),
|
||||
type_params,
|
||||
vm,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let classcell = function.invoke_with_locals(().into(), Some(namespace.clone()), vm)?;
|
||||
let classcell = <Option<PyCellRef>>::try_from_object(vm, classcell)?;
|
||||
|
||||
@@ -943,9 +960,27 @@ mod builtins {
|
||||
)?;
|
||||
}
|
||||
|
||||
// Remove .type_params from namespace before creating the class
|
||||
namespace
|
||||
.as_object()
|
||||
.del_item(vm.ctx.intern_str(".type_params"), vm)
|
||||
.ok();
|
||||
|
||||
let args = FuncArgs::new(vec![name_obj.into(), bases, namespace.into()], kwargs);
|
||||
let class = metaclass.call(args, vm)?;
|
||||
|
||||
// For PEP 695 classes, set __type_params__ on the class from the function
|
||||
if let Ok(type_params) = function
|
||||
.as_object()
|
||||
.get_attr(identifier!(vm, __type_params__), vm)
|
||||
{
|
||||
if let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>() {
|
||||
if !type_params_tuple.is_empty() {
|
||||
class.set_attr(identifier!(vm, __type_params__), type_params, vm)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref classcell) = classcell {
|
||||
let classcell = classcell.get().ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
|
||||
Reference in New Issue
Block a user