Skip to content

Commit b26c534

Browse files
committed
Re-switch order of arguments; defer handling semantics to typeanal
1 parent 7d92e6c commit b26c534

File tree

8 files changed

+66
-151
lines changed

8 files changed

+66
-151
lines changed

mypy/exprtotype.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
from mypy.nodes import (
44
Expression, NameExpr, MemberExpr, IndexExpr, TupleExpr,
55
ListExpr, StrExpr, BytesExpr, UnicodeExpr, EllipsisExpr, CallExpr,
6-
ARG_POS, ARG_NAMED,
76
)
8-
from mypy.sharedparse import ARG_KINDS_BY_CONSTRUCTOR, STAR_ARG_CONSTRUCTORS
97
from mypy.parsetype import parse_str_as_type, TypeParseError
108
from mypy.types import Type, UnboundType, ArgumentList, EllipsisType, AnyType, Optional
119

@@ -56,14 +54,14 @@ def expr_to_unanalyzed_type(expr: Expression) -> Type:
5654
elif isinstance(expr, ListExpr):
5755
types = [] # type: List[Type]
5856
names = [] # type: List[Optional[str]]
59-
constructors = [] # type: List[UnboundArgumentConstructor]
57+
constructors = [] # type: List[Optional[str]]
6058
for it in expr.items:
6159
if isinstance(it, CallExpr):
6260
callee = it.callee
6361
if isinstance(callee, NameExpr):
64-
constructor = UnboundArgumentConstructor(callee.name)
65-
elif isinstance(it.callee, MemberExpr):
66-
constructor = UnboundArgumentConstructor(get_member_expr_fullname(callee))
62+
constructor = callee.name
63+
elif isinstance(callee, MemberExpr):
64+
constructor = get_member_expr_fullname(callee)
6765
else:
6866
raise TypeTranslationError()
6967
name = None
@@ -90,7 +88,7 @@ def expr_to_unanalyzed_type(expr: Expression) -> Type:
9088
else:
9189
types.append(expr_to_unanalyzed_type(it))
9290
names.append(None)
93-
constructors.append(UnboundArgumentConstructor(None))
91+
constructors.append(None)
9492
return ArgumentList(types, names, constructors,
9593
line=expr.line, column=expr.column)
9694
elif isinstance(expr, (StrExpr, BytesExpr, UnicodeExpr)):

mypy/fastparse.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from typing import Tuple, Union, TypeVar, Callable, Sequence, Optional, Any, cast, List, Set
55
from mypy.sharedparse import (
66
special_function_elide_names, argument_elide_name,
7-
ARG_KINDS_BY_CONSTRUCTOR, STAR_ARG_CONSTRUCTORS,
87
)
98
from mypy.nodes import (
109
MypyFile, Node, ImportBase, Import, ImportAll, ImportFrom, FuncDef, OverloadedFuncDef,
@@ -953,22 +952,21 @@ def translate_expr_list(self, l: Sequence[ast3.AST]) -> List[Type]:
953952
def translate_argument_list(self, l: Sequence[ast3.AST]) -> ArgumentList:
954953
types = [] # type: List[Type]
955954
names = [] # type: List[Optional[str]]
956-
constructors = [] # type: List[UnboundArgumentConstructor]
955+
constructors = [] # type: List[Optional[str]]
957956
for e in l:
958-
constructor = UnboundArgumentConstructor(None)
957+
constructor = None # type: Optional[str]
959958
if isinstance(e, ast3.Call):
960959
name = None # type: Optional[str]
961960
# Parse the arg constructor
962961
f = e.func
963962
if isinstance(f, ast3.Name):
964-
constructor = UnboundArgumentConstructor(f.id, line=self.line)
963+
constructor = f.id
965964
elif isinstance(f, ast3.NameConstant):
966-
constructor = UnboundArgumentConstructor(str(f.value), line=self.line)
965+
constructor = str(f.value)
967966
elif isinstance(f, ast3.Attribute):
968967
before_dot = self.visit(f.value)
969968
if isinstance(before_dot, UnboundType):
970-
constructor = UnboundArgumentConstructor(
971-
"{}.{}".format(before_dot.name, f.attr), line = self.line)
969+
constructor = "{}.{}".format(before_dot.name, f.attr)
972970

973971
typ = AnyType(implicit=True) # type: Type
974972
if len(e.args) >= 1:
@@ -980,7 +978,7 @@ def translate_argument_list(self, l: Sequence[ast3.AST]) -> ArgumentList:
980978
f.lineno, getattr(f, 'col_offset', -1))
981979
for k in e.keywords:
982980
value = k.value
983-
if k.arg == "name" and not star:
981+
if k.arg == "name":
984982
name = self._extract_str(value)
985983
elif k.arg == "typ":
986984
typ = self.visit(value)
@@ -1052,7 +1050,7 @@ def visit_Ellipsis(self, n: ast3.Ellipsis) -> Type:
10521050
def visit_List(self, n: ast3.List) -> Type:
10531051
return self.translate_argument_list(n.elts)
10541052

