Skip to content

Commit 8808ade

Browse files
authored
Merge pull request #1613 from google/google_sync
Google sync
2 parents d1c01f3 + 2707c42 commit 8808ade

16 files changed

Lines changed: 244 additions & 48 deletions

pytype/abstract/_interpreter_function.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,6 @@ def __init__(self, name, def_opcode, code, f_locals, f_globals, defaults,
186186
self.last_frame = None # for BuildClass
187187
self._store_call_records = False
188188
self.is_class_builder = False # Will be set by BuildClass.
189-
if name.endswith(".__init_subclass__"):
190-
# __init_subclass__ is automatically promoted to a classmethod
191-
self.is_classmethod = True
192189
# Whether to cache the return value irrespective of call args
193190
self.cache_return = False
194191

pytype/overlays/special_builtins.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,8 @@ def call(self, node, func, args, alias_map=None):
776776
arg = args.posargs[0]
777777
if not _check_method_decorator_arg(arg, "classmethod", self.ctx):
778778
return node, self.ctx.new_unsolvable(node)
779+
if any(isinstance(v, ClassMethodInstance) for v in arg.data):
780+
return node, arg
779781
for d in arg.data:
780782
d.is_classmethod = True
781783
d.is_attribute_of_class = True

pytype/rewrite/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ py_test(
116116
load_abstract_test.py
117117
DEPS
118118
pytype.rewrite.abstract.abstract
119+
pytype.rewrite.flow.flow
119120
pytype.rewrite.tests.test_utils
120121
)
121122

pytype/rewrite/abstract/CMakeLists.txt

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ py_library(
88
DEPS
99
.base
1010
.classes
11+
.containers
1112
.functions
12-
.instances
1313
.internal
1414
.utils
1515
)
@@ -63,43 +63,43 @@ py_test(
6363

6464
py_library(
6565
NAME
66-
functions
66+
containers
6767
SRCS
68-
functions.py
68+
containers.py
6969
DEPS
7070
.base
71-
pytype.blocks.blocks
72-
pytype.pytd.pytd
7371
)
7472

7573
py_test(
7674
NAME
77-
functions_test
75+
containers_test
7876
SRCS
79-
functions_test.py
77+
containers_test.py
8078
DEPS
81-
.classes
82-
.functions
79+
.base
80+
.containers
8381
pytype.rewrite.tests.test_utils
8482
)
8583

8684
py_library(
8785
NAME
88-
instances
86+
functions
8987
SRCS
90-
instances.py
88+
functions.py
9189
DEPS
9290
.base
91+
pytype.blocks.blocks
92+
pytype.pytd.pytd
9393
)
9494

9595
py_test(
9696
NAME
97-
instances_test
97+
functions_test
9898
SRCS
99-
instances_test.py
99+
functions_test.py
100100
DEPS
101-
.base
102-
.instances
101+
.classes
102+
.functions
103103
pytype.rewrite.tests.test_utils
104104
)
105105

pytype/rewrite/abstract/abstract.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from pytype.rewrite.abstract import base as _base
44
from pytype.rewrite.abstract import classes as _classes
5+
from pytype.rewrite.abstract import containers as _containers
56
from pytype.rewrite.abstract import functions as _functions
6-
from pytype.rewrite.abstract import instances as _instances
77
from pytype.rewrite.abstract import internal as _internal
88
from pytype.rewrite.abstract import utils as _utils
99

@@ -17,6 +17,7 @@
1717
BaseInstance = _classes.BaseInstance
1818
FrozenInstance = _classes.FrozenInstance
1919
InterpreterClass = _classes.InterpreterClass
20+
Module = _classes.Module
2021
MutableInstance = _classes.MutableInstance
2122

2223
Args = _functions.Args
@@ -30,12 +31,13 @@
3031
SimpleFunction = _functions.SimpleFunction
3132
SimpleReturn = _functions.SimpleReturn
3233

33-
Dict = _instances.Dict
34-
List = _instances.List
35-
Set = _instances.Set
36-
Tuple = _instances.Tuple
34+
Dict = _containers.Dict
35+
List = _containers.List
36+
Set = _containers.Set
37+
Tuple = _containers.Tuple
3738

3839
ConstKeyDict = _internal.ConstKeyDict
40+
FunctionArgTuple = _internal.FunctionArgTuple
3941
Splat = _internal.Splat
4042

4143
get_atomic_constant = _utils.get_atomic_constant

pytype/rewrite/abstract/classes.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ def get_attribute(self, name: str) -> Optional[base.BaseValue]:
8080

8181
def set_attribute(self, name: str, value: base.BaseValue) -> None:
8282
# SimpleClass is used to model imported classes, which we treat as frozen.
83-
log.info('Ignoring attribute set on %r: %s -> %r',
84-
self, name, value)
83+
log.info('Ignoring attribute set on %r: %s -> %r', self, name, value)
8584

8685
def instantiate(self) -> 'FrozenInstance':
8786
"""Creates an instance of this class."""
8887
if self._canonical_instance:
89-
log.info('Getting cached instance of class %s', self.full_name)
88+
if self.module not in ('builtins', 'typing'):
89+
log.info('Getting cached instance of class %s', self.full_name)
9090
return self._canonical_instance
9191
log.info('Instantiating class %s', self.full_name)
9292
for setup_method_name in self.setup_methods:
@@ -208,5 +208,30 @@ def _attrs(self):
208208
def set_attribute(self, name: str, value: base.BaseValue) -> None:
209209
# The VM may try to set an attribute on a frozen instance in the process of
210210
# analyzing a class's methods. This is fine; we just ignore it.
211-
log.info('Ignoring attribute set on %r: %s -> %r',
212-
self, name, value)
211+
log.info('Ignoring attribute set on %r: %s -> %r', self, name, value)
212+
213+
214+
class Module(BaseInstance):
215+
"""A module."""
216+
217+
def __init__(self, ctx: base.ContextType, name: str):
218+
cls = ctx.abstract_loader.load_builtin('module')
219+
super().__init__(ctx, cls, members={})
220+
self.name = name
221+
222+
def __repr__(self):
223+
return f'Module({self.name})'
224+
225+
@property
226+
def _attrs(self):
227+
return (self.name,)
228+
229+
def set_attribute(self, name: str, value: base.BaseValue) -> None:
230+
# We don't allow modifying imported modules.
231+
log.info('Ignoring attribute set on %r: %s -> %r', self, name, value)
232+
233+
def get_attribute(self, name: str) -> Optional[base.BaseValue]:
234+
try:
235+
return self._ctx.abstract_loader.load_value(self.name, name)
236+
except KeyError:
237+
return super().get_attribute(name)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Abstract representations of class instances."""
1+
"""Abstract representations of builtin containers."""
22

33
import logging
44

pytype/rewrite/abstract/instances_test.py renamed to pytype/rewrite/abstract/containers_test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Dict, List, Set, Tuple
22

33
from pytype.rewrite.abstract import base
4-
from pytype.rewrite.abstract import instances
4+
from pytype.rewrite.abstract import containers
55
from pytype.rewrite.tests import test_utils
66
from typing_extensions import assert_type
77

@@ -22,7 +22,7 @@ class ListTest(BaseTest):
2222

2323
def test_constant_type(self):
2424
a = self.const_var("a")
25-
c = instances.List(self.ctx, [a])
25+
c = containers.List(self.ctx, [a])
2626
assert_type(c.constant, List[_AbstractVariable])
2727

2828

@@ -31,15 +31,15 @@ class DictTest(BaseTest):
3131
def test_constant_type(self):
3232
a = self.const_var("a")
3333
b = self.const_var("b")
34-
c = instances.Dict(self.ctx, {a: b})
34+
c = containers.Dict(self.ctx, {a: b})
3535
assert_type(c.constant, Dict[_AbstractVariable, _AbstractVariable])
3636

3737

3838
class SetTest(BaseTest):
3939

4040
def test_constant_type(self):
4141
a = self.const_var("a")
42-
c = instances.Set(self.ctx, {a})
42+
c = containers.Set(self.ctx, {a})
4343
assert_type(c.constant, Set[_AbstractVariable])
4444

4545

@@ -48,7 +48,7 @@ class TupleTest(BaseTest):
4848
def test_constant_type(self):
4949
a = self.const_var("a")
5050
b = self.const_var("b")
51-
c = instances.Tuple(self.ctx, (a, b))
51+
c = containers.Tuple(self.ctx, (a, b))
5252
assert_type(c.constant, Tuple[_AbstractVariable, ...])
5353

5454

pytype/rewrite/abstract/internal.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Abstract types used internally by pytype."""
22

3-
from typing import Any, Dict, Sequence
3+
from typing import Dict, Sequence, Tuple
44

55
import immutabledict
66

@@ -17,7 +17,7 @@ class ConstKeyDict(base.BaseValue):
1717
Used by the python interpreter to construct function args.
1818
"""
1919

20-
def __init__(self, ctx: base.ContextType, constant: Dict[Any, _Variable]):
20+
def __init__(self, ctx: base.ContextType, constant: Dict[str, _Variable]):
2121
super().__init__(ctx)
2222
assert isinstance(constant, dict), constant
2323
self.constant = constant
@@ -30,6 +30,22 @@ def _attrs(self):
3030
return (immutabledict.immutabledict(self.constant),)
3131

3232

33+
class FunctionArgTuple(base.BaseValue):
34+
"""Representation of a function arg tuple."""
35+
36+
def __init__(self, ctx: base.ContextType, constant: Tuple[_Variable, ...]):
37+
super().__init__(ctx)
38+
assert isinstance(constant, tuple), constant
39+
self.constant = constant
40+
41+
def __repr__(self):
42+
return f"FunctionArgTuple({self.constant!r})"
43+
44+
@property
45+
def _attrs(self):
46+
return (self.constant,)
47+
48+
3349
class Splat(base.BaseValue):
3450
"""Representation of unpacked iterables.
3551

pytype/rewrite/frame.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def load_global(self, name) -> _AbstractVariable:
221221
return self.load_builtin(name)
222222

223223
def load_builtin(self, name) -> _AbstractVariable:
224-
builtin = self._ctx.abstract_loader.load_builtin_by_name(name)
224+
builtin = self._ctx.abstract_loader.load_builtin(name)
225225
return builtin.to_variable(name)
226226

227227
def load_deref(self, name) -> _AbstractVariable:
@@ -392,8 +392,15 @@ def byte_RESUME(self, opcode):
392392
# Load and store operations
393393

394394
def byte_LOAD_CONST(self, opcode):
395-
constant = self._ctx.consts[self._code.consts[opcode.arg]]
396-
self._stack.push(constant.to_variable())
395+
const = self._code.consts[opcode.arg]
396+
if isinstance(const, tuple):
397+
# Tuple literals with all primitive elements are stored as a single raw
398+
# constant; we need to wrap each element in a variable for consistency
399+
# with tuples created via BUILD_TUPLE
400+
val = self._ctx.abstract_loader.build_tuple(const)
401+
else:
402+
val = self._ctx.consts[const]
403+
self._stack.push(val.to_variable())
397404

398405
def byte_RETURN_VALUE(self, opcode):
399406
self._returns.append(self._stack.pop())
@@ -524,6 +531,12 @@ def byte_LOAD_METHOD(self, opcode):
524531
self._stack.push(self._ctx.consts.singles['NULL'].to_variable())
525532
self._stack.push(self._load_attr(instance_var, method_name))
526533

534+
def byte_IMPORT_NAME(self, opcode):
535+
full_name = opcode.argval
536+
unused_level_var, unused_fromlist = self._stack.popn(2)
537+
module = abstract.Module(self._ctx, full_name)
538+
return self._stack.push(module.to_variable())
539+
527540
# ---------------------------------------------------------------
528541
# Function and method calls
529542

@@ -558,6 +571,40 @@ def byte_CALL_FUNCTION(self, opcode):
558571
callargs = abstract.Args(posargs=tuple(args), frame=self)
559572
self._call_function(func, callargs)
560573

574+
def _unpack_starargs(self, starargs):
575+
# TODO(b/331853896): This follows vm_utils.ensure_unpacked_starargs, but
576+
# does not yet handle indefinite iterables.
577+
posargs = starargs.get_atomic_value()
578+
if isinstance(posargs, abstract.FunctionArgTuple):
579+
# This has already been converted
580+
pass
581+
elif isinstance(posargs, abstract.Tuple):
582+
posargs = abstract.FunctionArgTuple(self._ctx, posargs.constant)
583+
elif isinstance(posargs, tuple):
584+
posargs = abstract.FunctionArgTuple(self._ctx, posargs)
585+
else:
586+
assert False, f'unexpected posargs type: {posargs}: {type(posargs)}'
587+
return posargs
588+
589+
def _unpack_starstarargs(self, starstarargs):
590+
kwargs = abstract.get_atomic_constant(starstarargs, dict)
591+
return {abstract.get_atomic_constant(k, str): v
592+
for k, v in kwargs.items()}
593+
594+
def byte_CALL_FUNCTION_EX(self, opcode):
595+
if opcode.arg & _Flags.CALL_FUNCTION_EX_HAS_KWARGS:
596+
starstarargs = self._stack.pop()
597+
kwargs = self._unpack_starstarargs(starstarargs)
598+
else:
599+
kwargs = _EMPTY_MAP
600+
starargs = self._stack.pop()
601+
posargs = self._unpack_starargs(starargs).constant
602+
func = self._stack.pop()
603+
if self._code.python_version >= (3, 11):
604+
self._stack.pop_and_discard()
605+
callargs = abstract.Args(posargs=posargs, kwargs=kwargs, frame=self)
606+
self._call_function(func, callargs)
607+
561608
def byte_CALL_METHOD(self, opcode):
562609
args = self._stack.popn(opcode.arg)
563610
func = self._stack.pop()
@@ -615,6 +662,8 @@ def byte_BUILD_CONST_KEY_MAP(self, opcode):
615662
# to abstract objects because they are used internally to construct function
616663
# call args.
617664
keys = abstract.get_atomic_constant(keys, tuple)
665+
# Unpack the keys into raw strings.
666+
keys = [abstract.get_atomic_constant(k, str) for k in keys]
618667
assert len(keys) == n_elts
619668
vals = self._stack.popn(n_elts)
620669
ret = dict(zip(keys, vals))

0 commit comments

Comments
 (0)