| author | |
| committer | |
| log | f11b9480192dea44acb92cb9edd7a91c7c73cd2f |
| tree | 5172a83b0a23842d661d4e2d8bf74587e902913d |
| parent | b66547e98c9034e52c5647735b47dc24939c8d15 |
Allow implicit casts from container types to nullable const pointers to
said container type. That is:
fn f() void {
const s = S {};
g(s); // Works.
g(&s); // So does this.
}
fn g(_: ?&const S) void { // Nullable const pointer.
}
Fixes #731.2 files changed, 86 insertions(+), 2 deletions(-)
src/ir.cpp+15-2| ... | @@ -8817,16 +8817,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8817,16 +8817,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8817 | 8817 | ||
| 8818 | // explicit cast from child type of maybe type to maybe type | 8818 | // explicit cast from child type of maybe type to maybe type |
| 8819 | if (wanted_type->id == TypeTableEntryIdMaybe) { | 8819 | if (wanted_type->id == TypeTableEntryIdMaybe) { |
| 8820 | if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) { | 8820 | TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; |
| 8821 | if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) { | ||
| 8821 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | 8822 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); |
| 8822 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || | 8823 | } else if (actual_type->id == TypeTableEntryIdNumLitInt || |
| 8823 | actual_type->id == TypeTableEntryIdNumLitFloat) | 8824 | actual_type->id == TypeTableEntryIdNumLitFloat) |
| 8824 | { | 8825 | { |
| 8825 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) { | 8826 | if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { |
| 8826 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); | 8827 | return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); |
| 8827 | } else { | 8828 | } else { |
| 8828 | return ira->codegen->invalid_instruction; | 8829 | return ira->codegen->invalid_instruction; |
| 8829 | } | 8830 | } |
| 8831 | } else if (wanted_child_type->id == TypeTableEntryIdPointer && | ||
| 8832 | wanted_child_type->data.pointer.is_const && | ||
| 8833 | is_container(actual_type)) { | ||
| 8834 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value); | ||
| 8835 | if (type_is_invalid(cast1->value.type)) | ||
| 8836 | return ira->codegen->invalid_instruction; | ||
| 8837 | |||
| 8838 | IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 8839 | if (type_is_invalid(cast2->value.type)) | ||
| 8840 | return ira->codegen->invalid_instruction; | ||
| 8841 | |||
| 8842 | return cast2; | ||
| 8830 | } | 8843 | } |
| 8831 | } | 8844 | } |
| 8832 | 8845 |
test/cases/cast.zig+71| ... | @@ -32,6 +32,77 @@ fn funcWithConstPtrPtr(x: &const &i32) void { | ... | @@ -32,6 +32,77 @@ fn funcWithConstPtrPtr(x: &const &i32) void { |
| 32 | **x += 1; | 32 | **x += 1; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | test "implicitly cast a container to a const pointer of it" { | ||
| 36 | const z = Struct(void) { .x = void{} }; | ||
| 37 | assert(0 == @sizeOf(@typeOf(z))); | ||
| 38 | assert(void{} == Struct(void).pointer(z).x); | ||
| 39 | assert(void{} == Struct(void).pointer(&z).x); | ||
| 40 | assert(void{} == Struct(void).maybePointer(z).x); | ||
| 41 | assert(void{} == Struct(void).maybePointer(&z).x); | ||
| 42 | assert(void{} == Struct(void).maybePointer(null).x); | ||
| 43 | const s = Struct(u8) { .x = 42 }; | ||
| 44 | assert(0 != @sizeOf(@typeOf(s))); | ||
| 45 | assert(42 == Struct(u8).pointer(s).x); | ||
| 46 | assert(42 == Struct(u8).pointer(&s).x); | ||
| 47 | assert(42 == Struct(u8).maybePointer(s).x); | ||
| 48 | assert(42 == Struct(u8).maybePointer(&s).x); | ||
| 49 | assert(0 == Struct(u8).maybePointer(null).x); | ||
| 50 | const u = Union { .x = 42 }; | ||
| 51 | assert(42 == Union.pointer(u).x); | ||
| 52 | assert(42 == Union.pointer(&u).x); | ||
| 53 | assert(42 == Union.maybePointer(u).x); | ||
| 54 | assert(42 == Union.maybePointer(&u).x); | ||
| 55 | assert(0 == Union.maybePointer(null).x); | ||
| 56 | const e = Enum.Some; | ||
| 57 | assert(Enum.Some == Enum.pointer(e)); | ||
| 58 | assert(Enum.Some == Enum.pointer(&e)); | ||
| 59 | assert(Enum.Some == Enum.maybePointer(e)); | ||
| 60 | assert(Enum.Some == Enum.maybePointer(&e)); | ||
| 61 | assert(Enum.None == Enum.maybePointer(null)); | ||
| 62 | } | ||
| 63 | |||
| 64 | fn Struct(comptime T: type) type { | ||
| 65 | return struct { | ||
| 66 | const Self = this; | ||
| 67 | x: T, | ||
| 68 | |||
| 69 | fn pointer(self: &const Self) Self { | ||
| 70 | return *self; | ||
| 71 | } | ||
| 72 | |||
| 73 | fn maybePointer(self: ?&const Self) Self { | ||
| 74 | const none = Self { .x = if (T == void) void{} else 0 }; | ||
| 75 | return *(self ?? &none); | ||
| 76 | } | ||
| 77 | }; | ||
| 78 | } | ||
| 79 | |||
| 80 | const Union = union { | ||
| 81 | x: u8, | ||
| 82 | |||
| 83 | fn pointer(self: &const Union) Union { | ||
| 84 | return *self; | ||
| 85 | } | ||
| 86 | |||
| 87 | fn maybePointer(self: ?&const Union) Union { | ||
| 88 | const none = Union { .x = 0 }; | ||
| 89 | return *(self ?? &none); | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | |||
| 93 | const Enum = enum { | ||
| 94 | None, | ||
| 95 | Some, | ||
| 96 | |||
| 97 | fn pointer(self: &const Enum) Enum { | ||
| 98 | return *self; | ||
| 99 | } | ||
| 100 | |||
| 101 | fn maybePointer(self: ?&const Enum) Enum { | ||
| 102 | return *(self ?? &Enum.None); | ||
| 103 | } | ||
| 104 | }; | ||
| 105 | |||
| 35 | test "explicit cast from integer to error type" { | 106 | test "explicit cast from integer to error type" { |
| 36 | testCastIntToErr(error.ItBroke); | 107 | testCastIntToErr(error.ItBroke); |
| 37 | comptime testCastIntToErr(error.ItBroke); | 108 | comptime testCastIntToErr(error.ItBroke); |