1919 StarExpr , YieldFromExpr , NonlocalDecl , DictionaryComprehension ,
2020 SetComprehension , ComplexExpr , EllipsisExpr , YieldExpr , Argument ,
2121 AwaitExpr , TempNode , Expression , Statement ,
22- ARG_POS , ARG_OPT , ARG_STAR , ARG_NAMED , ARG_NAMED_OPT , ARG_STAR2
22+ ARG_POS , ARG_OPT , ARG_STAR , ARG_NAMED , ARG_NAMED_OPT , ARG_STAR2 ,
23+ check_arg_names ,
2324)
2425from mypy .types import (
2526 Type , CallableType , AnyType , UnboundType , TupleType , TypeList , EllipsisType ,
27+ CallableArgument ,
2628)
2729from mypy import defaults
2830from mypy import experiments
@@ -444,24 +446,12 @@ def make_argument(arg: ast3.arg, default: Optional[ast3.expr], kind: int) -> Arg
444446 new_args .append (make_argument (args .kwarg , None , ARG_STAR2 ))
445447 names .append (args .kwarg )
446448
447- seen_names = set () # type: Set[str]
448- for name in names :
449- if name .arg in seen_names :
450- self .fail ("duplicate argument '{}' in function definition" .format (name .arg ),
451- name .lineno , name .col_offset )
452- break
453- seen_names .add (name .arg )
449+ def fail_arg (msg : str , arg : ast3 .arg ) -> None :
450+ self .fail (msg , arg .lineno , arg .col_offset )
454451
455- return new_args
452+ check_arg_names ([ name . arg for name in names ], names , fail_arg )
456453
457- def stringify_name (self , n : ast3 .AST ) -> str :
458- if isinstance (n , ast3 .Name ):
459- return n .id
460- elif isinstance (n , ast3 .Attribute ):
461- sv = self .stringify_name (n .value )
462- if sv is not None :
463- return "{}.{}" .format (sv , n .attr )
464- return None # Can't do it.
454+ return new_args
465455
466456 # ClassDef(identifier name,
467457 # expr* bases,
@@ -474,7 +464,7 @@ def visit_ClassDef(self, n: ast3.ClassDef) -> ClassDef:
474464 metaclass_arg = find (lambda x : x .arg == 'metaclass' , n .keywords )
475465 metaclass = None
476466 if metaclass_arg :
477- metaclass = self . stringify_name (metaclass_arg .value )
467+ metaclass = stringify_name (metaclass_arg .value )
478468 if metaclass is None :
479469 metaclass = '<error>' # To be reported later
480470
@@ -965,6 +955,21 @@ class TypeConverter(ast3.NodeTransformer): # type: ignore # typeshed PR #931
965955 def __init__ (self , errors : Errors , line : int = - 1 ) -> None :
966956 self .errors = errors
967957 self .line = line
958+ self .node_stack = [] # type: List[ast3.AST]
959+
960+ def visit (self , node : ast3 .AST ) -> Type :
961+ """Modified visit -- keep track of the stack of nodes"""
962+ self .node_stack .append (node )
963+ try :
964+ return super ().visit (node )
965+ finally :
966+ self .node_stack .pop ()
967+
968+ def parent (self ) -> ast3 .AST :
969+ """Return the AST node above the one we are processing"""
970+ if len (self .node_stack ) < 2 :
971+ return None
972+ return self .node_stack [- 2 ]
968973
969974 def fail (self , msg : str , line : int , column : int ) -> None :
970975 self .errors .report (line , column , msg )
@@ -985,6 +990,55 @@ def visit_NoneType(self, n: Any) -> Type:
985990 def translate_expr_list (self , l : Sequence [ast3 .AST ]) -> List [Type ]:
986991 return [self .visit (e ) for e in l ]
987992
993+ def visit_Call (self , e : ast3 .Call ) -> Type :
994+ # Parse the arg constructor
995+ if not isinstance (self .parent (), ast3 .List ):
996+ return self .generic_visit (e )
997+ f = e .func
998+ constructor = stringify_name (f )
999+ if not constructor :
1000+ self .fail ("Expected arg constructor name" , e .lineno , e .col_offset )
1001+ name = None # type: Optional[str]
1002+ default_type = AnyType (implicit = True )
1003+ typ = default_type # type: Type
1004+ for i , arg in enumerate (e .args ):
1005+ if i == 0 :
1006+ typ = self .visit (arg )
1007+ elif i == 1 :
1008+ name = self ._extract_argument_name (arg )
1009+ else :
1010+ self .fail ("Too many arguments for argument constructor" ,
1011+ f .lineno , f .col_offset )
1012+ for k in e .keywords :
1013+ value = k .value
1014+ if k .arg == "name" :
1015+ if name is not None :
1016+ self .fail ('"{}" gets multiple values for keyword argument "name"' .format (
1017+ constructor ), f .lineno , f .col_offset )
1018+ name = self ._extract_argument_name (value )
1019+ elif k .arg == "type" :
1020+ if typ is not default_type :
1021+ self .fail ('"{}" gets multiple values for keyword argument "type"' .format (
1022+ constructor ), f .lineno , f .col_offset )
1023+ typ = self .visit (value )
1024+ else :
1025+ self .fail (
1026+ 'Unexpected argument "{}" for argument constructor' .format (k .arg ),
1027+ value .lineno , value .col_offset )
1028+ return CallableArgument (typ , name , constructor , e .lineno , e .col_offset )
1029+
1030+ def translate_argument_list (self , l : Sequence [ast3 .AST ]) -> TypeList :
1031+ return TypeList ([self .visit (e ) for e in l ], line = self .line )
1032+
1033+ def _extract_argument_name (self , n : ast3 .expr ) -> str :
1034+ if isinstance (n , ast3 .Str ):
1035+ return n .s .strip ()
1036+ elif isinstance (n , ast3 .NameConstant ) and str (n .value ) == 'None' :
1037+ return None
1038+ self .fail ('Expected string literal for argument name, got {}' .format (
1039+ type (n ).__name__ ), self .line , 0 )
1040+ return None
1041+
9881042 def visit_Name (self , n : ast3 .Name ) -> Type :
9891043 return UnboundType (n .id , line = self .line )
9901044
@@ -1036,4 +1090,14 @@ def visit_Ellipsis(self, n: ast3.Ellipsis) -> Type:
10361090
10371091 # List(expr* elts, expr_context ctx)
10381092 def visit_List (self , n : ast3 .List ) -> Type :
1039- return TypeList (self .translate_expr_list (n .elts ), line = self .line )
1093+ return self .translate_argument_list (n .elts )
1094+
1095+
1096+ def stringify_name (n : ast3 .AST ) -> Optional [str ]:
1097+ if isinstance (n , ast3 .Name ):
1098+ return n .id
1099+ elif isinstance (n , ast3 .Attribute ):
1100+ sv = stringify_name (n .value )
1101+ if sv is not None :
1102+ return "{}.{}" .format (sv , n .attr )
1103+ return None # Can't do it.
0 commit comments