/
optional.py
122 lines (92 loc) · 4.09 KB
/
optional.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from __future__ import print_function, absolute_import, division
import operator
from numba import types, cgutils, typing
from .imputils import (lower_cast, lower_builtin, lower_getattr_generic,
impl_ret_untracked, lower_setattr_generic)
def always_return_true_impl(context, builder, sig, args):
return cgutils.true_bit
def always_return_false_impl(context, builder, sig, args):
return cgutils.false_bit
def optional_is_none(context, builder, sig, args):
"""
Check if an Optional value is invalid
"""
[lty, rty] = sig.args
[lval, rval] = args
# Make sure None is on the right
if lty == types.none:
lty, rty = rty, lty
lval, rval = rval, lval
opt_type = lty
opt_val = lval
opt = context.make_helper(builder, opt_type, opt_val)
res = builder.not_(cgutils.as_bool_bit(builder, opt.valid))
return impl_ret_untracked(context, builder, sig.return_type, res)
# None is/not None
lower_builtin(operator.is_, types.none, types.none)(always_return_true_impl)
# Optional is None
lower_builtin(operator.is_, types.Optional, types.none)(optional_is_none)
lower_builtin(operator.is_, types.none, types.Optional)(optional_is_none)
@lower_getattr_generic(types.Optional)
def optional_getattr(context, builder, typ, value, attr):
"""
Optional.__getattr__ => redirect to the wrapped type.
"""
inner_type = typ.type
val = context.cast(builder, value, typ, inner_type)
imp = context.get_getattr(inner_type, attr)
return imp(context, builder, inner_type, val, attr)
@lower_setattr_generic(types.Optional)
def optional_setattr(context, builder, sig, args, attr):
"""
Optional.__setattr__ => redirect to the wrapped type.
"""
basety, valty = sig.args
target, val = args
target_type = basety.type
target = context.cast(builder, target, basety, target_type)
newsig = typing.signature(sig.return_type, target_type, valty)
imp = context.get_setattr(attr, newsig)
return imp(builder, (target, val))
@lower_cast(types.Optional, types.Optional)
def optional_to_optional(context, builder, fromty, toty, val):
"""
The handling of optional->optional cast must be special cased for
correct propagation of None value. Given type T and U. casting of
T? to U? (? denotes optional) should always succeed. If the from-value
is None, the None value the casted value (U?) should be None; otherwise,
the from-value is casted to U. This is different from casting T? to U,
which requires the from-value must not be None.
"""
optval = context.make_helper(builder, fromty, value=val)
validbit = cgutils.as_bool_bit(builder, optval.valid)
# Create uninitialized optional value
outoptval = context.make_helper(builder, toty)
with builder.if_else(validbit) as (is_valid, is_not_valid):
with is_valid:
# Cast internal value
outoptval.valid = cgutils.true_bit
outoptval.data = context.cast(builder, optval.data,
fromty.type, toty.type)
with is_not_valid:
# Store None to result
outoptval.valid = cgutils.false_bit
outoptval.data = cgutils.get_null_value(
outoptval.data.type)
return outoptval._getvalue()
@lower_cast(types.Any, types.Optional)
def any_to_optional(context, builder, fromty, toty, val):
if fromty == types.none:
return context.make_optional_none(builder, toty.type)
else:
val = context.cast(builder, val, fromty, toty.type)
return context.make_optional_value(builder, toty.type, val)
@lower_cast(types.Optional, types.Any)
@lower_cast(types.Optional, types.Boolean)
def optional_to_any(context, builder, fromty, toty, val):
optval = context.make_helper(builder, fromty, value=val)
validbit = cgutils.as_bool_bit(builder, optval.valid)
with builder.if_then(builder.not_(validbit), likely=False):
msg = "expected %s, got None" % (fromty.type,)
context.call_conv.return_user_exc(builder, TypeError, (msg,))
return context.cast(builder, optval.data, fromty.type, toty)