Skip to content

Commit 1eecfda

Browse files
authored
Merge pull request #785 from bnoordhuis/fix731
allow implicit cast from `S` to `?&const S`
2 parents 08d595b + f11b948 commit 1eecfda

File tree

2 files changed

+86
-2
lines changed

2 files changed

+86
-2
lines changed

src/ir.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8817,16 +8817,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
88178817

88188818
// explicit cast from child type of maybe type to maybe type
88198819
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) {
88218822
return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
88228823
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
88238824
actual_type->id == TypeTableEntryIdNumLitFloat)
88248825
{
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)) {
88268827
return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
88278828
} else {
88288829
return ira->codegen->invalid_instruction;
88298830
}
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;
88308843
}
88318844
}
88328845

test/cases/cast.zig

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,77 @@ fn funcWithConstPtrPtr(x: &const &i32) void {
3232
**x += 1;
3333
}
3434

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+
35106
test "explicit cast from integer to error type" {
36107
testCastIntToErr(error.ItBroke);
37108
comptime testCastIntToErr(error.ItBroke);

0 commit comments

Comments
 (0)