File tree 3 files changed +36
-5
lines changed
3 files changed +36
-5
lines changed Original file line number Diff line number Diff line change @@ -180,7 +180,12 @@ def __init__(
180
180
self .attrs_with_defaults : set [str ] = set ()
181
181
182
182
# 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).
184
189
self ._always_initialized_attrs : set [str ] = set ()
185
190
186
191
# Attributes that are sometimes initialized in __init__
@@ -191,8 +196,8 @@ def __init__(
191
196
192
197
# Definedness of these attributes is backed by a bitmap. Index in the list
193
198
# 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
196
201
# value of an attribute is the same as the error value.
197
202
self .bitmap_attrs : list [str ] = []
198
203
Original file line number Diff line number Diff line change @@ -58,8 +58,21 @@ class RType:
58
58
# to checking for error value as the return value of a function.
59
59
#
60
60
# 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.)
63
76
error_overlap = False
64
77
65
78
@abstractmethod
Original file line number Diff line number Diff line change @@ -457,6 +457,19 @@ def run(x: object) -> object: ...
457
457
async def sleep(t: float) -> None: ...
458
458
459
459
[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
+
460
473
import asyncio
461
474
462
475
from mypy_extensions import i64, i32, i16, u8
You can’t perform that action at this time.
0 commit comments