1use crate::common::lock::LazyLock;
3
4use super::type_;
5use crate::{
6 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
7 VirtualMachine, atomic_func,
8 builtins::{PyList, PyStr, PyTuple, PyTupleRef, PyType},
9 class::PyClassImpl,
10 common::hash,
11 convert::ToPyObject,
12 function::{FuncArgs, PyComparisonValue},
13 protocol::{PyMappingMethods, PyNumberMethods},
14 types::{
15 AsMapping, AsNumber, Callable, Comparable, Constructor, GetAttr, Hashable, IterNext,
16 Iterable, PyComparisonOp, Representable,
17 },
18};
19use alloc::fmt;
20
21static ATTR_EXCEPTIONS: [&str; 9] = [
23 "__class__",
24 "__origin__",
25 "__args__",
26 "__unpacked__",
27 "__parameters__",
28 "__typing_unpacked_tuple_args__",
29 "__mro_entries__",
30 "__reduce_ex__", "__reduce__",
32];
33
34static ATTR_BLOCKED: [&str; 3] = ["__bases__", "__copy__", "__deepcopy__"];
36
37#[pyclass(module = "types", name = "GenericAlias")]
38pub struct PyGenericAlias {
39 origin: PyObjectRef,
40 args: PyTupleRef,
41 parameters: PyTupleRef,
42 starred: bool, }
44
45impl fmt::Debug for PyGenericAlias {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.write_str("GenericAlias")
48 }
49}
50
51impl PyPayload for PyGenericAlias {
52 #[inline]
53 fn class(ctx: &Context) -> &'static Py<PyType> {
54 ctx.types.generic_alias_type
55 }
56}
57
58impl Constructor for PyGenericAlias {
59 type Args = FuncArgs;
60
61 fn py_new(_cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
62 if !args.kwargs.is_empty() {
63 return Err(vm.new_type_error("GenericAlias() takes no keyword arguments"));
64 }
65 let (origin, arguments): (PyObjectRef, PyObjectRef) = args.bind(vm)?;
66 let args = if let Ok(tuple) = arguments.try_to_ref::<PyTuple>(vm) {
67 tuple.to_owned()
68 } else {
69 PyTuple::new_ref(vec![arguments], &vm.ctx)
70 };
71 Ok(Self::new(origin, args, false, vm))
72 }
73}
74
75#[pyclass(
76 with(
77 AsNumber,
78 AsMapping,
79 Callable,
80 Comparable,
81 Constructor,
82 GetAttr,
83 Hashable,
84 Iterable,
85 Representable
86 ),
87 flags(BASETYPE, HAS_WEAKREF)
88)]
89impl PyGenericAlias {
90 pub fn new(
91 origin: impl Into<PyObjectRef>,
92 args: PyTupleRef,
93 starred: bool,
94 vm: &VirtualMachine,
95 ) -> Self {
96 let parameters = make_parameters(&args, vm);
97 Self {
98 origin: origin.into(),
99 args,
100 parameters,
101 starred,
102 }
103 }
104
105 pub fn from_args(
107 origin: impl Into<PyObjectRef>,
108 args: PyObjectRef,
109 vm: &VirtualMachine,
110 ) -> Self {
111 let args = if let Ok(tuple) = args.try_to_ref::<PyTuple>(vm) {
112 tuple.to_owned()
113 } else {
114 PyTuple::new_ref(vec![args], &vm.ctx)
115 };
116 Self::new(origin, args, false, vm)
117 }
118
119 fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
120 fn repr_item(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
121 if obj.is(&vm.ctx.ellipsis) {
122 return Ok("...".to_string());
123 }
124
125 if vm
126 .get_attribute_opt(obj.clone(), identifier!(vm, __origin__))?
127 .is_some()
128 && vm
129 .get_attribute_opt(obj.clone(), identifier!(vm, __args__))?
130 .is_some()
131 {
132 return Ok(obj.repr(vm)?.to_string());
133 }
134
135 match (
136 vm.get_attribute_opt(obj.clone(), identifier!(vm, __qualname__))?
137 .and_then(|o| o.downcast_ref::<PyStr>().map(|n| n.to_string())),
138 vm.get_attribute_opt(obj.clone(), identifier!(vm, __module__))?
139 .and_then(|o| o.downcast_ref::<PyStr>().map(|m| m.to_string())),
140 ) {
141 (None, _) | (_, None) => Ok(obj.repr(vm)?.to_string()),
142 (Some(qualname), Some(module)) => Ok(if module == "builtins" {
143 qualname
144 } else {
145 format!("{module}.{qualname}")
146 }),
147 }
148 }
149
150 fn repr_arg(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
151 if obj.class().is(vm.ctx.types.list_type) {
153 let list = obj.downcast_ref::<crate::builtins::PyList>().unwrap();
154 let len = list.borrow_vec().len();
155 let mut parts = Vec::with_capacity(len);
156 for i in 0..len {
158 let item = list
159 .borrow_vec()
160 .get(i)
161 .cloned()
162 .ok_or_else(|| vm.new_index_error("list index out of range"))?;
163 parts.push(repr_item(item, vm)?);
164 }
165 Ok(format!("[{}]", parts.join(", ")))
166 } else {
167 repr_item(obj, vm)
168 }
169 }
170
171 let repr_str = format!(
172 "{}[{}]",
173 repr_item(self.origin.clone(), vm)?,
174 if self.args.is_empty() {
175 "()".to_owned()
176 } else {
177 self.args
178 .iter()
179 .map(|o| repr_arg(o.clone(), vm))
180 .collect::<PyResult<Vec<_>>>()?
181 .join(", ")
182 }
183 );
184
185 Ok(if self.starred {
187 format!("*{repr_str}")
188 } else {
189 repr_str
190 })
191 }
192
193 #[pygetset]
194 fn __parameters__(&self) -> PyObjectRef {
195 self.parameters.clone().into()
196 }
197
198 #[pygetset]
199 fn __args__(&self) -> PyObjectRef {
200 self.args.clone().into()
201 }
202
203 #[pygetset]
204 fn __origin__(&self) -> PyObjectRef {
205 self.origin.clone()
206 }
207
208 #[pygetset]
209 const fn __unpacked__(&self) -> bool {
210 self.starred
211 }
212
213 #[pygetset]
214 fn __typing_unpacked_tuple_args__(&self, vm: &VirtualMachine) -> PyObjectRef {
215 if self.starred && self.origin.is(vm.ctx.types.tuple_type.as_object()) {
216 self.args.clone().into()
217 } else {
218 vm.ctx.none()
219 }
220 }
221
222 fn __getitem__(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
223 let new_args = subs_parameters(
224 zelf.to_owned().into(),
225 zelf.args.clone(),
226 zelf.parameters.clone(),
227 needle,
228 vm,
229 )?;
230
231 Ok(Self::new(zelf.origin.clone(), new_args, false, vm).into_pyobject(vm))
232 }
233
234 #[pymethod]
235 fn __dir__(&self, vm: &VirtualMachine) -> PyResult<PyList> {
236 let dir = vm.dir(Some(self.__origin__()))?;
237 for exc in &ATTR_EXCEPTIONS {
238 if !dir.__contains__((*exc).to_pyobject(vm), vm)? {
239 dir.append((*exc).to_pyobject(vm));
240 }
241 }
242 Ok(dir)
243 }
244
245 #[pymethod]
246 fn __reduce__(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
247 if zelf.starred {
248 let next_fn = vm.builtins.get_attr("next", vm)?;
250 let non_starred = Self::new(zelf.origin.clone(), zelf.args.clone(), false, vm);
251 let iter_obj = PyGenericAliasIterator {
252 obj: crate::common::lock::PyMutex::new(Some(non_starred.into_pyobject(vm))),
253 }
254 .into_pyobject(vm);
255 Ok(PyTuple::new_ref(
256 vec![next_fn, PyTuple::new_ref(vec![iter_obj], &vm.ctx).into()],
257 &vm.ctx,
258 ))
259 } else {
260 Ok(PyTuple::new_ref(
261 vec![
262 vm.ctx.types.generic_alias_type.to_owned().into(),
263 PyTuple::new_ref(vec![zelf.origin.clone(), zelf.args.clone().into()], &vm.ctx)
264 .into(),
265 ],
266 &vm.ctx,
267 ))
268 }
269 }
270
271 #[pymethod]
272 fn __mro_entries__(&self, _bases: PyObjectRef, vm: &VirtualMachine) -> PyTupleRef {
273 PyTuple::new_ref(vec![self.__origin__()], &vm.ctx)
274 }
275
276 #[pymethod]
277 fn __instancecheck__(_zelf: PyRef<Self>, _obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
278 Err(vm.new_type_error("isinstance() argument 2 cannot be a parameterized generic"))
279 }
280
281 #[pymethod]
282 fn __subclasscheck__(_zelf: PyRef<Self>, _obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
283 Err(vm.new_type_error("issubclass() argument 2 cannot be a parameterized generic"))
284 }
285
286 fn __ror__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
287 type_::or_(other, zelf, vm)
288 }
289
290 fn __or__(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
291 type_::or_(zelf, other, vm)
292 }
293}
294
295pub(crate) fn make_parameters(args: &Py<PyTuple>, vm: &VirtualMachine) -> PyTupleRef {
296 make_parameters_from_slice(args.as_slice(), vm)
297}
298
299fn make_parameters_from_slice(args: &[PyObjectRef], vm: &VirtualMachine) -> PyTupleRef {
300 let mut parameters: Vec<PyObjectRef> = Vec::with_capacity(args.len());
301
302 for arg in args {
303 if arg.class().is(vm.ctx.types.type_type) {
305 continue;
306 }
307
308 if arg.get_attr(identifier!(vm, __typing_subst__), vm).is_ok() {
310 if tuple_index(¶meters, arg).is_none() {
311 parameters.push(arg.clone());
312 }
313 } else if let Ok(subparams) = arg.get_attr(identifier!(vm, __parameters__), vm)
314 && let Ok(sub_params) = subparams.try_to_ref::<PyTuple>(vm)
315 {
316 for sub_param in sub_params {
317 if tuple_index(¶meters, sub_param).is_none() {
318 parameters.push(sub_param.clone());
319 }
320 }
321 } else if arg.try_to_ref::<PyTuple>(vm).is_ok() || arg.try_to_ref::<PyList>(vm).is_ok() {
322 let items: Vec<PyObjectRef> = if let Ok(t) = arg.try_to_ref::<PyTuple>(vm) {
324 t.as_slice().to_vec()
325 } else {
326 let list = arg.downcast_ref::<PyList>().unwrap();
327 list.borrow_vec().to_vec()
328 };
329 let sub = make_parameters_from_slice(&items, vm);
330 for sub_param in sub.iter() {
331 if tuple_index(¶meters, sub_param).is_none() {
332 parameters.push(sub_param.clone());
333 }
334 }
335 }
336 }
337
338 PyTuple::new_ref(parameters, &vm.ctx)
339}
340
341#[inline]
342fn tuple_index(vec: &[PyObjectRef], item: &PyObject) -> Option<usize> {
343 vec.iter().position(|element| element.is(item))
344}
345
346fn is_unpacked_typevartuple(arg: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
347 if arg.class().is(vm.ctx.types.type_type) {
348 return Ok(false);
349 }
350
351 if let Ok(attr) = arg.get_attr(identifier!(vm, __typing_is_unpacked_typevartuple__), vm) {
352 attr.try_to_bool(vm)
353 } else {
354 Ok(false)
355 }
356}
357
358fn subs_tvars(
359 obj: PyObjectRef,
360 params: &Py<PyTuple>,
361 arg_items: &[PyObjectRef],
362 vm: &VirtualMachine,
363) -> PyResult {
364 obj.get_attr(identifier!(vm, __parameters__), vm)
365 .ok()
366 .and_then(|sub_params| {
367 PyTupleRef::try_from_object(vm, sub_params)
368 .ok()
369 .filter(|sub_params| !sub_params.is_empty())
370 .map(|sub_params| {
371 let mut sub_args = Vec::new();
372
373 for arg in sub_params.iter() {
374 if let Some(idx) = tuple_index(params.as_slice(), arg) {
375 let param = ¶ms[idx];
376 let substituted_arg = &arg_items[idx];
377
378 if param.class().slots.iter.load().is_some()
380 && substituted_arg.try_to_ref::<PyTuple>(vm).is_ok()
381 {
382 if let Ok(tuple) = substituted_arg.try_to_ref::<PyTuple>(vm) {
384 for elem in tuple {
385 sub_args.push(elem.clone());
386 }
387 continue;
388 }
389 }
390
391 sub_args.push(substituted_arg.clone());
392 } else {
393 sub_args.push(arg.clone());
394 }
395 }
396
397 let sub_args: PyObjectRef = PyTuple::new_ref(sub_args, &vm.ctx).into();
398 obj.get_item(&*sub_args, vm)
399 })
400 })
401 .unwrap_or(Ok(obj))
402}
403
404fn unpack_args(item: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
406 let mut new_args = Vec::new();
407
408 let arg_items = if let Ok(tuple) = item.try_to_ref::<PyTuple>(vm) {
409 tuple.as_slice().to_vec()
410 } else {
411 vec![item]
412 };
413
414 for item in arg_items {
415 if item.class().is(vm.ctx.types.type_type) {
417 new_args.push(item);
418 continue;
419 }
420
421 if let Ok(sub_args) = item.get_attr(identifier!(vm, __typing_unpacked_tuple_args__), vm)
423 && !sub_args.is(&vm.ctx.none)
424 && let Ok(tuple) = sub_args.try_to_ref::<PyTuple>(vm)
425 {
426 let has_ellipsis_at_end = tuple
428 .as_slice()
429 .last()
430 .is_some_and(|item| item.is(&vm.ctx.ellipsis));
431
432 if !has_ellipsis_at_end {
433 for arg in tuple {
435 new_args.push(arg.clone());
436 }
437 continue;
438 }
439 }
440
441 new_args.push(item);
443 }
444
445 Ok(PyTuple::new_ref(new_args, &vm.ctx))
446}
447
448pub fn subs_parameters(
450 alias: PyObjectRef, args: PyTupleRef,
452 parameters: PyTupleRef,
453 item: PyObjectRef,
454 vm: &VirtualMachine,
455) -> PyResult<PyTupleRef> {
456 let n_params = parameters.len();
457 if n_params == 0 {
458 return Err(vm.new_type_error(format!("{} is not a generic class", alias.repr(vm)?)));
459 }
460
461 let mut item: PyObjectRef = unpack_args(item, vm)?.into();
463
464 for param in parameters.iter() {
466 if let Ok(prepare) = param.get_attr(identifier!(vm, __typing_prepare_subst__), vm)
467 && !prepare.is(&vm.ctx.none)
468 {
469 item = if item.try_to_ref::<PyTuple>(vm).is_ok() {
471 prepare.call((alias.clone(), item.clone()), vm)?
472 } else {
473 let tuple_args = PyTuple::new_ref(vec![item.clone()], &vm.ctx);
475 prepare.call((alias.clone(), tuple_args.to_pyobject(vm)), vm)?
476 };
477 }
478 }
479
480 let arg_items = if let Ok(tuple) = item.try_to_ref::<PyTuple>(vm) {
482 tuple.as_slice().to_vec()
483 } else {
484 vec![item.clone()]
485 };
486 let n_items = arg_items.len();
487
488 if n_items != n_params {
489 return Err(vm.new_type_error(format!(
490 "Too {} arguments for {}; actual {}, expected {}",
491 if n_items > n_params { "many" } else { "few" },
492 alias.repr(vm)?,
493 n_items,
494 n_params
495 )));
496 }
497
498 let mut new_args = Vec::new();
500
501 for arg in args.iter() {
502 if arg.class().is(vm.ctx.types.type_type) {
504 new_args.push(arg.clone());
505 continue;
506 }
507
508 let is_list = arg.try_to_ref::<PyList>(vm).is_ok();
510 if arg.try_to_ref::<PyTuple>(vm).is_ok() || is_list {
511 let sub_items: Vec<PyObjectRef> = if let Ok(t) = arg.try_to_ref::<PyTuple>(vm) {
512 t.as_slice().to_vec()
513 } else {
514 arg.downcast_ref::<PyList>().unwrap().borrow_vec().to_vec()
515 };
516 let sub_tuple = PyTuple::new_ref(sub_items, &vm.ctx);
517 let sub_result = subs_parameters(
518 alias.clone(),
519 sub_tuple,
520 parameters.clone(),
521 item.clone(),
522 vm,
523 )?;
524 let substituted: PyObjectRef = if is_list {
525 PyList::from(sub_result.as_slice().to_vec())
527 .into_ref(&vm.ctx)
528 .into()
529 } else {
530 sub_result.into()
531 };
532 new_args.push(substituted);
533 continue;
534 }
535
536 let unpack = is_unpacked_typevartuple(arg, vm)?;
538
539 let substituted_arg = if let Ok(subst) = arg.get_attr(identifier!(vm, __typing_subst__), vm)
541 {
542 if let Some(iparam) = tuple_index(parameters.as_slice(), arg) {
543 subst.call((arg_items[iparam].clone(),), vm)?
544 } else {
545 subs_tvars(arg.clone(), ¶meters, &arg_items, vm)?
546 }
547 } else {
548 subs_tvars(arg.clone(), ¶meters, &arg_items, vm)?
549 };
550
551 if unpack {
552 if let Ok(tuple) = substituted_arg.try_to_ref::<PyTuple>(vm) {
553 for elem in tuple {
554 new_args.push(elem.clone());
555 }
556 } else {
557 new_args.push(substituted_arg);
558 }
559 } else {
560 new_args.push(substituted_arg);
561 }
562 }
563
564 Ok(PyTuple::new_ref(new_args, &vm.ctx))
565}
566
567impl AsMapping for PyGenericAlias {
568 fn as_mapping() -> &'static PyMappingMethods {
569 static AS_MAPPING: LazyLock<PyMappingMethods> = LazyLock::new(|| PyMappingMethods {
570 subscript: atomic_func!(|mapping, needle, vm| {
571 let zelf = PyGenericAlias::mapping_downcast(mapping);
572 PyGenericAlias::__getitem__(zelf.to_owned(), needle.to_owned(), vm)
573 }),
574 ..PyMappingMethods::NOT_IMPLEMENTED
575 });
576 &AS_MAPPING
577 }
578}
579
580impl AsNumber for PyGenericAlias {
581 fn as_number() -> &'static PyNumberMethods {
582 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
583 or: Some(|a, b, vm| PyGenericAlias::__or__(a.to_owned(), b.to_owned(), vm)),
584 ..PyNumberMethods::NOT_IMPLEMENTED
585 };
586 &AS_NUMBER
587 }
588}
589
590impl Callable for PyGenericAlias {
591 type Args = FuncArgs;
592 fn call(zelf: &Py<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
593 zelf.origin.call(args, vm).map(|obj| {
594 if let Err(exc) = obj.set_attr(identifier!(vm, __orig_class__), zelf.to_owned(), vm)
595 && !exc.fast_isinstance(vm.ctx.exceptions.attribute_error)
596 && !exc.fast_isinstance(vm.ctx.exceptions.type_error)
597 {
598 return Err(exc);
599 }
600 Ok(obj)
601 })?
602 }
603}
604
605impl Comparable for PyGenericAlias {
606 fn cmp(
607 zelf: &Py<Self>,
608 other: &PyObject,
609 op: PyComparisonOp,
610 vm: &VirtualMachine,
611 ) -> PyResult<PyComparisonValue> {
612 op.eq_only(|| {
613 let other = class_or_notimplemented!(Self, other);
614 if zelf.starred != other.starred {
615 return Ok(PyComparisonValue::Implemented(false));
616 }
617 Ok(PyComparisonValue::Implemented(
618 zelf.__origin__()
619 .rich_compare_bool(&other.__origin__(), PyComparisonOp::Eq, vm)?
620 && zelf.__args__().rich_compare_bool(
621 &other.__args__(),
622 PyComparisonOp::Eq,
623 vm,
624 )?,
625 ))
626 })
627 }
628}
629
630impl Hashable for PyGenericAlias {
631 #[inline]
632 fn hash(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<hash::PyHash> {
633 Ok(zelf.origin.hash(vm)? ^ zelf.args.as_object().hash(vm)?)
634 }
635}
636
637impl GetAttr for PyGenericAlias {
638 fn getattro(zelf: &Py<Self>, attr: &Py<PyStr>, vm: &VirtualMachine) -> PyResult {
639 let attr_str = attr.as_wtf8();
640 for exc in &ATTR_EXCEPTIONS {
641 if attr_str == *exc {
642 return zelf.as_object().generic_getattr(attr, vm);
643 }
644 }
645 for blocked in &ATTR_BLOCKED {
646 if attr_str == *blocked {
647 return zelf.as_object().generic_getattr(attr, vm);
648 }
649 }
650 zelf.__origin__().get_attr(attr, vm)
651 }
652}
653
654impl Representable for PyGenericAlias {
655 #[inline]
656 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
657 zelf.repr(vm)
658 }
659}
660
661impl Iterable for PyGenericAlias {
662 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
663 Ok(PyGenericAliasIterator {
664 obj: crate::common::lock::PyMutex::new(Some(zelf.into())),
665 }
666 .into_pyobject(vm))
667 }
668}
669
670#[pyclass(module = "types", name = "generic_alias_iterator")]
672#[derive(Debug, PyPayload)]
673pub struct PyGenericAliasIterator {
674 obj: crate::common::lock::PyMutex<Option<PyObjectRef>>,
675}
676
677#[pyclass(with(Representable, Iterable, IterNext))]
678impl PyGenericAliasIterator {
679 #[pymethod]
680 fn __reduce__(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
681 let iter_fn = vm.builtins.get_attr("iter", vm)?;
682 let guard = self.obj.lock();
683 let arg: PyObjectRef = if let Some(ref obj) = *guard {
684 PyTuple::new_ref(vec![obj.clone()], &vm.ctx).into()
686 } else {
687 let empty = PyTuple::new_ref(vec![], &vm.ctx);
689 PyTuple::new_ref(vec![empty.into()], &vm.ctx).into()
690 };
691 Ok(PyTuple::new_ref(vec![iter_fn, arg], &vm.ctx))
692 }
693}
694
695impl Representable for PyGenericAliasIterator {
696 fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
697 Ok("<generic_alias_iterator>".to_owned())
698 }
699}
700
701impl Iterable for PyGenericAliasIterator {
702 fn iter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult {
703 Ok(zelf.into())
704 }
705}
706
707impl crate::types::IterNext for PyGenericAliasIterator {
708 fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<crate::protocol::PyIterReturn> {
709 use crate::protocol::PyIterReturn;
710 let mut guard = zelf.obj.lock();
711 let obj = match guard.take() {
712 Some(obj) => obj,
713 None => return Ok(PyIterReturn::StopIteration(None)),
714 };
715 let alias = obj
717 .downcast_ref::<PyGenericAlias>()
718 .ok_or_else(|| vm.new_type_error("generic_alias_iterator expected GenericAlias"))?;
719 let starred = PyGenericAlias::new(alias.origin.clone(), alias.args.clone(), true, vm);
720 Ok(PyIterReturn::Return(starred.into_pyobject(vm)))
721 }
722}
723
724pub fn subscript_generic(type_params: PyObjectRef, vm: &VirtualMachine) -> PyResult {
728 let typing_module = vm.import("typing", 0)?;
729 let generic_type = typing_module.get_attr("Generic", vm)?;
730 let generic_alias_class = typing_module.get_attr("_GenericAlias", vm)?;
731
732 let params = if let Ok(tuple) = type_params.try_to_ref::<PyTuple>(vm) {
733 tuple.to_owned()
734 } else {
735 PyTuple::new_ref(vec![type_params], &vm.ctx)
736 };
737
738 let args = crate::stdlib::_typing::unpack_typevartuples(¶ms, vm)?;
739
740 generic_alias_class.call((generic_type, args.to_pyobject(vm)), vm)
741}
742
743pub fn init(context: &'static Context) {
744 PyGenericAlias::extend_class(context, context.types.generic_alias_type);
745 PyGenericAliasIterator::extend_class(context, context.types.generic_alias_iterator_type);
746}