Appearance
| 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 |