File tree Expand file tree Collapse file tree 3 files changed +36
-5
lines changed Expand file tree Collapse file tree 3 files changed +36
-5
lines changed Original file line number Diff line number Diff line change @@ -180,7 +180,12 @@ def __init__(
180180 self .attrs_with_defaults : set [str ] = set ()
181181
182182 # Attributes that are always initialized in __init__ or class body
183- # (inferred in mypyc.analysis.attrdefined using interprocedural analysis)
183+ # (inferred in mypyc.analysis.attrdefined using interprocedural analysis).
184+ # These can never raise AttributeError when accessed. If an attribute
185+ # is *not* always initialized, we normally use the error value for
186+ # an undefined value. If the attribute byte has an overlapping error value
187+ # (the error_overlap attribute is true for the RType), we use a bitmap
188+ # to track if the attribute is defined instead (see bitmap_attrs).
184189 self ._always_initialized_attrs : set [str ] = set ()
185190
186191 # Attributes that are sometimes initialized in __init__
@@ -191,8 +196,8 @@ def __init__(
191196
192197 # Definedness of these attributes is backed by a bitmap. Index in the list
193198 # indicates the bit number. Includes inherited attributes. We need the
194- # bitmap for types such as native ints that can't have a dedicated error
195- # value that doesn't overlap a valid value. The bitmap is used if the
199+ # bitmap for types such as native ints (i64 etc.) that can't have a dedicated
200+ # error value that doesn't overlap a valid value. The bitmap is used if the
196201 # value of an attribute is the same as the error value.
197202 self .bitmap_attrs : list [str ] = []
198203
Original file line number Diff line number Diff line change @@ -58,8 +58,21 @@ class RType:
5858 # to checking for error value as the return value of a function.
5959 #
6060 # For example, no i64 value can be reserved for error value, so we
61- # pick an arbitrary value (e.g. -113) to signal error, but this is
62- # also a valid non-error value.
61+ # pick an arbitrary value (-113) to signal error, but this is
62+ # also a valid non-error value. The chosen value is rare as a
63+ # normal, non-error value, so most of the time we can avoid calling
64+ # PyErr_Occurred() when checking for errors raised by called
65+ # functions.
66+ #
67+ # This also means that if an attribute with this type might be
68+ # undefined, we can't just rely on the error value to signal this.
69+ # Instead, we add a bitfield to keep track whether attributes with
70+ # "error overlap" have a value. If there is no value, AttributeError
71+ # is raised on attribute read. Parameters with default values also
72+ # use the bitfield trick to indicate whether the caller passed a
73+ # value. (If we can determine that an attribute is "always defined",
74+ # we never raise an AttributeError and don't need the bitfield
75+ # entry.)
6376 error_overlap = False
6477
6578 @abstractmethod
Original file line number Diff line number Diff line change @@ -457,6 +457,19 @@ def run(x: object) -> object: ...
457457async def sleep(t: float) -> None: ...
458458
459459[case testRunAsyncMiscTypesInEnvironment]
460+ # Here we test that values of various kinds of types can be spilled to the
461+ # environment. In particular, types with "overlapping error values" such as
462+ # i64 can be tricky, since they require extra work to support undefined
463+ # attribute values (which raise AttributeError when accessed). For these,
464+ # the object struct has a bitfield which keeps track of whether certain
465+ # attributes have an assigned value.
466+ #
467+ # In practice we mark these attributes as "always defined", which causes these
468+ # checks to be skipped on attribute access, and thus we don't require the
469+ # bitfield to exist.
470+ #
471+ # See the comment of RType.error_overlap for more information.
472+
460473import asyncio
461474
462475from mypy_extensions import i64, i32, i16, u8
You can’t perform that action at this time.
0 commit comments