From 6a434b4535b6b2ae77744db741991df706dfd2c9 Mon Sep 17 00:00:00 2001 From: Jairo Velasco <1904410+jairov4@users.noreply.github.com> Date: Sun, 24 Nov 2024 03:59:10 -0500 Subject: [PATCH] Use feature flag in INCOMPLETE_FEATURES --- mypy/options.py | 3 ++- mypyc/build.py | 7 ++++++- mypyc/codegen/emit.py | 11 ++++++++++- mypyc/irbuild/prepare.py | 2 +- mypyc/options.py | 3 +++ mypyc/test/test_run.py | 3 ++- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mypy/options.py b/mypy/options.py index d315d297e023..ae702edecd59 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -75,7 +75,8 @@ class BuildType: PRECISE_TUPLE_TYPES: Final = "PreciseTupleTypes" NEW_GENERIC_SYNTAX: Final = "NewGenericSyntax" INLINE_TYPEDDICT: Final = "InlineTypedDict" -INCOMPLETE_FEATURES: Final = frozenset((PRECISE_TUPLE_TYPES, INLINE_TYPEDDICT)) +MYPYC_VALUE_TYPES: Final = "MypycValueTypes" +INCOMPLETE_FEATURES: Final = frozenset((PRECISE_TUPLE_TYPES, INLINE_TYPEDDICT, MYPYC_VALUE_TYPES)) COMPLETE_FEATURES: Final = frozenset((TYPE_VAR_TUPLE, UNPACK, NEW_GENERIC_SYNTAX)) diff --git a/mypyc/build.py b/mypyc/build.py index 6d59113ef872..9267c3d5877e 100644 --- a/mypyc/build.py +++ b/mypyc/build.py @@ -31,7 +31,7 @@ from mypy.errors import CompileError from mypy.fscache import FileSystemCache from mypy.main import process_options -from mypy.options import Options +from mypy.options import MYPYC_VALUE_TYPES, Options from mypy.util import write_junit_xml from mypyc.codegen import emitmodule from mypyc.common import RUNTIME_C_FILES, shared_lib_name @@ -418,6 +418,11 @@ def mypyc_build( paths, only_compile_paths, compiler_options, fscache ) + # Enable value types option via mypy options + compiler_options.experimental_value_types = ( + MYPYC_VALUE_TYPES in options.enable_incomplete_feature + ) + # We generate a shared lib if there are multiple modules or if any # of the modules are in package. (Because I didn't want to fuss # around with making the single module code handle packages.) diff --git a/mypyc/codegen/emit.py b/mypyc/codegen/emit.py index cbffecb5bcac..f04d7dd9129d 100644 --- a/mypyc/codegen/emit.py +++ b/mypyc/codegen/emit.py @@ -526,6 +526,9 @@ def emit_inc_ref(self, dest: str, rtype: RType, *, rare: bool = False) -> None: elif isinstance(rtype, RTuple): for i, item_type in enumerate(rtype.types): self.emit_inc_ref(f"{dest}.f{i}", item_type) + elif isinstance(rtype, RInstanceValue): + for i, (attr, attr_type) in enumerate(rtype.class_ir.all_attributes().items()): + self.emit_inc_ref(f"{dest}.{self.attr(attr)}", attr_type) elif not rtype.is_unboxed: # Always inline, since this is a simple op self.emit_line("CPy_INCREF(%s);" % dest) @@ -1089,7 +1092,7 @@ def emit_box( attr_name = self.attr(attr) self.emit_line(f"{temp_dest}->{attr_name} = {src}.{attr_name};", ann="box") if attr_type.is_refcounted: - self.emit_inc_ref(temp_dest, attr_type) + self.emit_inc_ref(f"{temp_dest}->{attr_name}", attr_type) self.emit_line(f"{declaration}{dest} = (PyObject *){temp_dest};") else: @@ -1131,6 +1134,9 @@ def emit_gc_visit(self, target: str, rtype: RType) -> None: elif isinstance(rtype, RTuple): for i, item_type in enumerate(rtype.types): self.emit_gc_visit(f"{target}.f{i}", item_type) + elif isinstance(rtype, RInstanceValue): + for i, (attr, attr_type) in enumerate(rtype.class_ir.all_attributes().items()): + self.emit_gc_visit(f"{target}.{self.attr(attr)}", attr_type) elif self.ctype(rtype) == "PyObject *": # The simplest case. self.emit_line(f"Py_VISIT({target});") @@ -1155,6 +1161,9 @@ def emit_gc_clear(self, target: str, rtype: RType) -> None: elif isinstance(rtype, RTuple): for i, item_type in enumerate(rtype.types): self.emit_gc_clear(f"{target}.f{i}", item_type) + elif isinstance(rtype, RInstanceValue): + for i, (attr, attr_type) in enumerate(rtype.class_ir.all_attributes().items()): + self.emit_gc_clear(f"{target}.{self.attr(attr)}", attr_type) elif self.ctype(rtype) == "PyObject *" and self.c_undefined_value(rtype) == "NULL": # The simplest case. self.emit_line(f"Py_CLEAR({target});") diff --git a/mypyc/irbuild/prepare.py b/mypyc/irbuild/prepare.py index 27f00848b695..a32a55fbd9b5 100644 --- a/mypyc/irbuild/prepare.py +++ b/mypyc/irbuild/prepare.py @@ -91,7 +91,7 @@ def build_type_map( is_abstract=cdef.info.is_abstract, is_final_class=cdef.info.is_final, is_ext_class=is_extension_class(cdef), - is_value_type=is_value_type(cdef), + is_value_type=is_value_type(cdef) and options.experimental_value_types, ) if class_ir.is_value_type: diff --git a/mypyc/options.py b/mypyc/options.py index 24e68163bb11..4db72abfb0a9 100644 --- a/mypyc/options.py +++ b/mypyc/options.py @@ -38,3 +38,6 @@ def __init__( # will assume the return type of the method strictly, which can lead to # more optimization opportunities. self.strict_dunders_typing = strict_dunder_typing + # Enable value types for the generated code. This option is experimental until + # the feature reference get removed from INCOMPLETE_FEATURES. + self.experimental_value_types = True # overridden by the mypy command line option diff --git a/mypyc/test/test_run.py b/mypyc/test/test_run.py index 99a43a7a841f..984c62c3a23d 100644 --- a/mypyc/test/test_run.py +++ b/mypyc/test/test_run.py @@ -15,7 +15,7 @@ from mypy import build from mypy.errors import CompileError -from mypy.options import Options +from mypy.options import MYPYC_VALUE_TYPES, Options from mypy.test.config import test_temp_dir from mypy.test.data import DataDrivenTestCase from mypy.test.helpers import assert_module_equivalence, perform_file_operations @@ -199,6 +199,7 @@ def run_case_step(self, testcase: DataDrivenTestCase, incremental_step: int) -> options.preserve_asts = True options.allow_empty_bodies = True options.incremental = self.separate + options.enable_incomplete_feature.append(MYPYC_VALUE_TYPES) # Avoid checking modules/packages named 'unchecked', to provide a way # to test interacting with code we don't have types for.