Skip to content

[mypyc] Add more comments about overlapping error values #18963

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 1 commit into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 8 additions & 3 deletions mypyc/ir/class_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,12 @@ def __init__(
self.attrs_with_defaults: set[str] = set()

# Attributes that are always initialized in __init__ or class body
# (inferred in mypyc.analysis.attrdefined using interprocedural analysis)
# (inferred in mypyc.analysis.attrdefined using interprocedural analysis).
# These can never raise AttributeError when accessed. If an attribute
# is *not* always initialized, we normally use the error value for
# an undefined value. If the attribute byte has an overlapping error value
# (the error_overlap attribute is true for the RType), we use a bitmap
# to track if the attribute is defined instead (see bitmap_attrs).
self._always_initialized_attrs: set[str] = set()

# Attributes that are sometimes initialized in __init__
Expand All @@ -191,8 +196,8 @@ def __init__(

# Definedness of these attributes is backed by a bitmap. Index in the list
# indicates the bit number. Includes inherited attributes. We need the
# bitmap for types such as native ints that can't have a dedicated error
# value that doesn't overlap a valid value. The bitmap is used if the
# bitmap for types such as native ints (i64 etc.) that can't have a dedicated
# error value that doesn't overlap a valid value. The bitmap is used if the
# value of an attribute is the same as the error value.
self.bitmap_attrs: list[str] = []

Expand Down
17 changes: 15 additions & 2 deletions mypyc/ir/rtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,21 @@ class RType:
# to checking for error value as the return value of a function.
#
# For example, no i64 value can be reserved for error value, so we
# pick an arbitrary value (e.g. -113) to signal error, but this is
# also a valid non-error value.
# pick an arbitrary value (-113) to signal error, but this is
# also a valid non-error value. The chosen value is rare as a
# normal, non-error value, so most of the time we can avoid calling
# PyErr_Occurred() when checking for errors raised by called
# functions.
#
# This also means that if an attribute with this type might be
# undefined, we can't just rely on the error value to signal this.
# Instead, we add a bitfield to keep track whether attributes with
# "error overlap" have a value. If there is no value, AttributeError
# is raised on attribute read. Parameters with default values also
# use the bitfield trick to indicate whether the caller passed a
# value. (If we can determine that an attribute is "always defined",
# we never raise an AttributeError and don't need the bitfield
# entry.)
error_overlap = False

@abstractmethod
Expand Down
13 changes: 13 additions & 0 deletions mypyc/test-data/run-async.test
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,19 @@ def run(x: object) -> object: ...
async def sleep(t: float) -> None: ...

[case testRunAsyncMiscTypesInEnvironment]
# Here we test that values of various kinds of types can be spilled to the
# environment. In particular, types with "overlapping error values" such as
# i64 can be tricky, since they require extra work to support undefined
# attribute values (which raise AttributeError when accessed). For these,
# the object struct has a bitfield which keeps track of whether certain
# attributes have an assigned value.
#
# In practice we mark these attributes as "always defined", which causes these
# checks to be skipped on attribute access, and thus we don't require the
# bitfield to exist.
#
# See the comment of RType.error_overlap for more information.

import asyncio

from mypy_extensions import i64, i32, i16, u8
Expand Down