From 434f017aeefc392bcf524732940e2f2b908222f3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 10 Mar 2017 11:21:41 -0500 Subject: [PATCH] codegen nullable void the same way as bool See #104 --- src/analyze.cpp | 14 +++++++++++--- src/codegen.cpp | 41 +++++++++++++++++++++++++++++------------ test/cases/null.zig | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b1753af264..870f06dfe8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -397,7 +397,10 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { buf_resize(&entry->name, 0); buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); - if (child_type->id == TypeTableEntryIdPointer || + if (child_type->zero_bits) { + entry->type_ref = LLVMInt1Type(); + entry->di_type = g->builtin_types.entry_bool->di_type; + } else if (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn) { // this is an optimization but also is necessary for calling C @@ -2958,7 +2961,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { assert(type_entry->data.enumeration.complete); return type_entry->data.enumeration.gen_field_count != 0; case TypeTableEntryIdMaybe: - return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && + return !type_entry->data.maybe.child_type->zero_bits && + type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && type_entry->data.maybe.child_type->id != TypeTableEntryIdFn; case TypeTableEntryIdTypeDecl: return handle_is_ptr(type_entry->data.type_decl.canonical_type); @@ -3632,7 +3636,11 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { case TypeTableEntryIdNullLit: zig_panic("TODO"); case TypeTableEntryIdMaybe: - zig_panic("TODO"); + if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) { + return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr); + } else { + return const_values_equal(a->data.x_maybe, b->data.x_maybe); + } case TypeTableEntryIdErrorUnion: zig_panic("TODO"); case TypeTableEntryIdTypeDecl: diff --git a/src/codegen.cpp b/src/codegen.cpp index cefcf8df6f..28dd4f2198 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1755,12 +1755,16 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) { assert(maybe_type->id == TypeTableEntryIdMaybe); TypeTableEntry *child_type = maybe_type->data.maybe.child_type; - bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn); - if (maybe_is_ptr) { - return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); + if (child_type->zero_bits) { + return maybe_handle; } else { - LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); - return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); + bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn); + if (maybe_is_ptr) { + return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), ""); + } else { + LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, ""); + return LLVMBuildLoad(g->builder, maybe_field_ptr, ""); + } } } @@ -1779,7 +1783,6 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == TypeTableEntryIdMaybe); TypeTableEntry *child_type = maybe_type->data.maybe.child_type; - bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn); LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, is_volatile); if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) { @@ -1793,11 +1796,16 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, LLVMPositionBuilderAtEnd(g->builder, ok_block); } - if (maybe_is_ptr) { - return maybe_ptr; + if (child_type->zero_bits) { + return nullptr; } else { - LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, is_volatile); - return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, ""); + bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn); + if (maybe_is_ptr) { + return maybe_ptr; + } else { + LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, is_volatile); + return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, ""); + } } } @@ -2319,6 +2327,10 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I TypeTableEntry *child_type = wanted_type->data.maybe.child_type; + if (child_type->zero_bits) { + return LLVMConstInt(LLVMInt1Type(), 1, false); + } + LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); if (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn) @@ -2806,7 +2818,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { case TypeTableEntryIdMaybe: { TypeTableEntry *child_type = canon_type->data.maybe.child_type; - if (child_type->id == TypeTableEntryIdPointer || + if (child_type->zero_bits) { + return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false); + } else if (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn) { if (const_val->data.x_maybe) { @@ -4322,7 +4336,10 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { case TypeTableEntryIdMaybe: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; - if (child_type->id == TypeTableEntryIdPointer || + if (child_type->zero_bits) { + buf_init_from_str(out_buf, "bool"); + return; + } else if (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn) { return get_c_type(g, child_type, out_buf); diff --git a/test/cases/null.zig b/test/cases/null.zig index 5359f0309f..d2f65e1ae2 100644 --- a/test/cases/null.zig +++ b/test/cases/null.zig @@ -51,11 +51,21 @@ fn rhsMaybeUnwrapReturn() { fn maybeReturn() { @setFnTest(this); + maybeReturnImpl(); + comptime maybeReturnImpl(); +} + +fn maybeReturnImpl() { assert(??foo(1235)); assert(if (const _ ?= foo(null)) false else true); assert(!??foo(1234)); } +fn foo(x: ?i32) -> ?bool { + const value = ?return x; + return value > 1234; +} + fn ifVarMaybePointer() { @setFnTest(this); @@ -97,12 +107,6 @@ const here_is_a_null_literal = SillyStruct { }; -// TODO test static eval maybe return -fn foo(x: ?i32) -> ?bool { - const value = ?return x; - return value > 1234; -} - fn testNullRuntime() { @setFnTest(this); @@ -112,3 +116,23 @@ fn testTestNullRuntime(x: ?i32) { assert(x == null); assert(!(x != null)); } + +fn nullableVoid() { + @setFnTest(this); + + nullableVoidImpl(); + comptime nullableVoidImpl(); +} + +fn nullableVoidImpl() { + assert(bar(null) == null); + assert(bar({}) != null); +} + +fn bar(x: ?void) -> ?void { + if (const _ ?= x) { + return {}; + } else { + return null; + } +}