1pub use typevar::*;
4
5#[pymodule(sub, name = "_typing")]
6pub(crate) mod typevar {
7 use crate::{
8 AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
9 builtins::{PyTuple, PyTupleRef, PyType, PyTypeRef, make_union},
10 common::lock::PyMutex,
11 function::{FuncArgs, PyComparisonValue},
12 protocol::PyNumberMethods,
13 stdlib::_typing::{call_typing_func_object, decl::const_evaluator_alloc},
14 types::{AsNumber, Comparable, Constructor, Iterable, PyComparisonOp, Representable},
15 };
16
17 fn type_check(arg: PyObjectRef, msg: &str, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
18 if vm.is_none(&arg) {
20 return Ok(arg.class().to_owned().into());
21 }
22 let message_str: PyObjectRef = vm.ctx.new_str(msg).into();
23 call_typing_func_object(vm, "_type_check", (arg, message_str))
24 }
25
26 fn variance_repr(
27 name: &str,
28 infer_variance: bool,
29 covariant: bool,
30 contravariant: bool,
31 ) -> String {
32 if infer_variance {
33 return name.to_owned();
34 }
35 let prefix = if covariant {
36 '+'
37 } else if contravariant {
38 '-'
39 } else {
40 '~'
41 };
42 format!("{prefix}{name}")
43 }
44
45 fn caller(vm: &VirtualMachine) -> Option<PyObjectRef> {
53 let globals = crate::frame::current_globals()?;
54 globals.get_item("__name__", vm).ok()
55 }
56
57 fn set_module_from_caller(obj: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
60 let module_value: PyObjectRef = if let Some(module_name) = caller(vm) {
63 if let Ok(name_str) = module_name.str(vm)
65 && let Some(name) = name_str.to_str()
66 && (name == "builtins" || name.starts_with('<'))
67 {
68 return Ok(());
69 }
70 module_name
71 } else {
72 vm.ctx.none()
73 };
74 obj.set_attr("__module__", module_value, vm)?;
75 Ok(())
76 }
77
78 #[pyattr]
79 #[pyclass(name = "TypeVar", module = "typing")]
80 #[derive(Debug, PyPayload)]
81 pub struct TypeVar {
82 #[pymember(name = "__name__")]
83 name: PyObjectRef, bound: PyMutex<PyObjectRef>,
85 evaluate_bound: PyObjectRef,
86 constraints: PyMutex<PyObjectRef>,
87 evaluate_constraints: PyObjectRef,
88 default_value: PyMutex<PyObjectRef>,
89 evaluate_default: PyMutex<PyObjectRef>,
90 #[pymember(name = "__covariant__")]
91 covariant: bool,
92 #[pymember(name = "__contravariant__")]
93 contravariant: bool,
94 #[pymember(name = "__infer_variance__")]
95 infer_variance: bool,
96 }
97
98 #[pyclass(
99 flags(HAS_DICT, HAS_WEAKREF),
100 with(AsNumber, Constructor, Representable)
101 )]
102 impl Py<TypeVar> {
103 #[pymethod]
104 fn __mro_entries__(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
105 Err(vm.new_type_error("Cannot subclass an instance of TypeVar"))
106 }
107
108 #[pygetset]
109 fn __constraints__(&self, vm: &VirtualMachine) -> PyResult {
110 let mut constraints = self.constraints.lock();
111 if !vm.is_none(&constraints) {
112 return Ok(constraints.clone());
113 }
114 let r = if !vm.is_none(&self.evaluate_constraints) {
115 *constraints = self.evaluate_constraints.call((1i32,), vm)?;
116 constraints.clone()
117 } else {
118 vm.ctx.empty_tuple.clone().into()
119 };
120 Ok(r)
121 }
122
123 #[pygetset]
124 fn __bound__(&self, vm: &VirtualMachine) -> PyResult {
125 let mut bound = self.bound.lock();
126 if !vm.is_none(&bound) {
127 return Ok(bound.clone());
128 }
129 let r = if !vm.is_none(&self.evaluate_bound) {
130 *bound = self.evaluate_bound.call((1i32,), vm)?;
131 bound.clone()
132 } else {
133 vm.ctx.none()
134 };
135 Ok(r)
136 }
137
138 #[pygetset]
139 fn __default__(&self, vm: &VirtualMachine) -> PyResult {
140 {
141 let default_value = self.default_value.lock();
142 if !default_value.is(&vm.ctx.typing_no_default) {
143 return Ok(default_value.clone());
144 }
145 }
146 let evaluator = self.evaluate_default.lock().clone();
147 if !vm.is_none(&evaluator) {
148 let result = evaluator.call((1i32,), vm)?;
149 *self.default_value.lock() = result.clone();
150 Ok(result)
151 } else {
152 Ok(vm.ctx.typing_no_default.clone().into())
153 }
154 }
155
156 #[pygetset]
157 fn evaluate_bound(&self, vm: &VirtualMachine) -> PyObjectRef {
158 if !vm.is_none(&self.evaluate_bound) {
159 return self.evaluate_bound.clone();
160 }
161
162 let bound = self.bound.lock();
163 if !vm.is_none(&bound) {
164 return const_evaluator_alloc(bound.clone(), vm);
165 }
166
167 vm.ctx.none()
168 }
169
170 #[pygetset]
171 fn evaluate_constraints(&self, vm: &VirtualMachine) -> PyObjectRef {
172 if !vm.is_none(&self.evaluate_constraints) {
173 return self.evaluate_constraints.clone();
174 }
175
176 let constraints = self.constraints.lock();
177 if !vm.is_none(&constraints) {
178 return const_evaluator_alloc(constraints.clone(), vm);
179 }
180
181 vm.ctx.none()
182 }
183
184 #[pygetset]
185 fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
186 let evaluator = self.evaluate_default.lock().clone();
187 if !vm.is_none(&evaluator) {
188 return evaluator;
189 }
190
191 let default_value = self.default_value.lock().clone();
192 if !default_value.is(&vm.ctx.typing_no_default) {
193 return const_evaluator_alloc(default_value, vm);
194 }
195
196 vm.ctx.none()
197 }
198
199 #[pymethod]
200 fn __typing_subst__(
201 zelf: crate::PyRef<TypeVar>,
202 arg: PyObjectRef,
203 vm: &VirtualMachine,
204 ) -> PyResult {
205 let self_obj: PyObjectRef = zelf.into();
206 call_typing_func_object(vm, "_typevar_subst", (self_obj, arg))
207 }
208
209 #[pymethod]
210 fn __reduce__(&self) -> PyObjectRef {
211 self.name.clone()
212 }
213
214 #[pymethod]
215 fn has_default(&self, vm: &VirtualMachine) -> bool {
216 if !vm.is_none(&self.evaluate_default.lock()) {
217 return true;
218 }
219 let default_value = self.default_value.lock();
220 !default_value.is(&vm.ctx.typing_no_default)
222 }
223
224 #[pymethod]
225 fn __typing_prepare_subst__(
226 zelf: crate::PyRef<TypeVar>,
227 alias: PyObjectRef,
228 args: PyObjectRef,
229 vm: &VirtualMachine,
230 ) -> PyResult {
231 let args_tuple =
233 if let Ok(tuple) = args.try_to_ref::<rustpython_vm::builtins::PyTuple>(vm) {
234 tuple
235 } else {
236 return Ok(args);
237 };
238
239 let parameters = alias.get_attr(identifier!(vm, __parameters__), vm)?;
241 let params_tuple: PyTupleRef = parameters.try_into_value(vm)?;
242
243 let self_obj: PyObjectRef = zelf.to_owned().into();
245 let param_index = params_tuple.as_slice().iter().position(|p| p.is(&self_obj));
246
247 if let Some(index) = param_index {
248 if args_tuple.as_slice().len() <= index && zelf.has_default(vm) {
250 let mut new_args = args_tuple.as_slice().to_vec();
252
253 while new_args.len() <= index {
255 if new_args.len() == index {
257 let default_val = zelf.__default__(vm)?;
258 new_args.push(default_val);
259 } else {
260 break;
262 }
263 }
264
265 return Ok(rustpython_vm::builtins::PyTuple::new_ref(new_args, &vm.ctx).into());
266 }
267 }
268
269 Ok(args)
271 }
272 }
273
274 impl Representable for TypeVar {
275 #[inline(always)]
276 fn repr_str(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
277 let name = zelf.name.str_utf8(vm)?;
278 Ok(variance_repr(
279 name.as_str(),
280 zelf.infer_variance,
281 zelf.covariant,
282 zelf.contravariant,
283 ))
284 }
285 }
286
287 impl AsNumber for TypeVar {
288 fn as_number() -> &'static PyNumberMethods {
289 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
290 or: Some(|a, b, vm| {
291 let args = PyTuple::new_ref(vec![a.to_owned(), b.to_owned()], &vm.ctx);
292 make_union(&args, vm)
293 }),
294 ..PyNumberMethods::NOT_IMPLEMENTED
295 };
296 &AS_NUMBER
297 }
298 }
299
300 impl Constructor for TypeVar {
301 type Args = FuncArgs;
302
303 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
304 let typevar = <Self as Constructor>::py_new(&cls, args, vm)?;
305 let obj = typevar.into_ref_with_type(vm, cls)?;
306 let obj_ref: PyObjectRef = obj.into();
307 set_module_from_caller(&obj_ref, vm)?;
308 Ok(obj_ref)
309 }
310
311 fn py_new(_cls: &Py<PyType>, args: Self::Args, vm: &VirtualMachine) -> PyResult<Self> {
312 let mut kwargs = args.kwargs;
313 let (name, constraints) = if args.args.is_empty() {
315 if let Some(name) = kwargs.swap_remove("name") {
317 (name, vec![])
318 } else {
319 return Err(
320 vm.new_type_error("TypeVar() missing required argument: 'name' (pos 1)")
321 );
322 }
323 } else if args.args.len() == 1 {
324 (args.args[0].clone(), vec![])
325 } else {
326 let name = args.args[0].clone();
327 let constraints = args.args[1..].to_vec();
328 (name, constraints)
329 };
330
331 let bound = kwargs.swap_remove("bound");
332 let covariant = kwargs
333 .swap_remove("covariant")
334 .map(|v| v.try_to_bool(vm))
335 .transpose()?
336 .unwrap_or(false);
337 let contravariant = kwargs
338 .swap_remove("contravariant")
339 .map(|v| v.try_to_bool(vm))
340 .transpose()?
341 .unwrap_or(false);
342 let infer_variance = kwargs
343 .swap_remove("infer_variance")
344 .map(|v| v.try_to_bool(vm))
345 .transpose()?
346 .unwrap_or(false);
347 let default = kwargs.swap_remove("default");
348
349 if let Some(invalid_key) = kwargs.keys().next() {
351 return Err(
352 vm.new_unexpected_keyword_type_error(Some("typevar"), &invalid_key.to_string())
353 );
354 }
355
356 if covariant && contravariant {
358 return Err(vm.new_value_error("Bivariant type variables are not supported."));
359 }
360
361 if infer_variance && (covariant || contravariant) {
362 return Err(vm.new_value_error("Variance cannot be specified with infer_variance"));
363 }
364
365 let (constraints_obj, evaluate_constraints) = if !constraints.is_empty() {
367 if constraints.len() == 1 {
369 return Err(vm.new_type_error("A single constraint is not allowed"));
370 }
371 if bound.is_some() {
372 return Err(vm.new_type_error("Constraints cannot be used with bound"));
373 }
374 let constraints_tuple = vm.ctx.new_tuple(constraints);
375 (constraints_tuple.into(), vm.ctx.none())
376 } else {
377 (vm.ctx.none(), vm.ctx.none())
378 };
379
380 let (bound_obj, evaluate_bound) = if let Some(bound) = bound {
382 if vm.is_none(&bound) {
383 (vm.ctx.none(), vm.ctx.none())
384 } else {
385 let bound = type_check(bound, "Bound must be a type.", vm)?;
387 (bound, vm.ctx.none())
388 }
389 } else {
390 (vm.ctx.none(), vm.ctx.none())
391 };
392
393 let (default_value, evaluate_default) = if let Some(default) = default {
395 (default, vm.ctx.none())
396 } else {
397 (vm.ctx.typing_no_default.clone().into(), vm.ctx.none())
399 };
400
401 Ok(Self {
402 name,
403 bound: PyMutex::new(bound_obj),
404 evaluate_bound,
405 constraints: PyMutex::new(constraints_obj),
406 evaluate_constraints,
407 default_value: PyMutex::new(default_value),
408 evaluate_default: PyMutex::new(evaluate_default),
409 covariant,
410 contravariant,
411 infer_variance,
412 })
413 }
414 }
415
416 impl TypeVar {
417 pub fn new(
418 vm: &VirtualMachine,
419 name: PyObjectRef,
420 evaluate_bound: PyObjectRef,
421 evaluate_constraints: PyObjectRef,
422 ) -> Self {
423 Self {
424 name,
425 bound: PyMutex::new(vm.ctx.none()),
426 evaluate_bound,
427 constraints: PyMutex::new(vm.ctx.none()),
428 evaluate_constraints,
429 default_value: PyMutex::new(vm.ctx.typing_no_default.clone().into()),
430 evaluate_default: PyMutex::new(vm.ctx.none()),
431 covariant: false,
432 contravariant: false,
433 infer_variance: true,
434 }
435 }
436 }
437
438 #[pyattr]
439 #[pyclass(name = "ParamSpec", module = "typing")]
440 #[derive(Debug, PyPayload)]
441 pub struct ParamSpec {
442 #[pymember(name = "__name__")]
443 name: PyObjectRef,
444 #[pymember(name = "__bound__")]
445 bound: Option<PyObjectRef>,
446 default_value: PyMutex<PyObjectRef>,
447 evaluate_default: PyMutex<PyObjectRef>,
448 #[pymember(name = "__covariant__")]
449 covariant: bool,
450 #[pymember(name = "__contravariant__")]
451 contravariant: bool,
452 #[pymember(name = "__infer_variance__")]
453 infer_variance: bool,
454 }
455
456 #[pyclass(
457 flags(HAS_DICT, HAS_WEAKREF),
458 with(AsNumber, Constructor, Representable)
459 )]
460 impl Py<ParamSpec> {
461 #[pymethod]
462 fn __mro_entries__(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
463 Err(vm.new_type_error("Cannot subclass an instance of ParamSpec"))
464 }
465
466 #[pygetset]
467 fn args(zelf: crate::PyRef<ParamSpec>, vm: &VirtualMachine) -> PyObjectRef {
468 let self_obj: PyObjectRef = zelf.into();
469 let psa = ParamSpecArgs {
470 __origin__: self_obj,
471 };
472 psa.into_ref(&vm.ctx).into()
473 }
474
475 #[pygetset]
476 fn kwargs(zelf: crate::PyRef<ParamSpec>, vm: &VirtualMachine) -> PyObjectRef {
477 let self_obj: PyObjectRef = zelf.into();
478 let psk = ParamSpecKwargs {
479 __origin__: self_obj,
480 };
481 psk.into_ref(&vm.ctx).into()
482 }
483
484 #[pygetset]
485 fn __default__(&self, vm: &VirtualMachine) -> PyResult {
486 {
487 let default_value = self.default_value.lock();
488 if !default_value.is(&vm.ctx.typing_no_default) {
489 return Ok(default_value.clone());
490 }
491 }
492 let evaluator = self.evaluate_default.lock().clone();
493 if !vm.is_none(&evaluator) {
494 let result = evaluator.call((1i32,), vm)?;
495 *self.default_value.lock() = result.clone();
496 Ok(result)
497 } else {
498 Ok(vm.ctx.typing_no_default.clone().into())
499 }
500 }
501
502 #[pygetset]
503 fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
504 let evaluator = self.evaluate_default.lock().clone();
505 if !vm.is_none(&evaluator) {
506 return evaluator;
507 }
508
509 let default_value = self.default_value.lock().clone();
510 if !default_value.is(&vm.ctx.typing_no_default) {
511 return const_evaluator_alloc(default_value, vm);
512 }
513
514 vm.ctx.none()
515 }
516
517 #[pymethod]
518 fn __reduce__(&self) -> PyObjectRef {
519 self.name.clone()
520 }
521
522 #[pymethod]
523 fn has_default(&self, vm: &VirtualMachine) -> bool {
524 if !vm.is_none(&self.evaluate_default.lock()) {
525 return true;
526 }
527 !self.default_value.lock().is(&vm.ctx.typing_no_default)
528 }
529
530 #[pymethod]
531 fn __typing_subst__(
532 zelf: crate::PyRef<ParamSpec>,
533 arg: PyObjectRef,
534 vm: &VirtualMachine,
535 ) -> PyResult {
536 let self_obj: PyObjectRef = zelf.into();
537 call_typing_func_object(vm, "_paramspec_subst", (self_obj, arg))
538 }
539
540 #[pymethod]
541 fn __typing_prepare_subst__(
542 zelf: crate::PyRef<ParamSpec>,
543 alias: PyObjectRef,
544 args: PyObjectRef,
545 vm: &VirtualMachine,
546 ) -> PyResult {
547 let self_obj: PyObjectRef = zelf.into();
548 call_typing_func_object(vm, "_paramspec_prepare_subst", (self_obj, alias, args))
549 }
550 }
551
552 impl AsNumber for ParamSpec {
553 fn as_number() -> &'static PyNumberMethods {
554 static AS_NUMBER: PyNumberMethods = PyNumberMethods {
555 or: Some(|a, b, vm| {
556 let args = PyTuple::new_ref(vec![a.to_owned(), b.to_owned()], &vm.ctx);
557 make_union(&args, vm)
558 }),
559 ..PyNumberMethods::NOT_IMPLEMENTED
560 };
561 &AS_NUMBER
562 }
563 }
564
565 impl Constructor for ParamSpec {
566 type Args = FuncArgs;
567
568 fn slot_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
569 let mut kwargs = args.kwargs;
570 let name = if args.args.is_empty() {
572 if let Some(name) = kwargs.swap_remove("name") {
574 name
575 } else {
576 return Err(
577 vm.new_type_error("ParamSpec() missing required argument: 'name' (pos 1)")
578 );
579 }
580 } else if args.args.len() == 1 {
581 args.args[0].clone()
582 } else {
583 return Err(vm.new_type_error("ParamSpec() takes at most 1 positional argument"));
584 };
585
586 let bound = kwargs
587 .swap_remove("bound")
588 .map(|b| type_check(b, "Bound must be a type.", vm))
589 .transpose()?;
590 let covariant = kwargs
591 .swap_remove("covariant")
592 .map(|v| v.try_to_bool(vm))
593 .transpose()?
594 .unwrap_or(false);
595 let contravariant = kwargs
596 .swap_remove("contravariant")
597 .map(|v| v.try_to_bool(vm))
598 .transpose()?
599 .unwrap_or(false);
600 let infer_variance = kwargs
601 .swap_remove("infer_variance")
602 .map(|v| v.try_to_bool(vm))
603 .transpose()?
604 .unwrap_or(false);
605 let default = kwargs.swap_remove("default");
606
607 if let Some(invalid_key) = kwargs.keys().next() {
609 return Err(vm.new_unexpected_keyword_type_error(
610 Some("paramspec"),
611 &invalid_key.to_string(),
612 ));
613 }
614
615 if covariant && contravariant {
617 return Err(vm.new_value_error("Bivariant type variables are not supported."));
618 }
619
620 if infer_variance && (covariant || contravariant) {
621 return Err(vm.new_value_error("Variance cannot be specified with infer_variance"));
622 }
623
624 let default_value = default.unwrap_or_else(|| vm.ctx.typing_no_default.clone().into());
626
627 let paramspec = Self {
628 name,
629 bound,
630 default_value: PyMutex::new(default_value),
631 evaluate_default: PyMutex::new(vm.ctx.none()),
632 covariant,
633 contravariant,
634 infer_variance,
635 };
636
637 let obj = paramspec.into_ref_with_type(vm, cls)?;
638 let obj_ref: PyObjectRef = obj.into();
639 set_module_from_caller(&obj_ref, vm)?;
640 Ok(obj_ref)
641 }
642
643 fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
644 unimplemented!("use slot_new")
645 }
646 }
647
648 impl Representable for ParamSpec {
649 #[inline(always)]
650 fn repr_str(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
651 let name = zelf.name.str_utf8(vm)?;
652 Ok(variance_repr(
653 name.as_str(),
654 zelf.infer_variance,
655 zelf.covariant,
656 zelf.contravariant,
657 ))
658 }
659 }
660
661 impl ParamSpec {
662 pub fn new(name: PyObjectRef, vm: &VirtualMachine) -> Self {
663 Self {
664 name,
665 bound: None,
666 default_value: PyMutex::new(vm.ctx.typing_no_default.clone().into()),
667 evaluate_default: PyMutex::new(vm.ctx.none()),
668 covariant: false,
669 contravariant: false,
670 infer_variance: true,
671 }
672 }
673 }
674
675 #[pyattr]
676 #[pyclass(name = "TypeVarTuple", module = "typing")]
677 #[derive(Debug, PyPayload)]
678 pub struct TypeVarTuple {
679 #[pymember(name = "__name__")]
680 name: PyObjectRef,
681 default_value: PyMutex<PyObjectRef>,
682 evaluate_default: PyMutex<PyObjectRef>,
683 }
684
685 #[pyclass(
686 flags(HAS_DICT, HAS_WEAKREF),
687 with(Constructor, Representable, Iterable)
688 )]
689 impl Py<TypeVarTuple> {
690 #[pygetset]
691 fn __default__(&self, vm: &VirtualMachine) -> PyResult {
692 {
693 let default_value = self.default_value.lock();
694 if !default_value.is(&vm.ctx.typing_no_default) {
695 return Ok(default_value.clone());
696 }
697 }
698 let evaluator = self.evaluate_default.lock().clone();
699 if !vm.is_none(&evaluator) {
700 let result = evaluator.call((1i32,), vm)?;
701 *self.default_value.lock() = result.clone();
702 Ok(result)
703 } else {
704 Ok(vm.ctx.typing_no_default.clone().into())
705 }
706 }
707
708 #[pygetset]
709 fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
710 let evaluator = self.evaluate_default.lock().clone();
711 if !vm.is_none(&evaluator) {
712 return evaluator;
713 }
714
715 let default_value = self.default_value.lock().clone();
716 if !default_value.is(&vm.ctx.typing_no_default) {
717 return const_evaluator_alloc(default_value, vm);
718 }
719
720 vm.ctx.none()
721 }
722
723 #[pymethod]
724 fn has_default(&self, vm: &VirtualMachine) -> bool {
725 if !vm.is_none(&self.evaluate_default.lock()) {
726 return true;
727 }
728 let default_value = self.default_value.lock();
729 !default_value.is(&vm.ctx.typing_no_default)
730 }
731
732 #[pymethod]
733 fn __reduce__(&self) -> PyObjectRef {
734 self.name.clone()
735 }
736
737 #[pymethod]
738 fn __mro_entries__(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
739 Err(vm.new_type_error("Cannot subclass an instance of TypeVarTuple"))
740 }
741
742 #[pymethod]
743 fn __typing_subst__(&self, _arg: PyObjectRef, vm: &VirtualMachine) -> PyResult {
744 Err(vm.new_type_error("Substitution of bare TypeVarTuple is not supported"))
745 }
746
747 #[pymethod]
748 fn __typing_prepare_subst__(
749 zelf: crate::PyRef<TypeVarTuple>,
750 alias: PyObjectRef,
751 args: PyObjectRef,
752 vm: &VirtualMachine,
753 ) -> PyResult {
754 let self_obj: PyObjectRef = zelf.into();
755 call_typing_func_object(vm, "_typevartuple_prepare_subst", (self_obj, alias, args))
756 }
757 }
758
759 impl Iterable for TypeVarTuple {
760 fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
761 let typing = vm.import("typing", 0)?;
764 let unpack = typing.get_attr("Unpack", vm)?;
765 let zelf_obj: PyObjectRef = zelf.into();
766 let unpacked = vm.call_method(&unpack, "__getitem__", (zelf_obj,))?;
767 let list = vm.ctx.new_list(vec![unpacked]);
768 let list_obj: PyObjectRef = list.into();
769 vm.call_method(&list_obj, "__iter__", ())
770 }
771 }
772
773 impl Constructor for TypeVarTuple {
774 type Args = FuncArgs;
775
776 fn slot_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
777 let mut kwargs = args.kwargs;
778 let name = if args.args.is_empty() {
780 if let Some(name) = kwargs.swap_remove("name") {
782 name
783 } else {
784 return Err(vm.new_type_error(
785 "TypeVarTuple() missing required argument: 'name' (pos 1)",
786 ));
787 }
788 } else if args.args.len() == 1 {
789 args.args[0].clone()
790 } else {
791 return Err(vm.new_type_error("TypeVarTuple() takes at most 1 positional argument"));
792 };
793
794 let default = kwargs.swap_remove("default");
795
796 if let Some(invalid_key) = kwargs.keys().next() {
798 return Err(vm.new_unexpected_keyword_type_error(
799 Some("typevartuple"),
800 &invalid_key.to_string(),
801 ));
802 }
803
804 let (default_value, evaluate_default) = if let Some(default) = default {
806 (default, vm.ctx.none())
807 } else {
808 (vm.ctx.typing_no_default.clone().into(), vm.ctx.none())
810 };
811
812 let typevartuple = Self {
813 name,
814 default_value: PyMutex::new(default_value),
815 evaluate_default: PyMutex::new(evaluate_default),
816 };
817
818 let obj = typevartuple.into_ref_with_type(vm, cls)?;
819 let obj_ref: PyObjectRef = obj.into();
820 set_module_from_caller(&obj_ref, vm)?;
821 Ok(obj_ref)
822 }
823
824 fn py_new(_cls: &Py<PyType>, _args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
825 unimplemented!("use slot_new")
826 }
827 }
828
829 impl Representable for TypeVarTuple {
830 #[inline(always)]
831 fn repr_str(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
832 let name = zelf.name.str(vm)?;
833 Ok(name.to_string())
834 }
835 }
836
837 impl TypeVarTuple {
838 pub fn new(name: PyObjectRef, vm: &VirtualMachine) -> Self {
839 Self {
840 name,
841 default_value: PyMutex::new(vm.ctx.typing_no_default.clone().into()),
842 evaluate_default: PyMutex::new(vm.ctx.none()),
843 }
844 }
845 }
846
847 #[pyattr]
848 #[pyclass(name = "ParamSpecArgs", module = "typing", unhashable = true)]
849 #[derive(Debug, PyPayload)]
850 pub struct ParamSpecArgs {
851 #[pymember]
852 __origin__: PyObjectRef,
853 }
854
855 #[pyclass(with(Constructor, Representable, Comparable), flags(HAS_WEAKREF))]
856 impl Py<ParamSpecArgs> {
857 #[pymethod]
858 fn __mro_entries__(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
859 Err(vm.new_type_error("Cannot subclass an instance of ParamSpecArgs"))
860 }
861 }
862
863 impl Constructor for ParamSpecArgs {
864 type Args = (PyObjectRef,);
865
866 fn py_new(_cls: &Py<PyType>, args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
867 let origin = args.0;
868 Ok(Self { __origin__: origin })
869 }
870 }
871
872 impl Representable for ParamSpecArgs {
873 #[inline(always)]
874 fn repr_str(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
875 if let Some(param_spec) = zelf.__origin__.downcast_ref::<ParamSpec>() {
878 return Ok(format!("{}.args", param_spec.name.str_utf8(vm)?));
879 }
880 Ok(format!("{}.args", zelf.__origin__.repr(vm)?))
881 }
882 }
883
884 impl Comparable for ParamSpecArgs {
885 fn cmp(
886 zelf: &crate::Py<Self>,
887 other: &PyObject,
888 op: PyComparisonOp,
889 vm: &VirtualMachine,
890 ) -> PyResult<PyComparisonValue> {
891 op.eq_only(|| {
892 if other.class().is(zelf.class())
893 && let Some(other_args) = other.downcast_ref::<Self>()
894 {
895 let eq = zelf.__origin__.rich_compare_bool(
896 &other_args.__origin__,
897 PyComparisonOp::Eq,
898 vm,
899 )?;
900 return Ok(PyComparisonValue::Implemented(eq));
901 }
902 Ok(PyComparisonValue::NotImplemented)
903 })
904 }
905 }
906
907 #[pyattr]
908 #[pyclass(name = "ParamSpecKwargs", module = "typing", unhashable = true)]
909 #[derive(Debug, PyPayload)]
910 pub struct ParamSpecKwargs {
911 #[pymember]
912 __origin__: PyObjectRef,
913 }
914
915 #[pyclass(with(Constructor, Representable, Comparable), flags(HAS_WEAKREF))]
916 impl Py<ParamSpecKwargs> {
917 #[pymethod]
918 fn __mro_entries__(&self, _object: PyObjectRef, vm: &VirtualMachine) -> PyResult {
919 Err(vm.new_type_error("Cannot subclass an instance of ParamSpecKwargs"))
920 }
921 }
922
923 impl Constructor for ParamSpecKwargs {
924 type Args = (PyObjectRef,);
925
926 fn py_new(_cls: &Py<PyType>, args: Self::Args, _vm: &VirtualMachine) -> PyResult<Self> {
927 let origin = args.0;
928 Ok(Self { __origin__: origin })
929 }
930 }
931
932 impl Representable for ParamSpecKwargs {
933 #[inline(always)]
934 fn repr_str(zelf: &crate::Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
935 if let Some(param_spec) = zelf.__origin__.downcast_ref::<ParamSpec>() {
938 return Ok(format!("{}.kwargs", param_spec.name.str_utf8(vm)?));
939 }
940 Ok(format!("{}.kwargs", zelf.__origin__.repr(vm)?))
941 }
942 }
943
944 impl Comparable for ParamSpecKwargs {
945 fn cmp(
946 zelf: &crate::Py<Self>,
947 other: &PyObject,
948 op: PyComparisonOp,
949 vm: &VirtualMachine,
950 ) -> PyResult<PyComparisonValue> {
951 op.eq_only(|| {
952 if other.class().is(zelf.class())
953 && let Some(other_kwargs) = other.downcast_ref::<Self>()
954 {
955 let eq = zelf.__origin__.rich_compare_bool(
956 &other_kwargs.__origin__,
957 PyComparisonOp::Eq,
958 vm,
959 )?;
960 return Ok(PyComparisonValue::Implemented(eq));
961 }
962 Ok(PyComparisonValue::NotImplemented)
963 })
964 }
965 }
966
967 fn call_typing_args_kwargs(
970 name: &'static str,
971 cls: PyTypeRef,
972 args: FuncArgs,
973 vm: &VirtualMachine,
974 ) -> PyResult {
975 let typing = vm.import("typing", 0)?;
976 let func = typing.get_attr(name, vm)?;
977
978 let mut call_args = vec![cls.into()];
980 call_args.extend(args.args);
981
982 let func_args = FuncArgs {
984 args: call_args,
985 kwargs: args.kwargs,
986 };
987
988 func.call(func_args, vm)
989 }
990
991 #[pyattr]
992 #[pyclass(name = "Generic", module = "typing")]
993 #[derive(Debug, PyPayload)]
994 pub struct Generic;
995
996 #[pyclass(flags(BASETYPE, HEAPTYPE))]
997 impl Generic {
998 #[pyattr]
999 fn __slots__(ctx: &Context) -> PyTupleRef {
1000 ctx.empty_tuple.clone()
1001 }
1002
1003 #[pyclassmethod]
1004 fn __class_getitem__(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1005 call_typing_args_kwargs("_generic_class_getitem", cls, args, vm)
1006 }
1007
1008 #[pyclassmethod]
1009 fn __init_subclass__(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1010 call_typing_args_kwargs("_generic_init_subclass", cls, args, vm)
1011 }
1012 }
1013
1014 pub fn set_typeparam_default(
1017 type_param: PyObjectRef,
1018 evaluate_default: PyObjectRef,
1019 vm: &VirtualMachine,
1020 ) -> PyResult {
1021 fn try_set_default<T>(
1023 obj: &PyObject,
1024 evaluate_default: &PyObject,
1025 get_field: impl FnOnce(&T) -> &PyMutex<PyObjectRef>,
1026 ) -> bool
1027 where
1028 T: PyPayload,
1029 {
1030 if let Some(typed_obj) = obj.downcast_ref::<T>() {
1031 *get_field(typed_obj).lock() = evaluate_default.to_owned();
1032 true
1033 } else {
1034 false
1035 }
1036 }
1037
1038 if try_set_default::<TypeVar>(&type_param, &evaluate_default, |tv| &tv.evaluate_default)
1040 || try_set_default::<ParamSpec>(&type_param, &evaluate_default, |ps| {
1041 &ps.evaluate_default
1042 })
1043 || try_set_default::<TypeVarTuple>(&type_param, &evaluate_default, |tvt| {
1044 &tvt.evaluate_default
1045 })
1046 {
1047 Ok(type_param)
1048 } else {
1049 Err(vm.new_type_error(format!(
1050 "Expected a type param, got {}",
1051 type_param.class().name()
1052 )))
1053 }
1054 }
1055}