Skip to content
← Back

src/ir/values/cast.ghul

1
namespace IR.Values is
2
use Semantic.Types.Type
3
4
// A cast the program wrote is checked: to a non-optional reference type
5
// it emits `castclass`, so a value that is not one faults here rather
6
// than becoming a null in a slot whose type says it is never absent.
7
// `cast T?(v)` is the spelling for a cast that is allowed to fail, and
8
// keeps `isinst`.
9
//
10
// A coercion the compiler synthesises is unchecked, because declining is
11
// the answer it wants: a refutable type test, a narrowing, and the
12
// equality bridge that has to report a different type as unequal rather
13
// than throw out of `Equals`.
14
//
15
// A value-type target keeps `isinst` whichever it is, since the unbox
16
// that follows is conditional on the result being absent. So does a type
17
// variable, which can be instantiated at a value type.
18
class CAST: Value is
19
type: Type
20
value: Value
21
is_checked: bool
22
23
// Whether the emitted cast faults rather than declining. Read by
24
// `gen` to choose the instruction, and separately testable: a
25
// fixture can settle the decision without an emitter able to
26
// resolve a token for the target.
27
faults_on_failure: bool =>
28
is_checked /\
29
!type.is_optional /\
30
!type.is_value_type /\
31
!type.is_type_variable
32
33
init(
34
type: Type,
35
value: Value,
36
is_checked: bool
37
) is
38
super.init()
39
40
self.type = type
41
self.value = value
42
self.is_checked = is_checked
43
si
44
45
gen(context: IR.CONTEXT) is
46
TYPE_TEST_OPERAND.gen(value, context)
47
48
let body = context.current_srm_body_emitter!
49
if faults_on_failure then
50
body.cast_class(context.resolve_type_token(type))
51
else
52
body.is_instance(context.resolve_type_token(type))
53
fi
54
si
55
56
to_string() -> string =>
57
"cast:[{type}]{if is_checked then "!" else "?" fi}({value})"
58
si
59
si