1055-
def _extract_str(arg: ast3.expr) -> Optional[str]:
1053+
def _extract_str(self, arg: ast3.expr) -> Optional[str]:
10561054
if isinstance(arg, ast3.Name) and arg.id == 'None':
10571055
return None
10581056
elif isinstance(arg, ast3.NameConstant) and arg.value is None:
@@ -1061,3 +1059,4 @@ def _extract_str(arg: ast3.expr) -> Optional[str]:
10611059
return arg.s
10621060
else:
10631061
self.fail("Bad type for name of argument", arg.lineno, arg.col_offset)
1062+
return None

mypy/messages.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def format(self, typ: Type, verbosity: int = 0) -> str:
209209
verbosity = max(verbosity - 1, 0))))
210210
else:
211211
constructor = ARG_CONSTRUCTOR_NAMES[arg_kind]
212-
if arg_kind in (ARG_STAR, ARG_STAR2):
212+
if arg_kind in (ARG_STAR, ARG_STAR2) or arg_name is None:
213213
arg_strings.append("{}({})".format(
214214
constructor,
215215
strip_quotes(self.format(arg_type))))

mypy/parsetype.py

+17-90
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
"""Type parser"""
22

3-
from typing import List, Tuple, Union, Optional, TypeVar, cast
4-
5-
import typing
3+
from typing import List, Tuple, Union, Optional
64

75
from mypy.types import (
86
Type, UnboundType, TupleType, ArgumentList, CallableType, StarType,
9-
EllipsisType, AnyType, ArgNameException, ArgKindException
7+
EllipsisType
108
)
11-
12-
from mypy.sharedparse import ARG_KINDS_BY_CONSTRUCTOR, STAR_ARG_CONSTRUCTORS
13-
149
from mypy.lex import Token, Name, StrLit, lex
1510
from mypy import nodes
1611

17-
T = TypeVar('T', bound=Token)
1812

1913
none = Token('') # Empty token
2014

@@ -108,80 +102,23 @@ def parse_types(self) -> Type:
108102
type = TupleType(items, None, type.line, implicit=True)
109103
return type
110104

111-
def parse_argument_spec(self) -> Tuple[Type, Optional[str], int]:
112-
current = self.current_token()
113-
nxt = self.next_token()
114-
# This is a small recreation of a subset of parsing a CallExpr; just
115-
# enough to parse what happens in an arugment list.
116-
# TODO: Doesn't handle an explicit name of None yet.
117-
if isinstance(current, Name) and nxt is not None and nxt.string == '(':
118-
arg_const = self.expect_type(Name).string
119-
name = None # type: Optional[str]
120-
typ = AnyType(implicit=True) # type: Type
121-
try:
122-
kind = ARG_KINDS_BY_CONSTRUCTOR[arg_const]
123-
except KeyError:
124-
raise self.parse_error("Unknown argument constructor {}".format(arg_const))
125-
name, typ = self.parse_arg_args(read_name = arg_const not in STAR_ARG_CONSTRUCTORS)
126-
return typ, name, kind
127-
else:
128-
return self.parse_type(), None, nodes.ARG_POS
129-
130-
def parse_arg_args(self, *, read_name: bool) -> Tuple[Optional[str], Optional[Type]]:
131-
self.expect('(')
132-
name = None # type: Optional[str]
133-
typ = AnyType(implicit=True) # type: Type
134-
i = 0
135-
while self.current_token_str() != ')':
136-
if i > 0:
137-
self.expect(',')
138-
if self.next_token() and self.next_token().string == '=':
139-
arg_arg_name = self.current_token_str()
140-
if arg_arg_name == 'name' and read_name:
141-
self.expect('name')
142-
self.expect('=')
143-
if self.current_token_str() == 'None':
144-
self.expect('None')
145-
else:
146-
name = self.expect_type(StrLit).parsed()
147-
elif arg_arg_name == 'typ':
148-
self.expect('typ')
149-
self.expect('=')
150-
typ = self.parse_type()
151-
else:
152-
raise self.parse_error(
153-
'Unexpected argument "{}" for argument constructor'.format(arg_arg_name))
154-
elif i == 0 and read_name:
155-
if self.current_token_str() == 'None':
156-
self.expect('None')
157-
else:
158-
name = self.expect_type(StrLit).parsed()
159-
elif i == 0 and not read_name or i == 1 and read_name:
160-
typ = self.parse_type()
161-
else:
162-
raise self.parse_error("Unexpected argument for argument constructor")
163-
i += 1
164-
self.expect(')')
165-
return name, typ
166-
167105
def parse_argument_list(self) -> ArgumentList:
168106
"""Parse type list [t, ...]."""
169107
lbracket = self.expect('[')
170108
commas = [] # type: List[Token]
171109
items = [] # type: List[Type]
172-
names = [] # type: List[Optional[str]]
173-
kinds = [] # type: List[int]
174110
while self.current_token_str() != ']':
175-
t, name, kind = self.parse_argument_spec()
111+
t = self.parse_type()
176112
items.append(t)
177-
names.append(name)
178-
kinds.append(kind)
179-
180113
if self.current_token_str() != ',':
181114
break
182115
commas.append(self.skip())
183116
self.expect(']')
184-
return ArgumentList(items, names, kinds, line=lbracket.line)
117+
return ArgumentList(
118+
items,
119+
[None] * len(items),
120+
[None] * len(items),
121+
line=lbracket.line)
185122

