From f11b9480192dea44acb92cb9edd7a91c7c73cd2f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 23 Feb 2018 15:25:42 +0100 Subject: [PATCH] allow implicit cast from `S` to `?&const S` 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. --- src/ir.cpp | 17 +++++++++-- test/cases/cast.zig | 71 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index b276abff3..e79235830 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8817,16 +8817,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { - if (types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, actual_type, source_node).id == ConstCastResultIdOk) { + TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; + if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) { return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else if (actual_type->id == TypeTableEntryIdNumLitInt || actual_type->id == TypeTableEntryIdNumLitFloat) { - if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type, true)) { + if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; } + } else if (wanted_child_type->id == TypeTableEntryIdPointer && + wanted_child_type->data.pointer.is_const && + is_container(actual_type)) { + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + if (type_is_invalid(cast2->value.type)) + return ira->codegen->invalid_instruction; + + return cast2; } } diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 6ffb55817..dabf97a79 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -32,6 +32,77 @@ fn funcWithConstPtrPtr(x: &const &i32) void { **x += 1; } +test "implicitly cast a container to a const pointer of it" { + const z = Struct(void) { .x = void{} }; + assert(0 == @sizeOf(@typeOf(z))); + assert(void{} == Struct(void).pointer(z).x); + assert(void{} == Struct(void).pointer(&z).x); + assert(void{} == Struct(void).maybePointer(z).x); + assert(void{} == Struct(void).maybePointer(&z).x); + assert(void{} == Struct(void).maybePointer(null).x); + const s = Struct(u8) { .x = 42 }; + assert(0 != @sizeOf(@typeOf(s))); + assert(42 == Struct(u8).pointer(s).x); + assert(42 == Struct(u8).pointer(&s).x); + assert(42 == Struct(u8).maybePointer(s).x); + assert(42 == Struct(u8).maybePointer(&s).x); + assert(0 == Struct(u8).maybePointer(null).x); + const u = Union { .x = 42 }; + assert(42 == Union.pointer(u).x); + assert(42 == Union.pointer(&u).x); + assert(42 == Union.maybePointer(u).x); + assert(42 == Union.maybePointer(&u).x); + assert(0 == Union.maybePointer(null).x); + const e = Enum.Some; + assert(Enum.Some == Enum.pointer(e)); + assert(Enum.Some == Enum.pointer(&e)); + assert(Enum.Some == Enum.maybePointer(e)); + assert(Enum.Some == Enum.maybePointer(&e)); + assert(Enum.None == Enum.maybePointer(null)); +} + +fn Struct(comptime T: type) type { + return struct { + const Self = this; + x: T, + + fn pointer(self: &const Self) Self { + return *self; + } + + fn maybePointer(self: ?&const Self) Self { + const none = Self { .x = if (T == void) void{} else 0 }; + return *(self ?? &none); + } + }; +} + +const Union = union { + x: u8, + + fn pointer(self: &const Union) Union { + return *self; + } + + fn maybePointer(self: ?&const Union) Union { + const none = Union { .x = 0 }; + return *(self ?? &none); + } +}; + +const Enum = enum { + None, + Some, + + fn pointer(self: &const Enum) Enum { + return *self; + } + + fn maybePointer(self: ?&const Enum) Enum { + return *(self ?? &Enum.None); + } +}; + test "explicit cast from integer to error type" { testCastIntToErr(error.ItBroke); comptime testCastIntToErr(error.ItBroke);