Skip to content

Commit d40f63c

Browse files
authored
[mypyc] Allow per-class free list to be used with inheritance (#19790)
It's still unsupported if interpreted subclasses are allowed.
1 parent 2ae0667 commit d40f63c

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

mypyc/codegen/emitclass.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,6 @@ def generate_class_reuse(
205205
TODO: Generalize to support a free list with up to N objects.
206206
"""
207207
assert cl.reuse_freed_instance
208-
209-
# The free list implementation doesn't support class hierarchies
210-
assert cl.is_final_class or cl.children == []
211-
212208
context = c_emitter.context
213209
name = cl.name_prefix(c_emitter.names) + "_free_instance"
214210
struct_name = cl.struct_name(c_emitter.names)

mypyc/irbuild/prepare.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ def prepare_class_def(
363363
line = attrs_lines["free_list_len"]
364364
if ir.is_trait:
365365
errors.error('"free_list_len" can\'t be used with traits', path, line)
366+
if ir.allow_interpreted_subclasses:
367+
errors.error(
368+
'"free_list_len" can\'t be used in a class that allows interpreted subclasses',
369+
path,
370+
line,
371+
)
366372
if free_list_len == 1:
367373
ir.reuse_freed_instance = True
368374
else:

mypyc/test-data/irbuild-classes.test

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,3 +1754,7 @@ class FreeListError:
17541754
@mypyc_attr(free_list_len=1) # E: "free_list_len" can't be used with traits
17551755
class NonNative:
17561756
pass
1757+
1758+
@mypyc_attr(free_list_len=1, allow_interpreted_subclasses=True) # E: "free_list_len" can't be used in a class that allows interpreted subclasses
1759+
class InterpSub:
1760+
pass

mypyc/test-data/run-classes.test

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3802,7 +3802,7 @@ from mypy_extensions import mypyc_attr
38023802

38033803
a = []
38043804

3805-
@mypyc_attr(free_list=1)
3805+
@mypyc_attr(free_list_len=1)
38063806
class Foo:
38073807
def __init__(self, x: int) -> None:
38083808
self.x = x
@@ -3830,3 +3830,64 @@ def test_alloc() -> None:
38303830
y = Foo(5)
38313831
assert x.x == 4
38323832
assert y.x == 5
3833+
3834+
@mypyc_attr(free_list_len=1)
3835+
class Base:
3836+
def __init__(self, x: str) -> None:
3837+
self.x = x
3838+
3839+
class Deriv(Base):
3840+
def __init__(self, x: str, y: str) -> None:
3841+
super().__init__(x)
3842+
self.y = y
3843+
3844+
@mypyc_attr(free_list_len=1)
3845+
class Deriv2(Base):
3846+
def __init__(self, x: str, y: str) -> None:
3847+
super().__init__(x)
3848+
self.y = y
3849+
3850+
def test_inheritance() -> None:
3851+
x: Base | None
3852+
y: Base | None
3853+
x = Base('x' + str())
3854+
y = Base('y' + str())
3855+
y = None
3856+
d = Deriv('a' + str(), 'b' + str())
3857+
assert type(d) is Deriv
3858+
assert d.x == 'a'
3859+
assert d.y == 'b'
3860+
assert x.x == 'x'
3861+
y = Base('z' + str())
3862+
assert d.x == 'a'
3863+
assert d.y == 'b'
3864+
assert y.x == 'z'
3865+
x = None
3866+
y = None
3867+
3868+
def test_inheritance_2() -> None:
3869+
x: Base | None
3870+
y: Base | None
3871+
d: Deriv2 | None
3872+
x = Base('x' + str())
3873+
y = Base('y' + str())
3874+
y = None
3875+
d = Deriv2('a' + str(), 'b' + str())
3876+
assert type(d) is Deriv2
3877+
assert d.x == 'a'
3878+
assert d.y == 'b'
3879+
assert x.x == 'x'
3880+
d = None
3881+
d = Deriv2('c' + str(), 'd' + str())
3882+
assert type(d) is Deriv2
3883+
assert d.x == 'c'
3884+
assert d.y == 'd'
3885+
assert x.x == 'x'
3886+
y = Base('z' + str())
3887+
assert type(y) is Base
3888+
assert d.x == 'c'
3889+
assert d.y == 'd'
3890+
assert y.x == 'z'
3891+
x = None
3892+
y = None
3893+
d = None

0 commit comments

Comments
 (0)