8
8
TupleType , TypedDictType , UnionType , Overloaded , ErasedType , PartialType , DeletedType ,
9
9
UninhabitedType , TypeType , TypeVarId , TypeQuery , is_named_instance , TypeOfAny , LiteralType ,
10
10
ProperType , ParamSpecType , get_proper_type , TypeAliasType , is_union_with_any ,
11
- UnpackType , callable_with_ellipsis , TUPLE_LIKE_INSTANCE_NAMES ,
11
+ UnpackType , callable_with_ellipsis , Parameters , TUPLE_LIKE_INSTANCE_NAMES ,
12
12
)
13
13
from mypy .maptype import map_instance_to_supertype
14
14
import mypy .subtypes
@@ -406,6 +406,9 @@ def visit_param_spec(self, template: ParamSpecType) -> List[Constraint]:
406
406
def visit_unpack_type (self , template : UnpackType ) -> List [Constraint ]:
407
407
raise NotImplementedError
408
408
409
+ def visit_parameters (self , template : Parameters ) -> List [Constraint ]:
410
+ raise RuntimeError ("Parameters cannot be constrained to" )
411
+
409
412
# Non-leaf types
410
413
411
414
def visit_instance (self , template : Instance ) -> List [Constraint ]:
@@ -446,7 +449,7 @@ def visit_instance(self, template: Instance) -> List[Constraint]:
446
449
# N.B: We use zip instead of indexing because the lengths might have
447
450
# mismatches during daemon reprocessing.
448
451
for tvar , mapped_arg , instance_arg in zip (tvars , mapped .args , instance .args ):
449
- # TODO: ParamSpecType
452
+ # TODO(PEP612): More ParamSpec work (or is Parameters the only thing accepted)
450
453
if isinstance (tvar , TypeVarType ):
451
454
# The constraints for generic type parameters depend on variance.
452
455
# Include constraints from both directions if invariant.
@@ -456,6 +459,27 @@ def visit_instance(self, template: Instance) -> List[Constraint]:
456
459
if tvar .variance != COVARIANT :
457
460
res .extend (infer_constraints (
458
461
mapped_arg , instance_arg , neg_op (self .direction )))
462
+ elif isinstance (tvar , ParamSpecType ) and isinstance (mapped_arg , ParamSpecType ):
463
+ suffix = get_proper_type (instance_arg )
464
+
465
+ if isinstance (suffix , CallableType ):
466
+ prefix = mapped_arg .prefix
467
+ from_concat = bool (prefix .arg_types ) or suffix .from_concatenate
468
+ suffix = suffix .copy_modified (from_concatenate = from_concat )
469
+
470
+ if isinstance (suffix , Parameters ) or isinstance (suffix , CallableType ):
471
+ # no such thing as variance for ParamSpecs
472
+ # TODO: is there a case I am missing?
473
+ # TODO: constraints between prefixes
474
+ prefix = mapped_arg .prefix
475
+ suffix = suffix .copy_modified (
476
+ suffix .arg_types [len (prefix .arg_types ):],
477
+ suffix .arg_kinds [len (prefix .arg_kinds ):],
478
+ suffix .arg_names [len (prefix .arg_names ):])
479
+ res .append (Constraint (mapped_arg .id , SUPERTYPE_OF , suffix ))
480
+ elif isinstance (suffix , ParamSpecType ):
481
+ res .append (Constraint (mapped_arg .id , SUPERTYPE_OF , suffix ))
482
+
459
483
return res
460
484
elif (self .direction == SUPERTYPE_OF and
461
485
instance .type .has_base (template .type .fullname )):
@@ -464,7 +488,6 @@ def visit_instance(self, template: Instance) -> List[Constraint]:
464
488
# N.B: We use zip instead of indexing because the lengths might have
465
489
# mismatches during daemon reprocessing.
466
490
for tvar , mapped_arg , template_arg in zip (tvars , mapped .args , template .args ):
467
- # TODO: ParamSpecType
468
491
if isinstance (tvar , TypeVarType ):
469
492
# The constraints for generic type parameters depend on variance.
470
493
# Include constraints from both directions if invariant.
@@ -474,6 +497,28 @@ def visit_instance(self, template: Instance) -> List[Constraint]:
474
497
if tvar .variance != COVARIANT :
475
498
res .extend (infer_constraints (
476
499
template_arg , mapped_arg , neg_op (self .direction )))
500
+ elif (isinstance (tvar , ParamSpecType ) and
501
+ isinstance (template_arg , ParamSpecType )):
502
+ suffix = get_proper_type (mapped_arg )
503
+
504
+ if isinstance (suffix , CallableType ):
505
+ prefix = template_arg .prefix
506
+ from_concat = bool (prefix .arg_types ) or suffix .from_concatenate
507
+ suffix = suffix .copy_modified (from_concatenate = from_concat )
508
+
509
+ if isinstance (suffix , Parameters ) or isinstance (suffix , CallableType ):
510
+ # no such thing as variance for ParamSpecs
511
+ # TODO: is there a case I am missing?
512
+ # TODO: constraints between prefixes
513
+ prefix = template_arg .prefix
514
+
515
+ suffix = suffix .copy_modified (
516
+ suffix .arg_types [len (prefix .arg_types ):],
517
+ suffix .arg_kinds [len (prefix .arg_kinds ):],
518
+ suffix .arg_names [len (prefix .arg_names ):])
519
+ res .append (Constraint (template_arg .id , SUPERTYPE_OF , suffix ))
520
+ elif isinstance (suffix , ParamSpecType ):
521
+ res .append (Constraint (template_arg .id , SUPERTYPE_OF , suffix ))
477
522
return res
478
523
if (template .type .is_protocol and self .direction == SUPERTYPE_OF and
479
524
# We avoid infinite recursion for structural subtypes by checking
@@ -564,11 +609,34 @@ def visit_callable_type(self, template: CallableType) -> List[Constraint]:
564
609
# Negate direction due to function argument type contravariance.
565
610
res .extend (infer_constraints (t , a , neg_op (self .direction )))
566
611
else :
612
+ # sometimes, it appears we try to get constraints between two paramspec callables?
567
613
# TODO: Direction
568
- # TODO: Deal with arguments that come before param spec ones?
569
- res .append (Constraint (param_spec .id ,
570
- SUBTYPE_OF ,
571
- cactual .copy_modified (ret_type = NoneType ())))
614
+ # TODO: check the prefixes match
615
+ prefix = param_spec .prefix
616
+ prefix_len = len (prefix .arg_types )
617
+ cactual_ps = cactual .param_spec ()
618
+
619
+ if not cactual_ps :
620
+ res .append (Constraint (param_spec .id ,
621
+ SUBTYPE_OF ,
622
+ cactual .copy_modified (
623
+ arg_types = cactual .arg_types [prefix_len :],
624
+ arg_kinds = cactual .arg_kinds [prefix_len :],
625
+ arg_names = cactual .arg_names [prefix_len :],
626
+ ret_type = NoneType ())))
627
+ else :
628
+ res .append (Constraint (param_spec .id , SUBTYPE_OF , cactual_ps ))
629
+
630
+ # compare prefixes
631
+ cactual_prefix = cactual .copy_modified (
632
+ arg_types = cactual .arg_types [:prefix_len ],
633
+ arg_kinds = cactual .arg_kinds [:prefix_len ],
634
+ arg_names = cactual .arg_names [:prefix_len ])
635
+
636
+ # TODO: see above "FIX" comments for param_spec is None case
637
+ # TODO: this assume positional arguments
638
+ for t , a in zip (prefix .arg_types , cactual_prefix .arg_types ):
639
+ res .extend (infer_constraints (t , a , neg_op (self .direction )))
572
640
573
641
template_ret_type , cactual_ret_type = template .ret_type , cactual .ret_type
574
642
if template .type_guard is not None :
0 commit comments