186123
def parse_named_type(self) -> Type:
187124
line = self.current_token().line
@@ -235,26 +172,21 @@ def expect(self, string: str) -> Token:
235172
else:
236173
raise self.parse_error()
237174

238-
def expect_type(self, typ: typing.Type[T]) -> T:
175+
def expect_type(self, typ: type) -> Token:
239176
if isinstance(self.current_token(), typ):
240177
self.ind += 1
241-
return cast(T, self.tok[self.ind - 1])
178+
return self.tok[self.ind - 1]
242179
else:
243180
raise self.parse_error()
244181

245182
def current_token(self) -> Token:
246183
return self.tok[self.ind]
247184

248-
def next_token(self) -> Optional[Token]:
249-
if self.ind + 1 >= len(self.tok):
250-
return None
251-
return self.tok[self.ind + 1]
252-
253185
def current_token_str(self) -> str:
254186
return self.current_token().string
255187

256-
def parse_error(self, message: Optional[str] = None) -> TypeParseError:
257-
return TypeParseError(self.tok[self.ind], self.ind, message=message)
188+
def parse_error(self) -> TypeParseError:
189+
return TypeParseError(self.tok[self.ind], self.ind)
258190

259191

260192
def parse_str_as_type(typestr: str, line: int) -> Type:
@@ -279,8 +211,6 @@ def parse_signature(tokens: List[Token]) -> Tuple[CallableType, int]:
279211
i = 0
280212
if tokens[i].string != '(':
281213
raise TypeParseError(tokens[i], i)
282-
begin = tokens[i]
283-
begin_idx = i
284214
i += 1
285215
arg_types = [] # type: List[Type]
286216
arg_kinds = [] # type: List[int]
@@ -316,11 +246,8 @@ def parse_signature(tokens: List[Token]) -> Tuple[CallableType, int]:
316246
raise TypeParseError(tokens[i], i)
317247
i += 1
318248
ret_type, i = parse_type(tokens, i)
319-
try:
320-
return CallableType(arg_types,
321-
arg_kinds,
322-
[None] * len(arg_types),
323-
ret_type, None,
324-
is_ellipsis_args=encountered_ellipsis), i
325-
except (ArgKindException, ArgNameException) as e:
326-
raise TypeParseError(begin, begin_idx, e.message)
249+
return CallableType(arg_types,
250+
arg_kinds,
251+
[None] * len(arg_types),
252+
ret_type, None,
253+
is_ellipsis_args=encountered_ellipsis), i

mypy/sharedparse.py

-12
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,6 @@
9494
MAGIC_METHODS_POS_ARGS_ONLY = MAGIC_METHODS - MAGIC_METHODS_ALLOWING_KWARGS
9595

9696

97-
ARG_KINDS_BY_CONSTRUCTOR = {
98-
'Arg': ARG_POS,
99-
'DefaultArg': ARG_OPT,
100-
'NamedArg': ARG_NAMED,
101-
'DefaultNamedArg': ARG_NAMED_OPT,
102-
'StarArg': ARG_STAR,
103-
'KwArg': ARG_STAR2,
104-
}
105-
106-
STAR_ARG_CONSTRUCTORS = {'StarArg', 'KwArg'}
107-
108-
10997
def special_function_elide_names(name: str) -> bool:
11098
return name in MAGIC_METHODS_POS_ARGS_ONLY
11199

