8000 [mypyc] Add a mypyc_attr to support interpreted children by msullivan · Pull Request #8004 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

[mypyc] Add a mypyc_attr to support interpreted children #8004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 28, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change attribute name
  • Loading branch information
msullivan committed Nov 27, 2019
commit 632af66f310843f0be5580251913a6df349b76dc
6 changes: 3 additions & 3 deletions mypyc/emitclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def emit_line() -> None:
emit_line()
generate_native_getters_and_setters(cl, emitter)

if cl.allow_interpreted_children:
if cl.allow_interpreted_subclasses:
shadow_vtable_name = generate_vtables(
cl, vtable_setup_name + "_shadow", vtable_name + "_shadow", emitter, shadow=True
) # type: Optional[str]
Expand Down Expand Up @@ -394,7 +394,7 @@ def trait_vtable_name(trait: ClassIR) -> str:
emitter.emit_line('{}{}(void)'.format(NATIVE_PREFIX, vtable_setup_name))
emitter.emit_line('{')

if base.allow_interpreted_children and not shadow:
if base.allow_interpreted_subclasses and not shadow:
emitter.emit_line('{}{}_shadow();'.format(NATIVE_PREFIX, vtable_setup_name))

subtables = []
Expand Down Expand Up @@ -557,7 +557,7 @@ def generate_new_for_class(cl: ClassIR,
'{}(PyTypeObject *type, PyObject *args, PyObject *kwds)'.format(func_name))
emitter.emit_line('{')
# TODO: Check and unbox arguments
if not cl.allow_interpreted_children:
if not cl.allow_interpreted_subclasses:
emitter.emit_line('if (type != {}) {{'.format(emitter.type_struct_name(cl)))
emitter.emit_line(
'PyErr_SetString(PyExc_TypeError, "interpreted classes cannot inherit from compiled");'
Expand Down
16 changes: 9 additions & 7 deletions mypyc/genops.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,8 @@ def prepare_class_def(path: str, module_name: str, cdef: ClassDef,
info = cdef.info

attrs = get_mypyc_attrs(cdef)
if attrs.get("allow_interpreted_children") is True:
ir.allow_interpreted_children = True
if attrs.get("allow_interpreted_subclasses") is True:
ir.allow_interpreted_subclasses = True

# We sort the table for determinism here on Python 3.5
for name, node in sorted(info.names.items()):
Expand Down Expand Up @@ -1235,7 +1235,7 @@ def handle_ext_method(self, cdef: ClassDef, fdef: FuncDef) -> None:
# methods that dispatch via the Python API. These will go in a
# "shadow vtable" that will be assigned to interpreted
# children.
if class_ir.allow_interpreted_children:
if class_ir.allow_interpreted_subclasses:
f = self.gen_glue(func_ir.sig, func_ir, class_ir, class_ir, fdef, do_py_ops=True)
class_ir.glue_methods[(class_ir, name)] = f
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if a class that allow interpreted children has a native subclass? Will these glue methods cause trouble?

I wonder if putting the python glue methods in a separate data structure would be clearer.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't cause trouble

self.functions.append(f)
Expand Down Expand Up @@ -1538,10 +1538,12 @@ def visit_class_def(self, cdef: ClassDef) -> None:
if any(ir.base_mro[i].base != ir. base_mro[i + 1] for i in range(len(ir.base_mro) - 1)):
self.error("Non-trait MRO must be linear", cdef.line)

if ir.allow_interpreted_children and any(
not parent.allow_interpreted_children for parent in ir.mro
):
self.error("Parents must allow interpreted children also", cdef.line)
if ir.allow_interpreted_subclasses:
for parent in ir.mro:
if not parent.allow_interpreted_subclasses:
self.error(
'Base class "{}" does not allow interpreted subclasses'.format(
parent.fullname), cdef.line)

# Currently, we only create non-extension classes for classes that are
# decorated or inherit from Enum. Classes decorated with @trait do not
Expand Down
8 changes: 4 additions & 4 deletions mypyc/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ def __init__(self, name: str, module_name: str, is_trait: bool = False,
self.inherits_python = False
self.has_dict = False
# Do we allow interpreted subclasses? Derived from a mypyc_attr.
self.allow_interpreted_children = False
self.allow_interpreted_subclasses = False
# If this a subclass of some built-in python class, the name
# of the object for that class. We currently only support this
# in a few ad-hoc cases.
Expand Down Expand Up @@ -1896,7 +1896,7 @@ def subclasses(self) -> Optional[Set['ClassIR']]:
Return None if it is impossible to identify all subclasses, for example
because we are performing separate compilation.
"""
if self.children is None or self.allow_interpreted_children:
if self.children is None or self.allow_interpreted_subclasses:
return None
result = set(self.children)
for child in self.children:
Expand Down Expand Up @@ -1932,7 +1932,7 @@ def serialize(self) -> JsonDict:
'is_augmented': self.is_augmented,
'inherits_python': self.inherits_python,
'has_dict': self.has_dict,
'allow_interpreted_children': self.allow_interpreted_children,
'allow_interpreted_subclasses': self.allow_interpreted_subclasses,
'builtin_base': self.builtin_base,
'ctor': self.ctor.serialize(),
# We serialize dicts as lists to ensure order is preserved
Expand Down Expand Up @@ -1982,7 +1982,7 @@ def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> 'ClassIR':
ir.is_augmented = data['is_augmented']
ir.inherits_python = data['inherits_python']
ir.has_dict = data['has_dict']
ir.allow_interpreted_children = data['allow_interpreted_children']
ir.allow_interpreted_subclasses = data['allow_interpreted_subclasses']
ir.builtin_base = data['builtin_base']
ir.ctor = FuncDecl.deserialize(data['ctor'], ctx)
ir.attributes = OrderedDict(
Expand Down
8 changes: 4 additions & 4 deletions mypyc/test-data/commandline.test
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ def f(l: List[object]) -> None:
if x is None:
x = i

@mypyc_attr(allow_interpreted_children=True)
class AllowInterp1(Concrete1): # E: Parents must allow interpreted children also
@mypyc_attr(allow_interpreted_subclasses=True)
class AllowInterp1(Concrete1): # E: Base class "test.Concrete1" does not allow interpreted subclasses
pass

@mypyc_attr(allow_interpreted_children=True)
class AllowInterp2(PureTrait): # E: Parents must allow interpreted children also
@mypyc_attr(allow_interpreted_subclasses=True)
class AllowInterp2(PureTrait): # E: Base class "test.PureTrait" does not allow interpreted subclasses
pass
6 changes: 3 additions & 3 deletions mypyc/test-data/run-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -1220,18 +1220,18 @@ test(D, -2)
[case testInterpretedInherit]
from mypy_extensions import mypyc_attr, trait

@mypyc_attr(allow_interpreted_children=True)
@mypyc_attr(allow_interpreted_subclasses=True)
class Top:
def spam(self) -> str:
return "grandparent"

@mypyc_attr(allow_interpreted_children=True)
@mypyc_attr(allow_interpreted_subclasses=True)
@trait
class Trait:
def trait_method(self) -> str:
return "trait"

@mypyc_attr(allow_interpreted_children=True)
@mypyc_attr(allow_interpreted_subclasses=True)
class Foo(Top, Trait):
def __init__(self, x: int) -> None:
self.x = 10
Expand Down
0