Skip to content
This repository was archived by the owner on May 11, 2022. It is now read-only.

Commit cbb481c

Browse files
pludemannmatthiaskramm
authored andcommitted
Improve __builtins__.pytd
Small improvements to solver test cases. Allow multiple matches for method call (with __any_object__). Remove some potential causes of non-determinism (still haven't found them all). Started finding missing/wrong stuff in pytree.pytd, but it's not finished.
1 parent 333d275 commit cbb481c

File tree

7 files changed

+254
-183
lines changed

7 files changed

+254
-183
lines changed

builtins/__builtin__.pytd

Lines changed: 203 additions & 157 deletions
Large diffs are not rendered by default.

parse/ast_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def add(x : int, y : int) -> int
305305
["int", "bool"])
306306

307307
def testComplexFunction(self):
308-
"""Test parsing of a function with unions, noneable etc."""
308+
"""Test parsing of a function with unions, none-able etc."""
309309

310310
canonical = textwrap.dedent("""
311311
def foo(a: int, b: int or float or None, c: Foo and `s.Bar` and Zot) -> int raises Bad

parse/builtins.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def _FindBuiltinFile(name):
3333
_cached_builtins = {}
3434

3535

36-
def GetBuiltins(stdlib=True):
36+
def GetBuiltins(stdlib=True, builtin_name="__builtin__"):
3737
"""Get the "default" AST used to lookup built in types.
3838
3939
Get an AST for all Python builtins as well as the most commonly used standard
@@ -43,6 +43,7 @@ def GetBuiltins(stdlib=True):
4343
stdlib: Whether to load the standard library, too. If this is False,
4444
TypeDeclUnit.modules will be empty. If it's True, it'll contain modules
4545
like itertools and signal.
46+
builtin_name: The base part of the builtins file name.
4647
4748
Returns:
4849
A pytd.TypeDeclUnit instance. It'll directly contain the builtin classes
@@ -57,7 +58,8 @@ def GetBuiltins(stdlib=True):
5758
# We use the same parser instance to parse all builtin files. This changes
5859
# the run time from 1.0423s to 0.5938s (for 21 builtins).
5960
p = parser.TypeDeclParser()
60-
builtins = p.Parse(_FindBuiltinFile("__builtin__.pytd"), name="__builtin__")
61+
builtins = p.Parse(
62+
_FindBuiltinFile(builtin_name + ".pytd"), name=builtin_name)
6163
# We list modules explicitly, because we might have to extract them out of
6264
# a PAR file, which doesn't have good support for listing directories.
6365
modules = ["array", "codecs", "errno", "fcntl", "gc", "itertools", "marshal",

parse/parser.py

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -718,28 +718,14 @@ def p_type_and(self, p):
718718
# "type1 and type2" would be useful for anything. We
719719
# should remove it.
720720
# This rule depends on precedence specification
721-
if (isinstance(p[1], pytd.IntersectionType) and
722-
isinstance(p[3], pytd.NamedType)):
723-
p[0] = pytd.IntersectionType(p[1].type_list + (p[3],))
724-
elif (isinstance(p[1], pytd.NamedType) and
725-
isinstance(p[3], pytd.IntersectionType)):
726-
# associative
727-
p[0] = pytd.IntersectionType(((p[1],) + p[3].type_list))
728-
else:
729-
p[0] = pytd.IntersectionType((p[1], p[3]))
721+
# IntersectionType flattens any contained IntersectinType's
722+
p[0] = pytd.IntersectionType((p[1], p[3]))
730723

731724
def p_type_or(self, p):
732725
"""type : type OR type"""
733726
# This rule depends on precedence specification
734-
if (isinstance(p[1], pytd.UnionType) and
735-
isinstance(p[3], pytd.NamedType)):
736-
p[0] = pytd.UnionType(p[1].type_list + (p[3],))
737-
elif (isinstance(p[1], pytd.NamedType) and
738-
isinstance(p[3], pytd.UnionType)):
739-
# associative
740-
p[0] = pytd.UnionType((p[1],) + p[3].type_list)
741-
else:
742-
p[0] = pytd.UnionType((p[1], p[3]))
727+
# UnionType flattens any contained UnionType's
728+
p[0] = pytd.UnionType((p[1], p[3]))
743729

744730
# This is parameterized type
745731
# TODO(raoulDoc): support data types in future?

parse/visitors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ def VisitNamedType(self, node):
346346
raise ValueError("Unreplaced NamedType: {!s} {!r}".format(node, node))
347347

348348
def VisitClassType(self, node):
349+
# TODO: Can we give more context for this error? It's not very
350+
# useful when it says that "T" is unresolved (e.g., from
351+
# "def foo(x: list<T>))" ... it would be nice to know what
352+
# it's inside.
349353
if node.cls is None:
350354
raise ValueError("Unresolved ClassType: {!s} {!r}".format(node, node))
351355

pytd.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"""AST representation of a pytd file."""
2121

2222

23+
import itertools
2324
import re
2425
from pytypedecl.parse import node
2526

@@ -292,10 +293,14 @@ class UnionType(node.Node('type_list')):
292293
__slots__ = ()
293294

294295
# NOTE: type_list is kept as a tuple, to preserve the original order
295-
# even though in most respects it acts like a frozenset
296+
# even though in most respects it acts like a frozenset.
297+
# It also flattens the input, such that printing without
298+
# parentheses gives the same result.
296299

297300
def __new__(cls, type_list):
298-
return super(UnionType, cls).__new__(cls, tuple(type_list))
301+
flattened = itertools.chain.from_iterable(
302+
t.type_list if isinstance(t, UnionType) else [t] for t in type_list)
303+
return super(UnionType, cls).__new__(cls, tuple(flattened))
299304

300305
def __hash__(self):
301306
# See __eq__ - order doesn't matter, so use frozenset
@@ -315,8 +320,35 @@ def __ne__(self, other):
315320

316321
# TODO: Do we still need this?
317322
class IntersectionType(node.Node('type_list')):
323+
"""An intersection type that contains all types in self.type_list."""
318324
__slots__ = ()
319325

326+
# NOTE: type_list is kept as a tuple, to preserve the original order
327+
# even though in most respects it acts like a frozenset.
328+
# It also flattens the input, such that printing without
329+
# parentheses gives the same result.
330+
331+
def __new__(cls, type_list):
332+
flattened = itertools.chain.from_iterable(
333+
t.type_list if isinstance(t, IntersectionType) else [t]
334+
for t in type_list)
335+
return super(IntersectionType, cls).__new__(cls, tuple(flattened))
336+
337+
def __hash__(self):
338+
# See __eq__ - order doesn't matter, so use frozenset
339+
return hash(frozenset(self.type_list))
340+
341+
def __eq__(self, other):
342+
if self is other:
343+
return True
344+
if isinstance(other, IntersectionType):
345+
# equality doesn't care about the ordering of the type_list
346+
return frozenset(self.type_list) == frozenset(other.type_list)
347+
return NotImplemented
348+
349+
def __ne__(self, other):
350+
return not self == other
351+
320352

321353
class GenericType(node.Node('base_type', 'parameters')):
322354
"""Generic type. Takes a base type and type paramters.

type_match.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ def match_type_against_type(self, t1, t2, subst):
279279
raise AssertionError("Don't know how to match %s against %s" % (
280280
type(t1), type(t2)))
281281

282-
def match_signature_again_signature(self, sig1, sig2, subst, skip_self):
282+
def match_signature_against_signature(self, sig1, sig2, subst, skip_self):
283283
"""Match a pytd.Signature against another pytd.Signature.
284284
285285
Args:
@@ -318,8 +318,9 @@ def match_signature_against_function(self, sig, f, subst, skip_self=False):
318318
# TODO: We should abort after the first matching signature, to get
319319
# more precise types in the presence of overloading.
320320
return booleq.And(
321-
booleq.Or(self.match_signature_again_signature(sig, s, subst, skip_self)
322-
for s in f.signatures)
321+
booleq.Or(
322+
self.match_signature_against_signature(sig, s, subst, skip_self)
323+
for s in f.signatures)
323324
for inner_sig in sig.Visit(optimize.ExpandSignatures()))
324325

325326
def match_function_against_function(self, f1, f2, subst, skip_self=False):

0 commit comments

Comments
 (0)