mypy/typeanal.py

+19-7
Original file line numberDiff line numberDiff line change
@@ -342,19 +342,18 @@ def visit_type_type(self, t: TypeType) -> Type:
342342
def argument_list_to_kinds(self, a: ArgumentList) -> List[int]:
343343
res = [] # type: List[int]
344344
for constructor in a.constructors:
345-
if constructor.name is None:
345+
if constructor is None:
346346
res.append(nodes.ARG_POS)
347347
else:
348-
sym = self.lookup(constructor.name, constructor)
349-
if sym.node is None:
350-
assert sym.kind == UNBOUND_IMPORTED
351-
self.fail("Argument constructor not found: {}".format(constructor.name),
352-
constructor)
348+
sym = self.lookup(constructor, a)
349+
if sym is None or sym.node is None:
350+
self.fail("Argument constructor not found: {}".format(constructor),
351+
a)
353352
res.append(nodes.ARG_POS)
354353
continue
355354
fullname = sym.node.fullname()
356355
if fullname not in ARG_KINDS_BY_CONSTRUCTOR:
357-
self.fail("Not an argument constructor: {}".format(fullname), constructor)
356+
self.fail("Unknown argument constructor {}".format(constructor), a)
358357
res.append(nodes.ARG_POS)
359358
else:
360359
res.append(ARG_KINDS_BY_CONSTRUCTOR[fullname])
@@ -375,6 +374,19 @@ def analyze_callable_type(self, t: UnboundType) -> Type:
375374
if isinstance(t.args[0], ArgumentList):
376375
# Callable[[ARG, ...], RET] (ordinary callable type)
377376
kinds = self.argument_list_to_kinds(t.args[0])
377+
names = t.args[0].names
378+
seen_names = set() # type: Set[str]
379+
for name, kind, const in zip(names, kinds, t.args[0].constructors):
380+
if name is not None:
381+
if kind in {nodes.ARG_STAR, nodes.ARG_STAR2}:
382+
self.fail(
383+
"{} should not have a specified name".format(const),
384+
t.args[0])
385+
if name in seen_names:
386+
self.fail(
387+
"duplicate argument '{}' in callable type".format(name),
388+
t.args[0])
389+
seen_names.add(name)
378390
args = t.args[0].types
379391
try:
380392
return CallableType(self.anal_array(args),

mypy/types.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,12 @@ class ArgumentList(Type):
241241

242242
types = None # type: List[Type]
243243
names = None # type: List[Optional[str]]
244-
constructors = None # type: List[UnboundArgumentConstructor]
244+
constructors = None # type: List[Optional[str]]
245245

246246
def __init__(self,
247247
types: List[Type],
248248
names: List[Optional[str]],
249-
constructors: List[UnboundArgumentConstructor],
249+
constructors: List[Optional[str]],
250250
line: int = -1,
251251
column: int = -1) -> None:
252252
super().__init__(line, column)
@@ -268,7 +268,7 @@ def deserialize(cls, data: JsonDict) -> 'ArgumentList':
268268
assert data['.class'] == 'ArgumentList' or data['.class'] == 'TypeList'
269269
types = [Type.deserialize(t) for t in data['items']]
270270
names = cast(List[Optional[str]], data.get('names', [None] * len(types)))
271-
constructors = [UnboundArgumentConstructor.deserialize(c) for c in data['constructors']]
271+
constructors = data['constructors']
272272
return ArgumentList(types=types, names=names, constructors=constructors)
273273

274274

@@ -625,7 +625,6 @@ def __init__(self,
625625
special_sig: Optional[str] = None,
626626
) -> None:
627627
self._process_kinds_on_init(arg_kinds)
628-
self._process_names_on_init(arg_names)
629628
if variables is None:
630629
variables = []
631630
assert len(arg_types) == len(arg_kinds)
@@ -644,15 +643,6 @@ def __init__(self,
644643
self.special_sig = special_sig
645644
super().__init__(line, column)
646645

647-
def _process_names_on_init(self, arg_names: Iterable[str]) -> None:
648-
seen = set() # type: Set[str]
649-
for name in arg_names:
650-
if name is None:
651-
continue
652-
if name in seen:
653-
raise ArgNameException('Duplicate argument name "{}"'.format(name))
654-
seen.add(name)
655-
656646
def _process_kinds_on_init(self, arg_kinds: Iterable[int]) -> None:
657647
self.is_var_arg = False
658648
self.is_kw_arg = False

0 commit comments

Comments
 (0)