From b883bc873df7f1a8fa3a13800402e1ec8da74328 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 12 Dec 2018 20:19:46 -0500 Subject: breaking API changes to all readInt/writeInt functions & more * add `@bswap` builtin function. See #767 * comptime evaluation facilities are improved to be able to handle a `@ptrCast` with a backing array. * `@truncate` allows "truncating" a u0 value to any integer type, and the result is always comptime known to be `0`. * when specifying pointer alignment in a type expression, the alignment value of pointers which do not have addresses at runtime is ignored, and always has the default/ABI alignment * threw in a fix to freebsd/x86_64.zig to update syntax from language changes * some improvements are pending #863 closes #638 closes #1733 std lib API changes * io.InStream().readIntNe renamed to readIntNative * io.InStream().readIntLe renamed to readIntLittle * io.InStream().readIntBe renamed to readIntBig * introduced io.InStream().readIntForeign * io.InStream().readInt has parameter order changed * io.InStream().readVarInt has parameter order changed * io.InStream().writeIntNe renamed to writeIntNative * introduced io.InStream().writeIntForeign * io.InStream().writeIntLe renamed to writeIntLittle * io.InStream().writeIntBe renamed to writeIntBig * io.InStream().writeInt has parameter order changed * mem.readInt has different parameters and semantics * introduced mem.readIntNative * introduced mem.readIntForeign * mem.readIntBE renamed to mem.readIntBig and different API * mem.readIntLE renamed to mem.readIntLittle and different API * introduced mem.readIntSliceNative * introduced mem.readIntSliceForeign * introduced mem.readIntSliceLittle * introduced mem.readIntSliceBig * introduced mem.readIntSlice * mem.writeInt has different parameters and semantics * introduced mem.writeIntNative * introduced mem.writeIntForeign * mem.writeIntBE renamed to mem.readIntBig and different semantics * mem.writeIntLE renamed to mem.readIntLittle and different semantics * introduced mem.writeIntSliceForeign * introduced mem.writeIntSliceNative * introduced mem.writeIntSliceBig * introduced mem.writeIntSliceLittle * introduced mem.writeIntSlice * removed mem.endianSwapIfLe * removed mem.endianSwapIfBe * removed mem.endianSwapIf * added mem.littleToNative * added mem.bigToNative * added mem.toNative * added mem.nativeTo * added mem.nativeToLittle * added mem.nativeToBig --- src/ir.cpp | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 146 insertions(+), 10 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 68a0b7f6f6..dc87f040bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -856,6 +856,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { return IrInstructionIdSqrt; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { + return IrInstructionIdBswap; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2705,6 +2709,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc return &instruction->base; } +static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBswap *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -4689,6 +4704,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBswap: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -13674,18 +13704,55 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, return ErrorNone; } - if (dst_size > src_size) { - ir_add_error_node(ira, source_node, - buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", - dst_size, buf_ptr(&pointee->type->name), src_size)); - return ErrorSemanticAnalyzeFail; + if (dst_size <= src_size) { + Buf buf = BUF_INIT; + buf_resize(&buf, src_size); + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; } - Buf buf = BUF_INIT; - buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); - return ErrorNone; + switch (ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", + dst_size, buf_ptr(&pointee->type->name), src_size)); + return ErrorSemanticAnalyzeFail; + } + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + size_t elem_size = src_size; + src_size = elem_size * + (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + if (dst_size > src_size) { + ir_add_error_node(ira, source_node, + buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", + dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, + src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + return ErrorNone; + } + case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialDiscard: + case ConstPtrSpecialHardCodedAddr: + case ConstPtrSpecialFunction: + zig_panic("TODO"); + } + zig_unreachable(); } static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { @@ -18054,6 +18121,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + if (src_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); @@ -20299,6 +20372,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; + if (!type_has_bits(child_type)) { + align_bytes = 0; + } } else { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20898,6 +20974,63 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS return result; } +static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + if (int_type->data.integral.bit_count % 8 != 0) { + ir_add_error(ira, instruction->type, + buf_sprintf("@bswap integer type '%s' has %" PRIu32 " bits which is not evenly divisible by 8", + buf_ptr(&int_type->name), int_type->data.integral.bit_count)); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (int_type->data.integral.bit_count == 8) { + return casted_op; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t buf_size = int_type->data.integral.bit_count / 8; + uint8_t *buf = allocate_nonzero(buf_size); + bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); + bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, + int_type->data.integral.is_signed); + return result; + } + + IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; IrInstruction *target = instruction->target->child; @@ -21233,6 +21366,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); case IrInstructionIdSqrt: return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); + case IrInstructionIdBswap: + return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21454,6 +21589,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCoroPromise: case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: + case IrInstructionIdBswap: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: -- cgit v1.2.3 From 757d0665ae951bdd5cb754adbe433488f0bea8c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Dec 2018 12:03:37 -0500 Subject: implement comptime pointer cast closes #955 closes #1835 --- src/ir.cpp | 25 ++++++++++++++++++++++--- std/mem.zig | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index dc87f040bc..ef7ad221cf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -166,6 +166,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); +static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -7364,15 +7365,31 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, return ir_add_error_node(ira, source_instruction->source_node, msg); } +// This function takes a comptime ptr and makes the child const value conform to the type +// described by the pointer. +static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, AstNode *source_node, ConstExprValue *ptr_val) { + Error err; + assert(ptr_val->type->id == ZigTypeIdPointer); + ConstExprValue tmp = {}; + tmp.special = ConstValSpecialStatic; + tmp.type = ptr_val->type->data.pointer.child_type; + if ((err = ir_read_const_ptr(ira, source_node, &tmp, ptr_val))) + return err; + ConstExprValue *child_val = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + copy_const_val(child_val, &tmp, false); + return ErrorNone; +} + static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) { + Error err; ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val); assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { - ir_add_error_node(ira, source_node, - buf_sprintf("TODO handle comptime reinterpreted pointer. See https://github.com/ziglang/zig/issues/955")); - return nullptr; + if ((err = eval_comptime_ptr_reinterpret(ira, source_node, const_val))) + return nullptr; + return const_ptr_pointee_unchecked(ira->codegen, const_val); } return val; } @@ -19990,6 +20007,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { + if (val->special == ConstValSpecialUndef) + val->special = ConstValSpecialStatic; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: diff --git a/std/mem.zig b/std/mem.zig index b9772acd6d..0e51601eb2 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -510,6 +510,15 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); } +test "comptime read/write int" { + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntLittle(u16, &bytes, 0x1234); + const result = std.mem.readIntBig(u16, &bytes); + std.debug.assert(result == 0x3412); + } +} + test "readIntBig and readIntLittle" { assert(readIntSliceBig(u0, []u8{}) == 0x0); assert(readIntSliceLittle(u0, []u8{}) == 0x0); -- cgit v1.2.3 From f75262b79f0656ebfac7fb5bd2d6d8e8cce01258 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Dec 2018 11:05:50 -0500 Subject: fix comptime pointer reinterpretation array index offset closes #1835 --- src/ir.cpp | 9 ++++----- std/mem.zig | 6 ++++++ test/behavior.zig | 1 + test/cases/ptrcast.zig | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 test/cases/ptrcast.zig (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index ef7ad221cf..09a9fceabe 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13744,20 +13744,19 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, if (array_val->data.x_array.special != ConstArraySpecialNone) zig_panic("TODO"); size_t elem_size = src_size; - src_size = elem_size * - (array_val->type->data.array.len - ptr_val->data.x_ptr.data.base_array.elem_index); + size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; + src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { ir_add_error_node(ira, source_node, buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", - dst_size, buf_ptr(&array_val->type->name), ptr_val->data.x_ptr.data.base_array.elem_index, - src_size)); + dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; } size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); Buf buf = BUF_INIT; buf_resize(&buf, elem_count * elem_size); for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); diff --git a/std/mem.zig b/std/mem.zig index 0e51601eb2..fb5f6fd5da 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -517,6 +517,12 @@ test "comptime read/write int" { const result = std.mem.readIntBig(u16, &bytes); std.debug.assert(result == 0x3412); } + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntBig(u16, &bytes, 0x1234); + const result = std.mem.readIntLittle(u16, &bytes); + std.debug.assert(result == 0x3412); + } } test "readIntBig and readIntLittle" { diff --git a/test/behavior.zig b/test/behavior.zig index 499c20ee20..e32063dec8 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -52,6 +52,7 @@ comptime { _ = @import("cases/optional.zig"); _ = @import("cases/pointers.zig"); _ = @import("cases/popcount.zig"); + _ = @import("cases/ptrcast.zig"); _ = @import("cases/pub_enum/index.zig"); _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("cases/reflection.zig"); diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig new file mode 100644 index 0000000000..071087c5c4 --- /dev/null +++ b/test/cases/ptrcast.zig @@ -0,0 +1,17 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "reinterpret bytes as integer with nonzero offset" { + testReinterpretBytesAsInteger(); + comptime testReinterpretBytesAsInteger(); +} + +fn testReinterpretBytesAsInteger() void { + const bytes = "\x12\x34\x56\x78\xab"; + const expected = switch (builtin.endian) { + builtin.Endian.Little => 0xab785634, + builtin.Endian.Big => 0x345678ab, + }; + assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); +} -- cgit v1.2.3 From e077a446566b0aa77a121f9554f3cb355899653a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Dec 2018 15:48:26 -0500 Subject: ir: delete dead code --- src/all_types.hpp | 1 - src/codegen.cpp | 26 -------------------------- src/ir.cpp | 3 +-- 3 files changed, 1 insertion(+), 29 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 83b7e8495f..11304e536d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -605,7 +605,6 @@ enum CastOp { CastOpFloatToInt, CastOpBoolToInt, CastOpResizeSlice, - CastOpBytesToSlice, CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, diff --git a/src/codegen.cpp b/src/codegen.cpp index 08dd11800a..e37703d5f0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2882,32 +2882,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - return cast_instruction->tmp_ptr; - } - case CastOpBytesToSlice: - { - assert(cast_instruction->tmp_ptr); - assert(wanted_type->id == ZigTypeIdStruct); - assert(wanted_type->data.structure.is_slice); - assert(actual_type->id == ZigTypeIdArray); - - ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; - ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type; - - - size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index; - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_ptr_index, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, ""); - gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); - - size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index; - LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - (unsigned)wanted_len_index, ""); - LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, - actual_type->data.array.len / type_size(g, wanted_child_type), false); - gen_store_untyped(g, len_val, len_ptr, 0, false); - return cast_instruction->tmp_ptr; } case CastOpIntToFloat: diff --git a/src/ir.cpp b/src/ir.cpp index 09a9fceabe..76dd6c6391 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9339,7 +9339,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ const_val->type = new_type; break; case CastOpResizeSlice: - case CastOpBytesToSlice: // can't do it zig_unreachable(); case CastOpIntToFloat: @@ -9396,7 +9395,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst ZigType *wanted_type, CastOp cast_op, bool need_alloca) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && - cast_op != CastOpResizeSlice && cast_op != CastOpBytesToSlice) + cast_op != CastOpResizeSlice) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); -- cgit v1.2.3 From 45e72c0b3944b2fa6d06c7018e9648b4ae60006a Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 19 Dec 2018 15:39:18 +0100 Subject: Fixed intToPtr to fn type when the address is hardcoded (#1842) * Fixed intToPtr to fn type * Added test * Import inttoptr.zig in behavior.zig --- src/ir.cpp | 1 + test/behavior.zig | 1 + test/cases/inttoptr.zig | 13 +++++++++++++ 3 files changed, 15 insertions(+) create mode 100644 test/cases/inttoptr.zig (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 76dd6c6391..028582f87f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12495,6 +12495,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct case ReqCompTimeNo: if (casted_init_value->value.special == ConstValSpecialStatic && casted_init_value->value.type->id == ZigTypeIdFn && + casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) { var_class_requires_const = true; diff --git a/test/behavior.zig b/test/behavior.zig index e32063dec8..8090359772 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -42,6 +42,7 @@ comptime { _ = @import("cases/if.zig"); _ = @import("cases/import.zig"); _ = @import("cases/incomplete_struct_param_tld.zig"); + _ = @import("cases/inttoptr.zig"); _ = @import("cases/ir_block_deps.zig"); _ = @import("cases/math.zig"); _ = @import("cases/merge_error_sets.zig"); diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig new file mode 100644 index 0000000000..6695352383 --- /dev/null +++ b/test/cases/inttoptr.zig @@ -0,0 +1,13 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "casting random address to function pointer" { + randomAddressToFunction(); + comptime randomAddressToFunction(); +} + +fn randomAddressToFunction() void { + var addr: usize = 0xdeadbeef; + var ptr = @intToPtr(fn () void, addr); +} -- cgit v1.2.3 From 218a4d4b30f320797121ad9900d48743da77a1b3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 22 Dec 2018 23:06:30 -0500 Subject: comptime: ability to @ptrCast to an extern struct and read fields --- src/ir.cpp | 64 ++++++++++++++++++++++++++++++++++++++------------ test/cases/ptrcast.zig | 19 +++++++++++++++ 2 files changed, 68 insertions(+), 15 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 028582f87f..83960f2eee 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -159,7 +159,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); @@ -13725,7 +13725,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, Buf buf = BUF_INIT; buf_resize(&buf, src_size); buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } @@ -13759,7 +13760,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } - buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val); + if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; return ErrorNone; } case ConstPtrSpecialBaseStruct: @@ -20077,7 +20079,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } -static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { +static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { + Error err; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { case ZigTypeIdInvalid: @@ -20094,30 +20097,60 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdPromise: zig_unreachable(); case ZigTypeIdVoid: - return; + return ErrorNone; case ZigTypeIdBool: val->data.x_bool = (buf[0] != 0); - return; + return ErrorNone; case ZigTypeIdInt: bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - codegen->is_big_endian, val->type->data.integral.is_signed); - return; + ira->codegen->is_big_endian, val->type->data.integral.is_signed); + return ErrorNone; case ZigTypeIdFloat: - float_read_ieee597(val, buf, codegen->is_big_endian); - return; + float_read_ieee597(val, buf, ira->codegen->is_big_endian); + return ErrorNone; case ZigTypeIdPointer: { val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; BigInt bn; - bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, - codegen->is_big_endian, false); + bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count, + ira->codegen->is_big_endian, false); val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); - return; + return ErrorNone; } case ZigTypeIdArray: zig_panic("TODO buf_read_value_bytes array type"); case ZigTypeIdStruct: - zig_panic("TODO buf_read_value_bytes struct type"); + switch (val->type->data.structure.layout) { + case ContainerLayoutAuto: { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", + buf_ptr(&val->type->name))); + add_error_note(ira->codegen, msg, val->type->data.structure.decl_node, + buf_sprintf("declared here")); + return ErrorSemanticAnalyzeFail; + } + case ContainerLayoutExtern: { + size_t src_field_count = val->type->data.structure.src_field_count; + val->data.x_struct.fields = create_const_vals(src_field_count); + for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { + ConstExprValue *field_val = &val->data.x_struct.fields[field_i]; + field_val->special = ConstValSpecialStatic; + TypeStructField *type_field = &val->type->data.structure.fields[field_i]; + field_val->type = type_field->type_entry; + if (type_field->gen_index == SIZE_MAX) + continue; + size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref, + type_field->gen_index); + uint8_t *new_buf = buf + offset; + if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val))) + return err; + } + return ErrorNone; + } + case ContainerLayoutPacked: + zig_panic("TODO buf_read_value_bytes packed struct"); + } + zig_unreachable(); case ZigTypeIdOptional: zig_panic("TODO buf_read_value_bytes maybe type"); case ZigTypeIdErrorUnion: @@ -20220,7 +20253,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - buf_read_value_bytes(ira->codegen, buf, &result->value); + if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value))) + return ira->codegen->invalid_instruction; return result; } diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig index 071087c5c4..6f0e6e5946 100644 --- a/test/cases/ptrcast.zig +++ b/test/cases/ptrcast.zig @@ -15,3 +15,22 @@ fn testReinterpretBytesAsInteger() void { }; assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); } + +test "reinterpret bytes of an array into an extern struct" { + testReinterpretBytesAsExternStruct(); + comptime testReinterpretBytesAsExternStruct(); +} + +fn testReinterpretBytesAsExternStruct() void { + var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; + + const S = extern struct { + a: u8, + b: u16, + c: u8, + }; + + var ptr = @ptrCast(*const S, &bytes); + var val = ptr.c; + assertOrPanic(val == 5); +} -- cgit v1.2.3 From 4a1f0e141893fe56f540709c8fb12b8b8dc22218 Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 26 Dec 2018 10:31:45 -0600 Subject: Switching on bools with duplicate and missing value detection: Issue 1768 --- src/ir.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 83960f2eee..b1429ae8ac 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19787,6 +19787,39 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, return ira->codegen->invalid_instruction; } } + } else if (switch_type->id == ZigTypeIdBool) { + int seenTrue = 0; + int seenFalse = 0; + for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { + IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; + + IrInstruction *value = range->start->child; + + IrInstruction *casted_value = ir_implicit_cast(ira, value, switch_type); + if (type_is_invalid(casted_value->value.type)) + return ira->codegen->invalid_instruction; + + ConstExprValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); + if (!const_expr_val) + return ira->codegen->invalid_instruction; + + assert(const_expr_val->type->id == ZigTypeIdBool); + + if (const_expr_val->data.x_bool == true) { + seenTrue += 1; + } else { + seenFalse += 1; + } + + if ((seenTrue > 1) || (seenFalse > 1)) { + ir_add_error(ira, value, buf_sprintf("duplicate switch value")); + return ira->codegen->invalid_instruction; + } + } + if (((seenTrue < 1) || (seenFalse < 1)) && !instruction->have_else_prong) { + ir_add_error(ira, &instruction->base, buf_sprintf("switch must handle all possibilities")); + return ira->codegen->invalid_instruction; + } } else if (!instruction->have_else_prong) { ir_add_error(ira, &instruction->base, buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); -- cgit v1.2.3 From f6cd68386d76e4a9a489187c47f218b59e1734f3 Mon Sep 17 00:00:00 2001 From: vegecode <39607947+vegecode@users.noreply.github.com> Date: Wed, 2 Jan 2019 15:47:47 -0600 Subject: @bitreverse intrinsic, part of #767 (#1865) * bitreverse - give bswap behavior * bitreverse, comptime_ints, negative values still not working? * bitreverse working for negative comptime ints * Finished bitreverse test cases * Undo exporting a bigint function. @bitreverse test name includes ampersand * added docs entry for @bitreverse --- doc/langref.html.in | 12 ++++++ src/all_types.hpp | 13 +++++++ src/analyze.cpp | 4 ++ src/bigint.cpp | 1 + src/codegen.cpp | 16 ++++++++ src/ir.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++++- src/ir_print.cpp | 15 ++++++++ test/behavior.zig | 1 + test/cases/bitreverse.zig | 81 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 test/cases/bitreverse.zig (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 2a2b4003fb..6e03d3ec6d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5316,6 +5316,18 @@ comptime {

{#header_close#} + {#header_open|@bitreverse#} +
{#syntax#}@bitreverse(comptime T: type, value: T) T{#endsyntax#}
+

{#syntax#}T{#endsyntax#} accepts any integer type.

+

+ Reverses the bitpattern of an integer value, including the sign bit if applicable. +

+

+ For example 0b10110110 ({#syntax#}u8 = 182{#endsyntax#}, {#syntax#}i8 = -74{#endsyntax#}) + becomes 0b01101101 ({#syntax#}u8 = 109{#endsyntax#}, {#syntax#}i8 = 109{#endsyntax#}). +

+ {#header_close#} + {#header_open|@byteOffsetOf#}
{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}

diff --git a/src/all_types.hpp b/src/all_types.hpp index 2b55f8ee2e..df318729f5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1415,6 +1415,7 @@ enum BuiltinFnId { BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, BuiltinFnIdBswap, + BuiltinFnIdBitReverse, }; struct BuiltinFnEntry { @@ -1488,6 +1489,7 @@ enum ZigLLVMFnId { ZigLLVMFnIdCeil, ZigLLVMFnIdSqrt, ZigLLVMFnIdBswap, + ZigLLVMFnIdBitReverse, }; enum AddSubMul { @@ -1520,6 +1522,9 @@ struct ZigLLVMFnKey { struct { uint32_t bit_count; } bswap; + struct { + uint32_t bit_count; + } bit_reverse; } data; }; @@ -2162,6 +2167,7 @@ enum IrInstructionId { IrInstructionIdMarkErrRetTracePtr, IrInstructionIdSqrt, IrInstructionIdBswap, + IrInstructionIdBitReverse, IrInstructionIdErrSetCast, IrInstructionIdToBytes, IrInstructionIdFromBytes, @@ -3262,6 +3268,13 @@ struct IrInstructionBswap { IrInstruction *op; }; +struct IrInstructionBitReverse { + IrInstruction base; + + IrInstruction *type; + IrInstruction *op; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 0f2b8e48cc..b9794114a0 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6121,6 +6121,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; case ZigLLVMFnIdBswap: return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; + case ZigLLVMFnIdBitReverse: + return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + @@ -6141,6 +6143,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.pop_count.bit_count == b.data.pop_count.bit_count; case ZigLLVMFnIdBswap: return a.data.bswap.bit_count == b.data.bswap.bit_count; + case ZigLLVMFnIdBitReverse: + return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: diff --git a/src/bigint.cpp b/src/bigint.cpp index 8a8d028e82..7299f2379c 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -1722,3 +1722,4 @@ void bigint_incr(BigInt *x) { bigint_add(x, ©, &one); } + diff --git a/src/codegen.cpp b/src/codegen.cpp index 6a0596f62f..db8a5f7bb2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3789,6 +3789,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI n_args = 1; key.id = ZigLLVMFnIdBswap; key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; + } else if (fn_id == BuiltinFnIdBitReverse) { + fn_name = "bitreverse"; + n_args = 1; + key.id = ZigLLVMFnIdBitReverse; + key.data.bit_reverse.bit_count = (uint32_t)int_type->data.integral.bit_count; } else { zig_unreachable(); } @@ -5096,6 +5101,14 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, ""); } +static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { + LLVMValueRef op = ir_llvm_value(g, instruction->op); + ZigType *int_type = instruction->base.value.type; + assert(int_type->id == ZigTypeIdInt); + LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBitReverse); + return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5335,6 +5348,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); } zig_unreachable(); } @@ -6758,6 +6773,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2); + create_builtin_fn(g, BuiltinFnIdBitReverse, "bitreverse", 2); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index b1429ae8ac..dac5403550 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -861,6 +861,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBswap *) { return IrInstructionIdBswap; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitReverse *) { + return IrInstructionIdBitReverse; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { return IrInstructionIdCheckRuntimeScope; } @@ -2721,6 +2725,17 @@ static IrInstruction *ir_build_bswap(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } +static IrInstruction *ir_build_bit_reverse(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { + IrInstructionBitReverse *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { IrInstructionCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); instruction->scope_is_comptime = scope_is_comptime; @@ -3646,7 +3661,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo Buf *name = fn_ref_expr->data.symbol_expr.symbol; auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - if (!entry) { + if (!entry) { // new built in not found add_node_error(irb->codegen, node, buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); return irb->codegen->invalid_instruction; @@ -4720,6 +4735,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdBitReverse: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval); + } } zig_unreachable(); } @@ -21115,6 +21145,69 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction return result; } +static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + if (type_is_invalid(int_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *op = instruction->op->child; + if (type_is_invalid(op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->id != ZigTypeIdInt) { + ir_add_error(ira, instruction->type, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *casted_op = ir_implicit_cast(ira, op, int_type); + if (type_is_invalid(casted_op->value.type)) + return ira->codegen->invalid_instruction; + + if (int_type->data.integral.bit_count == 0) { + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + bigint_init_unsigned(&result->value.data.x_bigint, 0); + return result; + } + + if (instr_is_comptime(casted_op)) { + ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); + if (!val) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, int_type); + size_t num_bits = int_type->data.integral.bit_count; + size_t buf_size = (num_bits + 7) / 8; + uint8_t *comptime_buf = allocate_nonzero(buf_size); + uint8_t *result_buf = allocate_nonzero(buf_size); + memset(comptime_buf,0,buf_size); + memset(result_buf,0,buf_size); + + bigint_write_twos_complement(&val->data.x_bigint,comptime_buf,num_bits,ira->codegen->is_big_endian); + + size_t bit_i = 0; + size_t bit_rev_i = num_bits - 1; + for (; bit_i < num_bits; bit_i++, bit_rev_i--) { + if (comptime_buf[bit_i / 8] & (1 << (bit_i % 8))) { + result_buf[bit_rev_i / 8] |= (1 << (bit_rev_i % 8)); + } + } + + bigint_read_twos_complement(&result->value.data.x_bigint, + result_buf, + int_type->data.integral.bit_count, + ira->codegen->is_big_endian, + int_type->data.integral.is_signed); + + return result; + } + + IrInstruction *result = ir_build_bit_reverse(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr, casted_op); + result->value.type = int_type; + return result; +} + static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; @@ -21453,6 +21546,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); case IrInstructionIdBswap: return ir_analyze_instruction_bswap(ira, (IrInstructionBswap *)instruction); + case IrInstructionIdBitReverse: + return ir_analyze_instruction_bit_reverse(ira, (IrInstructionBitReverse *)instruction); case IrInstructionIdIntToErr: return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: @@ -21675,6 +21770,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPromiseResultType: case IrInstructionIdSqrt: case IrInstructionIdBswap: + case IrInstructionIdBitReverse: case IrInstructionIdAtomicLoad: case IrInstructionIdIntCast: case IrInstructionIdFloatCast: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e09b0073eb..b5099db86a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1335,6 +1335,18 @@ static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { fprintf(irp->f, ")"); } +static void ir_print_bit_reverse(IrPrint *irp, IrInstructionBitReverse *instruction) { + fprintf(irp->f, "@bitreverse("); + if (instruction->type != nullptr) { + ir_print_other_instruction(irp, instruction->type); + } else { + fprintf(irp->f, "null"); + } + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->op); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1751,6 +1763,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBswap: ir_print_bswap(irp, (IrInstructionBswap *)instruction); break; + case IrInstructionIdBitReverse: + ir_print_bit_reverse(irp, (IrInstructionBitReverse *)instruction); + break; case IrInstructionIdAtomicLoad: ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); break; diff --git a/test/behavior.zig b/test/behavior.zig index 8090359772..10cd08dad7 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -9,6 +9,7 @@ comptime { _ = @import("cases/bitcast.zig"); _ = @import("cases/bool.zig"); _ = @import("cases/bswap.zig"); + _ = @import("cases/bitreverse.zig"); _ = @import("cases/bugs/1076.zig"); _ = @import("cases/bugs/1111.zig"); _ = @import("cases/bugs/1277.zig"); diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig new file mode 100644 index 0000000000..3721e68a94 --- /dev/null +++ b/test/cases/bitreverse.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const assert = std.debug.assert; +const minInt = std.math.minInt; + +test "@bitreverse" { + comptime testBitReverse(); + testBitReverse(); +} + +fn testBitReverse() void { + // using comptime_ints, unsigned + assert(@bitreverse(u0, 0) == 0); + assert(@bitreverse(u5, 0x12) == 0x9); + assert(@bitreverse(u8, 0x12) == 0x48); + assert(@bitreverse(u16, 0x1234) == 0x2c48); + assert(@bitreverse(u24, 0x123456) == 0x6a2c48); + assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using runtime uints, unsigned + var num0: u0 = 0; + assert(@bitreverse(u0, num0) == 0); + var num5: u5 = 0x12; + assert(@bitreverse(u5, num5) == 0x9); + var num8: u8 = 0x12; + assert(@bitreverse(u8, num8) == 0x48); + var num16: u16 = 0x1234; + assert(@bitreverse(u16, num16) == 0x2c48); + var num24: u24 = 0x123456; + assert(@bitreverse(u24, num24) == 0x6a2c48); + var num32: u32 = 0x12345678; + assert(@bitreverse(u32, num32) == 0x1e6a2c48); + var num40: u40 = 0x123456789a; + assert(@bitreverse(u40, num40) == 0x591e6a2c48); + var num48: u48 = 0x123456789abc; + assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); + var num56: u56 = 0x123456789abcde; + assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + var num64: u64 = 0x123456789abcdef1; + assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + var num128: u128 = 0x123456789abcdef11121314151617181; + assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using comptime_ints, signed, positive + assert(@bitreverse(i0, 0) == 0); + assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); + assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); + assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); + assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); + assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); + assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); + assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); + assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); + assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); + + // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. + var neg5: i5 = minInt(i5) + 1; + assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + var neg8: i8 = -18; + assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + var neg16: i16 = -32694; + assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + var neg24: i24 = -6773785; + assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + var neg32: i32 = -16773785; + assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + var neg40: i40 = minInt(i40) + 12345; + assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + var neg48: i48 = minInt(i48) + 12345; + assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + var neg56: i56 = minInt(i56) + 12345; + assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + var neg64: i64 = minInt(i64) + 12345; + assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + var neg128: i128 = minInt(i128) + 12345; + assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); +} -- cgit v1.2.3 From 1f08be4d7fdf08bda66312ab4b2e401de378083e Mon Sep 17 00:00:00 2001 From: vegecode <39607947+vegecode@users.noreply.github.com> Date: Fri, 4 Jan 2019 16:34:21 -0600 Subject: Mark comptime int hardcoded address pointee as a run time variable #1171 (#1868) * Mark comptime int hardcoded address as a run time variable #1171 * test case for dereferencing hardcoded address intToPtr --- src/ir.cpp | 1 + test/cases/inttoptr.zig | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index dac5403550..400b07368b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20363,6 +20363,7 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru IrInstruction *result = ir_const(ira, &instruction->base, dest_type); result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); return result; } diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig index 6695352383..ba3cc52f09 100644 --- a/test/cases/inttoptr.zig +++ b/test/cases/inttoptr.zig @@ -11,3 +11,17 @@ fn randomAddressToFunction() void { var addr: usize = 0xdeadbeef; var ptr = @intToPtr(fn () void, addr); } + +test "mutate through ptr initialized with constant intToPtr value" { + forceCompilerAnalyzeBranchHardCodedPtrDereference(false); +} + +fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { + const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); + if (x) { + hardCodedP.* = hardCodedP.* | 10; + } else { + return; + } +} + -- cgit v1.2.3 From db928915878c64f9e5c479739bd768bd4ac0b912 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:48:31 +0100 Subject: Respect the type system instead of ConstExprValue when getting field --- src/ir.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 400b07368b..d74bef2424 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14577,8 +14577,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_instruction; - ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_val->type, + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, PtrLenSingle, align_bytes, (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), (uint32_t)host_int_bytes_for_result_type); -- cgit v1.2.3 From e410b1f915974fe3daeebae324e8c4e4b42090dd Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:49:24 +0100 Subject: Implemented buf_read_value_bytes for ZigTypeIdArray * Only for x_array.special == ConstArraySpecialNone --- src/ir.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index d74bef2424..2353bb1086 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20179,8 +20179,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } - case ZigTypeIdArray: - zig_panic("TODO buf_read_value_bytes array type"); + case ZigTypeIdArray: { + uint64_t elem_size = type_size(ira->codegen, val->type->data.array.child_type); + size_t len = val->type->data.array.len; + + switch (val->data.x_array.special) { + case ConstArraySpecialNone: + val->data.x_array.data.s_none.elements = create_const_vals(len); + for (size_t i = 0; i < len; i++) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = val->type->data.array.child_type; + if ((err = buf_read_value_bytes(ira, source_node, buf + (elem_size * i), elem))) + return err; + } + break; + case ConstArraySpecialUndef: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); + case ConstArraySpecialBuf: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); + } + + return ErrorNone; + } case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { -- cgit v1.2.3 From 55e95daf543a27961fe9ca7a998d3cbd25d2973b Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 17:53:34 +0100 Subject: Fixed issue where TypeInfo would use types from a prev CodeGen instance When doing multible codegen passes (such as building compiler_rt and then something else) the TypeInfo cache code would point to types from the prev code gen (such as the prev 'bool' type), giving us errors like "expected type 'bool', but found type 'bool'" This disabling of caching might have a performance hit, but correctness is better than speed, so let's have this for now, until someone optimizes this correctly (probably in stage2) --- src/ir.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 2353bb1086..4e401b7249 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16882,16 +16882,12 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { Error err; - static ConstExprValue *type_info_var = nullptr; // TODO oops this global variable made it past code review - static ZigType *type_info_type = nullptr; // TODO oops this global variable made it past code review - if (type_info_var == nullptr) { - type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); - assert(type_info_var->type->id == ZigTypeIdMetaType); + ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); // TODO oops this global variable made it past code review + assert(type_info_var->type->id == ZigTypeIdMetaType); + assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - type_info_type = type_info_var->data.x_type; - assert(type_info_type->id == ZigTypeIdUnion); - } + ZigType *type_info_type = type_info_var->data.x_type; // TODO oops this global variable made it past code review + assert(type_info_type->id == ZigTypeIdUnion); if (type_name == nullptr && root == nullptr) return type_info_type; -- cgit v1.2.3 From da08525bb31c3608667254132b65e409f5869a03 Mon Sep 17 00:00:00 2001 From: Jimmi HC Date: Sun, 6 Jan 2019 18:02:00 +0100 Subject: Removed oops comments --- src/ir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 4e401b7249..531b705538 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16882,11 +16882,11 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { Error err; - ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); // TODO oops this global variable made it past code review + ConstExprValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); assert(type_info_var->type->id == ZigTypeIdMetaType); assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); - ZigType *type_info_type = type_info_var->data.x_type; // TODO oops this global variable made it past code review + ZigType *type_info_type = type_info_var->data.x_type; assert(type_info_type->id == ZigTypeIdUnion); if (type_name == nullptr && root == nullptr) -- cgit v1.2.3 From 4d5d0d3adad09e9ce34d281327c424de6402fcdb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 8 Jan 2019 14:40:56 -0500 Subject: `@typeInfo`: more correct return type info --- src/ir.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 531b705538..6e6c46885b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17100,12 +17100,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ensure_field_index(fn_def_val->type, "return_type", 7); fn_def_fields[7].special = ConstValSpecialStatic; fn_def_fields[7].type = ira->codegen->builtin_types.entry_type; - if (fn_entry->src_implicit_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->src_implicit_return_type; - else if (fn_entry->type_entry->data.fn.gen_return_type != nullptr) - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.gen_return_type; - else - fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; + fn_def_fields[7].data.x_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; // arg_names: [][] const u8 ensure_field_index(fn_def_val->type, "arg_names", 8); size_t fn_arg_count = fn_entry->variable_list.length; -- cgit v1.2.3 From 5864d92b4049e6d60a21a3f22220464808dd0518 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 9 Jan 2019 10:43:48 -0500 Subject: when rendering llvm const values, ensure the types align the representation of the const expr val in zig, and the type that we tell LLVM it is. --- src/analyze.cpp | 21 +++++++++- src/analyze.hpp | 3 ++ src/codegen.cpp | 8 ++++ src/ir.cpp | 125 ++++++++++++++++++++++++++++++-------------------------- src/ir.hpp | 5 ++- 5 files changed, 102 insertions(+), 60 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index af65838eae..00eb38de9e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5757,7 +5757,8 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy case ConstPtrSpecialRef: case ConstPtrSpecialBaseStruct: buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: if (const_val->data.x_ptr.data.base_array.is_cstr) { @@ -5765,7 +5766,8 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy return; } else { buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; } case ConstPtrSpecialHardCodedAddr: @@ -6599,3 +6601,18 @@ uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *f LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(struct_type->type_ref, field->gen_index); return LLVMStoreSizeOfType(g->target_data_ref, field_type); } + +Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *const_val, ZigType *wanted_type) +{ + ConstExprValue ptr_val = {}; + ptr_val.special = ConstValSpecialStatic; + ptr_val.type = get_pointer_to_type(codegen, wanted_type, true); + ptr_val.data.x_ptr.mut = ConstPtrMutComptimeConst; + ptr_val.data.x_ptr.special = ConstPtrSpecialRef; + ptr_val.data.x_ptr.data.ref.pointee = const_val; + if (const_ptr_pointee(ira, codegen, &ptr_val, source_node) == nullptr) + return ErrorSemanticAnalyzeFail; + + return ErrorNone; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index b506b533ca..efbc065a63 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -222,4 +222,7 @@ enum ReqCompTime { }; ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); +Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *const_val, ZigType *wanted_type); + #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 0c979386e3..47f2aa103f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5626,6 +5626,8 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con } static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { + Error err; + ZigType *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -5769,6 +5771,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c } ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; assert(field_val->type != nullptr); + if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, + type_struct_field->type_entry))) + { + zig_unreachable(); + } + LLVMValueRef val = gen_const_val(g, field_val, ""); fields[type_struct_field->gen_index] = val; make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val); diff --git a/src/ir.cpp b/src/ir.cpp index 6e6c46885b..c651f30dd5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -159,9 +159,9 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); -static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val); +static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); -static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, +static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src); @@ -7391,35 +7391,46 @@ static ErrorMsg *ir_add_error_node(IrAnalyze *ira, AstNode *source_node, Buf *ms return exec_add_error_node(ira->codegen, ira->new_irb.exec, source_node, msg); } +static ErrorMsg *opt_ir_add_error_node(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, Buf *msg) { + if (ira != nullptr) + return exec_add_error_node(codegen, ira->new_irb.exec, source_node, msg); + else + return add_node_error(codegen, source_node, msg); +} + static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInstruction *source_instruction, Buf *msg) { return ir_add_error_node(ira, source_instruction->source_node, msg); } // This function takes a comptime ptr and makes the child const value conform to the type // described by the pointer. -static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, AstNode *source_node, ConstExprValue *ptr_val) { +static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *ptr_val) +{ Error err; assert(ptr_val->type->id == ZigTypeIdPointer); ConstExprValue tmp = {}; tmp.special = ConstValSpecialStatic; tmp.type = ptr_val->type->data.pointer.child_type; - if ((err = ir_read_const_ptr(ira, source_node, &tmp, ptr_val))) + if ((err = ir_read_const_ptr(ira, codegen, source_node, &tmp, ptr_val))) return err; - ConstExprValue *child_val = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + ConstExprValue *child_val = const_ptr_pointee_unchecked(codegen, ptr_val); copy_const_val(child_val, &tmp, false); return ErrorNone; } -static ConstExprValue *ir_const_ptr_pointee(IrAnalyze *ira, ConstExprValue *const_val, AstNode *source_node) { +ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, + AstNode *source_node) +{ Error err; - ConstExprValue *val = const_ptr_pointee_unchecked(ira->codegen, const_val); + ConstExprValue *val = const_ptr_pointee_unchecked(codegen, const_val); assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { - if ((err = eval_comptime_ptr_reinterpret(ira, source_node, const_val))) + if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val))) return nullptr; - return const_ptr_pointee_unchecked(ira->codegen, const_val); + return const_ptr_pointee_unchecked(codegen, const_val); } return val; } @@ -9461,7 +9472,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { - ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -9497,7 +9508,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); if (instr_is_comptime(value)) { - ConstExprValue *pointee = ir_const_ptr_pointee(ira, &value->value, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -10456,7 +10467,7 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou return ira->codegen->invalid_instruction; assert(val->type->id == ZigTypeIdPointer); - ConstExprValue *pointee = ir_const_ptr_pointee(ira, val, source_instr->source_node); + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { @@ -11025,7 +11036,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); - if ((err = ir_read_const_ptr(ira, source_instruction->source_node, &result->value, + if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, &ptr->value))) { return ira->codegen->invalid_instruction; @@ -13730,21 +13741,21 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC // out_val->type must be the type to read the pointer as // if the type is different than the actual type then it does a comptime byte reinterpretation -static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, +static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val) { Error err; assert(out_val->type != nullptr); - ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, ptr_val); + ConstExprValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val); - if ((err = type_resolve(ira->codegen, pointee->type, ResolveStatusSizeKnown))) + if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - if ((err = type_resolve(ira->codegen, out_val->type, ResolveStatusSizeKnown))) + if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - size_t src_size = type_size(ira->codegen, pointee->type); - size_t dst_size = type_size(ira->codegen, out_val->type); + size_t src_size = type_size(codegen, pointee->type); + size_t dst_size = type_size(codegen, out_val->type); if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); @@ -13754,8 +13765,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, if (dst_size <= src_size) { Buf buf = BUF_INIT; buf_resize(&buf, src_size); - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee); - if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; return ErrorNone; } @@ -13764,7 +13775,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, case ConstPtrSpecialInvalid: zig_unreachable(); case ConstPtrSpecialRef: { - ir_add_error_node(ira, source_node, + opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; @@ -13778,7 +13789,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { - ir_add_error_node(ira, source_node, + opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; @@ -13788,9 +13799,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, buf_resize(&buf, elem_count * elem_size); for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i]; - buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); } - if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; return ErrorNone; } @@ -14227,7 +14238,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct array_type = array_type->data.pointer.child_type; ptr_type = ptr_type->data.pointer.child_type; if (orig_array_ptr_val->special != ConstValSpecialRuntime) { - orig_array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val, + orig_array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, elem_ptr_instruction->base.source_node); if (orig_array_ptr_val == nullptr) return ira->codegen->invalid_instruction; @@ -14271,7 +14282,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *args_val = ir_const_ptr_pointee(ira, ptr_val, elem_ptr_instruction->base.source_node); + ConstExprValue *args_val = const_ptr_pointee(ira, ira->codegen, ptr_val, elem_ptr_instruction->base.source_node); if (args_val == nullptr) return ira->codegen->invalid_instruction; size_t start = args_val->data.x_arg_tuple.start_index; @@ -14353,7 +14364,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == ZigTypeIdArray)) { - ConstExprValue *array_ptr_val = ir_const_ptr_pointee(ira, orig_array_ptr_val, + ConstExprValue *array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, elem_ptr_instruction->base.source_node); if (array_ptr_val == nullptr) return ira->codegen->invalid_instruction; @@ -14572,7 +14583,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *struct_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node); + ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (struct_val == nullptr) return ira->codegen->invalid_instruction; if (type_is_invalid(struct_val->type)) @@ -14614,7 +14625,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *union_val = ir_const_ptr_pointee(ira, ptr_val, source_instr->source_node); + ConstExprValue *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (union_val == nullptr) return ira->codegen->invalid_instruction; if (type_is_invalid(union_val->type)) @@ -14811,7 +14822,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node); + ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); if (child_val == nullptr) return ira->codegen->invalid_instruction; @@ -14837,7 +14848,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - ConstExprValue *child_val = ir_const_ptr_pointee(ira, container_ptr_val, source_node); + ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); if (child_val == nullptr) return ira->codegen->invalid_instruction; ZigType *child_type = child_val->data.x_type; @@ -15112,7 +15123,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (!container_ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *namespace_val = ir_const_ptr_pointee(ira, container_ptr_val, + ConstExprValue *namespace_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, field_ptr_instruction->base.source_node); if (namespace_val == nullptr) return ira->codegen->invalid_instruction; @@ -15187,7 +15198,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc } if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { if (instr_is_comptime(casted_value)) { - ConstExprValue *dest_val = ir_const_ptr_pointee(ira, &ptr->value, store_ptr_instruction->base.source_node); + ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node); if (dest_val == nullptr) return ira->codegen->invalid_instruction; if (dest_val->special != ConstValSpecialRuntime) { @@ -15735,7 +15746,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) return ira->codegen->invalid_instruction; - ConstExprValue *maybe_val = ir_const_ptr_pointee(ira, val, unwrap_maybe_instruction->base.source_node); + ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node); if (maybe_val == nullptr) return ira->codegen->invalid_instruction; @@ -16032,7 +16043,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type; ConstExprValue *pointee_val = nullptr; if (instr_is_comptime(target_value_ptr)) { - pointee_val = ir_const_ptr_pointee(ira, &target_value_ptr->value, target_value_ptr->source_node); + pointee_val = const_ptr_pointee(ira, ira->codegen, &target_value_ptr->value, target_value_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; @@ -16167,7 +16178,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru if (!target_value_ptr) return ira->codegen->invalid_instruction; - ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, target_val_ptr, instruction->base.source_node); + ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, target_val_ptr, instruction->base.source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; @@ -18882,18 +18893,18 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction if (array_type->id == ZigTypeIdPointer) { ZigType *child_array_type = array_type->data.pointer.child_type; assert(child_array_type->id == ZigTypeIdArray); - parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + parent_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_instruction; - array_val = ir_const_ptr_pointee(ira, parent_ptr, instruction->base.source_node); + array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.source_node); if (array_val == nullptr) return ira->codegen->invalid_instruction; rel_end = child_array_type->data.array.len; abs_offset = 0; } else { - array_val = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + array_val = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (array_val == nullptr) return ira->codegen->invalid_instruction; rel_end = array_type->data.array.len; @@ -18902,7 +18913,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction } } else if (array_type->id == ZigTypeIdPointer) { assert(array_type->data.pointer.ptr_len == PtrLenUnknown); - parent_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + parent_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_instruction; @@ -18942,7 +18953,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction zig_panic("TODO slice of ptr cast from function"); } } else if (is_slice(array_type)) { - ConstExprValue *slice_ptr = ir_const_ptr_pointee(ira, &ptr_ptr->value, instruction->base.source_node); + ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); if (slice_ptr == nullptr) return ira->codegen->invalid_instruction; @@ -19351,7 +19362,7 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr { BigInt *op1_bigint = &casted_op1->value.data.x_bigint; BigInt *op2_bigint = &casted_op2->value.data.x_bigint; - ConstExprValue *pointee_val = ir_const_ptr_pointee(ira, &casted_result_ptr->value, casted_result_ptr->source_node); + ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, &casted_result_ptr->value, casted_result_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; BigInt *dest_bigint = &pointee_val->data.x_bigint; @@ -19450,7 +19461,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { @@ -19502,7 +19513,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = ir_const_ptr_pointee(ira, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { @@ -20132,7 +20143,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } -static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { +static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { Error err; assert(val->special == ConstValSpecialStatic); switch (val->type->id) { @@ -20156,22 +20167,22 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t return ErrorNone; case ZigTypeIdInt: bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count, - ira->codegen->is_big_endian, val->type->data.integral.is_signed); + codegen->is_big_endian, val->type->data.integral.is_signed); return ErrorNone; case ZigTypeIdFloat: - float_read_ieee597(val, buf, ira->codegen->is_big_endian); + float_read_ieee597(val, buf, codegen->is_big_endian); return ErrorNone; case ZigTypeIdPointer: { val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; BigInt bn; - bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count, - ira->codegen->is_big_endian, false); + bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, + codegen->is_big_endian, false); val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } case ZigTypeIdArray: { - uint64_t elem_size = type_size(ira->codegen, val->type->data.array.child_type); + uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); size_t len = val->type->data.array.len; switch (val->data.x_array.special) { @@ -20181,7 +20192,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; elem->special = ConstValSpecialStatic; elem->type = val->type->data.array.child_type; - if ((err = buf_read_value_bytes(ira, source_node, buf + (elem_size * i), elem))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) return err; } break; @@ -20196,10 +20207,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { - ErrorMsg *msg = ir_add_error_node(ira, source_node, + ErrorMsg *msg = opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted", buf_ptr(&val->type->name))); - add_error_note(ira->codegen, msg, val->type->data.structure.decl_node, + add_error_note(codegen, msg, val->type->data.structure.decl_node, buf_sprintf("declared here")); return ErrorSemanticAnalyzeFail; } @@ -20213,10 +20224,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t field_val->type = type_field->type_entry; if (type_field->gen_index == SIZE_MAX) continue; - size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref, + size_t offset = LLVMOffsetOfElement(codegen->target_data_ref, val->type->type_ref, type_field->gen_index); uint8_t *new_buf = buf + offset; - if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val))) + if ((err = buf_read_value_bytes(ira, codegen, source_node, new_buf, field_val))) return err; } return ErrorNone; @@ -20327,7 +20338,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value))) + if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value))) return ira->codegen->invalid_instruction; return result; } diff --git a/src/ir.hpp b/src/ir.hpp index b298750dec..7af1d7f52b 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -22,6 +22,9 @@ ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_ ZigType *expected_type, AstNode *expected_type_source_node); bool ir_has_side_effects(IrInstruction *instruction); -ConstExprValue *const_ptr_pointee(CodeGen *codegen, ConstExprValue *const_val); + +struct IrAnalyze; +ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, + AstNode *source_node); #endif -- cgit v1.2.3 From 5bf9ffdc5be02e67b57fe9398ad9d13147bfb0c8 Mon Sep 17 00:00:00 2001 From: kristopher tate Date: Sat, 26 Jan 2019 05:10:40 +0900 Subject: Hint at use of and/or when &&/|| is improperly used (#1886) --- doc/langref.html.in | 2 +- src/ir.cpp | 227 ++++++++++++++++++++---------------------------- src/parser.cpp | 35 ++++++-- src/tokenizer.cpp | 12 +++ src/tokenizer.hpp | 1 + test/compile_errors.zig | 145 +++++++++++++++++++------------ 6 files changed, 226 insertions(+), 196 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 6e03d3ec6d..1fb751cef4 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6024,7 +6024,7 @@ fn add(a: i32, b: i32) i32 { This is typically used for type safety when interacting with C code that does not expose struct details. Example:

- {#code_begin|test_err|expected type '*Derp', found '*Wat'#} + {#code_begin|test_err|expected '*Derp' type, found '*Wat'#} const Derp = @OpaqueType(); const Wat = @OpaqueType(); diff --git a/src/ir.cpp b/src/ir.cpp index c651f30dd5..df2c8cc9be 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9771,13 +9771,19 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node return ir_exec_const_result(codegen, analyzed_executable); } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { +static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTypeId wanted_type) { if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; + const char *expected_type_str = type_id_name(ZigTypeIdMetaType); + + if (wanted_type != ZigTypeIdInvalid) { + expected_type_str = type_id_name(wanted_type); + } + if (type_value->value.type->id != ZigTypeIdMetaType) { - ir_add_error(ira, type_value, - buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); + ir_add_error( ira, type_value, + buf_sprintf("expected %s type, found '%s'", expected_type_str, buf_ptr(&type_value->value.type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -9786,7 +9792,16 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { return ira->codegen->builtin_types.entry_invalid; assert(const_val->data.x_type != nullptr); - return const_val->data.x_type; + + ZigType *out_type = const_val->data.x_type; + + if (wanted_type != ZigTypeIdInvalid && out_type->id != wanted_type) { + ir_add_error(ira, type_value, + buf_sprintf( "expected %s type, found '%s'", expected_type_str, buf_ptr(&out_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + return out_type; } static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { @@ -10986,7 +11001,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("expected type '%s', found '%s'", + buf_sprintf("expected '%s' type, found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name))); report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg); @@ -12214,7 +12229,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t op2_array_end; if (op2_type->id == ZigTypeIdArray) { if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12228,7 +12243,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.data.base_array.is_cstr) { if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12239,7 +12254,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12253,7 +12268,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); + buf_sprintf("expected array or C string literal type, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } @@ -12388,26 +12403,22 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { - ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child); - if (type_is_invalid(op1_type)) - return ira->codegen->invalid_instruction; - - if (op1_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->op1, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&op1_type->name))); + ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child, ZigTypeIdErrorSet); + if (type_is_invalid(op1_type)) { + if (ira->codegen->errors.length != 0) { + add_error_note( ira->codegen + , ira->codegen->errors.last() + , instruction->base.source_node + , buf_sprintf("did you mean to use `or`?") + ); + } return ira->codegen->invalid_instruction; } - ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child); + ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child, ZigTypeIdErrorSet); if (type_is_invalid(op2_type)) return ira->codegen->invalid_instruction; - if (op2_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->op2, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&op2_type->name))); - return ira->codegen->invalid_instruction; - } - if (type_is_global_error_set(op1_type) || type_is_global_error_set(op2_type)) { @@ -12495,7 +12506,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct IrInstruction *var_type = nullptr; if (decl_var_instruction->var_type != nullptr) { var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type); + ZigType *proposed_type = ir_resolve_type(ira, var_type, ZigTypeIdInvalid); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { var->value->type = ira->codegen->builtin_types.entry_invalid; @@ -12824,21 +12835,14 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, { Error err; - ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); + ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child, ZigTypeIdErrorSet); if (type_is_invalid(err_set_type)) return ira->codegen->invalid_instruction; - ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child, ZigTypeIdInvalid); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; - if (err_set_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->err_set->child, - buf_sprintf("expected error set type, found type '%s'", - buf_ptr(&err_set_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); @@ -12900,7 +12904,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type; if (alloc_fn_type->id != ZigTypeIdFn) { ir_add_error(ira, &call_instruction->base, - buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name))); + buf_sprintf("expected allocation function type, found '%s'", buf_ptr(&alloc_fn_type->name))); return ira->codegen->invalid_instruction; } @@ -13692,7 +13696,7 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC if (is_comptime || instr_is_comptime(fn_ref)) { if (fn_ref->value.type->id == ZigTypeIdMetaType) { - ZigType *dest_type = ir_resolve_type(ira, fn_ref); + ZigType *dest_type = ir_resolve_type(ira, fn_ref, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -13817,7 +13821,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { Error err; IrInstruction *value = un_op_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, value); + ZigType *type_entry = ir_resolve_type(ira, value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; if ((err = ensure_complete_type(ira->codegen, type_entry))) @@ -15300,16 +15304,10 @@ static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, IrInstructionPtrTypeChild *ptr_type_child_instruction) { IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdPointer); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - if (type_entry->id != ZigTypeIdPointer) { - ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, - buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); } @@ -15462,7 +15460,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); + ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -15545,7 +15543,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs AsmOutput *asm_output = asm_expr->output_list.at(i); if (asm_output->return_type) { output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i]); + return_type = ir_resolve_type(ira, output_types[i], ZigTypeIdInvalid); if (type_is_invalid(return_type)) return ira->codegen->invalid_instruction; } @@ -15560,7 +15558,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs (input_value->value.type->id == ZigTypeIdComptimeInt || input_value->value.type->id == ZigTypeIdComptimeFloat)) { ir_add_error_node(ira, input_value->source_node, - buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value.type->name))); + buf_sprintf("expected sized integer or sized float type, found %s", buf_ptr(&input_value->value.type->name))); return ira->codegen->invalid_instruction; } @@ -15586,7 +15584,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; IrInstruction *child_type_value = array_type_instruction->child_type->child; - ZigType *child_type = ir_resolve_type(ira, child_type_value); + ZigType *child_type = ir_resolve_type(ira, child_type_value, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; switch (child_type->id) { @@ -15635,7 +15633,7 @@ static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInst if (instruction->payload_type == nullptr) { promise_type = ira->codegen->builtin_types.entry_promise; } else { - ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child, ZigTypeIdInvalid); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; @@ -15650,7 +15648,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, { Error err; IrInstruction *type_value = size_of_instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if ((err = ensure_complete_type(ira->codegen, type_entry))) return ira->codegen->invalid_instruction; @@ -16485,7 +16483,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, size_t elem_count = instruction->item_count; if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16601,7 +16599,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16719,7 +16717,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value); + ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16732,12 +16730,6 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (type_is_invalid(field_ptr->value.type)) return ira->codegen->invalid_instruction; - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -16751,7 +16743,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (field_ptr->value.type->id != ZigTypeIdPointer) { ir_add_error(ira, field_ptr, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value.type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&field_ptr->value.type->name))); return ira->codegen->invalid_instruction; } @@ -16810,9 +16802,9 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { - ZigType *container_type = ir_resolve_type(ira, type_value); + ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); if (type_is_invalid(container_type)) return nullptr; @@ -16824,12 +16816,6 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, if (!field_name) return nullptr; - if (container_type->id != ZigTypeIdStruct) { - ir_add_error(ira, type_value, - buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); - return nullptr; - } - TypeStructField *field = find_struct_type_field(container_type, field_name); if (field == nullptr) { ir_add_error(ira, field_name_value, @@ -17807,7 +17793,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17835,7 +17821,7 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstructionTypeId *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17870,7 +17856,7 @@ static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ir static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -18147,7 +18133,7 @@ static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstruction static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18200,7 +18186,7 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstructionIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18233,7 +18219,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18273,16 +18259,10 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdErrorSet); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdErrorSet) { - ir_add_error(ira, instruction->dest_type, - buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *target = instruction->target->child; if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; @@ -18311,7 +18291,7 @@ static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_ali static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; - ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child); + ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_child_type)) return ira->codegen->invalid_instruction; @@ -18408,7 +18388,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct if (!is_slice(target->value.type)) { ir_add_error(ira, instruction->target, - buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected slice type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -18427,7 +18407,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18445,7 +18425,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18501,7 +18481,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr return ira->codegen->invalid_instruction; if (target->value.type->id != ZigTypeIdBool) { - ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'", + ir_add_error(ira, instruction->target, buf_sprintf("expected bool type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -19082,7 +19062,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst IrInstruction *container = instruction->container->child; if (type_is_invalid(container->value.type)) return ira->codegen->invalid_instruction; - ZigType *container_type = ir_resolve_type(ira, container); + ZigType *container_type = ir_resolve_type(ira, container, ZigTypeIdInvalid); if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -19116,7 +19096,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19159,7 +19139,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); + ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19252,7 +19232,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *type_entry = ir_resolve_type(ira, type_value); + ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; @@ -19302,16 +19282,10 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *dest_type = ir_resolve_type(ira, type_value); + ZigType *dest_type = ir_resolve_type(ira, type_value, ZigTypeIdInt); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdInt) { - ir_add_error(ira, type_value, - buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -19581,7 +19555,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *param_type = ir_resolve_type(ira, param_type_value); + ZigType *param_type = ir_resolve_type(ira, param_type_value, ZigTypeIdInvalid); switch (type_requires_comptime(ira->codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -19615,7 +19589,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct } IrInstruction *return_type_value = instruction->return_type->child; - fn_type_id.return_type = ir_resolve_type(ira, return_type_value); + fn_type_id.return_type = ir_resolve_type(ira, return_type_value, ZigTypeIdInvalid); if (type_is_invalid(fn_type_id.return_type)) return ira->codegen->invalid_instruction; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { @@ -19631,7 +19605,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child; - fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); + fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value, ZigTypeIdInvalid); if (type_is_invalid(fn_type_id.async_allocator_type)) return ira->codegen->invalid_instruction; } @@ -19939,7 +19913,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 result_type = get_slice_type(ira->codegen, result_ptr_type); } else { ir_add_error(ira, target, - buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); + buf_sprintf("expected pointer or slice type, found '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; } @@ -19985,13 +19959,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // validate src_type and dest_type. if (get_src_ptr_type(src_type) == nullptr) { - ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); + ir_add_error(ira, ptr, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_src, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20059,7 +20033,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20255,7 +20229,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20352,13 +20326,13 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; // We explicitly check for the size, so we can use get_src_ptr_type if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + ir_add_error(ira, dest_type_value, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20461,7 +20435,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru // We check size explicitly so we can use get_src_ptr_type here. if (get_src_ptr_type(target->value.type) == nullptr) { ir_add_error(ira, target, - buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20492,7 +20466,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { Error err; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); + ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child, ZigTypeIdInvalid); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -20591,7 +20565,7 @@ static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrI static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) { IrInstruction *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); + ZigType *fn_type = ir_resolve_type(ira, fn_type_inst, ZigTypeIdFn); if (type_is_invalid(fn_type)) return ira->codegen->invalid_instruction; @@ -20600,11 +20574,6 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) return ira->codegen->invalid_instruction; - if (fn_type->id != ZigTypeIdFn) { - ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); - return ira->codegen->invalid_instruction; - } - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; if (arg_index >= fn_type_id->param_count) { ir_add_error(ira, arg_index_inst, @@ -20629,7 +20598,7 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { Error err; IrInstruction *target_inst = instruction->target->child; - ZigType *enum_type = ir_resolve_type(ira, target_inst); + ZigType *enum_type = ir_resolve_type(ira, target_inst, ZigTypeIdInvalid); if (type_is_invalid(enum_type)) return ira->codegen->invalid_instruction; @@ -20654,7 +20623,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } } else { - ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", + ir_add_error(ira, target_inst, buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&enum_type->name))); return ira->codegen->invalid_instruction; } @@ -20808,7 +20777,7 @@ static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInst if (coro_handle->value.type->id != ZigTypeIdPromise || coro_handle->value.type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", buf_ptr(&coro_handle->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20839,7 +20808,7 @@ static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, I } static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { - ZigType *operand_type = ir_resolve_type(ira, op); + ZigType *operand_type = ir_resolve_type(ira, op, ZigTypeIdInvalid); if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; @@ -20969,12 +20938,12 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { - ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child); + ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child, ZigTypeIdInvalid); if (type_is_invalid(promise_type)) return ira->codegen->invalid_instruction; if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", buf_ptr(&promise_type->name))); return ira->codegen->invalid_instruction; } @@ -20983,7 +20952,7 @@ static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, } static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) { - ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child); + ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child, ZigTypeIdInvalid); if (type_is_invalid(promise_result_type)) return ira->codegen->invalid_instruction; @@ -21046,7 +21015,7 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i } static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { - ZigType *float_type = ir_resolve_type(ira, instruction->type->child); + ZigType *float_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(float_type)) return ira->codegen->invalid_instruction; @@ -21113,7 +21082,7 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS } static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21169,7 +21138,7 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction } static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21240,7 +21209,7 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr if (target->value.type->id != ZigTypeIdEnum) { ir_add_error(ira, instruction->target, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected enum type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -21255,16 +21224,10 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdEnum); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdEnum) { - ir_add_error(ira, instruction->dest_type, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; diff --git a/src/parser.cpp b/src/parser.cpp index 077365995e..9425df2430 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -122,19 +122,37 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc); static AstNode *ast_parse_byte_align(ParseContext *pc); ATTRIBUTE_PRINTF(3, 4) -ATTRIBUTE_NORETURN -static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { +static ErrorMsg *ast_error(ParseContext *pc, Token *token, const char *format, ...) { va_list ap; va_start(ap, format); Buf *msg = buf_vprintf(format, ap); va_end(ap); + ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column, + pc->owner->source_code, pc->owner->line_offsets, msg); + err->line_start = token->start_line; + err->column_start = token->start_column; + + return err; +} + +ATTRIBUTE_PRINTF(4, 5) +ATTRIBUTE_NORETURN +static void ast_error_exit(ParseContext *pc, Token *token, ErrorMsg *note, const char *format, ...) { + va_list ap; + va_start(ap, format); + Buf *msg = buf_vprintf(format, ap); + va_end(ap); ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column, pc->owner->source_code, pc->owner->line_offsets, msg); err->line_start = token->start_line; err->column_start = token->start_column; + if (note) { + err->notes.append(note); + } + print_err_msg(err, pc->err_color); exit(EXIT_FAILURE); } @@ -164,7 +182,7 @@ static Buf ast_token_str(Buf *input, Token *token) { ATTRIBUTE_NORETURN static void ast_invalid_token_error(ParseContext *pc, Token *token) { Buf token_value = ast_token_str(pc->buf, token); - ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); + ast_error_exit(pc, token, NULL, "invalid token: '%s'", buf_ptr(&token_value)); } static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { @@ -214,8 +232,13 @@ static Token *eat_token_if(ParseContext *pc, TokenId id) { static Token *expect_token(ParseContext *pc, TokenId id) { Token *res = eat_token(pc); - if (res->id != id) - ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); + if (res->id != id) { + ErrorMsg *note = NULL; + if (res->id == TokenIdAmpersandAmpersand) { + note = ast_error(pc, res, "did you mean to use `and`?"); + } + ast_error_exit(pc, res, note, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); + } return res; } @@ -837,7 +860,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { if (param_decl->data.param_decl.is_var_args) res->data.fn_proto.is_var_args = true; if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error(pc, first, "Function prototype have varargs as a none last paramter."); + ast_error_exit(pc, first, NULL, "Function prototype have varargs as a none last paramter."); } return res; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 921ee4de09..464412d443 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -199,6 +199,7 @@ enum TokenizeState { TokenizeStateSawDash, TokenizeStateSawMinusPercent, TokenizeStateSawAmpersand, + TokenizeStateSawAmpersandAmpersand, TokenizeStateSawCaret, TokenizeStateSawBar, TokenizeStateSawBarBar, @@ -891,6 +892,10 @@ void tokenize(Buf *buf, Tokenization *out) { end_token(&t); t.state = TokenizeStateStart; break; + case '&': + set_token_id(&t, t.cur_tok, TokenIdAmpersandAmpersand); + t.state = TokenizeStateSawAmpersandAmpersand; + break; default: t.pos -= 1; end_token(&t); @@ -898,6 +903,11 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; + case TokenizeStateSawAmpersandAmpersand: + t.pos -= 1; + end_token(&t); + t.state = TokenizeStateStart; + continue; case TokenizeStateSawCaret: switch (c) { case '=': @@ -1468,6 +1478,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawPlus: case TokenizeStateSawDash: case TokenizeStateSawAmpersand: + case TokenizeStateSawAmpersandAmpersand: case TokenizeStateSawCaret: case TokenizeStateSawBar: case TokenizeStateSawEq: @@ -1515,6 +1526,7 @@ void tokenize(Buf *buf, Tokenization *out) { const char * token_name(TokenId id) { switch (id) { case TokenIdAmpersand: return "&"; + case TokenIdAmpersandAmpersand: return "&&"; case TokenIdArrow: return "->"; case TokenIdAtSign: return "@"; case TokenIdBang: return "!"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 1574e95571..2e872ce4de 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -14,6 +14,7 @@ enum TokenId { TokenIdAmpersand, + TokenIdAmpersandAmpersand, TokenIdArrow, TokenIdAtSign, TokenIdBang, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d9603ba4ff..d262405feb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,36 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "Use of && in place of `and`", + \\export fn entry() void { + \\ if (true && false) return; + \\} + , + ".tmp_source.zig:2:14: error: expected token ')', found '&&'", + ".tmp_source.zig:2:14: note: did you mean to use `and`?", + ); + + cases.add( + "Use of || in place of `or` (using comptime_int)", + \\export fn entry() void { + \\ if (1 || 0) return; + \\} + , + ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'comptime_int'", + ".tmp_source.zig:2:11: note: did you mean to use `or`?", + ); + + cases.add( + "Use of || in place of `or` (using booleans)", + \\export fn entry() void { + \\ if (true || false) return; + \\} + , + ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'bool'", + ".tmp_source.zig:2:14: note: did you mean to use `or`?", + ); + cases.add( "compile log a pointer to an opaque value", \\export fn entry() void { @@ -68,7 +98,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ do_the_thing(bar); \\} , - ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void", + ".tmp_source.zig:4:18: error: expected 'fn(i32) void' type, found 'fn(bool) void", ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'", ); @@ -104,7 +134,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'", ".tmp_source.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'", - ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'", + ".tmp_source.zig:11:20: error: expected 'u8' type, found 'u16'", ); cases.add( @@ -124,7 +154,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , - ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'", + ".tmp_source.zig:2:14: error: expected 'f32' type, found 'f64'", ); cases.add( @@ -172,7 +202,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var ptr2: *c_void = &b; \\} , - ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'", + ".tmp_source.zig:5:26: error: expected '*c_void' type, found '**u32'", ); cases.add( @@ -222,7 +252,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const sliceA: []u8 = &buffer; \\} , - ".tmp_source.zig:3:27: error: expected type '[]u8', found '*const [1]u8'", + ".tmp_source.zig:3:27: error: expected '[]u8' type, found '*const [1]u8'", ); cases.add( @@ -267,8 +297,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const Errors = error{} || u16; \\} , - ".tmp_source.zig:2:20: error: expected error set type, found 'u8'", - ".tmp_source.zig:5:31: error: expected error set type, found 'u16'", + ".tmp_source.zig:2:20: error: expected ErrorSet type, found 'u8'", + ".tmp_source.zig:2:23: note: did you mean to use `or`?", + ".tmp_source.zig:5:31: error: expected ErrorSet type, found 'u16'", ); cases.add( @@ -763,7 +794,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\fn bar(x: *b.Foo) void {} , - ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'", + ".tmp_source.zig:6:10: error: expected '*Foo' type, found '*Foo'", ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'", "a.zig:1:17: note: Foo declared here", "b.zig:1:17: note: Foo declared here", @@ -833,7 +864,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var y = p.*; \\} , - ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'", + ".tmp_source.zig:4:23: error: expected '*?*i32' type, found '**i32'", ); cases.add( @@ -842,7 +873,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const x: [*]const bool = true; \\} , - ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'", + ".tmp_source.zig:2:30: error: expected '[*]const bool' type, found 'bool'", ); cases.add( @@ -887,7 +918,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var rule_set = try Foo.init(); \\} , - ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'", + ".tmp_source.zig:2:13: error: expected 'i32' type, found 'type'", ); cases.add( @@ -921,7 +952,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return null; \\} , - ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'", + ".tmp_source.zig:5:34: error: expected '?NextError!i32' type, found '?OtherError!i32'", ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'", ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'", ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set", @@ -991,7 +1022,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @panic(e); \\} , - ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'", + ".tmp_source.zig:3:12: error: expected '[]const u8' type, found 'error{Foo}'", ); cases.add( @@ -1019,7 +1050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.ShouldBeCompileError; \\} , - ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'", + ".tmp_source.zig:6:17: error: expected 'void' type, found 'error{ShouldBeCompileError}'", ); cases.add( @@ -1062,7 +1093,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a(c); \\} , - ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'", + ".tmp_source.zig:8:7: error: expected 'fn(*const u8) void' type, found 'fn(u8) void'", ); cases.add( @@ -1144,7 +1175,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ E.One => {}, \\ } \\} - , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'"); + , ".tmp_source.zig:9:10: error: expected 'usize' type, found 'E'"); cases.add( "range operator in switch used on error set", @@ -1190,7 +1221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const z = i32!i32; \\} , - ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'", + ".tmp_source.zig:2:15: error: expected ErrorSet type, found 'i32'", ); cases.add( @@ -1240,7 +1271,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'", + ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32' type, found 'anyerror!i32'", ".tmp_source.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'", ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set", ); @@ -1255,7 +1286,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'", + ".tmp_source.zig:3:31: error: expected 'SmallErrorSet' type, found 'anyerror'", ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set", ); @@ -1282,7 +1313,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: Set2 = set1; \\} , - ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'", + ".tmp_source.zig:7:19: error: expected 'Set2' type, found 'Set1'", ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set", ); @@ -1822,7 +1853,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() noreturn {return;} \\export fn entry() void { a(); } , - ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'", + ".tmp_source.zig:1:18: error: expected 'noreturn' type, found 'void'", ); cases.add( @@ -1830,7 +1861,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() i32 {} \\export fn entry() void { _ = a(); } , - ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'", + ".tmp_source.zig:1:12: error: expected 'i32' type, found 'void'", ); cases.add( @@ -1936,7 +1967,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return a; \\} , - ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'", + ".tmp_source.zig:3:12: error: expected 'i32' type, found '[*]const u8'", ); cases.add( @@ -1945,7 +1976,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (0) {} \\} , - ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'", + ".tmp_source.zig:2:9: error: expected 'bool' type, found 'comptime_int'", ); cases.add( @@ -2040,8 +2071,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ array[bad] = array[bad]; \\} , - ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", - ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'", + ".tmp_source.zig:4:11: error: expected 'usize' type, found 'bool'", + ".tmp_source.zig:4:24: error: expected 'usize' type, found 'bool'", ); cases.add( @@ -2455,7 +2486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn foo() *const i32 { return y; } \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'", + ".tmp_source.zig:3:30: error: expected '*const i32' type, found '*const comptime_int'", ); cases.add( @@ -2533,7 +2564,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn c() i32 {return 2;} \\export fn entry() usize { return @sizeOf(@typeOf(fns)); } , - ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'", + ".tmp_source.zig:1:27: error: expected 'fn() void' type, found 'fn() i32'", ); cases.add( @@ -2545,7 +2576,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(fns)); } , - ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'", + ".tmp_source.zig:1:36: error: expected 'fn(i32) i32' type, found 'extern fn(i32) i32'", ); cases.add( @@ -2649,7 +2680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'", + ".tmp_source.zig:1:16: error: expected '*u8' type, found '(null)'", ); cases.add( @@ -3289,7 +3320,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn something() anyerror!void { } , - ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'", + ".tmp_source.zig:2:5: error: expected 'void' type, found 'anyerror'", ".tmp_source.zig:1:15: note: return type declared here", ); @@ -3468,7 +3499,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ derp.init(); \\} , - ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'", + ".tmp_source.zig:14:5: error: expected 'i32' type, found 'Foo'", ); cases.add( @@ -3498,7 +3529,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.init(); \\} , - ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'", + ".tmp_source.zig:23:5: error: expected '*Allocator' type, found '*List'", ); cases.add( @@ -3670,7 +3701,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'", + ".tmp_source.zig:8:26: error: expected '*const u3' type, found '*align(:3:1) const u3'", ); cases.add( @@ -3799,7 +3830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'", + ".tmp_source.zig:4:19: error: expected '*[]const u8' type, found '*const []const u8'", ); cases.addCase(x: { @@ -3831,7 +3862,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ foo(global_array); \\} , - ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'", + ".tmp_source.zig:4:9: error: expected '[]i32' type, found '[10]i32'", ); cases.add( @@ -3840,7 +3871,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrCast(usize, a); \\} , - ".tmp_source.zig:2:21: error: expected pointer, found 'usize'", + ".tmp_source.zig:2:21: error: expected Pointer type, found 'usize'", ); cases.add( @@ -3887,7 +3918,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:3:28: error: expected struct type, found 'i32'", + ".tmp_source.zig:3:28: error: expected Struct type, found 'i32'", ); cases.add( @@ -3911,7 +3942,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:5:38: error: expected pointer, found 'i32'", + ".tmp_source.zig:5:38: error: expected Pointer type, found 'i32'", ); cases.add( @@ -3952,7 +3983,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @byteOffsetOf(Foo, "a",); \\} , - ".tmp_source.zig:3:26: error: expected struct type, found 'i32'", + ".tmp_source.zig:3:26: error: expected Struct type, found 'i32'", ); cases.add( @@ -4066,7 +4097,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() ?i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'", + ".tmp_source.zig:2:15: error: expected 'bool' type, found '?i32'", ); cases.add( @@ -4076,7 +4107,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() anyerror!i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected type 'bool', found 'anyerror!i32'", + ".tmp_source.zig:2:15: error: expected 'bool' type, found 'anyerror!i32'", ); cases.add( @@ -4337,7 +4368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrToInt(x); \\} , - ".tmp_source.zig:2:22: error: expected pointer, found 'i32'", + ".tmp_source.zig:2:22: error: expected Pointer type, found 'i32'", ); cases.add( @@ -4373,7 +4404,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x << y; \\} , - ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'", + ".tmp_source.zig:2:17: error: expected 'u3' type, found 'u8'", ); cases.add( @@ -4402,7 +4433,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.* += 1; \\} , - ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'", + ".tmp_source.zig:8:13: error: expected '*u32' type, found '*align(1) u32'", ); cases.add( @@ -4446,7 +4477,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @alignCast(4, u32(3)); \\} , - ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'", + ".tmp_source.zig:2:22: error: expected pointer or slice type, found 'u32'", ); cases.add( @@ -4459,7 +4490,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn alignedSmall() align(4) i32 { return 1234; } , - ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'", + ".tmp_source.zig:2:35: error: expected 'fn() align(8) i32' type, found 'fn() align(4) i32'", ); cases.add( @@ -4471,7 +4502,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x == 5678; \\} , - ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'", + ".tmp_source.zig:4:32: error: expected '*i32' type, found '*align(1) i32'", ); cases.add( @@ -4506,7 +4537,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ bar(@ptrCast(*c_void, &x)); \\} , - ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'", + ".tmp_source.zig:5:9: error: expected '*Derp' type, found '*c_void'", ); cases.add( @@ -4552,7 +4583,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {} \\} , - ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'", + ".tmp_source.zig:3:50: error: expected 'AtomicOrder' type, found 'u32'", ); cases.add( @@ -4562,7 +4593,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @export("entry", entry, u32(1234)); \\} , - ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'", + ".tmp_source.zig:3:32: error: expected 'GlobalLinkage' type, found 'u32'", ); cases.add( @@ -4739,7 +4770,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @ArgType(i32, 3); \\} , - ".tmp_source.zig:2:18: error: expected function, found 'i32'", + ".tmp_source.zig:2:18: error: expected Fn type, found 'i32'", ); cases.add( @@ -4837,7 +4868,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\pub extern fn foo(format: *const u8, ...) void; , - ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'", + ".tmp_source.zig:2:9: error: expected '*const u8' type, found '[5]u8'", ); cases.add( @@ -4906,7 +4937,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: u2 = Small.Two; \\} , - ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'", + ".tmp_source.zig:9:22: error: expected 'u2' type, found 'Small'", ); cases.add( @@ -4923,7 +4954,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x = @intToEnum(Small, y); \\} , - ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'", + ".tmp_source.zig:10:31: error: expected 'u2' type, found 'u3'", ); cases.add( @@ -5320,7 +5351,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ asm volatile ("" : : [bar]"r"(3) : ""); \\} , - ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", + ".tmp_source.zig:2:35: error: expected sized integer or sized float type, found comptime_int", ); cases.add( @@ -5329,6 +5360,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ asm volatile ("" : : [bar]"r"(3.17) : ""); \\} , - ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", + ".tmp_source.zig:2:35: error: expected sized integer or sized float type, found comptime_float", ); } -- cgit v1.2.3 From 9c328b42916d463465b134457c7f13b5c65da406 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 29 Jan 2019 22:28:33 -0500 Subject: simpler implementation of `&&` and `||` hints This accomplishes the same goal, but with less changes, so that I can backport copy elision stuff easier. --- doc/langref.html.in | 2 +- src/ir.cpp | 235 +++++++++++++++++++++++++++++------------------- src/parser.cpp | 35 ++------ src/tokenizer.cpp | 15 +--- src/tokenizer.hpp | 1 - test/compile_errors.zig | 152 +++++++++++++++---------------- 6 files changed, 228 insertions(+), 212 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 1fb751cef4..6e03d3ec6d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6024,7 +6024,7 @@ fn add(a: i32, b: i32) i32 { This is typically used for type safety when interacting with C code that does not expose struct details. Example:

- {#code_begin|test_err|expected '*Derp' type, found '*Wat'#} + {#code_begin|test_err|expected type '*Derp', found '*Wat'#} const Derp = @OpaqueType(); const Wat = @OpaqueType(); diff --git a/src/ir.cpp b/src/ir.cpp index df2c8cc9be..b184252a2e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9771,19 +9771,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node return ir_exec_const_result(codegen, analyzed_executable); } -static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTypeId wanted_type) { +static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { if (type_is_invalid(type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; - const char *expected_type_str = type_id_name(ZigTypeIdMetaType); - - if (wanted_type != ZigTypeIdInvalid) { - expected_type_str = type_id_name(wanted_type); - } - if (type_value->value.type->id != ZigTypeIdMetaType) { - ir_add_error( ira, type_value, - buf_sprintf("expected %s type, found '%s'", expected_type_str, buf_ptr(&type_value->value.type->name))); + ir_add_error(ira, type_value, + buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); return ira->codegen->builtin_types.entry_invalid; } @@ -9792,16 +9786,35 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value, ZigTy return ira->codegen->builtin_types.entry_invalid; assert(const_val->data.x_type != nullptr); + return const_val->data.x_type; +} - ZigType *out_type = const_val->data.x_type; +static ZigType *ir_resolve_error_set_type(IrAnalyze *ira, IrInstruction *op_source, IrInstruction *type_value) { + if (type_is_invalid(type_value->value.type)) + return ira->codegen->builtin_types.entry_invalid; - if (wanted_type != ZigTypeIdInvalid && out_type->id != wanted_type) { - ir_add_error(ira, type_value, - buf_sprintf( "expected %s type, found '%s'", expected_type_str, buf_ptr(&out_type->name))); + if (type_value->value.type->id != ZigTypeIdMetaType) { + ErrorMsg *msg = ir_add_error(ira, type_value, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&type_value->value.type->name))); + add_error_note(ira->codegen, msg, op_source->source_node, + buf_sprintf("`||` merges error sets; `or` performs boolean OR")); return ira->codegen->builtin_types.entry_invalid; } - return out_type; + ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); + if (!const_val) + return ira->codegen->builtin_types.entry_invalid; + + assert(const_val->data.x_type != nullptr); + ZigType *result_type = const_val->data.x_type; + if (result_type->id != ZigTypeIdErrorSet) { + ErrorMsg *msg = ir_add_error(ira, type_value, + buf_sprintf("expected error set type, found type '%s'", buf_ptr(&result_type->name))); + add_error_note(ira->codegen, msg, op_source->source_node, + buf_sprintf("`||` merges error sets; `or` performs boolean OR")); + return ira->codegen->builtin_types.entry_invalid; + } + return result_type; } static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { @@ -11001,7 +11014,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("expected '%s' type, found '%s'", + buf_sprintf("expected type '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name))); report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg); @@ -12229,7 +12242,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t op2_array_end; if (op2_type->id == ZigTypeIdArray) { if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12243,7 +12256,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.data.base_array.is_cstr) { if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12254,7 +12267,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of '%s' type, found '%s'", + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", buf_ptr(&child_type->name), buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; @@ -12268,7 +12281,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, - buf_sprintf("expected array or C string literal type, found '%s'", buf_ptr(&op2->value.type->name))); + buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } @@ -12403,19 +12416,11 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } static IrInstruction *ir_analyze_merge_error_sets(IrAnalyze *ira, IrInstructionBinOp *instruction) { - ZigType *op1_type = ir_resolve_type(ira, instruction->op1->child, ZigTypeIdErrorSet); - if (type_is_invalid(op1_type)) { - if (ira->codegen->errors.length != 0) { - add_error_note( ira->codegen - , ira->codegen->errors.last() - , instruction->base.source_node - , buf_sprintf("did you mean to use `or`?") - ); - } + ZigType *op1_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op1->child); + if (type_is_invalid(op1_type)) return ira->codegen->invalid_instruction; - } - ZigType *op2_type = ir_resolve_type(ira, instruction->op2->child, ZigTypeIdErrorSet); + ZigType *op2_type = ir_resolve_error_set_type(ira, &instruction->base, instruction->op2->child); if (type_is_invalid(op2_type)) return ira->codegen->invalid_instruction; @@ -12506,7 +12511,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct IrInstruction *var_type = nullptr; if (decl_var_instruction->var_type != nullptr) { var_type = decl_var_instruction->var_type->child; - ZigType *proposed_type = ir_resolve_type(ira, var_type, ZigTypeIdInvalid); + ZigType *proposed_type = ir_resolve_type(ira, var_type); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { var->value->type = ira->codegen->builtin_types.entry_invalid; @@ -12835,14 +12840,21 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, { Error err; - ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child, ZigTypeIdErrorSet); + ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); if (type_is_invalid(err_set_type)) return ira->codegen->invalid_instruction; - ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child, ZigTypeIdInvalid); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; + if (err_set_type->id != ZigTypeIdErrorSet) { + ir_add_error(ira, instruction->err_set->child, + buf_sprintf("expected error set type, found type '%s'", + buf_ptr(&err_set_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); @@ -12904,7 +12916,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *alloc_fn_type = ptr_to_alloc_fn_type->data.pointer.child_type; if (alloc_fn_type->id != ZigTypeIdFn) { ir_add_error(ira, &call_instruction->base, - buf_sprintf("expected allocation function type, found '%s'", buf_ptr(&alloc_fn_type->name))); + buf_sprintf("expected allocation function, found '%s'", buf_ptr(&alloc_fn_type->name))); return ira->codegen->invalid_instruction; } @@ -13696,7 +13708,7 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC if (is_comptime || instr_is_comptime(fn_ref)) { if (fn_ref->value.type->id == ZigTypeIdMetaType) { - ZigType *dest_type = ir_resolve_type(ira, fn_ref, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, fn_ref); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -13821,7 +13833,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { Error err; IrInstruction *value = un_op_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; if ((err = ensure_complete_type(ira->codegen, type_entry))) @@ -15304,10 +15316,16 @@ static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, IrInstructionPtrTypeChild *ptr_type_child_instruction) { IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdPointer); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; + if (type_entry->id != ZigTypeIdPointer) { + ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, + buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); + return ira->codegen->invalid_instruction; + } + return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); } @@ -15460,7 +15478,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -15543,7 +15561,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs AsmOutput *asm_output = asm_expr->output_list.at(i); if (asm_output->return_type) { output_types[i] = asm_instruction->output_types[i]->child; - return_type = ir_resolve_type(ira, output_types[i], ZigTypeIdInvalid); + return_type = ir_resolve_type(ira, output_types[i]); if (type_is_invalid(return_type)) return ira->codegen->invalid_instruction; } @@ -15558,7 +15576,7 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs (input_value->value.type->id == ZigTypeIdComptimeInt || input_value->value.type->id == ZigTypeIdComptimeFloat)) { ir_add_error_node(ira, input_value->source_node, - buf_sprintf("expected sized integer or sized float type, found %s", buf_ptr(&input_value->value.type->name))); + buf_sprintf("expected sized integer or sized float, found %s", buf_ptr(&input_value->value.type->name))); return ira->codegen->invalid_instruction; } @@ -15584,7 +15602,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; IrInstruction *child_type_value = array_type_instruction->child_type->child; - ZigType *child_type = ir_resolve_type(ira, child_type_value, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, child_type_value); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; switch (child_type->id) { @@ -15633,7 +15651,7 @@ static IrInstruction *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrInst if (instruction->payload_type == nullptr) { promise_type = ira->codegen->builtin_types.entry_promise; } else { - ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child, ZigTypeIdInvalid); + ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child); if (type_is_invalid(payload_type)) return ira->codegen->invalid_instruction; @@ -15648,7 +15666,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, { Error err; IrInstruction *type_value = size_of_instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if ((err = ensure_complete_type(ira->codegen, type_entry))) return ira->codegen->invalid_instruction; @@ -16483,7 +16501,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, size_t elem_count = instruction->item_count; if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16599,7 +16617,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16717,7 +16735,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); + ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -16730,6 +16748,12 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (type_is_invalid(field_ptr->value.type)) return ira->codegen->invalid_instruction; + if (container_type->id != ZigTypeIdStruct) { + ir_add_error(ira, type_value, + buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -16743,7 +16767,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, if (field_ptr->value.type->id != ZigTypeIdPointer) { ir_add_error(ira, field_ptr, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&field_ptr->value.type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value.type->name))); return ira->codegen->invalid_instruction; } @@ -16802,9 +16826,9 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { - ZigType *container_type = ir_resolve_type(ira, type_value, ZigTypeIdStruct); + ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) return nullptr; @@ -16816,6 +16840,12 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, if (!field_name) return nullptr; + if (container_type->id != ZigTypeIdStruct) { + ir_add_error(ira, type_value, + buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); + return nullptr; + } + TypeStructField *field = find_struct_type_field(container_type, field_name); if (field == nullptr) { ir_add_error(ira, field_name_value, @@ -17793,7 +17823,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, { Error err; IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17821,7 +17851,7 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstructionTypeId *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -17856,7 +17886,7 @@ static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ir static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { IrInstruction *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -18133,7 +18163,7 @@ static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstruction static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstructionTruncate *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18186,7 +18216,7 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstructionIntCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18219,7 +18249,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18259,10 +18289,16 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdErrorSet); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdErrorSet) { + ir_add_error(ira, instruction->dest_type, + buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + IrInstruction *target = instruction->target->child; if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; @@ -18291,7 +18327,7 @@ static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_ali static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; - ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child, ZigTypeIdInvalid); + ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child); if (type_is_invalid(dest_child_type)) return ira->codegen->invalid_instruction; @@ -18388,7 +18424,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct if (!is_slice(target->value.type)) { ir_add_error(ira, instruction->target, - buf_sprintf("expected slice type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -18407,7 +18443,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18425,7 +18461,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { - ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -18481,7 +18517,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr return ira->codegen->invalid_instruction; if (target->value.type->id != ZigTypeIdBool) { - ir_add_error(ira, instruction->target, buf_sprintf("expected bool type, found '%s'", + ir_add_error(ira, instruction->target, buf_sprintf("expected bool, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -19062,7 +19098,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst IrInstruction *container = instruction->container->child; if (type_is_invalid(container->value.type)) return ira->codegen->invalid_instruction; - ZigType *container_type = ir_resolve_type(ira, container, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container); if ((err = ensure_complete_type(ira->codegen, container_type))) return ira->codegen->invalid_instruction; @@ -19096,7 +19132,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19139,7 +19175,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { Error err; IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value, ZigTypeIdInvalid); + ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; @@ -19232,7 +19268,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *type_entry = ir_resolve_type(ira, type_value, ZigTypeIdInvalid); + ZigType *type_entry = ir_resolve_type(ira, type_value); if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) return ira->codegen->invalid_instruction; @@ -19282,10 +19318,16 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *dest_type = ir_resolve_type(ira, type_value, ZigTypeIdInt); + ZigType *dest_type = ir_resolve_type(ira, type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdInt) { + ir_add_error(ira, type_value, + buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -19555,7 +19597,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->invalid_instruction; - ZigType *param_type = ir_resolve_type(ira, param_type_value, ZigTypeIdInvalid); + ZigType *param_type = ir_resolve_type(ira, param_type_value); switch (type_requires_comptime(ira->codegen, param_type)) { case ReqCompTimeYes: if (!calling_convention_allows_zig_types(fn_type_id.cc)) { @@ -19589,7 +19631,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct } IrInstruction *return_type_value = instruction->return_type->child; - fn_type_id.return_type = ir_resolve_type(ira, return_type_value, ZigTypeIdInvalid); + fn_type_id.return_type = ir_resolve_type(ira, return_type_value); if (type_is_invalid(fn_type_id.return_type)) return ira->codegen->invalid_instruction; if (fn_type_id.return_type->id == ZigTypeIdOpaque) { @@ -19605,7 +19647,7 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->child; - fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value, ZigTypeIdInvalid); + fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value); if (type_is_invalid(fn_type_id.async_allocator_type)) return ira->codegen->invalid_instruction; } @@ -19913,7 +19955,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 result_type = get_slice_type(ira->codegen, result_ptr_type); } else { ir_add_error(ira, target, - buf_sprintf("expected pointer or slice type, found '%s'", buf_ptr(&target_type->name))); + buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; } @@ -19959,13 +20001,13 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // validate src_type and dest_type. if (get_src_ptr_type(src_type) == nullptr) { - ir_add_error(ira, ptr, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&src_type->name))); + ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } if (get_src_ptr_type(dest_type) == nullptr) { ir_add_error(ira, dest_type_src, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20033,7 +20075,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20229,7 +20271,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; @@ -20326,13 +20368,13 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdInvalid); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; // We explicitly check for the size, so we can use get_src_ptr_type if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&dest_type->name))); + ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -20435,7 +20477,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru // We check size explicitly so we can use get_src_ptr_type here. if (get_src_ptr_type(target->value.type) == nullptr) { ir_add_error(ira, target, - buf_sprintf("expected Pointer type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20466,7 +20508,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { Error err; - ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child, ZigTypeIdInvalid); + ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; @@ -20565,7 +20607,7 @@ static IrInstruction *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrI static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) { IrInstruction *fn_type_inst = instruction->fn_type->child; - ZigType *fn_type = ir_resolve_type(ira, fn_type_inst, ZigTypeIdFn); + ZigType *fn_type = ir_resolve_type(ira, fn_type_inst); if (type_is_invalid(fn_type)) return ira->codegen->invalid_instruction; @@ -20574,6 +20616,11 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct if (!ir_resolve_usize(ira, arg_index_inst, &arg_index)) return ira->codegen->invalid_instruction; + if (fn_type->id != ZigTypeIdFn) { + ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name))); + return ira->codegen->invalid_instruction; + } + FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; if (arg_index >= fn_type_id->param_count) { ir_add_error(ira, arg_index_inst, @@ -20598,7 +20645,7 @@ static IrInstruction *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruct static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { Error err; IrInstruction *target_inst = instruction->target->child; - ZigType *enum_type = ir_resolve_type(ira, target_inst, ZigTypeIdInvalid); + ZigType *enum_type = ir_resolve_type(ira, target_inst); if (type_is_invalid(enum_type)) return ira->codegen->invalid_instruction; @@ -20623,7 +20670,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } } else { - ir_add_error(ira, target_inst, buf_sprintf("expected enum or union type, found '%s'", + ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", buf_ptr(&enum_type->name))); return ira->codegen->invalid_instruction; } @@ -20777,7 +20824,7 @@ static IrInstruction *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInst if (coro_handle->value.type->id != ZigTypeIdPromise || coro_handle->value.type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", buf_ptr(&coro_handle->value.type->name))); return ira->codegen->invalid_instruction; } @@ -20808,7 +20855,7 @@ static IrInstruction *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, I } static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) { - ZigType *operand_type = ir_resolve_type(ira, op, ZigTypeIdInvalid); + ZigType *operand_type = ir_resolve_type(ira, op); if (type_is_invalid(operand_type)) return ira->codegen->builtin_types.entry_invalid; @@ -20938,12 +20985,12 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { - ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child, ZigTypeIdInvalid); + ZigType *promise_type = ir_resolve_type(ira, instruction->promise_type->child); if (type_is_invalid(promise_type)) return ira->codegen->invalid_instruction; if (promise_type->id != ZigTypeIdPromise || promise_type->data.promise.result_type == nullptr) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T type, found '%s'", + ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", buf_ptr(&promise_type->name))); return ira->codegen->invalid_instruction; } @@ -20952,7 +20999,7 @@ static IrInstruction *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, } static IrInstruction *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) { - ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child, ZigTypeIdInvalid); + ZigType *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->child); if (type_is_invalid(promise_result_type)) return ira->codegen->invalid_instruction; @@ -21015,7 +21062,7 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i } static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { - ZigType *float_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *float_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(float_type)) return ira->codegen->invalid_instruction; @@ -21082,7 +21129,7 @@ static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionS } static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21138,7 +21185,7 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction } static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstructionBitReverse *instruction) { - ZigType *int_type = ir_resolve_type(ira, instruction->type->child, ZigTypeIdInvalid); + ZigType *int_type = ir_resolve_type(ira, instruction->type->child); if (type_is_invalid(int_type)) return ira->codegen->invalid_instruction; @@ -21209,7 +21256,7 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr if (target->value.type->id != ZigTypeIdEnum) { ir_add_error(ira, instruction->target, - buf_sprintf("expected enum type, found '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } @@ -21224,10 +21271,16 @@ static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { Error err; IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value, ZigTypeIdEnum); + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; + if (dest_type->id != ZigTypeIdEnum) { + ir_add_error(ira, instruction->dest_type, + buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; diff --git a/src/parser.cpp b/src/parser.cpp index 9425df2430..077365995e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -122,37 +122,19 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc); static AstNode *ast_parse_byte_align(ParseContext *pc); ATTRIBUTE_PRINTF(3, 4) -static ErrorMsg *ast_error(ParseContext *pc, Token *token, const char *format, ...) { - va_list ap; - va_start(ap, format); - Buf *msg = buf_vprintf(format, ap); - va_end(ap); - - ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column, - pc->owner->source_code, pc->owner->line_offsets, msg); - err->line_start = token->start_line; - err->column_start = token->start_column; - - return err; -} - -ATTRIBUTE_PRINTF(4, 5) ATTRIBUTE_NORETURN -static void ast_error_exit(ParseContext *pc, Token *token, ErrorMsg *note, const char *format, ...) { +static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { va_list ap; va_start(ap, format); Buf *msg = buf_vprintf(format, ap); va_end(ap); + ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column, pc->owner->source_code, pc->owner->line_offsets, msg); err->line_start = token->start_line; err->column_start = token->start_column; - if (note) { - err->notes.append(note); - } - print_err_msg(err, pc->err_color); exit(EXIT_FAILURE); } @@ -182,7 +164,7 @@ static Buf ast_token_str(Buf *input, Token *token) { ATTRIBUTE_NORETURN static void ast_invalid_token_error(ParseContext *pc, Token *token) { Buf token_value = ast_token_str(pc->buf, token); - ast_error_exit(pc, token, NULL, "invalid token: '%s'", buf_ptr(&token_value)); + ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); } static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { @@ -232,13 +214,8 @@ static Token *eat_token_if(ParseContext *pc, TokenId id) { static Token *expect_token(ParseContext *pc, TokenId id) { Token *res = eat_token(pc); - if (res->id != id) { - ErrorMsg *note = NULL; - if (res->id == TokenIdAmpersandAmpersand) { - note = ast_error(pc, res, "did you mean to use `and`?"); - } - ast_error_exit(pc, res, note, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); - } + if (res->id != id) + ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); return res; } @@ -860,7 +837,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { if (param_decl->data.param_decl.is_var_args) res->data.fn_proto.is_var_args = true; if (i != params.length - 1 && res->data.fn_proto.is_var_args) - ast_error_exit(pc, first, NULL, "Function prototype have varargs as a none last paramter."); + ast_error(pc, first, "Function prototype have varargs as a none last paramter."); } return res; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 464412d443..6215541876 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -199,7 +199,6 @@ enum TokenizeState { TokenizeStateSawDash, TokenizeStateSawMinusPercent, TokenizeStateSawAmpersand, - TokenizeStateSawAmpersandAmpersand, TokenizeStateSawCaret, TokenizeStateSawBar, TokenizeStateSawBarBar, @@ -887,15 +886,14 @@ void tokenize(Buf *buf, Tokenization *out) { break; case TokenizeStateSawAmpersand: switch (c) { + case '&': + tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); + break; case '=': set_token_id(&t, t.cur_tok, TokenIdBitAndEq); end_token(&t); t.state = TokenizeStateStart; break; - case '&': - set_token_id(&t, t.cur_tok, TokenIdAmpersandAmpersand); - t.state = TokenizeStateSawAmpersandAmpersand; - break; default: t.pos -= 1; end_token(&t); @@ -903,11 +901,6 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; - case TokenizeStateSawAmpersandAmpersand: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; case TokenizeStateSawCaret: switch (c) { case '=': @@ -1478,7 +1471,6 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawPlus: case TokenizeStateSawDash: case TokenizeStateSawAmpersand: - case TokenizeStateSawAmpersandAmpersand: case TokenizeStateSawCaret: case TokenizeStateSawBar: case TokenizeStateSawEq: @@ -1526,7 +1518,6 @@ void tokenize(Buf *buf, Tokenization *out) { const char * token_name(TokenId id) { switch (id) { case TokenIdAmpersand: return "&"; - case TokenIdAmpersandAmpersand: return "&&"; case TokenIdArrow: return "->"; case TokenIdAtSign: return "@"; case TokenIdBang: return "!"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 2e872ce4de..1574e95571 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -14,7 +14,6 @@ enum TokenId { TokenIdAmpersand, - TokenIdAmpersandAmpersand, TokenIdArrow, TokenIdAtSign, TokenIdBang, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d262405feb..0754f223e8 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,33 +2,28 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( - "Use of && in place of `and`", - \\export fn entry() void { - \\ if (true && false) return; - \\} - , - ".tmp_source.zig:2:14: error: expected token ')', found '&&'", - ".tmp_source.zig:2:14: note: did you mean to use `and`?", - ); - - cases.add( - "Use of || in place of `or` (using comptime_int)", - \\export fn entry() void { - \\ if (1 || 0) return; + "attempted `&&`", + \\export fn entry(a: bool, b: bool) i32 { + \\ if (a && b) { + \\ return 1234; + \\ } + \\ return 5678; \\} , - ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'comptime_int'", - ".tmp_source.zig:2:11: note: did you mean to use `or`?", + ".tmp_source.zig:2:11: error: `&&` is invalid. Note that `and` is boolean AND.", ); cases.add( - "Use of || in place of `or` (using booleans)", - \\export fn entry() void { - \\ if (true || false) return; + "attempted `||` on boolean values", + \\export fn entry(a: bool, b: bool) i32 { + \\ if (a || b) { + \\ return 1234; + \\ } + \\ return 5678; \\} , - ".tmp_source.zig:2:9: error: expected ErrorSet type, found 'bool'", - ".tmp_source.zig:2:14: note: did you mean to use `or`?", + ".tmp_source.zig:2:9: error: expected error set type, found 'bool'", + ".tmp_source.zig:2:11: note: `||` merges error sets; `or` performs boolean OR", ); cases.add( @@ -98,7 +93,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ do_the_thing(bar); \\} , - ".tmp_source.zig:4:18: error: expected 'fn(i32) void' type, found 'fn(bool) void", + ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void", ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'", ); @@ -134,7 +129,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:3:31: error: integer value 300 cannot be implicitly casted to type 'u8'", ".tmp_source.zig:7:22: error: integer value 300 cannot be implicitly casted to type 'u8'", - ".tmp_source.zig:11:20: error: expected 'u8' type, found 'u16'", + ".tmp_source.zig:11:20: error: expected type 'u8', found 'u16'", ); cases.add( @@ -154,7 +149,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(y)); } , - ".tmp_source.zig:2:14: error: expected 'f32' type, found 'f64'", + ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'", ); cases.add( @@ -202,7 +197,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var ptr2: *c_void = &b; \\} , - ".tmp_source.zig:5:26: error: expected '*c_void' type, found '**u32'", + ".tmp_source.zig:5:26: error: expected type '*c_void', found '**u32'", ); cases.add( @@ -252,7 +247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const sliceA: []u8 = &buffer; \\} , - ".tmp_source.zig:3:27: error: expected '[]u8' type, found '*const [1]u8'", + ".tmp_source.zig:3:27: error: expected type '[]u8', found '*const [1]u8'", ); cases.add( @@ -297,9 +292,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const Errors = error{} || u16; \\} , - ".tmp_source.zig:2:20: error: expected ErrorSet type, found 'u8'", - ".tmp_source.zig:2:23: note: did you mean to use `or`?", - ".tmp_source.zig:5:31: error: expected ErrorSet type, found 'u16'", + ".tmp_source.zig:2:20: error: expected error set type, found type 'u8'", + ".tmp_source.zig:2:23: note: `||` merges error sets; `or` performs boolean OR", + ".tmp_source.zig:5:31: error: expected error set type, found type 'u16'", + ".tmp_source.zig:5:28: note: `||` merges error sets; `or` performs boolean OR", ); cases.add( @@ -794,7 +790,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\fn bar(x: *b.Foo) void {} , - ".tmp_source.zig:6:10: error: expected '*Foo' type, found '*Foo'", + ".tmp_source.zig:6:10: error: expected type '*Foo', found '*Foo'", ".tmp_source.zig:6:10: note: pointer type child 'Foo' cannot cast into pointer type child 'Foo'", "a.zig:1:17: note: Foo declared here", "b.zig:1:17: note: Foo declared here", @@ -864,7 +860,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var y = p.*; \\} , - ".tmp_source.zig:4:23: error: expected '*?*i32' type, found '**i32'", + ".tmp_source.zig:4:23: error: expected type '*?*i32', found '**i32'", ); cases.add( @@ -873,7 +869,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const x: [*]const bool = true; \\} , - ".tmp_source.zig:2:30: error: expected '[*]const bool' type, found 'bool'", + ".tmp_source.zig:2:30: error: expected type '[*]const bool', found 'bool'", ); cases.add( @@ -918,7 +914,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var rule_set = try Foo.init(); \\} , - ".tmp_source.zig:2:13: error: expected 'i32' type, found 'type'", + ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'", ); cases.add( @@ -952,7 +948,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return null; \\} , - ".tmp_source.zig:5:34: error: expected '?NextError!i32' type, found '?OtherError!i32'", + ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'", ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'", ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'", ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set", @@ -1022,7 +1018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @panic(e); \\} , - ".tmp_source.zig:3:12: error: expected '[]const u8' type, found 'error{Foo}'", + ".tmp_source.zig:3:12: error: expected type '[]const u8', found 'error{Foo}'", ); cases.add( @@ -1050,7 +1046,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.ShouldBeCompileError; \\} , - ".tmp_source.zig:6:17: error: expected 'void' type, found 'error{ShouldBeCompileError}'", + ".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'", ); cases.add( @@ -1093,7 +1089,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a(c); \\} , - ".tmp_source.zig:8:7: error: expected 'fn(*const u8) void' type, found 'fn(u8) void'", + ".tmp_source.zig:8:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'", ); cases.add( @@ -1175,7 +1171,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ E.One => {}, \\ } \\} - , ".tmp_source.zig:9:10: error: expected 'usize' type, found 'E'"); + , ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'"); cases.add( "range operator in switch used on error set", @@ -1221,7 +1217,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ const z = i32!i32; \\} , - ".tmp_source.zig:2:15: error: expected ErrorSet type, found 'i32'", + ".tmp_source.zig:2:15: error: expected error set type, found type 'i32'", ); cases.add( @@ -1271,7 +1267,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32' type, found 'anyerror!i32'", + ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'", ".tmp_source.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'", ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set", ); @@ -1286,7 +1282,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return error.B; \\} , - ".tmp_source.zig:3:31: error: expected 'SmallErrorSet' type, found 'anyerror'", + ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'", ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set", ); @@ -1313,7 +1309,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: Set2 = set1; \\} , - ".tmp_source.zig:7:19: error: expected 'Set2' type, found 'Set1'", + ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'", ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set", ); @@ -1853,7 +1849,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() noreturn {return;} \\export fn entry() void { a(); } , - ".tmp_source.zig:1:18: error: expected 'noreturn' type, found 'void'", + ".tmp_source.zig:1:18: error: expected type 'noreturn', found 'void'", ); cases.add( @@ -1861,7 +1857,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn a() i32 {} \\export fn entry() void { _ = a(); } , - ".tmp_source.zig:1:12: error: expected 'i32' type, found 'void'", + ".tmp_source.zig:1:12: error: expected type 'i32', found 'void'", ); cases.add( @@ -1967,7 +1963,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return a; \\} , - ".tmp_source.zig:3:12: error: expected 'i32' type, found '[*]const u8'", + ".tmp_source.zig:3:12: error: expected type 'i32', found '[*]const u8'", ); cases.add( @@ -1976,7 +1972,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (0) {} \\} , - ".tmp_source.zig:2:9: error: expected 'bool' type, found 'comptime_int'", + ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'", ); cases.add( @@ -2071,8 +2067,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ array[bad] = array[bad]; \\} , - ".tmp_source.zig:4:11: error: expected 'usize' type, found 'bool'", - ".tmp_source.zig:4:24: error: expected 'usize' type, found 'bool'", + ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", + ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'", ); cases.add( @@ -2486,7 +2482,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn foo() *const i32 { return y; } \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:3:30: error: expected '*const i32' type, found '*const comptime_int'", + ".tmp_source.zig:3:30: error: expected type '*const i32', found '*const comptime_int'", ); cases.add( @@ -2564,7 +2560,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\fn c() i32 {return 2;} \\export fn entry() usize { return @sizeOf(@typeOf(fns)); } , - ".tmp_source.zig:1:27: error: expected 'fn() void' type, found 'fn() i32'", + ".tmp_source.zig:1:27: error: expected type 'fn() void', found 'fn() i32'", ); cases.add( @@ -2576,7 +2572,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(fns)); } , - ".tmp_source.zig:1:36: error: expected 'fn(i32) i32' type, found 'extern fn(i32) i32'", + ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'", ); cases.add( @@ -2680,7 +2676,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - ".tmp_source.zig:1:16: error: expected '*u8' type, found '(null)'", + ".tmp_source.zig:1:16: error: expected type '*u8', found '(null)'", ); cases.add( @@ -3320,7 +3316,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn something() anyerror!void { } , - ".tmp_source.zig:2:5: error: expected 'void' type, found 'anyerror'", + ".tmp_source.zig:2:5: error: expected type 'void', found 'anyerror'", ".tmp_source.zig:1:15: note: return type declared here", ); @@ -3499,7 +3495,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ derp.init(); \\} , - ".tmp_source.zig:14:5: error: expected 'i32' type, found 'Foo'", + ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'", ); cases.add( @@ -3529,7 +3525,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.init(); \\} , - ".tmp_source.zig:23:5: error: expected '*Allocator' type, found '*List'", + ".tmp_source.zig:23:5: error: expected type '*Allocator', found '*List'", ); cases.add( @@ -3701,7 +3697,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:8:26: error: expected '*const u3' type, found '*align(:3:1) const u3'", + ".tmp_source.zig:8:26: error: expected type '*const u3', found '*align(:3:1) const u3'", ); cases.add( @@ -3830,7 +3826,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(foo)); } , - ".tmp_source.zig:4:19: error: expected '*[]const u8' type, found '*const []const u8'", + ".tmp_source.zig:4:19: error: expected type '*[]const u8', found '*const []const u8'", ); cases.addCase(x: { @@ -3862,7 +3858,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ foo(global_array); \\} , - ".tmp_source.zig:4:9: error: expected '[]i32' type, found '[10]i32'", + ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'", ); cases.add( @@ -3871,7 +3867,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrCast(usize, a); \\} , - ".tmp_source.zig:2:21: error: expected Pointer type, found 'usize'", + ".tmp_source.zig:2:21: error: expected pointer, found 'usize'", ); cases.add( @@ -3918,7 +3914,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:3:28: error: expected Struct type, found 'i32'", + ".tmp_source.zig:3:28: error: expected struct type, found 'i32'", ); cases.add( @@ -3942,7 +3938,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @fieldParentPtr(Foo, "a", a); \\} , - ".tmp_source.zig:5:38: error: expected Pointer type, found 'i32'", + ".tmp_source.zig:5:38: error: expected pointer, found 'i32'", ); cases.add( @@ -3983,7 +3979,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @byteOffsetOf(Foo, "a",); \\} , - ".tmp_source.zig:3:26: error: expected Struct type, found 'i32'", + ".tmp_source.zig:3:26: error: expected struct type, found 'i32'", ); cases.add( @@ -4097,7 +4093,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() ?i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected 'bool' type, found '?i32'", + ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'", ); cases.add( @@ -4107,7 +4103,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn bar() anyerror!i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected 'bool' type, found 'anyerror!i32'", + ".tmp_source.zig:2:15: error: expected type 'bool', found 'anyerror!i32'", ); cases.add( @@ -4368,7 +4364,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return @ptrToInt(x); \\} , - ".tmp_source.zig:2:22: error: expected Pointer type, found 'i32'", + ".tmp_source.zig:2:22: error: expected pointer, found 'i32'", ); cases.add( @@ -4404,7 +4400,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x << y; \\} , - ".tmp_source.zig:2:17: error: expected 'u3' type, found 'u8'", + ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'", ); cases.add( @@ -4433,7 +4429,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ x.* += 1; \\} , - ".tmp_source.zig:8:13: error: expected '*u32' type, found '*align(1) u32'", + ".tmp_source.zig:8:13: error: expected type '*u32', found '*align(1) u32'", ); cases.add( @@ -4477,7 +4473,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @alignCast(4, u32(3)); \\} , - ".tmp_source.zig:2:22: error: expected pointer or slice type, found 'u32'", + ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'", ); cases.add( @@ -4490,7 +4486,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\fn alignedSmall() align(4) i32 { return 1234; } , - ".tmp_source.zig:2:35: error: expected 'fn() align(8) i32' type, found 'fn() align(4) i32'", + ".tmp_source.zig:2:35: error: expected type 'fn() align(8) i32', found 'fn() align(4) i32'", ); cases.add( @@ -4502,7 +4498,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return x == 5678; \\} , - ".tmp_source.zig:4:32: error: expected '*i32' type, found '*align(1) i32'", + ".tmp_source.zig:4:32: error: expected type '*i32', found '*align(1) i32'", ); cases.add( @@ -4537,7 +4533,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ bar(@ptrCast(*c_void, &x)); \\} , - ".tmp_source.zig:5:9: error: expected '*Derp' type, found '*c_void'", + ".tmp_source.zig:5:9: error: expected type '*Derp', found '*c_void'", ); cases.add( @@ -4583,7 +4579,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ while (!@cmpxchgWeak(i32, &x, 1234, 5678, u32(1234), u32(1234))) {} \\} , - ".tmp_source.zig:3:50: error: expected 'AtomicOrder' type, found 'u32'", + ".tmp_source.zig:3:50: error: expected type 'AtomicOrder', found 'u32'", ); cases.add( @@ -4593,7 +4589,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ @export("entry", entry, u32(1234)); \\} , - ".tmp_source.zig:3:32: error: expected 'GlobalLinkage' type, found 'u32'", + ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'", ); cases.add( @@ -4770,7 +4766,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = @ArgType(i32, 3); \\} , - ".tmp_source.zig:2:18: error: expected Fn type, found 'i32'", + ".tmp_source.zig:2:18: error: expected function, found 'i32'", ); cases.add( @@ -4868,7 +4864,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} \\pub extern fn foo(format: *const u8, ...) void; , - ".tmp_source.zig:2:9: error: expected '*const u8' type, found '[5]u8'", + ".tmp_source.zig:2:9: error: expected type '*const u8', found '[5]u8'", ); cases.add( @@ -4937,7 +4933,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x: u2 = Small.Two; \\} , - ".tmp_source.zig:9:22: error: expected 'u2' type, found 'Small'", + ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'", ); cases.add( @@ -4954,7 +4950,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var x = @intToEnum(Small, y); \\} , - ".tmp_source.zig:10:31: error: expected 'u2' type, found 'u3'", + ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'", ); cases.add( @@ -5351,7 +5347,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ asm volatile ("" : : [bar]"r"(3) : ""); \\} , - ".tmp_source.zig:2:35: error: expected sized integer or sized float type, found comptime_int", + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", ); cases.add( @@ -5360,6 +5356,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ asm volatile ("" : : [bar]"r"(3.17) : ""); \\} , - ".tmp_source.zig:2:35: error: expected sized integer or sized float type, found comptime_float", + ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", ); } -- cgit v1.2.3 From 581edd643fb18a66c472f77e2f8cd3f4cea524a2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 29 Jan 2019 21:47:26 -0500 Subject: backport copy elision changes This commit contains everything from the copy-elision-2 branch that does not have to do with copy elision directly, but is generally useful for master branch. * All const values know their parents, when applicable, not just structs and unions. * Null pointers in const values are represented explicitly, rather than as a HardCodedAddr value of 0. * Rename "maybe" to "optional" in various code locations. * Separate DeclVarSrc and DeclVarGen * Separate PtrCastSrc and PtrCastGen * Separate CmpxchgSrc and CmpxchgGen * Represent optional error set as an integer, using the 0 value. In a const value, it uses nullptr. * Introduce type_has_one_possible_value and use it where applicable. * Fix debug builds not setting memory to 0xaa when storing undefined. * Separate the type of a variable from the const value of a variable. * Use copy_const_val where appropriate. * Rearrange structs to pack data more efficiently. * Move test/cases/* to test/behavior/* * Use `std.debug.assertOrPanic` in behavior tests instead of `std.debug.assert`. * Fix outdated slice syntax in docs. --- build.zig | 5 +- doc/langref.html.in | 13 +- src/all_types.hpp | 165 ++- src/analyze.cpp | 297 ++-- src/analyze.hpp | 9 +- src/ast_render.cpp | 8 +- src/codegen.cpp | 385 +++-- src/ir.cpp | 1471 +++++++++++--------- src/ir.hpp | 2 +- src/ir_print.cpp | 83 +- src/parser.cpp | 8 +- std/event/fs.zig | 49 +- test/behavior.zig | 82 -- test/cases/align.zig | 230 --- test/cases/alignof.zig | 17 - test/cases/array.zig | 173 --- test/cases/asm.zig | 48 - test/cases/atomics.zig | 71 - test/cases/bit_shifting.zig | 88 -- test/cases/bitcast.zig | 37 - test/cases/bitreverse.zig | 81 -- test/cases/bool.zig | 35 - test/cases/bswap.zig | 32 - test/cases/bugs/1076.zig | 16 - test/cases/bugs/1111.zig | 12 - test/cases/bugs/1277.zig | 15 - test/cases/bugs/1322.zig | 19 - test/cases/bugs/1381.zig | 21 - test/cases/bugs/1421.zig | 14 - test/cases/bugs/1442.zig | 11 - test/cases/bugs/1486.zig | 11 - test/cases/bugs/394.zig | 18 - test/cases/bugs/655.zig | 12 - test/cases/bugs/655_other_file.zig | 1 - test/cases/bugs/656.zig | 31 - test/cases/bugs/726.zig | 16 - test/cases/bugs/828.zig | 33 - test/cases/bugs/920.zig | 65 - test/cases/byval_arg_var.zig | 27 - test/cases/cancel.zig | 92 -- test/cases/cast.zig | 472 ------- test/cases/const_slice_child.zig | 45 - test/cases/coroutine_await_struct.zig | 47 - test/cases/coroutines.zig | 258 ---- test/cases/defer.zig | 78 -- test/cases/enum.zig | 894 ------------ test/cases/enum_with_members.zig | 27 - test/cases/error.zig | 245 ---- test/cases/eval.zig | 782 ----------- test/cases/field_parent_ptr.zig | 41 - test/cases/fn.zig | 207 --- test/cases/fn_in_struct_in_comptime.zig | 17 - test/cases/for.zig | 106 -- test/cases/generics.zig | 151 -- test/cases/if.zig | 37 - test/cases/import.zig | 10 - test/cases/import/a_namespace.zig | 3 - test/cases/incomplete_struct_param_tld.zig | 30 - test/cases/inttoptr.zig | 27 - test/cases/ir_block_deps.zig | 21 - test/cases/math.zig | 500 ------- test/cases/merge_error_sets.zig | 21 - test/cases/misc.zig | 681 --------- test/cases/namespace_depends_on_compile_var/a.zig | 1 - test/cases/namespace_depends_on_compile_var/b.zig | 1 - .../namespace_depends_on_compile_var/index.zig | 14 - test/cases/new_stack_call.zig | 26 - test/cases/null.zig | 162 --- test/cases/optional.zig | 30 - test/cases/pointers.zig | 44 - test/cases/popcount.zig | 24 - test/cases/ptrcast.zig | 52 - test/cases/pub_enum/index.zig | 13 - test/cases/pub_enum/other.zig | 6 - .../ref_var_in_if_after_if_2nd_switch_prong.zig | 37 - test/cases/reflection.zig | 95 -- test/cases/sizeof_and_typeof.zig | 69 - test/cases/slice.zig | 40 - test/cases/struct.zig | 470 ------- test/cases/struct_contains_null_ptr_itself.zig | 21 - test/cases/struct_contains_slice_of_itself.zig | 85 -- test/cases/switch.zig | 271 ---- test/cases/switch_prong_err_enum.zig | 30 - test/cases/switch_prong_implicit_cast.zig | 22 - test/cases/syntax.zig | 59 - test/cases/this.zig | 34 - test/cases/truncate.zig | 8 - test/cases/try.zig | 43 - test/cases/type_info.zig | 264 ---- test/cases/undefined.zig | 68 - test/cases/underscore.zig | 28 - test/cases/union.zig | 352 ----- test/cases/var_args.zig | 84 -- test/cases/void.zig | 30 - test/cases/while.zig | 227 --- test/cases/widening.zig | 27 - test/compile_errors.zig | 4 +- test/stage1/behavior.zig | 80 ++ test/stage1/behavior/align.zig | 230 +++ test/stage1/behavior/alignof.zig | 18 + test/stage1/behavior/array.zig | 270 ++++ test/stage1/behavior/asm.zig | 92 ++ test/stage1/behavior/atomics.zig | 71 + test/stage1/behavior/bit_shifting.zig | 88 ++ test/stage1/behavior/bitcast.zig | 36 + test/stage1/behavior/bitreverse.zig | 81 ++ test/stage1/behavior/bool.zig | 35 + test/stage1/behavior/bswap.zig | 32 + test/stage1/behavior/bugs/1076.zig | 16 + test/stage1/behavior/bugs/1111.zig | 12 + test/stage1/behavior/bugs/1277.zig | 15 + test/stage1/behavior/bugs/1322.zig | 19 + test/stage1/behavior/bugs/1381.zig | 21 + test/stage1/behavior/bugs/1421.zig | 14 + test/stage1/behavior/bugs/1442.zig | 11 + test/stage1/behavior/bugs/1486.zig | 11 + test/stage1/behavior/bugs/394.zig | 18 + test/stage1/behavior/bugs/655.zig | 12 + test/stage1/behavior/bugs/655_other_file.zig | 1 + test/stage1/behavior/bugs/656.zig | 31 + test/stage1/behavior/bugs/726.zig | 16 + test/stage1/behavior/bugs/828.zig | 33 + test/stage1/behavior/bugs/920.zig | 65 + test/stage1/behavior/byval_arg_var.zig | 27 + test/stage1/behavior/cancel.zig | 92 ++ test/stage1/behavior/cast.zig | 473 +++++++ test/stage1/behavior/const_slice_child.zig | 45 + test/stage1/behavior/coroutine_await_struct.zig | 47 + test/stage1/behavior/coroutines.zig | 258 ++++ test/stage1/behavior/defer.zig | 78 ++ test/stage1/behavior/enum.zig | 894 ++++++++++++ test/stage1/behavior/enum_with_members.zig | 27 + test/stage1/behavior/error.zig | 332 +++++ test/stage1/behavior/eval.zig | 784 +++++++++++ test/stage1/behavior/field_parent_ptr.zig | 41 + test/stage1/behavior/fn.zig | 208 +++ test/stage1/behavior/fn_in_struct_in_comptime.zig | 17 + test/stage1/behavior/for.zig | 106 ++ test/stage1/behavior/generics.zig | 151 ++ test/stage1/behavior/if.zig | 37 + test/stage1/behavior/import.zig | 10 + test/stage1/behavior/import/a_namespace.zig | 3 + .../behavior/incomplete_struct_param_tld.zig | 30 + test/stage1/behavior/inttoptr.zig | 26 + test/stage1/behavior/ir_block_deps.zig | 21 + test/stage1/behavior/math.zig | 500 +++++++ test/stage1/behavior/merge_error_sets.zig | 21 + test/stage1/behavior/misc.zig | 687 +++++++++ .../namespace_depends_on_compile_var/a.zig | 1 + .../namespace_depends_on_compile_var/b.zig | 1 + .../namespace_depends_on_compile_var/index.zig | 14 + test/stage1/behavior/new_stack_call.zig | 26 + test/stage1/behavior/null.zig | 162 +++ test/stage1/behavior/optional.zig | 81 ++ test/stage1/behavior/pointers.zig | 44 + test/stage1/behavior/popcount.zig | 25 + test/stage1/behavior/ptrcast.zig | 52 + test/stage1/behavior/pub_enum/index.zig | 13 + test/stage1/behavior/pub_enum/other.zig | 6 + .../ref_var_in_if_after_if_2nd_switch_prong.zig | 37 + test/stage1/behavior/reflection.zig | 96 ++ test/stage1/behavior/sizeof_and_typeof.zig | 69 + test/stage1/behavior/slice.zig | 40 + test/stage1/behavior/struct.zig | 470 +++++++ .../behavior/struct_contains_null_ptr_itself.zig | 21 + .../behavior/struct_contains_slice_of_itself.zig | 85 ++ test/stage1/behavior/switch.zig | 271 ++++ test/stage1/behavior/switch_prong_err_enum.zig | 30 + .../stage1/behavior/switch_prong_implicit_cast.zig | 22 + test/stage1/behavior/syntax.zig | 60 + test/stage1/behavior/this.zig | 35 + test/stage1/behavior/truncate.zig | 8 + test/stage1/behavior/try.zig | 43 + test/stage1/behavior/type_info.zig | 264 ++++ test/stage1/behavior/undefined.zig | 69 + test/stage1/behavior/underscore.zig | 28 + test/stage1/behavior/union.zig | 352 +++++ test/stage1/behavior/var_args.zig | 84 ++ test/stage1/behavior/void.zig | 35 + test/stage1/behavior/while.zig | 228 +++ test/stage1/behavior/widening.zig | 28 + 181 files changed, 10595 insertions(+), 9692 deletions(-) delete mode 100644 test/behavior.zig delete mode 100644 test/cases/align.zig delete mode 100644 test/cases/alignof.zig delete mode 100644 test/cases/array.zig delete mode 100644 test/cases/asm.zig delete mode 100644 test/cases/atomics.zig delete mode 100644 test/cases/bit_shifting.zig delete mode 100644 test/cases/bitcast.zig delete mode 100644 test/cases/bitreverse.zig delete mode 100644 test/cases/bool.zig delete mode 100644 test/cases/bswap.zig delete mode 100644 test/cases/bugs/1076.zig delete mode 100644 test/cases/bugs/1111.zig delete mode 100644 test/cases/bugs/1277.zig delete mode 100644 test/cases/bugs/1322.zig delete mode 100644 test/cases/bugs/1381.zig delete mode 100644 test/cases/bugs/1421.zig delete mode 100644 test/cases/bugs/1442.zig delete mode 100644 test/cases/bugs/1486.zig delete mode 100644 test/cases/bugs/394.zig delete mode 100644 test/cases/bugs/655.zig delete mode 100644 test/cases/bugs/655_other_file.zig delete mode 100644 test/cases/bugs/656.zig delete mode 100644 test/cases/bugs/726.zig delete mode 100644 test/cases/bugs/828.zig delete mode 100644 test/cases/bugs/920.zig delete mode 100644 test/cases/byval_arg_var.zig delete mode 100644 test/cases/cancel.zig delete mode 100644 test/cases/cast.zig delete mode 100644 test/cases/const_slice_child.zig delete mode 100644 test/cases/coroutine_await_struct.zig delete mode 100644 test/cases/coroutines.zig delete mode 100644 test/cases/defer.zig delete mode 100644 test/cases/enum.zig delete mode 100644 test/cases/enum_with_members.zig delete mode 100644 test/cases/error.zig delete mode 100644 test/cases/eval.zig delete mode 100644 test/cases/field_parent_ptr.zig delete mode 100644 test/cases/fn.zig delete mode 100644 test/cases/fn_in_struct_in_comptime.zig delete mode 100644 test/cases/for.zig delete mode 100644 test/cases/generics.zig delete mode 100644 test/cases/if.zig delete mode 100644 test/cases/import.zig delete mode 100644 test/cases/import/a_namespace.zig delete mode 100644 test/cases/incomplete_struct_param_tld.zig delete mode 100644 test/cases/inttoptr.zig delete mode 100644 test/cases/ir_block_deps.zig delete mode 100644 test/cases/math.zig delete mode 100644 test/cases/merge_error_sets.zig delete mode 100644 test/cases/misc.zig delete mode 100644 test/cases/namespace_depends_on_compile_var/a.zig delete mode 100644 test/cases/namespace_depends_on_compile_var/b.zig delete mode 100644 test/cases/namespace_depends_on_compile_var/index.zig delete mode 100644 test/cases/new_stack_call.zig delete mode 100644 test/cases/null.zig delete mode 100644 test/cases/optional.zig delete mode 100644 test/cases/pointers.zig delete mode 100644 test/cases/popcount.zig delete mode 100644 test/cases/ptrcast.zig delete mode 100644 test/cases/pub_enum/index.zig delete mode 100644 test/cases/pub_enum/other.zig delete mode 100644 test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig delete mode 100644 test/cases/reflection.zig delete mode 100644 test/cases/sizeof_and_typeof.zig delete mode 100644 test/cases/slice.zig delete mode 100644 test/cases/struct.zig delete mode 100644 test/cases/struct_contains_null_ptr_itself.zig delete mode 100644 test/cases/struct_contains_slice_of_itself.zig delete mode 100644 test/cases/switch.zig delete mode 100644 test/cases/switch_prong_err_enum.zig delete mode 100644 test/cases/switch_prong_implicit_cast.zig delete mode 100644 test/cases/syntax.zig delete mode 100644 test/cases/this.zig delete mode 100644 test/cases/truncate.zig delete mode 100644 test/cases/try.zig delete mode 100644 test/cases/type_info.zig delete mode 100644 test/cases/undefined.zig delete mode 100644 test/cases/underscore.zig delete mode 100644 test/cases/union.zig delete mode 100644 test/cases/var_args.zig delete mode 100644 test/cases/void.zig delete mode 100644 test/cases/while.zig delete mode 100644 test/cases/widening.zig create mode 100644 test/stage1/behavior.zig create mode 100644 test/stage1/behavior/align.zig create mode 100644 test/stage1/behavior/alignof.zig create mode 100644 test/stage1/behavior/array.zig create mode 100644 test/stage1/behavior/asm.zig create mode 100644 test/stage1/behavior/atomics.zig create mode 100644 test/stage1/behavior/bit_shifting.zig create mode 100644 test/stage1/behavior/bitcast.zig create mode 100644 test/stage1/behavior/bitreverse.zig create mode 100644 test/stage1/behavior/bool.zig create mode 100644 test/stage1/behavior/bswap.zig create mode 100644 test/stage1/behavior/bugs/1076.zig create mode 100644 test/stage1/behavior/bugs/1111.zig create mode 100644 test/stage1/behavior/bugs/1277.zig create mode 100644 test/stage1/behavior/bugs/1322.zig create mode 100644 test/stage1/behavior/bugs/1381.zig create mode 100644 test/stage1/behavior/bugs/1421.zig create mode 100644 test/stage1/behavior/bugs/1442.zig create mode 100644 test/stage1/behavior/bugs/1486.zig create mode 100644 test/stage1/behavior/bugs/394.zig create mode 100644 test/stage1/behavior/bugs/655.zig create mode 100644 test/stage1/behavior/bugs/655_other_file.zig create mode 100644 test/stage1/behavior/bugs/656.zig create mode 100644 test/stage1/behavior/bugs/726.zig create mode 100644 test/stage1/behavior/bugs/828.zig create mode 100644 test/stage1/behavior/bugs/920.zig create mode 100644 test/stage1/behavior/byval_arg_var.zig create mode 100644 test/stage1/behavior/cancel.zig create mode 100644 test/stage1/behavior/cast.zig create mode 100644 test/stage1/behavior/const_slice_child.zig create mode 100644 test/stage1/behavior/coroutine_await_struct.zig create mode 100644 test/stage1/behavior/coroutines.zig create mode 100644 test/stage1/behavior/defer.zig create mode 100644 test/stage1/behavior/enum.zig create mode 100644 test/stage1/behavior/enum_with_members.zig create mode 100644 test/stage1/behavior/error.zig create mode 100644 test/stage1/behavior/eval.zig create mode 100644 test/stage1/behavior/field_parent_ptr.zig create mode 100644 test/stage1/behavior/fn.zig create mode 100644 test/stage1/behavior/fn_in_struct_in_comptime.zig create mode 100644 test/stage1/behavior/for.zig create mode 100644 test/stage1/behavior/generics.zig create mode 100644 test/stage1/behavior/if.zig create mode 100644 test/stage1/behavior/import.zig create mode 100644 test/stage1/behavior/import/a_namespace.zig create mode 100644 test/stage1/behavior/incomplete_struct_param_tld.zig create mode 100644 test/stage1/behavior/inttoptr.zig create mode 100644 test/stage1/behavior/ir_block_deps.zig create mode 100644 test/stage1/behavior/math.zig create mode 100644 test/stage1/behavior/merge_error_sets.zig create mode 100644 test/stage1/behavior/misc.zig create mode 100644 test/stage1/behavior/namespace_depends_on_compile_var/a.zig create mode 100644 test/stage1/behavior/namespace_depends_on_compile_var/b.zig create mode 100644 test/stage1/behavior/namespace_depends_on_compile_var/index.zig create mode 100644 test/stage1/behavior/new_stack_call.zig create mode 100644 test/stage1/behavior/null.zig create mode 100644 test/stage1/behavior/optional.zig create mode 100644 test/stage1/behavior/pointers.zig create mode 100644 test/stage1/behavior/popcount.zig create mode 100644 test/stage1/behavior/ptrcast.zig create mode 100644 test/stage1/behavior/pub_enum/index.zig create mode 100644 test/stage1/behavior/pub_enum/other.zig create mode 100644 test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig create mode 100644 test/stage1/behavior/reflection.zig create mode 100644 test/stage1/behavior/sizeof_and_typeof.zig create mode 100644 test/stage1/behavior/slice.zig create mode 100644 test/stage1/behavior/struct.zig create mode 100644 test/stage1/behavior/struct_contains_null_ptr_itself.zig create mode 100644 test/stage1/behavior/struct_contains_slice_of_itself.zig create mode 100644 test/stage1/behavior/switch.zig create mode 100644 test/stage1/behavior/switch_prong_err_enum.zig create mode 100644 test/stage1/behavior/switch_prong_implicit_cast.zig create mode 100644 test/stage1/behavior/syntax.zig create mode 100644 test/stage1/behavior/this.zig create mode 100644 test/stage1/behavior/truncate.zig create mode 100644 test/stage1/behavior/try.zig create mode 100644 test/stage1/behavior/type_info.zig create mode 100644 test/stage1/behavior/undefined.zig create mode 100644 test/stage1/behavior/underscore.zig create mode 100644 test/stage1/behavior/union.zig create mode 100644 test/stage1/behavior/var_args.zig create mode 100644 test/stage1/behavior/void.zig create mode 100644 test/stage1/behavior/while.zig create mode 100644 test/stage1/behavior/widening.zig (limited to 'src/ir.cpp') diff --git a/build.zig b/build.zig index 16185eebf4..d99165a6de 100644 --- a/build.zig +++ b/build.zig @@ -104,7 +104,7 @@ pub fn build(b: *Builder) !void { } const modes = chosen_modes[0..chosen_mode_index]; - test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", modes)); + test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes)); test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes)); @@ -299,8 +299,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { } else if (exe.target.isFreeBSD()) { try addCxxKnownPath(b, ctx, exe, "libc++.a", null); exe.linkSystemLibrary("pthread"); - } - else if (exe.target.isDarwin()) { + } else if (exe.target.isDarwin()) { if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) { // Compiler is GCC. try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null); diff --git a/doc/langref.html.in b/doc/langref.html.in index 6e03d3ec6d..909c0f5817 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4327,7 +4327,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {

For example, if we were to introduce another function to the above snippet:

- {#code_begin|test_err|unable to evaluate constant expression#} + {#code_begin|test_err|values of type 'type' must be comptime known#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } @@ -5905,13 +5905,13 @@ fn add(a: i32, b: i32) i32 { return a + b; } This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:

-
{#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
+
{#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}

The optimizer is intelligent enough to turn the above snippet into a memcpy.

There is also a standard library function for this:

{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#} {#header_close#} {#header_open|@memset#} @@ -5923,7 +5923,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#} This function is a low level intrinsic with no safety mechanisms. Most code should not use this function, instead using something like this:

-
{#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
+
{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}

The optimizer is intelligent enough to turn the above snippet into a memset.

@@ -6592,9 +6592,10 @@ pub const TypeInfo = union(TypeId) { {#header_close#} {#header_open|@typeName#} -
{#syntax#}@typeName(T: type) []u8{#endsyntax#}
+
{#syntax#}@typeName(T: type) [N]u8{#endsyntax#}

- This function returns the string representation of a type. + This function returns the string representation of a type, as + an array. It is equivalent to a string literal of the type name.

{#header_close#} diff --git a/src/all_types.hpp b/src/all_types.hpp index 91b24e3110..4b134361a3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -56,9 +56,6 @@ struct IrExecutable { size_t next_debug_id; size_t *backward_branch_count; size_t backward_branch_quota; - bool invalid; - bool is_inline; - bool is_generic_instantiation; ZigFn *fn_entry; Buf *c_import_buf; AstNode *source_node; @@ -78,6 +75,10 @@ struct IrExecutable { IrBasicBlock *coro_suspend_block; IrBasicBlock *coro_final_cleanup_block; ZigVar *coro_allocator_var; + + bool invalid; + bool is_inline; + bool is_generic_instantiation; }; enum OutType { @@ -90,6 +91,9 @@ enum OutType { enum ConstParentId { ConstParentIdNone, ConstParentIdStruct, + ConstParentIdErrUnionCode, + ConstParentIdErrUnionPayload, + ConstParentIdOptionalPayload, ConstParentIdArray, ConstParentIdUnion, ConstParentIdScalar, @@ -107,6 +111,15 @@ struct ConstParent { ConstExprValue *struct_val; size_t field_index; } p_struct; + struct { + ConstExprValue *err_union_val; + } p_err_union_code; + struct { + ConstExprValue *err_union_val; + } p_err_union_payload; + struct { + ConstExprValue *optional_val; + } p_optional_payload; struct { ConstExprValue *union_val; } p_union; @@ -118,13 +131,11 @@ struct ConstParent { struct ConstStructValue { ConstExprValue *fields; - ConstParent parent; }; struct ConstUnionValue { BigInt tag; ConstExprValue *payload; - ConstParent parent; }; enum ConstArraySpecial { @@ -138,7 +149,6 @@ struct ConstArrayValue { union { struct { ConstExprValue *elements; - ConstParent parent; } s_none; Buf *s_buf; } data; @@ -153,19 +163,29 @@ enum ConstPtrSpecial { ConstPtrSpecialBaseArray, // The pointer points to a field in an underlying struct. ConstPtrSpecialBaseStruct, + // The pointer points to the error set field of an error union + ConstPtrSpecialBaseErrorUnionCode, + // The pointer points to the payload field of an error union + ConstPtrSpecialBaseErrorUnionPayload, + // The pointer points to the payload field of an optional + ConstPtrSpecialBaseOptionalPayload, // This means that we did a compile-time pointer reinterpret and we cannot // understand the value of pointee at compile time. However, we will still // emit a binary with a compile time known address. // In this case index is the numeric address value. - // We also use this for null pointer. We need the data layout for ConstCastOnly == true - // types to be the same, so all optionals of pointer types use x_ptr - // instead of x_optional ConstPtrSpecialHardCodedAddr, // This means that the pointer represents memory of assigning to _. // That is, storing discards the data, and loading is invalid. ConstPtrSpecialDiscard, // This is actually a function. ConstPtrSpecialFunction, + // This means the pointer is null. This is only allowed when the type is ?*T. + // We use this instead of ConstPtrSpecialHardCodedAddr because often we check + // for that value to avoid doing comptime work. + // We need the data layout for ConstCastOnly == true + // types to be the same, so all optionals of pointer types use x_ptr + // instead of x_optional. + ConstPtrSpecialNull, }; enum ConstPtrMut { @@ -199,6 +219,15 @@ struct ConstPtrValue { ConstExprValue *struct_val; size_t field_index; } base_struct; + struct { + ConstExprValue *err_union_val; + } base_err_union_code; + struct { + ConstExprValue *err_union_val; + } base_err_union_payload; + struct { + ConstExprValue *optional_val; + } base_optional_payload; struct { uint64_t addr; } hard_coded_addr; @@ -209,7 +238,7 @@ struct ConstPtrValue { }; struct ConstErrValue { - ErrorTableEntry *err; + ConstExprValue *error_set; ConstExprValue *payload; }; @@ -265,6 +294,7 @@ struct ConstGlobalRefs { struct ConstExprValue { ZigType *type; ConstValSpecial special; + ConstParent parent; ConstGlobalRefs *global_refs; union { @@ -433,7 +463,7 @@ enum NodeType { NodeTypeArrayType, NodeTypeErrorType, NodeTypeIfErrorExpr, - NodeTypeTestExpr, + NodeTypeIfOptional, NodeTypeErrorSetDecl, NodeTypeCancel, NodeTypeResume, @@ -677,7 +707,7 @@ struct AstNodeUse { AstNode *expr; TldResolution resolution; - IrInstruction *value; + ConstExprValue *value; }; struct AstNodeIfBoolExpr { @@ -1610,7 +1640,7 @@ struct CodeGen { HashMap fn_type_table; HashMap error_table; HashMap generic_table; - HashMap memoized_fn_eval_table; + HashMap memoized_fn_eval_table; HashMap llvm_fn_table; HashMap exported_symbol_names; HashMap external_prototypes; @@ -1802,10 +1832,9 @@ enum VarLinkage { struct ZigVar { Buf name; - ConstExprValue *value; + ConstExprValue *const_value; + ZigType *var_type; LLVMValueRef value_ref; - bool src_is_const; - bool gen_is_const; IrInstruction *is_comptime; // which node is the declaration of the variable AstNode *decl_node; @@ -1815,17 +1844,21 @@ struct ZigVar { Scope *parent_scope; Scope *child_scope; LLVMValueRef param_value_ref; - bool shadowable; size_t mem_slot_index; IrExecutable *owner_exec; size_t ref_count; - VarLinkage linkage; - uint32_t align_bytes; // In an inline loop, multiple variables may be created, // In this case, a reference to a variable should follow // this pointer to the redefined variable. ZigVar *next_var; + + uint32_t align_bytes; + VarLinkage linkage; + + bool shadowable; + bool src_is_const; + bool gen_is_const; }; struct ErrorTableEntry { @@ -1891,10 +1924,11 @@ struct ScopeBlock { ZigList *incoming_values; ZigList *incoming_blocks; - bool safety_off; AstNode *safety_set_node; - bool fast_math_on; AstNode *fast_math_set_node; + + bool safety_off; + bool fast_math_on; }; // This scope is created from every defer expression. @@ -2030,8 +2064,19 @@ struct IrBasicBlock { IrInstruction *must_be_comptime_source_instr; }; +// These instructions are in transition to having "pass 1" instructions +// and "pass 2" instructions. The pass 1 instructions are suffixed with Src +// and pass 2 are suffixed with Gen. +// Once all instructions are separated in this way, they'll have different +// base types for better type safety. +// Src instructions are generated by ir_gen_* functions in ir.cpp from AST. +// ir_analyze_* functions consume Src instructions and produce Gen instructions. +// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR. +// Src instructions do not have type information; Gen instructions do. enum IrInstructionId { IrInstructionIdInvalid, + IrInstructionIdDeclVarSrc, + IrInstructionIdDeclVarGen, IrInstructionIdBr, IrInstructionIdCondBr, IrInstructionIdSwitchBr, @@ -2040,7 +2085,6 @@ enum IrInstructionId { IrInstructionIdPhi, IrInstructionIdUnOp, IrInstructionIdBinOp, - IrInstructionIdDeclVar, IrInstructionIdLoadPtr, IrInstructionIdStorePtr, IrInstructionIdFieldPtr, @@ -2069,7 +2113,7 @@ enum IrInstructionId { IrInstructionIdAsm, IrInstructionIdSizeOf, IrInstructionIdTestNonNull, - IrInstructionIdUnwrapOptional, + IrInstructionIdOptionalUnwrapPtr, IrInstructionIdOptionalWrap, IrInstructionIdUnionTag, IrInstructionIdClz, @@ -2085,7 +2129,8 @@ enum IrInstructionId { IrInstructionIdCompileLog, IrInstructionIdErrName, IrInstructionIdEmbedFile, - IrInstructionIdCmpxchg, + IrInstructionIdCmpxchgSrc, + IrInstructionIdCmpxchgGen, IrInstructionIdFence, IrInstructionIdTruncate, IrInstructionIdIntCast, @@ -2114,7 +2159,8 @@ enum IrInstructionId { IrInstructionIdErrWrapPayload, IrInstructionIdFnProto, IrInstructionIdTestComptime, - IrInstructionIdPtrCast, + IrInstructionIdPtrCastSrc, + IrInstructionIdPtrCastGen, IrInstructionIdBitCast, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -2194,6 +2240,22 @@ struct IrInstruction { bool is_gen; }; +struct IrInstructionDeclVarSrc { + IrInstruction base; + + ZigVar *var; + IrInstruction *var_type; + IrInstruction *align_value; + IrInstruction *init_value; +}; + +struct IrInstructionDeclVarGen { + IrInstruction base; + + ZigVar *var; + IrInstruction *init_value; +}; + struct IrInstructionCondBr { IrInstruction base; @@ -2302,20 +2364,11 @@ struct IrInstructionBinOp { IrInstruction base; IrInstruction *op1; - IrBinOp op_id; IrInstruction *op2; + IrBinOp op_id; bool safety_check_on; }; -struct IrInstructionDeclVar { - IrInstruction base; - - ZigVar *var; - IrInstruction *var_type; - IrInstruction *align_value; - IrInstruction *init_value; -}; - struct IrInstructionLoadPtr { IrInstruction base; @@ -2335,7 +2388,6 @@ struct IrInstructionFieldPtr { IrInstruction *container_ptr; Buf *field_name_buffer; IrInstruction *field_name_expr; - bool is_const; }; struct IrInstructionStructFieldPtr { @@ -2378,13 +2430,13 @@ struct IrInstructionCall { ZigFn *fn_entry; size_t arg_count; IrInstruction **args; - bool is_comptime; LLVMValueRef tmp_ptr; - FnInline fn_inline; - bool is_async; IrInstruction *async_allocator; IrInstruction *new_stack; + FnInline fn_inline; + bool is_async; + bool is_comptime; }; struct IrInstructionConst { @@ -2527,9 +2579,9 @@ struct IrInstructionSliceType { IrInstruction base; IrInstruction *align_value; + IrInstruction *child_type; bool is_const; bool is_volatile; - IrInstruction *child_type; }; struct IrInstructionAsm { @@ -2557,10 +2609,12 @@ struct IrInstructionTestNonNull { IrInstruction *value; }; -struct IrInstructionUnwrapOptional { +// Takes a pointer to an optional value, returns a pointer +// to the payload. +struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *value; + IrInstruction *base_ptr; bool safety_check_on; }; @@ -2651,7 +2705,7 @@ struct IrInstructionEmbedFile { IrInstruction *name; }; -struct IrInstructionCmpxchg { +struct IrInstructionCmpxchgSrc { IrInstruction base; IrInstruction *type_value; @@ -2661,14 +2715,19 @@ struct IrInstructionCmpxchg { IrInstruction *success_order_value; IrInstruction *failure_order_value; - // if this instruction gets to runtime then we know these values: - ZigType *type; - AtomicOrder success_order; - AtomicOrder failure_order; - bool is_weak; +}; +struct IrInstructionCmpxchgGen { + IrInstruction base; + + IrInstruction *ptr; + IrInstruction *cmp_value; + IrInstruction *new_value; LLVMValueRef tmp_ptr; + AtomicOrder success_order; + AtomicOrder failure_order; + bool is_weak; }; struct IrInstructionFence { @@ -2851,7 +2910,7 @@ struct IrInstructionTestErr { struct IrInstructionUnwrapErrCode { IrInstruction base; - IrInstruction *value; + IrInstruction *err_union; }; struct IrInstructionUnwrapErrPayload { @@ -2899,13 +2958,19 @@ struct IrInstructionTestComptime { IrInstruction *value; }; -struct IrInstructionPtrCast { +struct IrInstructionPtrCastSrc { IrInstruction base; IrInstruction *dest_type; IrInstruction *ptr; }; +struct IrInstructionPtrCastGen { + IrInstruction base; + + IrInstruction *ptr; +}; + struct IrInstructionBitCast { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 15370983fc..194888068c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -570,7 +570,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { if (child_type->zero_bits) { entry->type_ref = LLVMInt1Type(); entry->di_type = g->builtin_types.entry_bool->di_type; - } else if (type_is_codegen_pointer(child_type)) { + } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { assert(child_type->di_type); // this is an optimization but also is necessary for calling C // functions where all pointers are maybe pointers @@ -1278,7 +1278,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { +static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name) +{ size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, @@ -1286,12 +1288,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); + if (type_is_invalid(result->type)) return g->builtin_types.entry_invalid; - assert(result->value.special != ConstValSpecialRuntime); - return result->value.data.x_type; + assert(result->special != ConstValSpecialRuntime); + return result->data.x_type; } ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { @@ -1342,11 +1344,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou } static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); - if (type_is_invalid(align_result->value.type)) + ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); + if (type_is_invalid(align_result->type)) return false; - uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); + uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint); if (align_bytes == 0) { add_node_error(g, node, buf_sprintf("alignment must be >= 1")); return false; @@ -1364,12 +1366,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(g, ptr_type); - IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); - if (type_is_invalid(instr->value.type)) + ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); + if (type_is_invalid(result_val->type)) return false; - ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; - ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; + ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index]; assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; @@ -2504,20 +2506,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { // In this first pass we resolve explicit tag values. // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { enum_type->data.enumeration.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt || - result_inst->value.type->id == ZigTypeIdComptimeInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt || + result->type->id == ZigTypeIdComptimeInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -2944,19 +2946,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { union_type->data.unionation.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -3419,7 +3421,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { resolve_top_level_decl(g, tld, false, tld->source_node); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - tld_var->var->value = value; + tld_var->var->const_value = value; + tld_var->var->var_type = value->type; tld_var->var->align_bytes = get_abi_alignment(g, value->type); } @@ -3513,7 +3516,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeArrayType: case NodeTypeErrorType: case NodeTypeIfErrorExpr: - case NodeTypeTestExpr: + case NodeTypeIfOptional: case NodeTypeErrorSetDecl: case NodeTypeCancel: case NodeTypeResume: @@ -3582,13 +3585,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry // Set name to nullptr to make the variable anonymous (not visible to programmer). // TODO merge with definition of add_local_var in ir.cpp ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ConstExprValue *value, Tld *src_tld) + bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type) { Error err; - assert(value); + assert(const_value != nullptr); + assert(var_type != nullptr); ZigVar *variable_entry = allocate(1); - variable_entry->value = value; + variable_entry->const_value = const_value; + variable_entry->var_type = var_type; variable_entry->parent_scope = parent_scope; variable_entry->shadowable = false; variable_entry->mem_slot_index = SIZE_MAX; @@ -3597,23 +3602,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf assert(name); buf_init_from_buf(&variable_entry->name, name); - if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) { - variable_entry->value->type = g->builtin_types.entry_invalid; + if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { + variable_entry->var_type = g->builtin_types.entry_invalid; } else { - variable_entry->align_bytes = get_abi_alignment(g, value->type); + variable_entry->align_bytes = get_abi_alignment(g, var_type); ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); if (existing_var && !existing_var->shadowable) { ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { ZigType *type; if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { add_node_error(g, source_node, buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { Scope *search_scope = nullptr; if (src_tld == nullptr) { @@ -3627,7 +3632,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } } } @@ -3677,7 +3682,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { linkage = VarLinkageInternal; } - IrInstruction *init_value = nullptr; + ConstExprValue *init_value = nullptr; // TODO more validation for types that can't be used for export/extern variables ZigType *implicit_type = nullptr; @@ -3686,7 +3691,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } else if (var_decl->expr) { init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); assert(init_value); - implicit_type = init_value->value.type; + implicit_type = init_value->type; if (implicit_type->id == ZigTypeIdUnreachable) { add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); @@ -3704,7 +3709,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); implicit_type = g->builtin_types.entry_invalid; } - assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime); + assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); } else if (linkage != VarLinkageExternal) { add_node_error(g, source_node, buf_sprintf("variables must be initialized")); implicit_type = g->builtin_types.entry_invalid; @@ -3713,19 +3718,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { ZigType *type = explicit_type ? explicit_type : implicit_type; assert(type != nullptr); // should have been caught by the parser - ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type); + ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type); tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, - is_const, init_val, &tld_var->base); + is_const, init_val, &tld_var->base, type); tld_var->var->linkage = linkage; if (implicit_type != nullptr && type_is_invalid(implicit_type)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } if (var_decl->align_expr != nullptr) { if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } } @@ -4090,7 +4095,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { } ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_name, true, create_const_runtime(param_type), nullptr); + param_name, true, create_const_runtime(param_type), nullptr, param_type); var->src_arg_index = i; fn_table_entry->child_scope = var->child_scope; var->shadowable = var->shadowable || is_var_args; @@ -4228,18 +4233,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * preview_use_decl(g, src_use_node); } - IrInstruction *use_target_value = src_use_node->data.use.value; - if (use_target_value->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *use_target_value = src_use_node->data.use.value; + if (type_is_invalid(use_target_value->type)) { dst_use_node->owner->any_imports_failed = true; return; } dst_use_node->data.use.resolution = TldResolutionOk; - ConstExprValue *const_val = &use_target_value->value; - assert(const_val->special != ConstValSpecialRuntime); + assert(use_target_value->special != ConstValSpecialRuntime); - ImportTableEntry *target_import = const_val->data.x_import; + ImportTableEntry *target_import = use_target_value->data.x_import; assert(target_import); if (target_import->any_imports_failed) { @@ -4302,10 +4306,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { } node->data.use.resolution = TldResolutionResolving; - IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, + ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base, node->data.use.expr, g->builtin_types.entry_namespace, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + if (type_is_invalid(result->type)) node->owner->any_imports_failed = true; node->data.use.value = result; @@ -4486,7 +4490,8 @@ bool handle_is_ptr(ZigType *type_entry) { return type_has_bits(type_entry->data.error_union.payload_type); case ZigTypeIdOptional: return type_has_bits(type_entry->data.maybe.child_type) && - !type_is_codegen_pointer(type_entry->data.maybe.child_type); + !type_is_codegen_pointer(type_entry->data.maybe.child_type) && + type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet; case ZigTypeIdUnion: assert(type_entry->data.unionation.zero_bits_known); if (type_entry->data.unionation.gen_field_count == 0) @@ -4732,6 +4737,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } +static uint32_t hash_const_val_error_set(ConstExprValue *const_val) { + assert(const_val->data.x_err_set != nullptr); + return const_val->data.x_err_set->value ^ 2630160122; +} + static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { uint32_t hash_val = 0; switch (const_val->data.x_ptr.mut) { @@ -4763,6 +4773,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); return hash_val; + case ConstPtrSpecialBaseErrorUnionCode: + hash_val += (uint32_t)2994743799; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val); + return hash_val; + case ConstPtrSpecialBaseErrorUnionPayload: + hash_val += (uint32_t)3456080131; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val); + return hash_val; + case ConstPtrSpecialBaseOptionalPayload: + hash_val += (uint32_t)3163140517; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val); + return hash_val; case ConstPtrSpecialHardCodedAddr: hash_val += (uint32_t)4048518294; hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); @@ -4774,6 +4796,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += (uint32_t)2590901619; hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); return hash_val; + case ConstPtrSpecialNull: + hash_val += (uint32_t)1486246455; + return hash_val; } zig_unreachable(); } @@ -4872,7 +4897,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return 2709806591; case ZigTypeIdOptional: if (get_codegen_ptr_type(const_val->type) != nullptr) { - return hash_const_val(const_val) * 1992916303; + return hash_const_val_ptr(const_val) * 1992916303; + } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { + return hash_const_val_error_set(const_val) * 3147031929; } else { if (const_val->data.x_optional) { return hash_const_val(const_val->data.x_optional) * 1992916303; @@ -4884,8 +4911,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { // TODO better hashing algorithm return 3415065496; case ZigTypeIdErrorSet: - assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set->value ^ 2630160122; + return hash_const_val_error_set(const_val); case ZigTypeIdNamespace: return hash_ptr(const_val->data.x_import); case ZigTypeIdBoundFn: @@ -4987,7 +5013,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { return can_mutate_comptime_var_state(value->data.x_optional); case ZigTypeIdErrorUnion: - if (value->data.x_err_union.err != nullptr) + if (value->data.x_err_union.error_set->data.x_err_set != nullptr) return false; assert(value->data.x_err_union.payload != nullptr); return can_mutate_comptime_var_state(value->data.x_err_union.payload); @@ -5048,9 +5074,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (type_is_invalid(var_scope->var->value->type)) + if (type_is_invalid(var_scope->var->var_type)) return false; - if (can_mutate_comptime_var_state(var_scope->var->value)) + if (can_mutate_comptime_var_state(var_scope->var->const_value)) return false; } else if (scope->id == ScopeIdFnDef) { return true; @@ -5068,7 +5094,7 @@ uint32_t fn_eval_hash(Scope* scope) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - result += hash_const_val(var_scope->var->value); + result += hash_const_val(var_scope->var->const_value); } else if (scope->id == ScopeIdFnDef) { ScopeFnDef *fn_scope = (ScopeFnDef *)scope; result += hash_ptr(fn_scope->fn_entry); @@ -5092,10 +5118,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { if (a->id == ScopeIdVarDecl) { ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; - if (a_var_scope->var->value->type != b_var_scope->var->value->type) - return false; - if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value)) + if (a_var_scope->var->var_type != b_var_scope->var->var_type) return false; + if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && + b_var_scope->var->var_type == b_var_scope->var->const_value->type) + { + if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) + return false; + } else { + zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); + } } else if (a->id == ScopeIdFnDef) { ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; @@ -5113,6 +5145,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { return false; } +// Whether the type has bits at runtime. bool type_has_bits(ZigType *type_entry) { assert(type_entry); assert(!type_is_invalid(type_entry)); @@ -5120,6 +5153,65 @@ bool type_has_bits(ZigType *type_entry) { return !type_entry->zero_bits; } +// Whether you can infer the value based solely on the type. +OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { + assert(type_entry != nullptr); + Error err; + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return OnePossibleValueInvalid; + switch (type_entry->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdOpaque: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdMetaType: + case ZigTypeIdNamespace: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdOptional: + case ZigTypeIdFn: + case ZigTypeIdBool: + case ZigTypeIdFloat: + case ZigTypeIdPromise: + case ZigTypeIdErrorUnion: + return OnePossibleValueNo; + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdVoid: + case ZigTypeIdUnreachable: + return OnePossibleValueYes; + case ZigTypeIdArray: + if (type_entry->data.array.len == 0) + return OnePossibleValueYes; + return type_has_one_possible_value(g, type_entry->data.array.child_type); + case ZigTypeIdStruct: + for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { + TypeStructField *field = &type_entry->data.structure.fields[i]; + switch (type_has_one_possible_value(g, field->type_entry)) { + case OnePossibleValueInvalid: + return OnePossibleValueInvalid; + case OnePossibleValueNo: + return OnePossibleValueNo; + case OnePossibleValueYes: + continue; + } + } + return OnePossibleValueYes; + case ZigTypeIdErrorSet: + case ZigTypeIdEnum: + case ZigTypeIdInt: + return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; + case ZigTypeIdPointer: + return type_has_one_possible_value(g, type_entry->data.pointer.child_type); + case ZigTypeIdUnion: + if (type_entry->data.unionation.src_field_count > 1) + return OnePossibleValueNo; + return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); + } + zig_unreachable(); +} + ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { Error err; if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) @@ -5574,6 +5666,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) return false; return true; + case ConstPtrSpecialBaseErrorUnionCode: + if (a->data.x_ptr.data.base_err_union_code.err_union_val != + b->data.x_ptr.data.base_err_union_code.err_union_val && + a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseErrorUnionPayload: + if (a->data.x_ptr.data.base_err_union_payload.err_union_val != + b->data.x_ptr.data.base_err_union_payload.err_union_val && + a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseOptionalPayload: + if (a->data.x_ptr.data.base_optional_payload.optional_val != + b->data.x_ptr.data.base_optional_payload.optional_val && + a->data.x_ptr.data.base_optional_payload.optional_val->global_refs != + b->data.x_ptr.data.base_optional_payload.optional_val->global_refs) + { + return false; + } + return true; case ConstPtrSpecialHardCodedAddr: if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) return false; @@ -5582,6 +5701,8 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { return true; case ConstPtrSpecialFunction: return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; + case ConstPtrSpecialNull: + return true; } zig_unreachable(); } @@ -5750,7 +5871,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v } } -void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { +static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { assert(type_entry->id == ZigTypeIdPointer); if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { @@ -5763,6 +5884,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy zig_unreachable(); case ConstPtrSpecialRef: case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialBaseErrorUnionCode: + case ConstPtrSpecialBaseErrorUnionPayload: + case ConstPtrSpecialBaseOptionalPayload: buf_appendf(buf, "*"); // TODO we need a source node for const_ptr_pointee because it can generate compile errors render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); @@ -5790,10 +5914,21 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); return; } + case ConstPtrSpecialNull: + buf_append_str(buf, "null"); + return; } zig_unreachable(); } +static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { + if (const_val->data.x_err_set == nullptr) { + buf_append_str(buf, "null"); + } else { + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); + } +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -5921,6 +6056,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { { if (get_codegen_ptr_type(const_val->type) != nullptr) return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); + if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) + return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); if (const_val->data.x_optional) { render_const_value(g, buf, const_val->data.x_optional); } else { @@ -5958,11 +6095,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdErrorUnion: { buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); - if (const_val->data.x_err_union.err == nullptr) { + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + if (err_set == nullptr) { render_const_value(g, buf, const_val->data.x_err_union.payload); } else { buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), - buf_ptr(&const_val->data.x_err_union.err->name)); + buf_ptr(&err_set->name)); } buf_appendf(buf, ")"); return; @@ -5977,10 +6115,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case ZigTypeIdErrorSet: - { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); - return; - } + return render_const_val_err_set(g, buf, const_val, type_entry); case ZigTypeIdArgTuple: { buf_appendf(buf, "(args value)"); @@ -6172,6 +6307,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { assert(const_val->type->id == ZigTypeIdArray); + if (const_val->special == ConstValSpecialUndef) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.special = ConstArraySpecialUndef; + } switch (const_val->data.x_array.special) { case ConstArraySpecialNone: return; @@ -6215,17 +6354,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { } ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { - assert(value->type); - ZigType *type_entry = value->type; - if (type_entry->id == ZigTypeIdArray) { - expand_undef_array(g, value); - return &value->data.x_array.data.s_none.parent; - } else if (type_entry->id == ZigTypeIdStruct) { - return &value->data.x_struct.parent; - } else if (type_entry->id == ZigTypeIdUnion) { - return &value->data.x_union.parent; - } - return nullptr; + return &value->parent; } static const ZigTypeId all_type_ids[] = { @@ -6453,7 +6582,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { resolve_top_level_decl(codegen, tld, false, nullptr); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - ConstExprValue *var_value = tld_var->var->value; + ConstExprValue *var_value = tld_var->var->const_value; assert(var_value != nullptr); return var_value; } diff --git a/src/analyze.hpp b/src/analyze.hpp index efbc065a63..1bac15ebcc 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -81,7 +81,7 @@ ZigFn *scope_fn_entry(Scope *scope); ImportTableEntry *get_scope_import(Scope *scope); void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ConstExprValue *init_value, Tld *src_tld); + bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); ZigFn *create_fn(CodeGen *g, AstNode *proto_node); ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); @@ -222,6 +222,13 @@ enum ReqCompTime { }; ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); +enum OnePossibleValue { + OnePossibleValueInvalid, + OnePossibleValueNo, + OnePossibleValueYes, +}; +OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); + Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *const_val, ZigType *wanted_type); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index f7eb646e16..994ba5f5b1 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) { return "ErrorType"; case NodeTypeIfErrorExpr: return "IfErrorExpr"; - case NodeTypeTestExpr: - return "TestExpr"; + case NodeTypeIfOptional: + return "IfOptional"; case NodeTypeErrorSetDecl: return "ErrorSetDecl"; case NodeTypeCancel: @@ -387,7 +387,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { if (node->data.if_err_expr.else_node) return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); return node->data.if_err_expr.then_node->type == NodeTypeBlock; - case NodeTypeTestExpr: + case NodeTypeIfOptional: if (node->data.test_expr.else_node) return statement_terminates_without_semicolon(node->data.test_expr.else_node); return node->data.test_expr.then_node->type == NodeTypeBlock; @@ -974,7 +974,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } break; } - case NodeTypeTestExpr: + case NodeTypeIfOptional: { fprintf(ar->f, "if ("); render_node_grouped(ar, node->data.test_expr.target_node); diff --git a/src/codegen.cpp b/src/codegen.cpp index 47f2aa103f..2f360735dd 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -313,6 +313,8 @@ static void render_const_val(CodeGen *g, ConstExprValue *const_val, const char * static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const char *name); static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name); static void generate_error_name_table(CodeGen *g); +static bool value_is_all_undef(ConstExprValue *const_val); +static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr); static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); @@ -461,6 +463,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag } } +static bool cc_want_sret_attr(CallingConvention cc) { + switch (cc) { + case CallingConventionNaked: + zig_unreachable(); + case CallingConventionC: + case CallingConventionCold: + case CallingConventionStdcall: + return true; + case CallingConventionAsync: + case CallingConventionUnspecified: + return false; + } + zig_unreachable(); +} + static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { if (fn_table_entry->llvm_value) return fn_table_entry->llvm_value; @@ -598,9 +615,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { } else if (type_is_codegen_pointer(return_type)) { addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { - addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); - if (cc == CallingConventionC) { + addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); + if (cc_want_sret_attr(cc)) { addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias"); } init_gen_i = 1; @@ -2200,10 +2217,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { assert(variable); assert(variable->value_ref); - if (!handle_is_ptr(variable->value->type)) { + if (!handle_is_ptr(variable->var_type)) { clear_debug_source_node(g); - gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref, - variable->align_bytes, false); + gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), + variable->value_ref, variable->align_bytes, false); } if (variable->decl_node) { @@ -2961,7 +2978,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, } static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, - IrInstructionPtrCast *instruction) + IrInstructionPtrCastGen *instruction) { ZigType *wanted_type = instruction->base.value.type; if (!type_has_bits(wanted_type)) { @@ -3149,11 +3166,11 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI } static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, - IrInstructionDeclVar *decl_var_instruction) + IrInstructionDeclVarGen *decl_var_instruction) { ZigVar *var = decl_var_instruction->var; - if (!type_has_bits(var->value->type)) + if (!type_has_bits(var->var_type)) return nullptr; if (var->ref_count == 0 && g->build_mode != BuildModeDebug) @@ -3161,34 +3178,16 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstruction *init_value = decl_var_instruction->init_value; - bool have_init_expr = false; - - ConstExprValue *const_val = &init_value->value; - if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) - have_init_expr = true; + bool have_init_expr = !value_is_all_undef(&init_value->value); if (have_init_expr) { - assert(var->value->type == init_value->value.type); - ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, + ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, PtrLenSingle, var->align_bytes, 0, 0); LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); - } else { - bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); - if (want_safe) { - ZigType *usize = g->builtin_types.entry_usize; - uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref); - assert(size_bytes > 0); - - assert(var->align_bytes > 0); - - // memset uninitialized memory to 0xa - LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); - LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); - LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, ""); - LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); - ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false); - } + } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { + uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes; + gen_undef_init(g, align_bytes, var->var_type, var->value_ref); } gen_var_debug_decl(g, var); @@ -3225,21 +3224,75 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); } -static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { - LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - LLVMValueRef value = ir_llvm_value(g, instruction->value); +static bool value_is_all_undef(ConstExprValue *const_val) { + switch (const_val->special) { + case ConstValSpecialRuntime: + return false; + case ConstValSpecialUndef: + return true; + case ConstValSpecialStatic: + if (const_val->type->id == ZigTypeIdStruct) { + for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { + if (!value_is_all_undef(&const_val->data.x_struct.fields[i])) + return false; + } + return true; + } else if (const_val->type->id == ZigTypeIdArray) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return true; + case ConstArraySpecialBuf: + return false; + case ConstArraySpecialNone: + for (size_t i = 0; i < const_val->type->data.array.len; i += 1) { + if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) + return false; + } + return true; + } + zig_unreachable(); + } else { + return false; + } + } + zig_unreachable(); +} - assert(instruction->ptr->value.type->id == ZigTypeIdPointer); - ZigType *ptr_type = instruction->ptr->value.type; +static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) { + assert(type_has_bits(value_type)); + uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref); + assert(size_bytes > 0); + assert(ptr_align_bytes > 0); + // memset uninitialized memory to 0xaa + LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); + LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false); + LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, ""); + ZigType *usize = g->builtin_types.entry_usize; + LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); + ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false); +} - gen_assign_raw(g, ptr, ptr_type, value); +static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { + ZigType *ptr_type = instruction->ptr->value.type; + assert(ptr_type->id == ZigTypeIdPointer); + if (!type_has_bits(ptr_type)) + return nullptr; + bool have_init_expr = !value_is_all_undef(&instruction->value->value); + if (have_init_expr) { + LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); + LLVMValueRef value = ir_llvm_value(g, instruction->value); + gen_assign_raw(g, ptr, ptr_type, value); + } else if (ir_want_runtime_safety(g, &instruction->base)) { + gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type, + ir_llvm_value(g, instruction->ptr)); + } return nullptr; } static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { ZigVar *var = instruction->var; - if (type_has_bits(var->value->type)) { + if (type_has_bits(var->var_type)) { assert(var->value_ref); return var->value_ref; } else { @@ -3553,7 +3606,8 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMPositionBuilderAtEnd(g->builder, ok_block); } - LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, ""); + LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, + union_type->data.unionation.gen_union_index, ""); LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); return bitcasted_union_field_ptr; } @@ -3715,8 +3769,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR if (child_type->zero_bits) { return maybe_handle; } else { - bool maybe_is_ptr = type_is_codegen_pointer(child_type); - if (maybe_is_ptr) { + bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; + if (is_scalar) { 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, ""); @@ -3731,17 +3785,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value)); } -static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, - IrInstructionUnwrapOptional *instruction) +static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionOptionalUnwrapPtr *instruction) { - ZigType *ptr_type = instruction->value->value.type; + ZigType *ptr_type = instruction->base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); - LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); + LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { + LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); @@ -3755,8 +3809,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, if (child_type->zero_bits) { return nullptr; } else { - bool maybe_is_ptr = type_is_codegen_pointer(child_type); - if (maybe_is_ptr) { + bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet; + if (is_scalar) { return maybe_ptr; } else { LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); @@ -4174,7 +4228,7 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed) zig_unreachable(); } -static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) { +static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) { LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr); LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value); LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value); @@ -4189,18 +4243,18 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - if (type_is_codegen_pointer(child_type)) { + if (!handle_is_ptr(maybe_type)) { LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, ""); } assert(instruction->tmp_ptr != nullptr); - assert(type_has_bits(instruction->type)); + assert(type_has_bits(child_type)); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); - gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val); + gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); @@ -4351,6 +4405,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst assert(array_type->data.structure.is_slice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); + assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index; assert(ptr_index != SIZE_MAX); @@ -4540,12 +4595,14 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); } -static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { - ZigType *ptr_type = instruction->value->value.type; +static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, + IrInstructionUnwrapErrCode *instruction) +{ + ZigType *ptr_type = instruction->err_union->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union); LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); if (type_has_bits(payload_type)) { @@ -4556,7 +4613,13 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab } } -static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { +static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, + IrInstructionUnwrapErrPayload *instruction) +{ + bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && + g->errors_by_index.length > 1; + if (!want_safety && !type_has_bits(instruction->base.value.type)) + return nullptr; ZigType *ptr_type = instruction->value->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; @@ -4568,7 +4631,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu return err_union_handle; } - if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) { + if (want_safety) { LLVMValueRef err_val; if (type_has_bits(payload_type)) { LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); @@ -4607,7 +4670,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I } LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); - if (type_is_codegen_pointer(child_type)) { + if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { return payload_val; } @@ -5184,12 +5247,15 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: case IrInstructionIdCheckRuntimeScope: + case IrInstructionIdDeclVarSrc: + case IrInstructionIdPtrCastSrc: + case IrInstructionIdCmpxchgSrc: zig_unreachable(); + case IrInstructionIdDeclVarGen: + return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); - case IrInstructionIdDeclVar: - return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction); case IrInstructionIdBinOp: return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction); case IrInstructionIdCast: @@ -5220,8 +5286,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); case IrInstructionIdTestNonNull: return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapOptional: - return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction); case IrInstructionIdClz: return ir_render_clz(g, executable, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -5236,8 +5302,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_ref(g, executable, (IrInstructionRef *)instruction); case IrInstructionIdErrName: return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); - case IrInstructionIdCmpxchg: - return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgGen: + return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction); case IrInstructionIdFence: return ir_render_fence(g, executable, (IrInstructionFence *)instruction); case IrInstructionIdTruncate: @@ -5278,8 +5344,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdUnionInit: return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); - case IrInstructionIdPtrCast: - return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastGen: + return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); case IrInstructionIdBitCast: return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction); case IrInstructionIdWidenOrShorten: @@ -5377,6 +5443,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val); +static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val); +static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val); +static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val); static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { switch (parent->id) { @@ -5387,6 +5456,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent case ConstParentIdStruct: return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, parent->data.p_struct.field_index); + case ConstParentIdErrUnionCode: + return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val); + case ConstParentIdErrUnionPayload: + return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val); + case ConstParentIdOptionalPayload: + return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val); case ConstParentIdArray: return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, parent->data.p_array.elem_index); @@ -5402,7 +5477,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { expand_undef_array(g, array_const_val); - ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent; + ConstParent *parent = &array_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); @@ -5427,7 +5502,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar } static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { - ConstParent *parent = &struct_const_val->data.x_struct.parent; + ConstParent *parent = &struct_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); ZigType *u32 = g->builtin_types.entry_u32; @@ -5438,8 +5513,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s return LLVMConstInBoundsGEP(base_ptr, indices, 2); } +static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { + ConstParent *parent = &err_union_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, err_union_err_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + +static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) { + ConstParent *parent = &err_union_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, err_union_payload_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + +static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) { + ConstParent *parent = &optional_const_val->parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent); + + ZigType *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, maybe_child_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { - ConstParent *parent = &union_const_val->data.x_union.parent; + ConstParent *parent = &union_const_val->parent; LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); ZigType *u32 = g->builtin_types.entry_u32; @@ -5609,6 +5720,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con render_const_val_global(g, const_val, ""); return ptr_val; } + case ConstPtrSpecialBaseErrorUnionCode: + { + render_const_val_global(g, const_val, name); + ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val; + assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); + if (err_union_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseErrorUnionPayload: + { + render_const_val_global(g, const_val, name); + ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val; + assert(err_union_const_val->type->id == ZigTypeIdErrorUnion); + if (err_union_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseOptionalPayload: + { + render_const_val_global(g, const_val, name); + ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val; + assert(optional_const_val->type->id == ZigTypeIdOptional); + if (optional_const_val->type->zero_bits) { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } case ConstPtrSpecialHardCodedAddr: { render_const_val_global(g, const_val, name); @@ -5621,10 +5789,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con } case ConstPtrSpecialFunction: return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); + case ConstPtrSpecialNull: + return LLVMConstNull(const_val->type->type_ref); } zig_unreachable(); } +static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) { + uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value; + return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false); +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { Error err; @@ -5644,9 +5819,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c case ZigTypeIdInt: return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); case ZigTypeIdErrorSet: - assert(const_val->data.x_err_set != nullptr); - return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, - const_val->data.x_err_set->value, false); + return gen_const_val_err_set(g, const_val, name); case ZigTypeIdFloat: switch (type_entry->data.floating.bit_count) { case 16: @@ -5680,6 +5853,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); } else if (type_is_codegen_pointer(child_type)) { return gen_const_val_ptr(g, const_val, name); + } else if (child_type->id == ZigTypeIdErrorSet) { + return gen_const_val_err_set(g, const_val, name); } else { LLVMValueRef child_val; LLVMValueRef maybe_val; @@ -5914,7 +6089,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c ZigType *err_set_type = type_entry->data.error_union.err_set_type; if (!type_has_bits(payload_type)) { assert(type_has_bits(err_set_type)); - uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0; + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + uint64_t value = (err_set == nullptr) ? 0 : err_set->value; return LLVMConstInt(g->err_tag_type->type_ref, value, false); } else if (!type_has_bits(err_set_type)) { assert(type_has_bits(payload_type)); @@ -5923,8 +6099,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c LLVMValueRef err_tag_value; LLVMValueRef err_payload_value; bool make_unnamed_struct; - if (const_val->data.x_err_union.err) { - err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false); + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + if (err_set != nullptr) { + err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false); err_payload_value = LLVMConstNull(payload_type->type_ref); make_unnamed_struct = false; } else { @@ -6130,10 +6307,13 @@ static void do_code_gen(CodeGen *g) { TldVar *tld_var = g->global_vars.at(i); ZigVar *var = tld_var->var; - if (var->value->type->id == ZigTypeIdComptimeFloat) { + if (var->var_type->id == ZigTypeIdComptimeFloat) { // Generate debug info for it but that's it. - ConstExprValue *const_val = var->value; + ConstExprValue *const_val = var->const_value; assert(const_val->special != ConstValSpecialRuntime); + if (const_val->type != var->var_type) { + zig_panic("TODO debug info for var with ptr casted value"); + } ZigType *var_type = g->builtin_types.entry_f128; ConstExprValue coerced_value; coerced_value.special = ConstValSpecialStatic; @@ -6144,10 +6324,13 @@ static void do_code_gen(CodeGen *g) { continue; } - if (var->value->type->id == ZigTypeIdComptimeInt) { + if (var->var_type->id == ZigTypeIdComptimeInt) { // Generate debug info for it but that's it. - ConstExprValue *const_val = var->value; + ConstExprValue *const_val = var->const_value; assert(const_val->special != ConstValSpecialRuntime); + if (const_val->type != var->var_type) { + zig_panic("TODO debug info for var with ptr casted value"); + } size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint); if (bits_needed < 8) { bits_needed = 8; @@ -6158,7 +6341,7 @@ static void do_code_gen(CodeGen *g) { continue; } - if (!type_has_bits(var->value->type)) + if (!type_has_bits(var->var_type)) continue; assert(var->decl_node); @@ -6167,9 +6350,9 @@ static void do_code_gen(CodeGen *g) { if (var->linkage == VarLinkageExternal) { LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); if (existing_llvm_var) { - global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0)); + global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0)); } else { - global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name)); + global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name)); // TODO debug info for the extern variable LLVMSetLinkage(global_value, LLVMExternalLinkage); @@ -6180,9 +6363,9 @@ static void do_code_gen(CodeGen *g) { } else { bool exported = (var->linkage == VarLinkageExport); const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); - render_const_val(g, var->value, mangled_name); - render_const_val_global(g, var->value, mangled_name); - global_value = var->value->global_refs->llvm_global; + render_const_val(g, var->const_value, mangled_name); + render_const_val_global(g, var->const_value, mangled_name); + global_value = var->const_value->global_refs->llvm_global; if (exported) { LLVMSetLinkage(global_value, LLVMExternalLinkage); @@ -6194,8 +6377,10 @@ static void do_code_gen(CodeGen *g) { LLVMSetAlignment(global_value, var->align_bytes); // TODO debug info for function pointers - if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) { - gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type); + // Here we use const_value->type because that's the type of the llvm global, + // which we const ptr cast upon use to whatever it needs to be. + if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) { + gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type); } LLVMSetGlobalConstant(global_value, var->gen_is_const); @@ -6281,8 +6466,8 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdErrWrapCode) { IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; slot = &err_wrap_code_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdCmpxchg) { - IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction; + } else if (instruction->id == IrInstructionIdCmpxchgGen) { + IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; } else { zig_unreachable(); @@ -6304,12 +6489,12 @@ static void do_code_gen(CodeGen *g) { for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { ZigVar *var = fn_table_entry->variable_list.at(var_i); - if (!type_has_bits(var->value->type)) { + if (!type_has_bits(var->var_type)) { continue; } if (ir_get_var_is_comptime(var)) continue; - switch (type_requires_comptime(g, var->value->type)) { + switch (type_requires_comptime(g, var->var_type)) { case ReqCompTimeInvalid: zig_unreachable(); case ReqCompTimeYes: @@ -6319,11 +6504,11 @@ static void do_code_gen(CodeGen *g) { } if (var->src_arg_index == SIZE_MAX) { - var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); + var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), - var->value->type->di_type, !g->strip_debug_symbols, 0); + var->var_type->di_type, !g->strip_debug_symbols, 0); } else if (is_c_abi) { fn_walk_var.data.vars.var = var; @@ -6333,16 +6518,16 @@ static void do_code_gen(CodeGen *g) { ZigType *gen_type; FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index]; - if (handle_is_ptr(var->value->type)) { + if (handle_is_ptr(var->var_type)) { if (gen_info->is_byval) { - gen_type = var->value->type; + gen_type = var->var_type; } else { gen_type = gen_info->type; } var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index); } else { - gen_type = var->value->type; - var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes); + gen_type = var->var_type; + var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); } if (var->decl_node) { var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), @@ -7458,9 +7643,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i]; this_val->special = ConstValSpecialStatic; this_val->type = struct_type; - this_val->data.x_struct.parent.id = ConstParentIdArray; - this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array; - this_val->data.x_struct.parent.data.p_array.elem_index = i; + this_val->parent.id = ConstParentIdArray; + this_val->parent.data.p_array.array_val = test_fn_array; + this_val->parent.data.p_array.elem_index = i; this_val->data.x_struct.fields = create_const_vals(2); ConstExprValue *name_field = &this_val->data.x_struct.fields[0]; diff --git a/src/ir.cpp b/src/ir.cpp index b184252a2e..06eb4a47f1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -167,6 +167,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *dest_type, IrInstruction *dest_type_src); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); +static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -178,15 +179,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c case ConstPtrSpecialRef: result = const_val->data.x_ptr.data.ref.pointee; break; - case ConstPtrSpecialBaseArray: - expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val); - result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[ - const_val->data.x_ptr.data.base_array.elem_index]; + case ConstPtrSpecialBaseArray: { + ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val; + expand_undef_array(g, array_val); + result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; break; + } case ConstPtrSpecialBaseStruct: result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ const_val->data.x_ptr.data.base_struct.field_index]; break; + case ConstPtrSpecialBaseErrorUnionCode: + result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set; + break; + case ConstPtrSpecialBaseErrorUnionPayload: + result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload; + break; + case ConstPtrSpecialBaseOptionalPayload: + result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional; + break; + case ConstPtrSpecialNull: + result = const_val; + break; case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialDiscard: @@ -198,6 +212,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c return result; } +static bool is_opt_err_set(ZigType *ty) { + return ty->id == ZigTypeIdErrorSet || + (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); +} + static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { if (a == b) return true; @@ -208,15 +227,10 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) return true; - return false; -} + if (is_opt_err_set(a) && is_opt_err_set(b)) + return true; -ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { - ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val); - if (const_val->type->id == ZigTypeIdPointer) { - assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type)); - } - return result; + return false; } static bool ir_should_inline(IrExecutable *exec, Scope *scope) { @@ -305,6 +319,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) { return new_bb; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) { + return IrInstructionIdDeclVarSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) { + return IrInstructionIdDeclVarGen; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) { return IrInstructionIdCondBr; } @@ -337,10 +359,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) { return IrInstructionIdBinOp; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { - return IrInstructionIdDeclVar; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { return IrInstructionIdExport; } @@ -449,8 +467,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { return IrInstructionIdTestNonNull; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) { - return IrInstructionIdUnwrapOptional; +static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) { + return IrInstructionIdOptionalUnwrapPtr; } static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { @@ -517,8 +535,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) { return IrInstructionIdEmbedFile; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) { - return IrInstructionIdCmpxchg; +static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) { + return IrInstructionIdCmpxchgSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) { + return IrInstructionIdCmpxchgGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) { @@ -649,8 +671,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) return IrInstructionIdTestComptime; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) { - return IrInstructionIdPtrCast; +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) { + return IrInstructionIdPtrCastSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { + return IrInstructionIdPtrCastGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { @@ -915,7 +941,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so ir_ref_instruction(condition, irb->current_basic_block); ir_ref_bb(then_block); ir_ref_bb(else_block); - if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); + if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); return &cond_br_instruction->base; } @@ -931,16 +957,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou return &return_instruction->base; } -static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - assert(type_entry); - IrInstructionConst *const_instruction = ir_create_instruction(irb, scope, source_node); - const_instruction->base.value.type = type_entry; - const_instruction->base.value.special = ConstValSpecialStatic; - return &const_instruction->base; -} - static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); const_instruction->base.value.type = irb->codegen->builtin_types.entry_void; @@ -1188,14 +1204,11 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - if (fn_ref) - ir_ref_instruction(fn_ref, irb->current_basic_block); + if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); for (size_t i = 0; i < arg_count; i += 1) ir_ref_instruction(args[i], irb->current_basic_block); - if (async_allocator) - ir_ref_instruction(async_allocator, irb->current_basic_block); - if (new_stack != nullptr) - ir_ref_instruction(new_stack, irb->current_basic_block); + if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block); + if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); return &call_instruction->base; } @@ -1280,7 +1293,7 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, container_init_list_instruction->item_count = item_count; container_init_list_instruction->items = items; - ir_ref_instruction(container_type, irb->current_basic_block); + if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < item_count; i += 1) { ir_ref_instruction(items[i], irb->current_basic_block); } @@ -1355,10 +1368,10 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } -static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value) { - IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; @@ -1366,13 +1379,28 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *s decl_var_instruction->align_value = align_value; decl_var_instruction->init_value = init_value; - if (var_type) ir_ref_instruction(var_type, irb->current_basic_block); - if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); + if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(init_value, irb->current_basic_block); return &decl_var_instruction->base; } +static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction, + ZigVar *var, IrInstruction *init_value) +{ + IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + decl_var_instruction->base.value.special = ConstValSpecialStatic; + decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void; + decl_var_instruction->var = var; + decl_var_instruction->init_value = init_value; + + ir_ref_instruction(init_value, ira->new_irb.current_basic_block); + + return &decl_var_instruction->base; +} + static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name, IrInstruction *target, IrInstruction *linkage) { @@ -1542,14 +1570,14 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod return &instruction->base; } -static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, - bool safety_check_on) +static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *base_ptr, bool safety_check_on) { - IrInstructionUnwrapOptional *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; instruction->safety_check_on = safety_check_on; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(base_ptr, irb->current_basic_block); return &instruction->base; } @@ -1765,13 +1793,12 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, - IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, +static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, IrInstruction *success_order_value, IrInstruction *failure_order_value, - bool is_weak, - ZigType *type, AtomicOrder success_order, AtomicOrder failure_order) + bool is_weak) { - IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; instruction->ptr = ptr; instruction->cmp_value = cmp_value; @@ -1779,16 +1806,33 @@ static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *so instruction->success_order_value = success_order_value; instruction->failure_order_value = failure_order_value; instruction->is_weak = is_weak; - instruction->type = type; - instruction->success_order = success_order; - instruction->failure_order = failure_order; - if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(type_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(cmp_value, irb->current_basic_block); ir_ref_instruction(new_value, irb->current_basic_block); - if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block); - if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block); + ir_ref_instruction(success_order_value, irb->current_basic_block); + ir_ref_instruction(failure_order_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, + AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) +{ + IrInstructionCmpxchgGen *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->ptr = ptr; + instruction->cmp_value = cmp_value; + instruction->new_value = new_value; + instruction->success_order = success_order; + instruction->failure_order = failure_order; + instruction->is_weak = is_weak; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); + ir_ref_instruction(new_value, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2060,12 +2104,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) + IrInstruction *err_union) { IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + instruction->err_union = err_union; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(err_union, irb->current_basic_block); return &instruction->base; } @@ -2115,20 +2159,33 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } -static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *ptr) { - IrInstructionPtrCast *instruction = ir_build_instruction( + IrInstructionPtrCastSrc *instruction = ir_build_instruction( irb, scope, source_node); instruction->dest_type = dest_type; instruction->ptr = ptr; - if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); return &instruction->base; } +static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *ptr_type, IrInstruction *ptr) +{ + IrInstructionPtrCastGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ptr_type; + instruction->ptr = ptr; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *value) { @@ -2807,10 +2864,13 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o Scope *defer_expr_scope = defer_node->data.defer.expr_scope; IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); if (defer_expr_value != irb->codegen->invalid_instruction) { - if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) { + if (defer_expr_value->value.type != nullptr && + defer_expr_value->value.type->id == ZigTypeIdUnreachable) + { is_noreturn = true; } else { - ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value)); + ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, + defer_expr_value)); } } } @@ -3065,7 +3125,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s variable_entry->mem_slot_index = SIZE_MAX; variable_entry->is_comptime = is_comptime; variable_entry->src_arg_index = SIZE_MAX; - variable_entry->value = create_const_vals(1); + variable_entry->const_value = create_const_vals(1); if (is_comptime != nullptr) { is_comptime->ref_count += 1; @@ -3080,20 +3140,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s ErrorMsg *msg = add_node_error(codegen, node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } else { ZigType *type; if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { add_node_error(codegen, node, buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } else { Tld *tld = find_decl(codegen, parent_scope, name); if (tld != nullptr) { ErrorMsg *msg = add_node_error(codegen, node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; + variable_entry->var_type = codegen->builtin_types.entry_invalid; } } } @@ -3156,7 +3216,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode scope_block->incoming_blocks = &incoming_blocks; scope_block->incoming_values = &incoming_values; scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); - scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope)); + scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, + ir_should_inline(irb->exec, parent_scope)); } bool is_continuation_unreachable = false; @@ -3174,9 +3235,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode // defer starts a new scope child_scope = statement_node->data.defer.child_scope; assert(child_scope); - } else if (statement_value->id == IrInstructionIdDeclVar) { + } else if (statement_value->id == IrInstructionIdDeclVarSrc) { // variable declarations start a new scope - IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; + IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value; child_scope = decl_var_instruction->var->child_scope; } else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) { // this statement's value must be void @@ -3331,7 +3392,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); } -static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeBinOpExpr); AstNode *op1_node = node->data.bin_op_expr.op1; @@ -3365,7 +3426,7 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -3483,7 +3544,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) case BinOpTypeMergeErrorSets: return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); case BinOpTypeUnwrapOptional: - return ir_gen_maybe_ok_or(irb, scope, node); + return ir_gen_orelse(irb, scope, node); case BinOpTypeErrorUnion: return ir_gen_error_union(irb, scope, node); } @@ -3542,6 +3603,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, buf_ptr(variable_name))); return irb->codegen->invalid_instruction; } + assert(err == ErrorPrimitiveTypeNotFound); } else { IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); if (lval == LValPtr) { @@ -3904,9 +3966,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg5_value == irb->codegen->invalid_instruction) return arg5_value; - IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), - nullptr, AtomicOrderUnordered, AtomicOrderUnordered); + IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, + arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); return ir_lval_wrap(irb, scope, cmpxchg, lval); } case BuiltinFnIdFence: @@ -4346,7 +4407,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, ptr_cast, lval); } case BuiltinFnIdBitCast: @@ -4784,7 +4845,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node } } - IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr); + IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, + is_async, async_allocator, nullptr); return ir_lval_wrap(irb, scope, fn_call, lval); } @@ -4793,7 +4855,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); if (condition == irb->codegen->invalid_instruction) - return condition; + return irb->codegen->invalid_instruction; IrInstruction *is_comptime; if (ir_should_inline(irb->exec, scope)) { @@ -4816,7 +4878,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); if (then_expr_result == irb->codegen->invalid_instruction) - return then_expr_result; + return irb->codegen->invalid_instruction; IrBasicBlock *after_then_block = irb->current_basic_block; if (!instr_is_unreachable(then_expr_result)) ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); @@ -4826,7 +4888,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode if (else_node) { else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); if (else_expr_result == irb->codegen->invalid_instruction) - return else_expr_result; + return irb->codegen->invalid_instruction; } else { else_expr_result = ir_build_const_void(irb, scope, node); } @@ -4927,7 +4989,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode ptr_len, align_value, bit_offset_start, host_int_bytes); } -static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, +static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, LVal lval) { IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); @@ -5053,11 +5115,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); - // we detect IrInstructionIdDeclVar in gen_block to make sure the next node + // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node // is inside var->child_scope if (!is_extern && !variable_declaration->expr) { - var->value->type = irb->codegen->builtin_types.entry_invalid; + var->var_type = irb->codegen->builtin_types.entry_invalid; add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); return irb->codegen->invalid_instruction; } @@ -5084,7 +5146,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod if (init_value == irb->codegen->invalid_instruction) return init_value; - return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value); + return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value); } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5140,7 +5202,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n err_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); - ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); } ZigList incoming_values = {0}; @@ -5180,7 +5242,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5220,10 +5282,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n } ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); - ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5380,7 +5442,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo Scope *child_scope = elem_var->child_scope; IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -5398,7 +5460,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); + ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); @@ -5622,8 +5684,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile); } -static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeTestExpr); +static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeIfOptional); Buf *var_symbol = node->data.test_expr.var_symbol; AstNode *expr_node = node->data.test_expr.target_node; @@ -5661,9 +5723,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -5738,7 +5800,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -5763,7 +5825,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * err_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -5818,7 +5880,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } IrInstruction *var_type = nullptr; // infer the type - ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); } else { child_scope = scope; } @@ -6228,7 +6290,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); } -static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node) { assert(node->type == NodeTypeUnwrapErrorExpr); AstNode *op1_node = node->data.unwrap_err_expr.op1; @@ -6242,7 +6304,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); return irb->codegen->invalid_instruction; } - return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone); + return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone); } @@ -6276,7 +6338,7 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val); } else { err_scope = parent_scope; } @@ -6312,7 +6374,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; if (need_comma) buf_append_char(name, ','); - render_const_value(codegen, name, var_scope->var->value); + // TODO: const ptr reinterpret here to make the var type agree with the value? + render_const_value(codegen, name, var_scope->var->const_value); return true; } @@ -6562,7 +6625,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6640,7 +6703,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6756,7 +6819,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7050,7 +7113,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); if (lval == LValPtr) return unwrapped_ptr; @@ -7074,8 +7137,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); case NodeTypeIfErrorExpr: return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); - case NodeTypeTestExpr: - return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval); + case NodeTypeIfOptional: + return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); case NodeTypeSwitchExpr: return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); case NodeTypeCompTime: @@ -7093,7 +7156,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSliceExpr: return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); case NodeTypeContainerDecl: return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); case NodeTypeFnProto: @@ -7152,6 +7215,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_ref_bb(irb->current_basic_block); ZigFn *fn_entry = exec_fn_entry(irb->exec); + bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; IrInstruction *coro_id; IrInstruction *u8_ptr_type; @@ -7172,27 +7236,27 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); - ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); + ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, ImplicitAllocatorIdArg); irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); - ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); + ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); @@ -7208,7 +7272,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); @@ -7286,8 +7350,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); - IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); - IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, + IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); + IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr); IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, fn_entry->type_entry->data.fn.fn_type_id.return_type); @@ -7303,7 +7367,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // Before we destroy the coroutine frame, we need to load the target promise into // a register or local variable which does not get spilled into the frame, // otherwise llvm tries to access memory inside the destroyed frame. - IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, + IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, false); IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); @@ -7338,7 +7402,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); @@ -7435,7 +7499,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal return val; } -static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { +static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) { IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); @@ -7445,16 +7509,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) if (value->value.special == ConstValSpecialRuntime) { exec_add_error_node(codegen, exec, value->source_node, buf_sprintf("unable to evaluate constant expression")); - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } - return value; + return &value->value; } else if (ir_has_side_effects(instruction)) { exec_add_error_node(codegen, exec, instruction->source_node, buf_sprintf("unable to evaluate constant expression")); - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } } - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; } static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { @@ -8768,13 +8832,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT size_t errors_count = 0; ZigType *err_set_type = nullptr; if (prev_inst->value.type->id == ZigTypeIdErrorSet) { + if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) { + return ira->codegen->builtin_types.entry_invalid; + } if (type_is_global_error_set(prev_inst->value.type)) { err_set_type = ira->codegen->builtin_types.entry_global_error_set; } else { err_set_type = prev_inst->value.type; - if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } update_errors_helper(ira->codegen, &errors, &errors_count); for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) { @@ -8933,6 +8997,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (prev_type->id == ZigTypeIdArray) { convert_to_const_slice = true; } + if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { + return ira->codegen->builtin_types.entry_invalid; + } if (type_is_global_error_set(cur_type)) { err_set_type = ira->codegen->builtin_types.entry_global_error_set; continue; @@ -8940,9 +9007,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) { continue; } - if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) { - return ira->codegen->builtin_types.entry_invalid; - } update_errors_helper(ira->codegen, &errors, &errors_count); @@ -9432,14 +9496,23 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ } return true; } + +static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, + old_instruction->scope, old_instruction->source_node); + IrInstruction *new_instruction = &const_instruction->base; + new_instruction->value.type = ty; + new_instruction->value.special = ConstValSpecialStatic; + return new_instruction; +} + static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type, CastOp cast_op, bool need_alloca) { if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) && cast_op != CastOpResizeSlice) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type, &result->value, wanted_type)) { @@ -9476,9 +9549,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; result->value.data.x_ptr.data.base_array.array_val = pointee; @@ -9517,8 +9588,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc assert(is_slice(wanted_type)); bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = value->value.data.x_ptr.mut; @@ -9653,15 +9723,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction) return instruction; } -static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) { - IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, - old_instruction->scope, old_instruction->source_node); - IrInstruction *new_instruction = &const_instruction->base; - new_instruction->value.type = ty; - new_instruction->value.special = ConstValSpecialStatic; - return new_instruction; -} - static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type); result->value.data.x_type = ty; @@ -9719,13 +9780,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un zig_unreachable(); } -IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, +ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec) { if (expected_type != nullptr && type_is_invalid(expected_type)) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; IrExecutable *ir_executable = allocate(1); ir_executable->source_node = source_node; @@ -9738,13 +9799,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node ir_gen(codegen, node, scope, ir_executable); if (ir_executable->invalid) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; if (codegen->verbose_ir) { fprintf(stderr, "\nSource: "); ast_render(codegen, stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); - ir_print(codegen, stderr, ir_executable, 4); + ir_print(codegen, stderr, ir_executable, 2); fprintf(stderr, "}\n"); } IrExecutable *analyzed_executable = allocate(1); @@ -9760,11 +9821,11 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node analyzed_executable->begin_scope = scope; ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); if (type_is_invalid(result_type)) - return codegen->invalid_instruction; + return &codegen->invalid_instruction->value; if (codegen->verbose_ir) { fprintf(stderr, "{ // (analyzed)\n"); - ir_print(codegen, stderr, analyzed_executable, 4); + ir_print(codegen, stderr, analyzed_executable, 2); fprintf(stderr, "}\n"); } @@ -9838,7 +9899,9 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { return const_val->data.x_ptr.data.fn.fn_entry; } -static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { +static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *wanted_type) +{ assert(wanted_type->id == ZigTypeIdOptional); if (instr_is_comptime(value)) { @@ -9854,7 +9917,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.special = ConstValSpecialStatic; - if (get_codegen_ptr_type(wanted_type) != nullptr) { + if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) { copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); } else { const_instruction->base.value.data.x_optional = val; @@ -9885,11 +9948,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction if (!val) return ira->codegen->invalid_instruction; + ConstExprValue *err_set_val = create_const_vals(1); + err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->special = ConstValSpecialStatic; + err_set_val->data.x_err_set = nullptr; + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_err_union.err = nullptr; + const_instruction->base.value.data.x_err_union.error_set = err_set_val; const_instruction->base.value.data.x_err_union.payload = val; return &const_instruction->base; } @@ -9954,11 +10022,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so if (!val) return ira->codegen->invalid_instruction; + ConstExprValue *err_set_val = create_const_vals(1); + err_set_val->special = ConstValSpecialStatic; + err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->data.x_err_set = val->data.x_err_set; + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_err_union.err = val->data.x_err_set; + const_instruction->base.value.data.x_err_union.error_set = err_set_val; const_instruction->base.value.data.x_err_union.payload = nullptr; return &const_instruction->base; } @@ -9980,8 +10053,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.special = ConstValSpecialStatic; if (get_codegen_ptr_type(wanted_type) != nullptr) { - const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; - const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull; + } else if (is_opt_err_set(wanted_type)) { + const_instruction->base.value.data.x_err_set = nullptr; } else { const_instruction->base.value.data.x_optional = nullptr; } @@ -10014,7 +10088,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi source_instruction->source_node, value, is_const, is_volatile); new_instruction->value.type = ptr_type; new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; - if (type_has_bits(ptr_type)) { + if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); assert(fn_entry); fn_entry->alloca_list.append(new_instruction); @@ -10040,20 +10114,17 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s ZigType *array_type = array->value.type; assert(array_type->id == ZigTypeIdArray); - if (instr_is_comptime(array)) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + if (instr_is_comptime(array) || array_type->data.array.len == 0) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true); result->value.type = wanted_type; return result; } - IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, ira->codegen->builtin_types.entry_usize); + IrInstruction *start = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); init_const_usize(ira->codegen, &start->value, 0); - IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, ira->codegen->builtin_types.entry_usize); + IrInstruction *end = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_usize); init_const_usize(ira->codegen, &end->value, array_type->data.array.len); if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); @@ -10092,8 +10163,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); return result; } @@ -10103,8 +10173,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour actual_type->data.enumeration.src_field_count == 1) { assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_bigint(&result->value, wanted_type, &actual_type->data.enumeration.fields[0].value); return result; @@ -10127,8 +10196,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag); @@ -10139,8 +10207,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && wanted_type->data.enumeration.src_field_count == 1) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field; @@ -10157,8 +10224,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *wanted_type) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_undefined(ira->codegen, &result->value); return result; } @@ -10190,8 +10256,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.special = ConstValSpecialStatic; result->value.type = wanted_type; bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); @@ -10246,8 +10311,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; } } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); result->value.type = wanted_type; if (wanted_type->id == ZigTypeIdInt) { bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); @@ -10301,8 +10365,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); return result; } @@ -10320,8 +10383,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (wanted_type->id == ZigTypeIdComptimeFloat) { float_init_float(&result->value, val); } else if (wanted_type->id == ZigTypeIdComptimeInt) { @@ -10344,8 +10406,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) { return ira->codegen->invalid_instruction; @@ -10409,12 +10470,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); + IrInstruction *result = ir_const(ira, source_instr, wanted_type); ErrorTableEntry *err; if (err_type->id == ZigTypeIdErrorUnion) { - err = val->data.x_err_union.err; + err = val->data.x_err_union.error_set->data.x_err_set; } else if (err_type->id == ZigTypeIdErrorSet) { err = val->data.x_err_set; } else { @@ -10449,15 +10509,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc return ira->codegen->invalid_instruction; } if (err_set_type->data.error_set.err_count == 0) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); bigint_init_unsigned(&result->value.data.x_bigint, 0); return result; } else if (err_set_type->data.error_set.err_count == 1) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, - source_instr->source_node, wanted_type); - result->value.type = wanted_type; + IrInstruction *result = ir_const(ira, source_instr, wanted_type); ErrorTableEntry *err = err_set_type->data.error_set.errors[0]; bigint_init_unsigned(&result->value.data.x_bigint, err->value); return result; @@ -10504,8 +10560,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou array_val->type = array_type; array_val->data.x_array.special = ConstArraySpecialNone; array_val->data.x_array.data.s_none.elements = pointee; - array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar; - array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee; + array_val->parent.id = ConstParentIdScalar; + array_val->parent.data.p_scalar.scalar_val = pointee; IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -10653,12 +10709,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { 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); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); } else { return ira->codegen->invalid_instruction; } @@ -10682,7 +10738,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type); } } } @@ -10735,6 +10791,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat)) { + if (value->value.special == ConstValSpecialUndef) { + IrInstruction *result = ir_const(ira, source_instr, wanted_type); + result->value.special = ConstValSpecialUndef; + return result; + } if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) { if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { IrInstruction *result = ir_const(ira, source_instr, wanted_type); @@ -10788,6 +10849,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // cast from [N]T to []const T + // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; assert(ptr_type->id == ZigTypeIdPointer); @@ -10800,6 +10862,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // cast from [N]T to ?[]const T + // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this if (wanted_type->id == ZigTypeIdOptional && is_slice(wanted_type->data.maybe.child_type) && actual_type->id == ZigTypeIdArray) @@ -10894,7 +10957,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // cast from error set to error union type + // cast from E to E!T if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorSet) { @@ -11046,8 +11109,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ZigType *child_type = type_entry->data.pointer.child_type; // dereferencing a *u0 is comptime known to be 0 if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, child_type); + IrInstruction *result = ir_const(ira, source_instruction, child_type); init_const_unsigned_negative(&result->value, child_type, 0, false); return result; } @@ -11061,8 +11123,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc { ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, child_type); + IrInstruction *result = ir_const(ira, source_instruction, child_type); if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, &ptr->value))) @@ -11074,7 +11135,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc } } } - // TODO if the instruction is a const ref instruction we can skip it + // if the instruction is a const ref instruction we can skip it + if (ptr->id == IrInstructionIdRef) { + IrInstructionRef *ref_inst = reinterpret_cast(ptr); + return ref_inst->value; + } IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); load_ptr_instruction->value.type = child_type; @@ -11321,8 +11386,7 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) { IrInstruction *result = ir_const(ira, &instruction->base, nullptr); - // TODO determine if we need to use copy_const_val here - result->value = instruction->base.value; + copy_const_val(&result->value, &instruction->base.value, true); return result; } @@ -11397,6 +11461,8 @@ static bool optional_value_is_null(ConstExprValue *val) { if (get_codegen_ptr_type(val->type) != nullptr) { return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else if (is_opt_err_set(val->type)) { + return val->data.x_err_set == nullptr; } else { return val->data.x_optional == nullptr; } @@ -11596,19 +11662,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; - bool requires_comptime; - switch (type_requires_comptime(ira->codegen, resolved_type)) { - case ReqCompTimeYes: - requires_comptime = true; + bool one_possible_value; + switch (type_has_one_possible_value(ira->codegen, resolved_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + one_possible_value = true; break; - case ReqCompTimeNo: - requires_comptime = false; + case OnePossibleValueNo: + one_possible_value = false; break; - case ReqCompTimeInvalid: - return ira->codegen->invalid_instruction; } - bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type); if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) { ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad); if (op1_val == nullptr) @@ -12497,13 +12562,15 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { +static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, + IrInstructionDeclVarSrc *decl_var_instruction) +{ Error err; ZigVar *var = decl_var_instruction->var; IrInstruction *init_value = decl_var_instruction->init_value->child; if (type_is_invalid(init_value->value.type)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -12514,7 +12581,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct ZigType *proposed_type = ir_resolve_type(ira, var_type); explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type); if (type_is_invalid(explicit_type)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } } @@ -12539,7 +12606,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct case ReqCompTimeInvalid: result_type = ira->codegen->builtin_types.entry_invalid; break; - case ReqCompTimeYes: { + case ReqCompTimeYes: var_class_requires_const = true; if (!var->gen_is_const && !is_comptime_var) { ir_add_error_node(ira, source_node, @@ -12548,7 +12615,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct result_type = ira->codegen->builtin_types.entry_invalid; } break; - } case ReqCompTimeNo: if (casted_init_value->value.special == ConstValSpecialStatic && casted_init_value->value.type->id == ZigTypeIdFn && @@ -12567,7 +12633,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct break; } - if (var->value->type != nullptr && !is_comptime_var) { + if (var->var_type != nullptr && !is_comptime_var) { // This is at least the second time we've seen this variable declaration during analysis. // This means that this is actually a different variable due to, e.g. an inline while loop. // We make a new variable so that it can hold a different type, and so the debug info can @@ -12589,8 +12655,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct // This must be done after possibly creating a new variable above var->ref_count = 0; - var->value->type = result_type; - assert(var->value->type); + var->var_type = result_type; + assert(var->var_type); if (type_is_invalid(result_type)) { return ir_const_void(ira, &decl_var_instruction->base); @@ -12598,13 +12664,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct if (decl_var_instruction->align_value == nullptr) { if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ir_const_void(ira, &decl_var_instruction->base); } var->align_bytes = get_abi_alignment(ira->codegen, result_type); } else { if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) { - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; } } @@ -12621,7 +12687,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct } else if (is_comptime_var) { ir_add_error(ira, &decl_var_instruction->base, buf_sprintf("cannot store runtime value in compile time variable")); - var->value->type = ira->codegen->builtin_types.entry_invalid; + var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -12629,11 +12695,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct if (fn_entry) fn_entry->variable_list.append(var); - IrInstruction *result = ir_build_var_decl(&ira->new_irb, - decl_var_instruction->base.scope, decl_var_instruction->base.source_node, - var, var_type, nullptr, casted_init_value); - result->value.type = ira->codegen->builtin_types.entry_void; - return result; + return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); } static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { @@ -12963,7 +13025,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node Buf *param_name = param_decl_node->data.param_decl.name; ZigVar *var = add_variable(ira->codegen, param_decl_node, - *exec_scope, param_name, true, arg_val, nullptr); + *exec_scope, param_name, true, arg_val, nullptr, arg_val->type); *exec_scope = var->child_scope; *next_proto_i += 1; @@ -13021,7 +13083,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod if (!param_name) return false; if (!is_var_args) { ZigVar *var = add_variable(ira->codegen, param_decl_node, - *child_scope, param_name, true, arg_val, nullptr); + *child_scope, param_name, true, arg_val, nullptr, arg_val->type); *child_scope = var->child_scope; var->shadowable = !comptime_arg; @@ -13075,9 +13137,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) { return fn_entry->variable_list.at(next_var_i); } -static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, - ZigVar *var) -{ +static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { while (var->next_var != nullptr) { var = var->next_var; } @@ -13086,14 +13146,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(ira->codegen->errors.length != 0); return ira->codegen->invalid_instruction; } - if (var->value->type == nullptr || type_is_invalid(var->value->type)) + if (var->var_type == nullptr || type_is_invalid(var->var_type)) return ira->codegen->invalid_instruction; bool comptime_var_mem = ir_get_var_is_comptime(var); ConstExprValue *mem_slot = nullptr; - if (var->value->special == ConstValSpecialStatic) { - mem_slot = var->value; + if (var->const_value->special == ConstValSpecialStatic) { + mem_slot = var->const_value; } else { if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { // find the relevant exec_context @@ -13122,7 +13182,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, assert(!comptime_var_mem); ptr_mut = ConstPtrMutRuntimeVar; } - return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, + return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, ptr_mut, is_const, is_volatile, var->align_bytes); } } @@ -13133,7 +13193,7 @@ no_mem_slot: IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, instruction->scope, instruction->source_node, var); - var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, + var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); @@ -13142,6 +13202,96 @@ no_mem_slot: return var_ptr_instruction; } +static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *ptr, IrInstruction *uncasted_value) +{ + if (ptr->value.type->id != ZigTypeIdPointer) { + ir_add_error(ira, ptr, + buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); + return ira->codegen->invalid_instruction; + } + + if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { + return ir_const_void(ira, source_instr); + } + + if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) { + ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); + return ira->codegen->invalid_instruction; + } + + ZigType *child_type = ptr->value.type->data.pointer.child_type; + IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type); + if (value == ira->codegen->invalid_instruction) + return ira->codegen->invalid_instruction; + + if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { + ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); + return ira->codegen->invalid_instruction; + } + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { + if (instr_is_comptime(value)) { + ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node); + if (dest_val == nullptr) + return ira->codegen->invalid_instruction; + if (dest_val->special != ConstValSpecialRuntime) { + // TODO this allows a value stored to have the original value modified and then + // have that affect what should be a copy. We need some kind of advanced copy-on-write + // system to make these two tests pass at the same time: + // * "string literal used as comptime slice is memoized" + // * "comptime modification of const struct field" - except modified to avoid + // ConstPtrMutComptimeVar, thus defeating the logic below. + bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; + copy_const_val(dest_val, &value->value, same_global_refs); + if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; + break; + case OnePossibleValueYes: + break; + } + } + return ir_const_void(ira, source_instr); + } + } + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in compile time variable")); + ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + dest_val->type = ira->codegen->builtin_types.entry_invalid; + + return ira->codegen->invalid_instruction; + } + } + + switch (type_requires_comptime(ira->codegen, child_type)) { + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeYes: + switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const_void(ira, source_instr); + } + zig_unreachable(); + case ReqCompTimeNo: + break; + } + + IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, + ptr, value); + result->value.type = ira->codegen->builtin_types.entry_void; + return result; +} + static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) @@ -13286,7 +13436,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call } bool cacheable = fn_eval_cacheable(exec_scope, return_type); - IrInstruction *result = nullptr; + ConstExprValue *result = nullptr; if (cacheable) { auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); if (entry) @@ -13302,18 +13452,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; - if (result->value.type->id == ZigTypeIdErrorUnion) { - if (result->value.data.x_err_union.err != nullptr) { + if (result->type->id == ZigTypeIdErrorUnion) { + ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set; + if (err != nullptr) { inferred_err_set_type->data.error_set.err_count = 1; inferred_err_set_type->data.error_set.errors = allocate(1); - inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err; + inferred_err_set_type->data.error_set.errors[0] = err; } - ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type; + ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type; inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count; inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors; - } else if (result->value.type->id == ZigTypeIdErrorSet) { - inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count; - inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors; + } else if (result->type->id == ZigTypeIdErrorSet) { + inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count; + inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors; } } @@ -13321,13 +13472,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ira->codegen->memoized_fn_eval_table.put(exec_scope, result); } - if (type_is_invalid(result->value.type)) + if (type_is_invalid(result->type)) return ira->codegen->invalid_instruction; } - IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type); - // TODO should we use copy_const_val? - new_instruction->value = result->value; + IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); + copy_const_val(&new_instruction->value, result, true); new_instruction->value.type = return_type; return ir_finish_anal(ira, new_instruction); } @@ -13486,18 +13636,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen, first_var_arg, inst_fn_type_id.param_count); ZigVar *var = add_variable(ira->codegen, param_decl_node, - impl_fn->child_scope, param_name, true, var_args_val, nullptr); + impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type); impl_fn->child_scope = var->child_scope; } if (fn_proto_node->data.fn_proto.align_expr != nullptr) { - IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, + ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, + impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); + const_instruction->base.value = *align_result; uint32_t align_bytes = 0; - ir_resolve_align(ira, align_result, &align_bytes); + ir_resolve_align(ira, &const_instruction->base, &align_bytes); impl_fn->align_bytes = align_bytes; inst_fn_type_id.alignment = align_bytes; } @@ -13575,12 +13728,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ira->codegen->fn_defs.append(impl_fn); } - ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type; - if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) { + FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; + if (fn_type_can_fail(impl_fn_type_id)) { parent_fn_entry->calls_or_awaits_errorable_fn = true; } - size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count; + size_t impl_param_count = impl_fn_type_id->param_count; if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); @@ -13593,9 +13746,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call call_instruction->base.scope, call_instruction->base.source_node, impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, call_instruction->is_async, nullptr, casted_new_stack); - new_call_instruction->value.type = return_type; + new_call_instruction->value.type = impl_fn_type_id->return_type; - ir_add_alloca(ira, new_call_instruction, return_type); + ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -13790,6 +13943,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source switch (ptr_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); + case ConstPtrSpecialNull: + if (dst_size == 0) + return ErrorNone; + opt_ir_add_error_node(ira, codegen, source_node, + buf_sprintf("attempt to read %zu bytes from null pointer", + dst_size)); + return ErrorSemanticAnalyzeFail; case ConstPtrSpecialRef: { opt_ir_add_error_node(ira, codegen, source_node, buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", @@ -13822,6 +13982,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source return ErrorNone; } case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialBaseErrorUnionCode: + case ConstPtrSpecialBaseErrorUnionPayload: + case ConstPtrSpecialBaseOptionalPayload: case ConstPtrSpecialDiscard: case ConstPtrSpecialHardCodedAddr: case ConstPtrSpecialFunction: @@ -14017,9 +14180,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime)) return ir_unreach_error(ira); - if (is_comptime || instr_is_comptime(condition)) { + ZigType *bool_type = ira->codegen->builtin_types.entry_bool; + IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); + if (type_is_invalid(casted_condition->value.type)) + return ir_unreach_error(ira); + + if (is_comptime || instr_is_comptime(casted_condition)) { bool cond_is_true; - if (!ir_resolve_bool(ira, condition, &cond_is_true)) + if (!ir_resolve_bool(ira, casted_condition, &cond_is_true)) return ir_unreach_error(ira); IrBasicBlock *old_dest_block = cond_is_true ? @@ -14038,11 +14206,6 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi return ir_finish_anal(ira, result); } - ZigType *bool_type = ira->codegen->builtin_types.entry_bool; - IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type); - if (casted_condition == ira->codegen->invalid_instruction) - return ir_unreach_error(ira); - assert(cond_br_instruction->then_block != cond_br_instruction->else_block); IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base); if (new_then_block == nullptr) @@ -14081,8 +14244,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh if (value->value.special != ConstValSpecialRuntime) { IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr); - // TODO use copy_const_val? - result->value = value->value; + copy_const_val(&result->value, &value->value, true); return result; } else { return value; @@ -14131,14 +14293,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh if (type_is_invalid(resolved_type)) return ira->codegen->invalid_instruction; - if (resolved_type->id == ZigTypeIdComptimeFloat || - resolved_type->id == ZigTypeIdComptimeInt || - resolved_type->id == ZigTypeIdNull || - resolved_type->id == ZigTypeIdUndefined) - { + switch (type_has_one_possible_value(ira->codegen, resolved_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const(ira, &phi_instruction->base, resolved_type); + case OnePossibleValueNo: + break; + } + + switch (type_requires_comptime(ira->codegen, resolved_type)) { + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeYes: ir_add_error_node(ira, phi_instruction->base.source_node, - buf_sprintf("unable to infer expression type")); + buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name))); return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + break; } bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer); @@ -14428,10 +14600,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } case ConstPtrSpecialBaseStruct: zig_panic("TODO elem ptr on a const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO elem ptr on a const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO elem ptr on a const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO elem ptr on a const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO element ptr of a function casted to a ptr"); + case ConstPtrSpecialNull: + zig_panic("TODO elem ptr on a null pointer"); } if (new_index >= mem_size) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, @@ -14481,10 +14661,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } case ConstPtrSpecialBaseStruct: zig_panic("TODO elem ptr on a slice backed by const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO elem ptr on a slice backed by const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO elem ptr on a slice backed by const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO elem ptr on a slice backed by const optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO elem ptr on a slice that was ptrcast from a function"); + case ConstPtrSpecialNull: + zig_panic("TODO elem ptr on a slice has a null pointer"); } return result; } else if (array_type->id == ZigTypeIdArray) { @@ -15171,74 +15359,23 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc } } -static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { - IrInstruction *ptr = load_ptr_instruction->ptr->child; - if (type_is_invalid(ptr->value.type)) - return ira->codegen->invalid_instruction; - return ir_get_deref(ira, &load_ptr_instruction->base, ptr); -} - -static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { - IrInstruction *ptr = store_ptr_instruction->ptr->child; +static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) { + IrInstruction *ptr = instruction->ptr->child; if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *value = store_ptr_instruction->value->child; + IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - if (ptr->value.type->id != ZigTypeIdPointer) { - ir_add_error(ira, ptr, - buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name))); - return ira->codegen->invalid_instruction; - } - - if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) { - return ir_const_void(ira, &store_ptr_instruction->base); - } - - if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) { - ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_instruction; - } + return ir_analyze_store_ptr(ira, &instruction->base, ptr, value); +} - ZigType *child_type = ptr->value.type->data.pointer.child_type; - IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type); - if (casted_value == ira->codegen->invalid_instruction) +static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) { + IrInstruction *ptr = instruction->ptr->child; + if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - - if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) { - ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant")); - return ira->codegen->invalid_instruction; - } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { - if (instr_is_comptime(casted_value)) { - ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node); - if (dest_val == nullptr) - return ira->codegen->invalid_instruction; - if (dest_val->special != ConstValSpecialRuntime) { - *dest_val = casted_value->value; - if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { - ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base; - } - return ir_const_void(ira, &store_ptr_instruction->base); - } - } - ir_add_error(ira, &store_ptr_instruction->base, - buf_sprintf("cannot store runtime value in compile time variable")); - ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; - - return ira->codegen->invalid_instruction; - } - } - - IrInstruction *result = ir_build_store_ptr(&ira->new_irb, - store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node, - ptr, casted_value); - result->value.type = ira->codegen->builtin_types.entry_void; - return result; + return ir_get_deref(ira, &instruction->base, ptr); } static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { @@ -15709,11 +15846,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) - return ira->codegen->invalid_instruction; - +static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) { ZigType *type_entry = value->value.type; if (type_entry->id == ZigTypeIdOptional) { @@ -15722,60 +15855,66 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns if (!maybe_val) return ira->codegen->invalid_instruction; - return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val)); + return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val)); } IrInstruction *result = ir_build_test_nonnull(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); + source_inst->scope, source_inst->source_node, value); result->value.type = ira->codegen->builtin_types.entry_bool; return result; } else if (type_entry->id == ZigTypeIdNull) { - return ir_const_bool(ira, &instruction->base, false); + return ir_const_bool(ira, source_inst, false); } else { - return ir_const_bool(ira, &instruction->base, true); + return ir_const_bool(ira, source_inst, true); } } -static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, - IrInstructionUnwrapOptional *unwrap_maybe_instruction) -{ - IrInstruction *value = unwrap_maybe_instruction->value->child; +static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) { + IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + return ir_analyze_test_non_null(ira, &instruction->base, value); +} + +static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on) +{ + ZigType *ptr_type = base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id != ZigTypeIdOptional) { - ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node, + + if (type_entry->id != ZigTypeIdOptional) { + ir_add_error_node(ira, base_ptr->source_node, buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + ZigType *child_type = type_entry->data.maybe.child_type; ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0); - if (instr_is_comptime(value)) { - ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); + if (instr_is_comptime(base_ptr)) { + ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); if (!val) return ira->codegen->invalid_instruction; - ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node); + ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); if (maybe_val == nullptr) return ira->codegen->invalid_instruction; if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { if (optional_value_is_null(maybe_val)) { - ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); + ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type); + IrInstruction *result = ir_const(ira, source_instr, result_type); ConstExprValue *out_val = &result->value; out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.mut = val->data.x_ptr.mut; - if (type_is_codegen_pointer(child_type)) { + if (types_have_same_zig_comptime_repr(type_entry, child_type)) { out_val->data.x_ptr.data.ref.pointee = maybe_val; } else { out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; @@ -15784,13 +15923,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, } } - IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb, - unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node, - value, unwrap_maybe_instruction->safety_check_on); + IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr, safety_check_on); result->value.type = result_type; return result; } +static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, + IrInstructionOptionalUnwrapPtr *instruction) +{ + IrInstruction *base_ptr = instruction->base_ptr->child; + if (type_is_invalid(base_ptr->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); +} + static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) { IrInstruction *value = ctz_instruction->value->child; if (type_is_invalid(value->value.type)) { @@ -16091,9 +16239,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *result = ir_build_load_ptr(&ira->new_irb, - switch_target_instruction->base.scope, switch_target_instruction->base.source_node, - target_value_ptr); + IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); result->value.type = target_type; return result; } @@ -16123,8 +16269,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); union_value->value.type = target_type; IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, @@ -16148,8 +16293,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, - switch_target_instruction->base.source_node, target_value_ptr); + IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); enum_value->value.type = target_type; return enum_value; } @@ -16306,7 +16450,7 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI Error err; assert(container_type->id == ZigTypeIdUnion); - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; if (instr_field_count != 1) { @@ -16350,12 +16494,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI ConstExprValue *out_val = &result->value; out_val->data.x_union.payload = field_val; out_val->data.x_union.tag = type_field->enum_field->value; - - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdUnion; - parent->data.p_union.union_val = out_val; - } + out_val->parent.id = ConstParentIdUnion; + out_val->parent.data.p_union.union_val = out_val; return result; } @@ -16382,7 +16522,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } - if ((err = ensure_complete_type(ira->codegen, container_type))) + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; size_t actual_field_count = container_type->data.structure.src_field_count; @@ -16461,9 +16601,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc if (const_val.special == ConstValSpecialStatic) { IrInstruction *result = ir_const(ira, instruction, nullptr); ConstExprValue *out_val = &result->value; - // TODO copy_const_val? - *out_val = const_val; - result->value.type = container_type; + copy_const_val(out_val, &const_val, true); + out_val->type = container_type; for (size_t i = 0; i < instr_field_count; i += 1) { ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; @@ -16495,127 +16634,119 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { - IrInstruction *container_type_value = instruction->container_type->child; - if (type_is_invalid(container_type_value->value.type)) + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; size_t elem_count = instruction->item_count; - if (container_type_value->value.type->id == ZigTypeIdMetaType) { - ZigType *container_type = ir_resolve_type(ira, container_type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; - if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, - 0, nullptr); - } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { - // array is same as slice init but we make a compile error if the length is wrong - ZigType *child_type; - if (container_type->id == ZigTypeIdArray) { - child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); + if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, + 0, nullptr); + } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) { + // array is same as slice init but we make a compile error if the length is wrong + ZigType *child_type; + if (container_type->id == ZigTypeIdArray) { + child_type = container_type->data.array.child_type; + if (container_type->data.array.len != elem_count) { + ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); - ir_add_error(ira, &instruction->base, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_instruction; - } - } else { - ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; - assert(pointer_type->id == ZigTypeIdPointer); - child_type = pointer_type->data.pointer.child_type; + ir_add_error(ira, &instruction->base, + buf_sprintf("expected %s literal, found %s literal", + buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); + return ira->codegen->invalid_instruction; } + } else { + ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; + assert(pointer_type->id == ZigTypeIdPointer); + child_type = pointer_type->data.pointer.child_type; + } - ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); + ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.type = fixed_size_array_type; - const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); + ConstExprValue const_val = {}; + const_val.special = ConstValSpecialStatic; + const_val.type = fixed_size_array_type; + const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); - IrInstruction **new_items = allocate(elem_count); + IrInstruction **new_items = allocate(elem_count); - IrInstruction *first_non_const_instruction = nullptr; + IrInstruction *first_non_const_instruction = nullptr; - for (size_t i = 0; i < elem_count; i += 1) { - IrInstruction *arg_value = instruction->items[i]->child; - if (type_is_invalid(arg_value->value.type)) - return ira->codegen->invalid_instruction; + for (size_t i = 0; i < elem_count; i += 1) { + IrInstruction *arg_value = instruction->items[i]->child; + if (type_is_invalid(arg_value->value.type)) + return ira->codegen->invalid_instruction; - IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); - if (casted_arg == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; + IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); + if (casted_arg == ira->codegen->invalid_instruction) + return ira->codegen->invalid_instruction; - new_items[i] = casted_arg; + new_items[i] = casted_arg; - if (const_val.special == ConstValSpecialStatic) { - if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { - ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); - if (!elem_val) - return ira->codegen->invalid_instruction; + if (const_val.special == ConstValSpecialStatic) { + if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { + ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); + if (!elem_val) + return ira->codegen->invalid_instruction; - copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); - } else { - first_non_const_instruction = casted_arg; - const_val.special = ConstValSpecialRuntime; - } + copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); + } else { + first_non_const_instruction = casted_arg; + const_val.special = ConstValSpecialRuntime; } } + } - if (const_val.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, nullptr); - ConstExprValue *out_val = &result->value; - // TODO copy_const_val? - *out_val = const_val; - result->value.type = fixed_size_array_type; - for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; - ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = out_val; - parent->data.p_array.elem_index = i; - } + if (const_val.special == ConstValSpecialStatic) { + IrInstruction *result = ir_const(ira, &instruction->base, nullptr); + ConstExprValue *out_val = &result->value; + copy_const_val(out_val, &const_val, true); + result->value.type = fixed_size_array_type; + for (size_t i = 0; i < elem_count; i += 1) { + ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; + ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); + if (parent != nullptr) { + parent->id = ConstParentIdArray; + parent->data.p_array.array_val = out_val; + parent->data.p_array.elem_index = i; } - return result; } + return result; + } - if (is_comptime) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_instruction; - } + if (is_comptime) { + ir_add_error_node(ira, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->invalid_instruction; + } - IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, - container_type_value, elem_count, new_items); - new_instruction->value.type = fixed_size_array_type; - ir_add_alloca(ira, new_instruction, fixed_size_array_type); - return new_instruction; - } else if (container_type->id == ZigTypeIdVoid) { - if (elem_count != 0) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); - return ira->codegen->invalid_instruction; - } - return ir_const_void(ira, &instruction->base); - } else { + IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, + nullptr, elem_count, new_items); + new_instruction->value.type = fixed_size_array_type; + ir_add_alloca(ira, new_instruction, fixed_size_array_type); + return new_instruction; + } else if (container_type->id == ZigTypeIdVoid) { + if (elem_count != 0) { ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); + buf_sprintf("void expression expects no arguments")); return ira->codegen->invalid_instruction; } + return ir_const_void(ira, &instruction->base); } else { - ir_add_error(ira, container_type_value, - buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name))); + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("type '%s' does not support array initialization", + buf_ptr(&container_type->name))); return ira->codegen->invalid_instruction; } } -static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { +static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, + IrInstructionContainerInitFields *instruction) +{ IrInstruction *container_type_value = instruction->container_type->child; ZigType *container_type = ir_resolve_type(ira, container_type_value); if (type_is_invalid(container_type)) @@ -16675,7 +16806,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type); + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set); if (type_is_invalid(casted_value->value.type)) return ira->codegen->invalid_instruction; @@ -16936,10 +17067,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig ZigVar *var = tld->var; - if ((err = ensure_complete_type(ira->codegen, var->value->type))) + if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) return ira->codegen->builtin_types.entry_invalid; - assert(var->value->type->id == ZigTypeIdMetaType); - return var->value->data.x_type; + + assert(var->const_value->type->id == ZigTypeIdMetaType); + return var->const_value->data.x_type; } static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) { @@ -16994,7 +17126,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco definition_array->special = ConstValSpecialStatic; definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count); definition_array->data.x_array.special = ConstArraySpecialNone; - definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count); init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false); @@ -17025,33 +17156,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub; inner_fields[2].special = ConstValSpecialStatic; inner_fields[2].type = type_info_definition_data_type; - inner_fields[2].data.x_union.parent.id = ConstParentIdStruct; - inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val; - inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1; + inner_fields[2].parent.id = ConstParentIdStruct; + inner_fields[2].parent.data.p_struct.struct_val = definition_val; + inner_fields[2].parent.data.p_struct.field_index = 1; switch (curr_entry->value->id) { case TldIdVar: { ZigVar *var = ((TldVar *)curr_entry->value)->var; - if ((err = ensure_complete_type(ira->codegen, var->value->type))) + if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) return ErrorSemanticAnalyzeFail; - if (var->value->type->id == ZigTypeIdMetaType) - { + if (var->const_value->type->id == ZigTypeIdMetaType) { // We have a variable of type 'type', so it's actually a type definition. // 0: Data.Type: type bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0); - inner_fields[2].data.x_union.payload = var->value; - } - else - { + inner_fields[2].data.x_union.payload = var->const_value; + } else { // We have a variable of another type, so we store the type of the variable. // 1: Data.Var: type bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1); ConstExprValue *payload = create_const_vals(1); payload->type = ira->codegen->builtin_types.entry_type; - payload->data.x_type = var->value->type; + payload->data.x_type = var->const_value->type; inner_fields[2].data.x_union.payload = payload; } @@ -17071,8 +17199,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco ConstExprValue *fn_def_val = create_const_vals(1); fn_def_val->special = ConstValSpecialStatic; fn_def_val->type = type_info_fn_def_type; - fn_def_val->data.x_struct.parent.id = ConstParentIdUnion; - fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2]; + fn_def_val->parent.id = ConstParentIdUnion; + fn_def_val->parent.data.p_union.union_val = &inner_fields[2]; ConstExprValue *fn_def_fields = create_const_vals(9); fn_def_val->data.x_struct.fields = fn_def_fields; @@ -17136,20 +17264,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco fn_arg_name_array->type = get_array_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr), fn_arg_count); fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false); - for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) - { + for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) { ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name); init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true); - fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray; - fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array; - fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; + fn_arg_name_val->parent.id = ConstParentIdArray; + fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array; + fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index; } inner_fields[2].data.x_union.payload = fn_def_val; @@ -17442,7 +17568,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE enum_field_array->special = ConstValSpecialStatic; enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); enum_field_array->data.x_array.special = ConstArraySpecialNone; - enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false); @@ -17452,9 +17577,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index]; ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index]; make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type); - enum_field_val->data.x_struct.parent.id = ConstParentIdArray; - enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array; - enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index; + enum_field_val->parent.id = ConstParentIdArray; + enum_field_val->parent.data.p_array.array_val = enum_field_array; + enum_field_val->parent.data.p_array.elem_index = enum_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); @@ -17481,7 +17606,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE error_array->special = ConstValSpecialStatic; error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); error_array->data.x_array.special = ConstArraySpecialNone; - error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false); @@ -17505,9 +17629,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value); error_val->data.x_struct.fields = inner_fields; - error_val->data.x_struct.parent.id = ConstParentIdArray; - error_val->data.x_struct.parent.data.p_array.array_val = error_array; - error_val->data.x_struct.parent.data.p_array.elem_index = error_index; + error_val->parent.id = ConstParentIdArray; + error_val->parent.data.p_array.array_val = error_array; + error_val->parent.data.p_array.elem_index = error_index; } break; @@ -17576,7 +17700,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE union_field_array->special = ConstValSpecialStatic; union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); union_field_array->data.x_array.special = ConstArraySpecialNone; - union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); @@ -17609,9 +17732,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true); union_field_val->data.x_struct.fields = inner_fields; - union_field_val->data.x_struct.parent.id = ConstParentIdArray; - union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array; - union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index; + union_field_val->parent.id = ConstParentIdArray; + union_field_val->parent.data.p_array.array_val = union_field_array; + union_field_val->parent.data.p_array.elem_index = union_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 3); @@ -17651,7 +17774,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE struct_field_array->special = ConstValSpecialStatic; struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); struct_field_array->data.x_array.special = ConstArraySpecialNone; - struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); @@ -17685,9 +17807,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true); struct_field_val->data.x_struct.fields = inner_fields; - struct_field_val->data.x_struct.parent.id = ConstParentIdArray; - struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array; - struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index; + struct_field_val->parent.id = ConstParentIdArray; + struct_field_val->parent.data.p_array.array_val = struct_field_array; + struct_field_val->parent.data.p_array.elem_index = struct_field_index; } // defs: []TypeInfo.Definition ensure_field_index(result->type, "defs", 2); @@ -17757,7 +17879,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE fn_arg_array->special = ConstValSpecialStatic; fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); fn_arg_array->data.x_array.special = ConstArraySpecialNone; - fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone; fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false); @@ -17794,9 +17915,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE } fn_arg_val->data.x_struct.fields = inner_fields; - fn_arg_val->data.x_struct.parent.id = ConstParentIdArray; - fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array; - fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index; + fn_arg_val->parent.id = ConstParentIdArray; + fn_arg_val->parent.data.p_array.array_val = fn_arg_array; + fn_arg_val->parent.data.p_array.elem_index = fn_arg_index; } break; @@ -17840,8 +17961,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, if (payload != nullptr) { assert(payload->type->id == ZigTypeIdStruct); - payload->data.x_struct.parent.id = ConstParentIdUnion; - payload->data.x_struct.parent.data.p_union.union_val = out_val; + payload->parent.id = ConstParentIdUnion; + payload->parent.data.p_union.union_val = out_val; } return result; @@ -17913,10 +18034,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct // Execute the C import block like an inline function ZigType *void_type = ira->codegen->builtin_types.entry_void; - IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, + ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, &cimport_scope->buf, block_node, nullptr, nullptr); - if (type_is_invalid(cimport_result->value.type)) + if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; find_libc_include_path(ira->codegen); @@ -18066,7 +18187,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru return result; } -static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { +static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) { ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child); if (type_is_invalid(operand_type)) return ira->codegen->invalid_instruction; @@ -18138,9 +18259,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi zig_panic("TODO compile-time execution of cmpxchg"); } - IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node, - nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak, - operand_type, success_order, failure_order); + IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, + casted_ptr, casted_cmp_value, casted_new_value, + success_order, failure_order, instruction->is_weak); result->value.type = get_optional_type(ira->codegen, operand_type); ir_add_alloca(ira, result, result->value.type); return result; @@ -18312,18 +18433,6 @@ static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInst return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type); } -static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { - Error err; - - if (ty->id == ZigTypeIdPointer) { - if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return err; - } - - *result_align = get_ptr_align(ira->codegen, ty); - return ErrorNone; -} - static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) { Error err; @@ -18442,6 +18551,20 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true); } +static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { + Error err; + + ZigType *ptr_type = get_src_ptr_type(ty); + assert(ptr_type != nullptr); + if (ptr_type->id == ZigTypeIdPointer) { + if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return err; + } + + *result_align = get_ptr_align(ira->codegen, ty); + return ErrorNone; +} + static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) { ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); if (type_is_invalid(dest_type)) @@ -18646,10 +18769,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memset on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memset on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memset on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memset on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memset on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memset on null ptr"); } size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); @@ -18761,10 +18892,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); } if (dest_start + count > dest_end) { @@ -18797,10 +18936,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio } case ConstPtrSpecialBaseStruct: zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO memcpy on const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO memcpy on const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO memcpy on const inner optional payload"); case ConstPtrSpecialHardCodedAddr: zig_unreachable(); case ConstPtrSpecialFunction: zig_panic("TODO memcpy on ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO memcpy on null ptr"); } if (src_start + count > src_end) { @@ -18828,9 +18975,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction if (type_is_invalid(ptr_ptr->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = ptr_ptr->value.type; - assert(ptr_type->id == ZigTypeIdPointer); - ZigType *array_type = ptr_type->data.pointer.child_type; + ZigType *ptr_ptr_type = ptr_ptr->value.type; + assert(ptr_ptr_type->id == ZigTypeIdPointer); + ZigType *array_type = ptr_ptr_type->data.pointer.child_type; IrInstruction *start = instruction->start->child; if (type_is_invalid(start->value.type)) @@ -18859,10 +19006,10 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic && ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, - ptr_type->data.pointer.is_const || is_comptime_const, - ptr_type->data.pointer.is_volatile, + ptr_ptr_type->data.pointer.is_const || is_comptime_const, + ptr_ptr_type->data.pointer.is_volatile, PtrLenUnknown, - ptr_type->data.pointer.explicit_alignment, 0, 0); + ptr_ptr_type->data.pointer.explicit_alignment, 0, 0); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else if (array_type->id == ZigTypeIdPointer) { if (array_type->data.pointer.ptr_len == PtrLenSingle) { @@ -18960,6 +19107,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialBaseStruct: zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO slice const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO slice const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO slice const inner optional payload"); case ConstPtrSpecialHardCodedAddr: array_val = nullptr; abs_offset = 0; @@ -18967,6 +19120,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO slice of ptr cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO slice of null ptr"); } } else if (is_slice(array_type)) { ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node); @@ -18997,6 +19152,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialBaseStruct: zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO slice const inner error union code"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO slice const inner error union payload"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO slice const inner optional payload"); case ConstPtrSpecialHardCodedAddr: array_val = nullptr; abs_offset = 0; @@ -19004,6 +19165,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO slice of slice cast from function"); + case ConstPtrSpecialNull: + zig_panic("TODO slice of null"); } } else { zig_unreachable(); @@ -19069,6 +19232,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction zig_unreachable(); case ConstPtrSpecialBaseStruct: zig_panic("TODO"); + case ConstPtrSpecialBaseErrorUnionCode: + zig_panic("TODO"); + case ConstPtrSpecialBaseErrorUnionPayload: + zig_panic("TODO"); + case ConstPtrSpecialBaseOptionalPayload: + zig_panic("TODO"); case ConstPtrSpecialHardCodedAddr: init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, parent_ptr->type->data.pointer.child_type, @@ -19077,6 +19246,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction break; case ConstPtrSpecialFunction: zig_panic("TODO"); + case ConstPtrSpecialNull: + zig_panic("TODO"); } ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; @@ -19432,7 +19603,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { - return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr)); + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + return ir_const_bool(ira, &instruction->base, (err != nullptr)); } } @@ -19458,48 +19630,47 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } -static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, - IrInstructionUnwrapErrCode *instruction) -{ - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) +static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { + IrInstruction *base_ptr = instruction->err_union->child; + if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_instruction; - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.err; - assert(err); - - IrInstruction *result = ir_const(ira, &instruction->base, - type_entry->data.error_union.err_set_type); - result->value.data.x_err_set = err; - return result; - } - } - IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); - result->value.type = type_entry->data.error_union.err_set_type; - return result; - } else { - ir_add_error(ira, value, + if (type_entry->id != ZigTypeIdErrorUnion) { + ir_add_error(ira, base_ptr, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + + if (instr_is_comptime(base_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + if (err_union_val == nullptr) + return ira->codegen->invalid_instruction; + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + assert(err); + + IrInstruction *result = ir_const(ira, &instruction->base, + type_entry->data.error_union.err_set_type); + result->value.data.x_err_set = err; + return result; + } + } + + IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, base_ptr); + result->value.type = type_entry->data.error_union.err_set_type; + return result; } static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, @@ -19515,48 +19686,48 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, assert(ptr_type->id == ZigTypeIdPointer); ZigType *type_entry = ptr_type->data.pointer.child_type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { - ZigType *payload_type = type_entry->data.error_union.payload_type; - if (type_is_invalid(payload_type)) { - return ira->codegen->invalid_instruction; - } - ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0); - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); - if (err_union_val == nullptr) - return ira->codegen->invalid_instruction; - if (err_union_val->special != ConstValSpecialRuntime) { - ErrorTableEntry *err = err_union_val->data.x_err_union.err; - if (err != nullptr) { - ir_add_error(ira, &instruction->base, - buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); - return ira->codegen->invalid_instruction; - } - IrInstruction *result = ir_const(ira, &instruction->base, result_type); - result->value.data.x_ptr.special = ConstPtrSpecialRef; - result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; - return result; - } - } - - IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); - result->value.type = result_type; - return result; - } else { + if (type_entry->id != ZigTypeIdErrorUnion) { ir_add_error(ira, value, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } + ZigType *payload_type = type_entry->data.error_union.payload_type; + if (type_is_invalid(payload_type)) + return ira->codegen->invalid_instruction; + + ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, + PtrLenSingle, 0, 0, 0); + if (instr_is_comptime(value)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + if (err_union_val == nullptr) + return ira->codegen->invalid_instruction; + if (err_union_val->special != ConstValSpecialRuntime) { + ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; + if (err != nullptr) { + ir_add_error(ira, &instruction->base, + buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); + return ira->codegen->invalid_instruction; + } + + IrInstruction *result = ir_const(ira, &instruction->base, result_type); + result->value.data.x_ptr.special = ConstPtrSpecialRef; + result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; + return result; + } + } + + IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, + instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); + result->value.type = result_type; + return result; } static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { @@ -19973,7 +20144,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type); + IrInstruction *result = ir_const(ira, target, result_type); copy_const_val(&result->value, val, false); result->value.type = result_type; return result; @@ -20021,8 +20192,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, - dest_type); + IrInstruction *result = ir_const(ira, source_instr, dest_type); copy_const_val(&result->value, val, false); result->value.type = dest_type; return result; @@ -20045,9 +20215,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return ira->codegen->invalid_instruction; } - IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope, - source_instr->source_node, nullptr, ptr); - casted_ptr->value.type = dest_type; + IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -20073,7 +20241,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return result; } -static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { +static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) @@ -20211,15 +20379,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) return err; } - break; + return ErrorNone; case ConstArraySpecialUndef: zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); case ConstArraySpecialBuf: zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); } - - return ErrorNone; + zig_unreachable(); } + case ZigTypeIdEnum: + switch (val->type->data.enumeration.layout) { + case ContainerLayoutAuto: + zig_panic("TODO buf_read_value_bytes enum auto"); + case ContainerLayoutPacked: + zig_panic("TODO buf_read_value_bytes enum packed"); + case ContainerLayoutExtern: { + ZigType *tag_int_type = val->type->data.enumeration.tag_int_type; + assert(tag_int_type->id == ZigTypeIdInt); + bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count, + codegen->is_big_endian, tag_int_type->data.integral.is_signed); + return ErrorNone; + } + } + zig_unreachable(); case ZigTypeIdStruct: switch (val->type->data.structure.layout) { case ContainerLayoutAuto: { @@ -20258,8 +20440,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_panic("TODO buf_read_value_bytes error union"); case ZigTypeIdErrorSet: zig_panic("TODO buf_read_value_bytes pure error type"); - case ZigTypeIdEnum: - zig_panic("TODO buf_read_value_bytes enum type"); case ZigTypeIdFn: zig_panic("TODO buf_read_value_bytes fn type"); case ZigTypeIdUnion: @@ -20426,8 +20606,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, case TldIdContainer: case TldIdCompTime: zig_unreachable(); - case TldIdVar: - { + case TldIdVar: { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; @@ -20445,8 +20624,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, return ir_get_deref(ira, &instruction->base, var_ptr); } } - case TldIdFn: - { + case TldIdFn: { TldFn *tld_fn = (TldFn *)tld; ZigFn *fn_entry = tld_fn->fn_entry; assert(fn_entry->type_entry); @@ -20492,8 +20670,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru if (!val) return ira->codegen->invalid_instruction; if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, usize); + IrInstruction *result = ir_const(ira, &instruction->base, usize); bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr); result->value.type = usize; return result; @@ -21331,6 +21508,9 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdCast: + case IrInstructionIdDeclVarGen: + case IrInstructionIdPtrCastGen: + case IrInstructionIdCmpxchgGen: zig_unreachable(); case IrInstructionIdReturn: @@ -21341,8 +21521,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction); case IrInstructionIdBinOp: return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); - case IrInstructionIdDeclVar: - return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); + case IrInstructionIdDeclVarSrc: + return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction); case IrInstructionIdLoadPtr: return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); case IrInstructionIdStorePtr: @@ -21387,8 +21567,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); case IrInstructionIdTestNonNull: return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapOptional: - return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction); case IrInstructionIdClz: return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -21429,8 +21609,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); case IrInstructionIdEmbedFile: return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction); - case IrInstructionIdCmpxchg: - return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgSrc: + return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction); case IrInstructionIdFence: return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction); case IrInstructionIdTruncate: @@ -21497,8 +21677,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); case IrInstructionIdPanic: return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); - case IrInstructionIdPtrCast: - return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastSrc: + return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); case IrInstructionIdBitCast: return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); case IrInstructionIdIntToPtr: @@ -21682,7 +21862,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdBr: case IrInstructionIdCondBr: case IrInstructionIdSwitchBr: - case IrInstructionIdDeclVar: + case IrInstructionIdDeclVarSrc: + case IrInstructionIdDeclVarGen: case IrInstructionIdStorePtr: case IrInstructionIdCall: case IrInstructionIdReturn: @@ -21697,7 +21878,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCInclude: case IrInstructionIdCDefine: case IrInstructionIdCUndef: - case IrInstructionIdCmpxchg: case IrInstructionIdFence: case IrInstructionIdMemset: case IrInstructionIdMemcpy: @@ -21725,6 +21905,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdMergeErrRetTraces: case IrInstructionIdMarkErrRetTracePtr: case IrInstructionIdAtomicRmw: + case IrInstructionIdCmpxchgGen: + case IrInstructionIdCmpxchgSrc: return true; case IrInstructionIdPhi: @@ -21750,7 +21932,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdTestNonNull: - case IrInstructionIdUnwrapOptional: + case IrInstructionIdOptionalUnwrapPtr: case IrInstructionIdClz: case IrInstructionIdCtz: case IrInstructionIdPopCount: @@ -21777,7 +21959,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: - case IrInstructionIdPtrCast: + case IrInstructionIdPtrCastSrc: + case IrInstructionIdPtrCastGen: case IrInstructionIdBitCast: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir.hpp b/src/ir.hpp index 7af1d7f52b..0a7c614812 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -13,7 +13,7 @@ bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); -IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, +ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, IrExecutable *parent_exec); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b5099db86a..a3ec8e9d35 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -172,7 +172,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction } } -static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) { +static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) { const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; const char *name = buf_ptr(&decl_var_instruction->var->name); if (decl_var_instruction->var_type) { @@ -332,8 +332,8 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { } static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { - fprintf(irp->f, "*"); ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ".*"); } static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { @@ -479,15 +479,15 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) { fprintf(irp->f, ")"); } -static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { - fprintf(irp->f, "*"); +static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) { ir_print_other_instruction(irp, instruction->value); fprintf(irp->f, " != null"); } -static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) { - fprintf(irp->f, "&??*"); - ir_print_other_instruction(irp, instruction->value); +static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) { + fprintf(irp->f, "&"); + ir_print_other_instruction(irp, instruction->base_ptr); + fprintf(irp->f, ".*.?"); if (!instruction->safety_check_on) { fprintf(irp->f, " // no safety"); } @@ -613,7 +613,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio fprintf(irp->f, ")"); } -static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { +static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) { fprintf(irp->f, "@cmpxchg("); ir_print_other_instruction(irp, instruction->ptr); fprintf(irp->f, ", "); @@ -627,6 +627,16 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) { fprintf(irp->f, ")"); } +static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { + fprintf(irp->f, "@cmpxchg("); + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->cmp_value); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->new_value); + fprintf(irp->f, ", TODO print atomic orders)"); +} + static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { fprintf(irp->f, "@fence("); ir_print_other_instruction(irp, instruction->order_value); @@ -820,13 +830,13 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { } static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { - fprintf(irp->f, "@unwrapErrorCode("); - ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, "UnwrapErrorCode("); + ir_print_other_instruction(irp, instruction->err_union); fprintf(irp->f, ")"); } static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { - fprintf(irp->f, "@unwrapErrorPayload("); + fprintf(irp->f, "ErrorUnionFieldPayload("); ir_print_other_instruction(irp, instruction->value); fprintf(irp->f, ")"); if (!instruction->safety_check_on) { @@ -879,7 +889,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst fprintf(irp->f, ")"); } -static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { +static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) { fprintf(irp->f, "@ptrCast("); if (instruction->dest_type) { ir_print_other_instruction(irp, instruction->dest_type); @@ -889,6 +899,12 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { fprintf(irp->f, ")"); } +static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) { + fprintf(irp->f, "@ptrCast("); + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, ")"); +} + static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { fprintf(irp->f, "@bitCast("); if (instruction->dest_type) { @@ -900,7 +916,7 @@ static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { } static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { - fprintf(irp->f, "@widenOrShorten("); + fprintf(irp->f, "WidenOrShorten("); ir_print_other_instruction(irp, instruction->target); fprintf(irp->f, ")"); } @@ -1323,6 +1339,20 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { fprintf(irp->f, ")"); } +static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) { + ZigVar *var = decl_var_instruction->var; + const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var"; + const char *name = buf_ptr(&decl_var_instruction->var->name); + fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), + var->align_bytes); + + ir_print_other_instruction(irp, decl_var_instruction->init_value); + if (decl_var_instruction->var->is_comptime != nullptr) { + fprintf(irp->f, " // comptime = "); + ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime); + } +} + static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) { fprintf(irp->f, "@bswap("); if (instruction->type != nullptr) { @@ -1361,8 +1391,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdBinOp: ir_print_bin_op(irp, (IrInstructionBinOp *)instruction); break; - case IrInstructionIdDeclVar: - ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction); + case IrInstructionIdDeclVarSrc: + ir_print_decl_var_src(irp, (IrInstructionDeclVarSrc *)instruction); break; case IrInstructionIdCast: ir_print_cast(irp, (IrInstructionCast *)instruction); @@ -1452,10 +1482,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_size_of(irp, (IrInstructionSizeOf *)instruction); break; case IrInstructionIdTestNonNull: - ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction); + ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction); break; - case IrInstructionIdUnwrapOptional: - ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction); + case IrInstructionIdOptionalUnwrapPtr: + ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction); break; case IrInstructionIdCtz: ir_print_ctz(irp, (IrInstructionCtz *)instruction); @@ -1508,8 +1538,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdEmbedFile: ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction); break; - case IrInstructionIdCmpxchg: - ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction); + case IrInstructionIdCmpxchgSrc: + ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction); + break; + case IrInstructionIdCmpxchgGen: + ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction); break; case IrInstructionIdFence: ir_print_fence(irp, (IrInstructionFence *)instruction); @@ -1607,8 +1640,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTestComptime: ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); break; - case IrInstructionIdPtrCast: - ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction); + case IrInstructionIdPtrCastSrc: + ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction); + break; + case IrInstructionIdPtrCastGen: + ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; case IrInstructionIdBitCast: ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); @@ -1775,6 +1811,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCheckRuntimeScope: ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction); break; + case IrInstructionIdDeclVarGen: + ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/parser.cpp b/src/parser.cpp index 077365995e..81bd469d1c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse else_body = ast_expect(pc, body_parser); } - assert(res->type == NodeTypeTestExpr); + assert(res->type == NodeTypeIfOptional); if (err_payload != nullptr) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; @@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { if (requires_semi && else_body == nullptr) expect_token(pc, TokenIdSemicolon); - assert(res->type == NodeTypeTestExpr); + assert(res->type == NodeTypeIfOptional); if (err_payload != nullptr) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; @@ -2204,7 +2204,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { Optional opt_payload = ast_parse_ptr_payload(pc); PtrPayload payload; - AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first); + AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); res->data.test_expr.target_node = condition; if (opt_payload.unwrap(&payload)) { res->data.test_expr.var_symbol = token_buf(payload.payload); @@ -2999,7 +2999,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.if_err_expr.then_node, visit, context); visit_field(&node->data.if_err_expr.else_node, visit, context); break; - case NodeTypeTestExpr: + case NodeTypeIfOptional: visit_field(&node->data.test_expr.target_node, visit, context); visit_field(&node->data.test_expr.then_node, visit, context); visit_field(&node->data.test_expr.else_node, visit, context); diff --git a/std/event/fs.zig b/std/event/fs.zig index 1b8e1aa5dc..7e77b3e6e2 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -1307,32 +1307,29 @@ pub fn Watch(comptime V: type) type { const test_tmp_dir = "std_event_fs_test"; -test "write a file, watch it, write it again" { - if (builtin.os == builtin.Os.windows) { - // TODO this test is disabled on windows until the coroutine rewrite is finished. - // https://github.com/ziglang/zig/issues/1363 - return error.SkipZigTest; - } - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const allocator = &da.allocator; - - // TODO move this into event loop too - try os.makePath(allocator, test_tmp_dir); - defer os.deleteTree(allocator, test_tmp_dir) catch {}; - - var loop: Loop = undefined; - try loop.initMultiThreaded(allocator); - defer loop.deinit(); - - var result: anyerror!void = error.ResultNeverWritten; - const handle = try async testFsWatchCantFail(&loop, &result); - defer cancel handle; - - loop.run(); - return result; -} +// TODO this test is disabled until the coroutine rewrite is finished. +//test "write a file, watch it, write it again" { +// return error.SkipZigTest; +// var da = std.heap.DirectAllocator.init(); +// defer da.deinit(); +// +// const allocator = &da.allocator; +// +// // TODO move this into event loop too +// try os.makePath(allocator, test_tmp_dir); +// defer os.deleteTree(allocator, test_tmp_dir) catch {}; +// +// var loop: Loop = undefined; +// try loop.initMultiThreaded(allocator); +// defer loop.deinit(); +// +// var result: anyerror!void = error.ResultNeverWritten; +// const handle = try async testFsWatchCantFail(&loop, &result); +// defer cancel handle; +// +// loop.run(); +// return result; +//} async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void { result.* = await (async testFsWatch(loop) catch unreachable); diff --git a/test/behavior.zig b/test/behavior.zig deleted file mode 100644 index 10cd08dad7..0000000000 --- a/test/behavior.zig +++ /dev/null @@ -1,82 +0,0 @@ -const builtin = @import("builtin"); - -comptime { - _ = @import("cases/align.zig"); - _ = @import("cases/alignof.zig"); - _ = @import("cases/array.zig"); - _ = @import("cases/asm.zig"); - _ = @import("cases/atomics.zig"); - _ = @import("cases/bitcast.zig"); - _ = @import("cases/bool.zig"); - _ = @import("cases/bswap.zig"); - _ = @import("cases/bitreverse.zig"); - _ = @import("cases/bugs/1076.zig"); - _ = @import("cases/bugs/1111.zig"); - _ = @import("cases/bugs/1277.zig"); - _ = @import("cases/bugs/1322.zig"); - _ = @import("cases/bugs/1381.zig"); - _ = @import("cases/bugs/1421.zig"); - _ = @import("cases/bugs/1442.zig"); - _ = @import("cases/bugs/1486.zig"); - _ = @import("cases/bugs/394.zig"); - _ = @import("cases/bugs/655.zig"); - _ = @import("cases/bugs/656.zig"); - _ = @import("cases/bugs/726.zig"); - _ = @import("cases/bugs/828.zig"); - _ = @import("cases/bugs/920.zig"); - _ = @import("cases/byval_arg_var.zig"); - _ = @import("cases/cancel.zig"); - _ = @import("cases/cast.zig"); - _ = @import("cases/const_slice_child.zig"); - _ = @import("cases/coroutine_await_struct.zig"); - _ = @import("cases/coroutines.zig"); - _ = @import("cases/defer.zig"); - _ = @import("cases/enum.zig"); - _ = @import("cases/enum_with_members.zig"); - _ = @import("cases/error.zig"); - _ = @import("cases/eval.zig"); - _ = @import("cases/field_parent_ptr.zig"); - _ = @import("cases/fn.zig"); - _ = @import("cases/fn_in_struct_in_comptime.zig"); - _ = @import("cases/for.zig"); - _ = @import("cases/generics.zig"); - _ = @import("cases/if.zig"); - _ = @import("cases/import.zig"); - _ = @import("cases/incomplete_struct_param_tld.zig"); - _ = @import("cases/inttoptr.zig"); - _ = @import("cases/ir_block_deps.zig"); - _ = @import("cases/math.zig"); - _ = @import("cases/merge_error_sets.zig"); - _ = @import("cases/misc.zig"); - _ = @import("cases/namespace_depends_on_compile_var/index.zig"); - _ = @import("cases/new_stack_call.zig"); - _ = @import("cases/null.zig"); - _ = @import("cases/optional.zig"); - _ = @import("cases/pointers.zig"); - _ = @import("cases/popcount.zig"); - _ = @import("cases/ptrcast.zig"); - _ = @import("cases/pub_enum/index.zig"); - _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); - _ = @import("cases/reflection.zig"); - _ = @import("cases/sizeof_and_typeof.zig"); - _ = @import("cases/slice.zig"); - _ = @import("cases/struct.zig"); - _ = @import("cases/struct_contains_null_ptr_itself.zig"); - _ = @import("cases/struct_contains_slice_of_itself.zig"); - _ = @import("cases/switch.zig"); - _ = @import("cases/switch_prong_err_enum.zig"); - _ = @import("cases/switch_prong_implicit_cast.zig"); - _ = @import("cases/syntax.zig"); - _ = @import("cases/this.zig"); - _ = @import("cases/truncate.zig"); - _ = @import("cases/try.zig"); - _ = @import("cases/type_info.zig"); - _ = @import("cases/undefined.zig"); - _ = @import("cases/underscore.zig"); - _ = @import("cases/union.zig"); - _ = @import("cases/var_args.zig"); - _ = @import("cases/void.zig"); - _ = @import("cases/while.zig"); - _ = @import("cases/widening.zig"); - _ = @import("cases/bit_shifting.zig"); -} diff --git a/test/cases/align.zig b/test/cases/align.zig deleted file mode 100644 index 3dff57feb8..0000000000 --- a/test/cases/align.zig +++ /dev/null @@ -1,230 +0,0 @@ -const assert = @import("std").debug.assert; -const builtin = @import("builtin"); - -var foo: u8 align(4) = 100; - -test "global variable alignment" { - assert(@typeOf(&foo).alignment == 4); - assert(@typeOf(&foo) == *align(4) u8); - const slice = (*[1]u8)(&foo)[0..]; - assert(@typeOf(slice) == []align(4) u8); -} - -fn derp() align(@sizeOf(usize) * 2) i32 { - return 1234; -} -fn noop1() align(1) void {} -fn noop4() align(4) void {} - -test "function alignment" { - assert(derp() == 1234); - assert(@typeOf(noop1) == fn () align(1) void); - assert(@typeOf(noop4) == fn () align(4) void); - noop1(); - noop4(); -} - -var baz: packed struct { - a: u32, - b: u32, -} = undefined; - -test "packed struct alignment" { - assert(@typeOf(&baz.b) == *align(1) u32); -} - -const blah: packed struct { - a: u3, - b: u3, - c: u2, -} = undefined; - -test "bit field alignment" { - assert(@typeOf(&blah.b) == *align(1:3:1) const u3); -} - -test "default alignment allows unspecified in type syntax" { - assert(*u32 == *align(@alignOf(u32)) u32); -} - -test "implicitly decreasing pointer alignment" { - const a: u32 align(4) = 3; - const b: u32 align(8) = 4; - assert(addUnaligned(&a, &b) == 7); -} - -fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { - return a.* + b.*; -} - -test "implicitly decreasing slice alignment" { - const a: u32 align(4) = 3; - const b: u32 align(8) = 4; - assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); -} -fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { - return a[0] + b[0]; -} - -test "specifying alignment allows pointer cast" { - testBytesAlign(0x33); -} -fn testBytesAlign(b: u8) void { - var bytes align(4) = []u8{ - b, - b, - b, - b, - }; - const ptr = @ptrCast(*u32, &bytes[0]); - assert(ptr.* == 0x33333333); -} - -test "specifying alignment allows slice cast" { - testBytesAlignSlice(0x33); -} -fn testBytesAlignSlice(b: u8) void { - var bytes align(4) = []u8{ - b, - b, - b, - b, - }; - const slice: []u32 = @bytesToSlice(u32, bytes[0..]); - assert(slice[0] == 0x33333333); -} - -test "@alignCast pointers" { - var x: u32 align(4) = 1; - expectsOnly1(&x); - assert(x == 2); -} -fn expectsOnly1(x: *align(1) u32) void { - expects4(@alignCast(4, x)); -} -fn expects4(x: *align(4) u32) void { - x.* += 1; -} - -test "@alignCast slices" { - var array align(4) = []u32{ - 1, - 1, - }; - const slice = array[0..]; - sliceExpectsOnly1(slice); - assert(slice[0] == 2); -} -fn sliceExpectsOnly1(slice: []align(1) u32) void { - sliceExpects4(@alignCast(4, slice)); -} -fn sliceExpects4(slice: []align(4) u32) void { - slice[0] += 1; -} - -test "implicitly decreasing fn alignment" { - testImplicitlyDecreaseFnAlign(alignedSmall, 1234); - testImplicitlyDecreaseFnAlign(alignedBig, 5678); -} - -fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { - assert(ptr() == answer); -} - -fn alignedSmall() align(8) i32 { - return 1234; -} -fn alignedBig() align(16) i32 { - return 5678; -} - -test "@alignCast functions" { - assert(fnExpectsOnly1(simple4) == 0x19); -} -fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { - return fnExpects4(@alignCast(4, ptr)); -} -fn fnExpects4(ptr: fn () align(4) i32) i32 { - return ptr(); -} -fn simple4() align(4) i32 { - return 0x19; -} - -test "generic function with align param" { - assert(whyWouldYouEverDoThis(1) == 0x1); - assert(whyWouldYouEverDoThis(4) == 0x1); - assert(whyWouldYouEverDoThis(8) == 0x1); -} - -fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { - return 0x1; -} - -test "@ptrCast preserves alignment of bigger source" { - var x: u32 align(16) = 1234; - const ptr = @ptrCast(*u8, &x); - assert(@typeOf(ptr) == *align(16) u8); -} - -test "runtime known array index has best alignment possible" { - // take full advantage of over-alignment - var array align(4) = []u8{ 1, 2, 3, 4 }; - assert(@typeOf(&array[0]) == *align(4) u8); - assert(@typeOf(&array[1]) == *u8); - assert(@typeOf(&array[2]) == *align(2) u8); - assert(@typeOf(&array[3]) == *u8); - - // because align is too small but we still figure out to use 2 - var bigger align(2) = []u64{ 1, 2, 3, 4 }; - assert(@typeOf(&bigger[0]) == *align(2) u64); - assert(@typeOf(&bigger[1]) == *align(2) u64); - assert(@typeOf(&bigger[2]) == *align(2) u64); - assert(@typeOf(&bigger[3]) == *align(2) u64); - - // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 - var smaller align(2) = []u32{ 1, 2, 3, 4 }; - comptime assert(@typeOf(smaller[0..]) == []align(2) u32); - comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32); - testIndex(smaller[0..].ptr, 0, *align(2) u32); - testIndex(smaller[0..].ptr, 1, *align(2) u32); - testIndex(smaller[0..].ptr, 2, *align(2) u32); - testIndex(smaller[0..].ptr, 3, *align(2) u32); - - // has to use ABI alignment because index known at runtime only - testIndex2(array[0..].ptr, 0, *u8); - testIndex2(array[0..].ptr, 1, *u8); - testIndex2(array[0..].ptr, 2, *u8); - testIndex2(array[0..].ptr, 3, *u8); -} -fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { - comptime assert(@typeOf(&smaller[index]) == T); -} -fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { - comptime assert(@typeOf(&ptr[index]) == T); -} - -test "alignstack" { - assert(fnWithAlignedStack() == 1234); -} - -fn fnWithAlignedStack() i32 { - @setAlignStack(256); - return 1234; -} - -test "alignment of structs" { - assert(@alignOf(struct { - a: i32, - b: *i32, - }) == @alignOf(usize)); -} - -test "alignment of extern() void" { - var runtime_nothing = nothing; - const casted1 = @ptrCast(*const u8, runtime_nothing); - const casted2 = @ptrCast(extern fn () void, casted1); - casted2(); -} - -extern fn nothing() void {} diff --git a/test/cases/alignof.zig b/test/cases/alignof.zig deleted file mode 100644 index 433e86e45e..0000000000 --- a/test/cases/alignof.zig +++ /dev/null @@ -1,17 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const builtin = @import("builtin"); -const maxInt = std.math.maxInt; - -const Foo = struct { - x: u32, - y: u32, - z: u32, -}; - -test "@alignOf(T) before referencing T" { - comptime assert(@alignOf(Foo) != maxInt(usize)); - if (builtin.arch == builtin.Arch.x86_64) { - comptime assert(@alignOf(Foo) == 4); - } -} diff --git a/test/cases/array.zig b/test/cases/array.zig deleted file mode 100644 index 7c63a649a8..0000000000 --- a/test/cases/array.zig +++ /dev/null @@ -1,173 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -test "arrays" { - var array: [5]u32 = undefined; - - var i: u32 = 0; - while (i < 5) { - array[i] = i + 1; - i = array[i]; - } - - i = 0; - var accumulator = u32(0); - while (i < 5) { - accumulator += array[i]; - - i += 1; - } - - assert(accumulator == 15); - assert(getArrayLen(array) == 5); -} -fn getArrayLen(a: []const u32) usize { - return a.len; -} - -test "void arrays" { - var array: [4]void = undefined; - array[0] = void{}; - array[1] = array[2]; - assert(@sizeOf(@typeOf(array)) == 0); - assert(array.len == 4); -} - -test "array literal" { - const hex_mult = []u16{ - 4096, - 256, - 16, - 1, - }; - - assert(hex_mult.len == 4); - assert(hex_mult[1] == 256); -} - -test "array dot len const expr" { - assert(comptime x: { - break :x some_array.len == 4; - }); -} - -const ArrayDotLenConstExpr = struct { - y: [some_array.len]u8, -}; -const some_array = []u8{ - 0, - 1, - 2, - 3, -}; - -test "nested arrays" { - const array_of_strings = [][]const u8{ - "hello", - "this", - "is", - "my", - "thing", - }; - for (array_of_strings) |s, i| { - if (i == 0) assert(mem.eql(u8, s, "hello")); - if (i == 1) assert(mem.eql(u8, s, "this")); - if (i == 2) assert(mem.eql(u8, s, "is")); - if (i == 3) assert(mem.eql(u8, s, "my")); - if (i == 4) assert(mem.eql(u8, s, "thing")); - } -} - -var s_array: [8]Sub = undefined; -const Sub = struct { - b: u8, -}; -const Str = struct { - a: []Sub, -}; -test "set global var array via slice embedded in struct" { - var s = Str{ .a = s_array[0..] }; - - s.a[0].b = 1; - s.a[1].b = 2; - s.a[2].b = 3; - - assert(s_array[0].b == 1); - assert(s_array[1].b == 2); - assert(s_array[2].b == 3); -} - -test "array literal with specified size" { - var array = [2]u8{ - 1, - 2, - }; - assert(array[0] == 1); - assert(array[1] == 2); -} - -test "array child property" { - var x: [5]i32 = undefined; - assert(@typeOf(x).Child == i32); -} - -test "array len property" { - var x: [5]i32 = undefined; - assert(@typeOf(x).len == 5); -} - -test "array len field" { - var arr = [4]u8{ 0, 0, 0, 0 }; - var ptr = &arr; - assert(arr.len == 4); - comptime assert(arr.len == 4); - assert(ptr.len == 4); - comptime assert(ptr.len == 4); -} - -test "single-item pointer to array indexing and slicing" { - testSingleItemPtrArrayIndexSlice(); - comptime testSingleItemPtrArrayIndexSlice(); -} - -fn testSingleItemPtrArrayIndexSlice() void { - var array = "aaaa"; - doSomeMangling(&array); - assert(mem.eql(u8, "azya", array)); -} - -fn doSomeMangling(array: *[4]u8) void { - array[1] = 'z'; - array[2..3][0] = 'y'; -} - -test "implicit cast single-item pointer" { - testImplicitCastSingleItemPtr(); - comptime testImplicitCastSingleItemPtr(); -} - -fn testImplicitCastSingleItemPtr() void { - var byte: u8 = 100; - const slice = (*[1]u8)(&byte)[0..]; - slice[0] += 1; - assert(byte == 101); -} - -fn testArrayByValAtComptime(b: [2]u8) u8 { - return b[0]; -} - -test "comptime evalutating function that takes array by value" { - const arr = []u8{ 0, 1 }; - _ = comptime testArrayByValAtComptime(arr); - _ = comptime testArrayByValAtComptime(arr); -} - -test "implicit comptime in array type size" { - var arr: [plusOne(10)]bool = undefined; - assert(arr.len == 11); -} - -fn plusOne(x: u32) u32 { - return x + 1; -} diff --git a/test/cases/asm.zig b/test/cases/asm.zig deleted file mode 100644 index 63e37c857c..0000000000 --- a/test/cases/asm.zig +++ /dev/null @@ -1,48 +0,0 @@ -const config = @import("builtin"); -const assert = @import("std").debug.assert; - -comptime { - if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - asm volatile ( - \\.globl aoeu; - \\.type aoeu, @function; - \\.set aoeu, derp; - ); - } -} - -test "module level assembly" { - if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(aoeu() == 1234); - } -} - -test "output constraint modifiers" { - // This is only testing compilation. - var a: u32 = 3; - asm volatile ("" : [_]"=m,r"(a) : : ""); - asm volatile ("" : [_]"=r,m"(a) : : ""); -} - -test "alternative constraints" { - // Make sure we allow commas as a separator for alternative constraints. - var a: u32 = 3; - asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : ""); -} - -test "sized integer/float in asm input" { - asm volatile ("" : : [_]"m"(usize(3)) : ""); - asm volatile ("" : : [_]"m"(i15(-3)) : ""); - asm volatile ("" : : [_]"m"(u3(3)) : ""); - asm volatile ("" : : [_]"m"(i3(3)) : ""); - asm volatile ("" : : [_]"m"(u121(3)) : ""); - asm volatile ("" : : [_]"m"(i121(3)) : ""); - asm volatile ("" : : [_]"m"(f32(3.17)) : ""); - asm volatile ("" : : [_]"m"(f64(3.17)) : ""); -} - -extern fn aoeu() i32; - -export fn derp() i32 { - return 1234; -} diff --git a/test/cases/atomics.zig b/test/cases/atomics.zig deleted file mode 100644 index 67c9ab3dd1..0000000000 --- a/test/cases/atomics.zig +++ /dev/null @@ -1,71 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const builtin = @import("builtin"); -const AtomicRmwOp = builtin.AtomicRmwOp; -const AtomicOrder = builtin.AtomicOrder; - -test "cmpxchg" { - var x: i32 = 1234; - if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == 1234); - } else { - @panic("cmpxchg should have failed"); - } - - while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == 1234); - } - assert(x == 5678); - - assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assert(x == 42); -} - -test "fence" { - var x: i32 = 1234; - @fence(AtomicOrder.SeqCst); - x = 5678; -} - -test "atomicrmw and atomicload" { - var data: u8 = 200; - testAtomicRmw(&data); - assert(data == 42); - testAtomicLoad(&data); -} - -fn testAtomicRmw(ptr: *u8) void { - const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); - assert(prev_value == 200); - comptime { - var x: i32 = 1234; - const y: i32 = 12345; - assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); - assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); - } -} - -fn testAtomicLoad(ptr: *u8) void { - const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); - assert(x == 42); -} - -test "cmpxchg with ptr" { - var data1: i32 = 1234; - var data2: i32 = 5678; - var data3: i32 = 9101; - var x: *i32 = &data1; - if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == &data1); - } else { - @panic("cmpxchg should have failed"); - } - - while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assert(x1 == &data1); - } - assert(x == &data3); - - assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assert(x == &data2); -} diff --git a/test/cases/bit_shifting.zig b/test/cases/bit_shifting.zig deleted file mode 100644 index 325e765bb0..0000000000 --- a/test/cases/bit_shifting.zig +++ /dev/null @@ -1,88 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { - assert(Key == @IntType(false, Key.bit_count)); - assert(Key.bit_count >= mask_bit_count); - const ShardKey = @IntType(false, mask_bit_count); - const shift_amount = Key.bit_count - ShardKey.bit_count; - return struct { - const Self = @This(); - shards: [1 << ShardKey.bit_count]?*Node, - - pub fn create() Self { - return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) }; - } - - fn getShardKey(key: Key) ShardKey { - // https://github.com/ziglang/zig/issues/1544 - // this special case is needed because you can't u32 >> 32. - if (ShardKey == u0) return 0; - - // this can be u1 >> u0 - const shard_key = key >> shift_amount; - - // TODO: https://github.com/ziglang/zig/issues/1544 - // This cast could be implicit if we teach the compiler that - // u32 >> 30 -> u2 - return @intCast(ShardKey, shard_key); - } - - pub fn put(self: *Self, node: *Node) void { - const shard_key = Self.getShardKey(node.key); - node.next = self.shards[shard_key]; - self.shards[shard_key] = node; - } - - pub fn get(self: *Self, key: Key) ?*Node { - const shard_key = Self.getShardKey(key); - var maybe_node = self.shards[shard_key]; - while (maybe_node) |node| : (maybe_node = node.next) { - if (node.key == key) return node; - } - return null; - } - - pub const Node = struct { - key: Key, - value: V, - next: ?*Node, - - pub fn init(self: *Node, key: Key, value: V) void { - self.key = key; - self.value = value; - self.next = null; - } - }; - }; -} - -test "sharded table" { - // realistic 16-way sharding - testShardedTable(u32, 4, 8); - - testShardedTable(u5, 0, 32); // ShardKey == u0 - testShardedTable(u5, 2, 32); - testShardedTable(u5, 5, 32); - - testShardedTable(u1, 0, 2); - testShardedTable(u1, 1, 2); // this does u1 >> u0 - - testShardedTable(u0, 0, 1); -} -fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void { - const Table = ShardedTable(Key, mask_bit_count, void); - - var table = Table.create(); - var node_buffer: [node_count]Table.Node = undefined; - for (node_buffer) |*node, i| { - const key = @intCast(Key, i); - assert(table.get(key) == null); - node.init(key, {}); - table.put(node); - } - - for (node_buffer) |*node, i| { - assert(table.get(@intCast(Key, i)) == node); - } -} diff --git a/test/cases/bitcast.zig b/test/cases/bitcast.zig deleted file mode 100644 index d85a84ed22..0000000000 --- a/test/cases/bitcast.zig +++ /dev/null @@ -1,37 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const maxInt = std.math.maxInt; - -test "@bitCast i32 -> u32" { - testBitCast_i32_u32(); - comptime testBitCast_i32_u32(); -} - -fn testBitCast_i32_u32() void { - assert(conv(-1) == maxInt(u32)); - assert(conv2(maxInt(u32)) == -1); -} - -fn conv(x: i32) u32 { - return @bitCast(u32, x); -} -fn conv2(x: u32) i32 { - return @bitCast(i32, x); -} - -test "@bitCast extern enum to its integer type" { - const SOCK = extern enum { - A, - B, - - fn testBitCastExternEnum() void { - var SOCK_DGRAM = @This().B; - var sock_dgram = @bitCast(c_int, SOCK_DGRAM); - assert(sock_dgram == 1); - } - }; - - SOCK.testBitCastExternEnum(); - comptime SOCK.testBitCastExternEnum(); -} - diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig deleted file mode 100644 index 3721e68a94..0000000000 --- a/test/cases/bitreverse.zig +++ /dev/null @@ -1,81 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const minInt = std.math.minInt; - -test "@bitreverse" { - comptime testBitReverse(); - testBitReverse(); -} - -fn testBitReverse() void { - // using comptime_ints, unsigned - assert(@bitreverse(u0, 0) == 0); - assert(@bitreverse(u5, 0x12) == 0x9); - assert(@bitreverse(u8, 0x12) == 0x48); - assert(@bitreverse(u16, 0x1234) == 0x2c48); - assert(@bitreverse(u24, 0x123456) == 0x6a2c48); - assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); - assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); - assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); - assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); - assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); - assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); - - // using runtime uints, unsigned - var num0: u0 = 0; - assert(@bitreverse(u0, num0) == 0); - var num5: u5 = 0x12; - assert(@bitreverse(u5, num5) == 0x9); - var num8: u8 = 0x12; - assert(@bitreverse(u8, num8) == 0x48); - var num16: u16 = 0x1234; - assert(@bitreverse(u16, num16) == 0x2c48); - var num24: u24 = 0x123456; - assert(@bitreverse(u24, num24) == 0x6a2c48); - var num32: u32 = 0x12345678; - assert(@bitreverse(u32, num32) == 0x1e6a2c48); - var num40: u40 = 0x123456789a; - assert(@bitreverse(u40, num40) == 0x591e6a2c48); - var num48: u48 = 0x123456789abc; - assert(@bitreverse(u48, num48) == 0x3d591e6a2c48); - var num56: u56 = 0x123456789abcde; - assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); - var num64: u64 = 0x123456789abcdef1; - assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); - var num128: u128 = 0x123456789abcdef11121314151617181; - assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); - - // using comptime_ints, signed, positive - assert(@bitreverse(i0, 0) == 0); - assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49))); - assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48))); - assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48))); - assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48))); - assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48))); - assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48))); - assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48))); - assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48))); - assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48))); - - // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. - var neg5: i5 = minInt(i5) + 1; - assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); - var neg8: i8 = -18; - assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); - var neg16: i16 = -32694; - assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); - var neg24: i24 = -6773785; - assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); - var neg32: i32 = -16773785; - assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); - var neg40: i40 = minInt(i40) + 12345; - assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); - var neg48: i48 = minInt(i48) + 12345; - assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); - var neg56: i56 = minInt(i56) + 12345; - assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); - var neg64: i64 = minInt(i64) + 12345; - assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); - var neg128: i128 = minInt(i128) + 12345; - assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); -} diff --git a/test/cases/bool.zig b/test/cases/bool.zig deleted file mode 100644 index 3e4ac9c1cf..0000000000 --- a/test/cases/bool.zig +++ /dev/null @@ -1,35 +0,0 @@ -const assert = @import("std").debug.assert; - -test "bool literals" { - assert(true); - assert(!false); -} - -test "cast bool to int" { - const t = true; - const f = false; - assert(@boolToInt(t) == u32(1)); - assert(@boolToInt(f) == u32(0)); - nonConstCastBoolToInt(t, f); -} - -fn nonConstCastBoolToInt(t: bool, f: bool) void { - assert(@boolToInt(t) == u32(1)); - assert(@boolToInt(f) == u32(0)); -} - -test "bool cmp" { - assert(testBoolCmp(true, false) == false); -} -fn testBoolCmp(a: bool, b: bool) bool { - return a == b; -} - -const global_f = false; -const global_t = true; -const not_global_f = !global_f; -const not_global_t = !global_t; -test "compile time bool not" { - assert(not_global_f); - assert(!not_global_t); -} diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig deleted file mode 100644 index 57993077e1..0000000000 --- a/test/cases/bswap.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "@bswap" { - comptime testByteSwap(); - testByteSwap(); -} - -fn testByteSwap() void { - assert(@bswap(u0, 0) == 0); - assert(@bswap(u8, 0x12) == 0x12); - assert(@bswap(u16, 0x1234) == 0x3412); - assert(@bswap(u24, 0x123456) == 0x563412); - assert(@bswap(u32, 0x12345678) == 0x78563412); - assert(@bswap(u40, 0x123456789a) == 0x9a78563412); - assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); - assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); - assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); - assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); - - assert(@bswap(i0, 0) == 0); - assert(@bswap(i8, -50) == -50); - assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); - assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); - assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); - assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); - assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); - assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); - assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); - assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == - @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); -} diff --git a/test/cases/bugs/1076.zig b/test/cases/bugs/1076.zig deleted file mode 100644 index 7b84312310..0000000000 --- a/test/cases/bugs/1076.zig +++ /dev/null @@ -1,16 +0,0 @@ -const std = @import("std"); -const mem = std.mem; -const assert = std.debug.assert; - -test "comptime code should not modify constant data" { - testCastPtrOfArrayToSliceAndPtr(); - comptime testCastPtrOfArrayToSliceAndPtr(); -} - -fn testCastPtrOfArrayToSliceAndPtr() void { - var array = "aoeu"; - const x: [*]u8 = &array; - x[0] += 1; - assert(mem.eql(u8, array[0..], "boeu")); -} - diff --git a/test/cases/bugs/1111.zig b/test/cases/bugs/1111.zig deleted file mode 100644 index f62107f9a3..0000000000 --- a/test/cases/bugs/1111.zig +++ /dev/null @@ -1,12 +0,0 @@ -const Foo = extern enum { - Bar = -1, -}; - -test "issue 1111 fixed" { - const v = Foo.Bar; - - switch (v) { - Foo.Bar => return, - else => return, - } -} diff --git a/test/cases/bugs/1277.zig b/test/cases/bugs/1277.zig deleted file mode 100644 index a83e7653e2..0000000000 --- a/test/cases/bugs/1277.zig +++ /dev/null @@ -1,15 +0,0 @@ -const std = @import("std"); - -const S = struct { - f: ?fn () i32, -}; - -const s = S{ .f = f }; - -fn f() i32 { - return 1234; -} - -test "don't emit an LLVM global for a const function when it's in an optional in a struct" { - std.debug.assertOrPanic(s.f.?() == 1234); -} diff --git a/test/cases/bugs/1322.zig b/test/cases/bugs/1322.zig deleted file mode 100644 index 2de92191ec..0000000000 --- a/test/cases/bugs/1322.zig +++ /dev/null @@ -1,19 +0,0 @@ -const std = @import("std"); - -const B = union(enum) { - c: C, - None, -}; - -const A = struct { - b: B, -}; - -const C = struct {}; - -test "tagged union with all void fields but a meaningful tag" { - var a: A = A{ .b = B{ .c = C{} } }; - std.debug.assert(@TagType(B)(a.b) == @TagType(B).c); - a = A{ .b = B.None }; - std.debug.assert(@TagType(B)(a.b) == @TagType(B).None); -} diff --git a/test/cases/bugs/1381.zig b/test/cases/bugs/1381.zig deleted file mode 100644 index 2d452da156..0000000000 --- a/test/cases/bugs/1381.zig +++ /dev/null @@ -1,21 +0,0 @@ -const std = @import("std"); - -const B = union(enum) { - D: u8, - E: u16, -}; - -const A = union(enum) { - B: B, - C: u8, -}; - -test "union that needs padding bytes inside an array" { - var as = []A{ - A{ .B = B{ .D = 1 } }, - A{ .B = B{ .D = 1 } }, - }; - - const a = as[0].B; - std.debug.assertOrPanic(a.D == 1); -} diff --git a/test/cases/bugs/1421.zig b/test/cases/bugs/1421.zig deleted file mode 100644 index fcbb8b70e4..0000000000 --- a/test/cases/bugs/1421.zig +++ /dev/null @@ -1,14 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -const S = struct { - fn method() builtin.TypeInfo { - return @typeInfo(S); - } -}; - -test "functions with return type required to be comptime are generic" { - const ti = S.method(); - assert(builtin.TypeId(ti) == builtin.TypeId.Struct); -} diff --git a/test/cases/bugs/1442.zig b/test/cases/bugs/1442.zig deleted file mode 100644 index e9dfd5d2ce..0000000000 --- a/test/cases/bugs/1442.zig +++ /dev/null @@ -1,11 +0,0 @@ -const std = @import("std"); - -const Union = union(enum) { - Text: []const u8, - Color: u32, -}; - -test "const error union field alignment" { - var union_or_err: anyerror!Union = Union{ .Color = 1234 }; - std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); -} diff --git a/test/cases/bugs/1486.zig b/test/cases/bugs/1486.zig deleted file mode 100644 index 98fae36d3a..0000000000 --- a/test/cases/bugs/1486.zig +++ /dev/null @@ -1,11 +0,0 @@ -const assert = @import("std").debug.assert; - -const ptr = &global; -var global: u64 = 123; - -test "constant pointer to global variable causes runtime load" { - global = 1234; - assert(&global == ptr); - assert(ptr.* == 1234); -} - diff --git a/test/cases/bugs/394.zig b/test/cases/bugs/394.zig deleted file mode 100644 index b0afec2357..0000000000 --- a/test/cases/bugs/394.zig +++ /dev/null @@ -1,18 +0,0 @@ -const E = union(enum) { - A: [9]u8, - B: u64, -}; -const S = struct { - x: u8, - y: E, -}; - -const assert = @import("std").debug.assert; - -test "bug 394 fixed" { - const x = S{ - .x = 3, - .y = E{ .B = 1 }, - }; - assert(x.x == 3); -} diff --git a/test/cases/bugs/655.zig b/test/cases/bugs/655.zig deleted file mode 100644 index ebb8da0658..0000000000 --- a/test/cases/bugs/655.zig +++ /dev/null @@ -1,12 +0,0 @@ -const std = @import("std"); -const other_file = @import("655_other_file.zig"); - -test "function with *const parameter with type dereferenced by namespace" { - const x: other_file.Integer = 1234; - comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer); - foo(&x); -} - -fn foo(x: *const other_file.Integer) void { - std.debug.assert(x.* == 1234); -} diff --git a/test/cases/bugs/655_other_file.zig b/test/cases/bugs/655_other_file.zig deleted file mode 100644 index df1df44955..0000000000 --- a/test/cases/bugs/655_other_file.zig +++ /dev/null @@ -1 +0,0 @@ -pub const Integer = u32; diff --git a/test/cases/bugs/656.zig b/test/cases/bugs/656.zig deleted file mode 100644 index f93f0ac4d5..0000000000 --- a/test/cases/bugs/656.zig +++ /dev/null @@ -1,31 +0,0 @@ -const assert = @import("std").debug.assert; - -const PrefixOp = union(enum) { - Return, - AddrOf: Value, -}; - -const Value = struct { - align_expr: ?u32, -}; - -test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { - foo(false, true); -} - -fn foo(a: bool, b: bool) void { - var prefix_op = PrefixOp{ - .AddrOf = Value{ .align_expr = 1234 }, - }; - if (a) {} else { - switch (prefix_op) { - PrefixOp.AddrOf => |addr_of_info| { - if (b) {} - if (addr_of_info.align_expr) |align_expr| { - assert(align_expr == 1234); - } - }, - PrefixOp.Return => {}, - } - } -} diff --git a/test/cases/bugs/726.zig b/test/cases/bugs/726.zig deleted file mode 100644 index 2acc91eb26..0000000000 --- a/test/cases/bugs/726.zig +++ /dev/null @@ -1,16 +0,0 @@ -const assert = @import("std").debug.assert; - -test "@ptrCast from const to nullable" { - const c: u8 = 4; - var x: ?*const u8 = @ptrCast(?*const u8, &c); - assert(x.?.* == 4); -} - -test "@ptrCast from var in empty struct to nullable" { - const container = struct { - var c: u8 = 4; - }; - var x: ?*const u8 = @ptrCast(?*const u8, &container.c); - assert(x.?.* == 4); -} - diff --git a/test/cases/bugs/828.zig b/test/cases/bugs/828.zig deleted file mode 100644 index 50ae0fd279..0000000000 --- a/test/cases/bugs/828.zig +++ /dev/null @@ -1,33 +0,0 @@ -const CountBy = struct { - a: usize, - - const One = CountBy{ .a = 1 }; - - pub fn counter(self: *const CountBy) Counter { - return Counter{ .i = 0 }; - } -}; - -const Counter = struct { - i: usize, - - pub fn count(self: *Counter) bool { - self.i += 1; - return self.i <= 10; - } -}; - -fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { - comptime { - var cnt = cb.counter(); - if (cnt.i != 0) @compileError("Counter instance reused!"); - while (cnt.count()) {} - } -} - -test "comptime struct return should not return the same instance" { - //the first parameter must be passed by reference to trigger the bug - //a second parameter is required to trigger the bug - const ValA = constCount(&CountBy.One, 12); - const ValB = constCount(&CountBy.One, 15); -} diff --git a/test/cases/bugs/920.zig b/test/cases/bugs/920.zig deleted file mode 100644 index 2903f05a29..0000000000 --- a/test/cases/bugs/920.zig +++ /dev/null @@ -1,65 +0,0 @@ -const std = @import("std"); -const math = std.math; -const Random = std.rand.Random; - -const ZigTable = struct { - r: f64, - x: [257]f64, - f: [257]f64, - - pdf: fn (f64) f64, - is_symmetric: bool, - zero_case: fn (*Random, f64) f64, -}; - -fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { - var tables: ZigTable = undefined; - - tables.is_symmetric = is_symmetric; - tables.r = r; - tables.pdf = f; - tables.zero_case = zero_case; - - tables.x[0] = v / f(r); - tables.x[1] = r; - - for (tables.x[2..256]) |*entry, i| { - const last = tables.x[2 + i - 1]; - entry.* = f_inv(v / last + f(last)); - } - tables.x[256] = 0; - - for (tables.f[0..]) |*entry, i| { - entry.* = f(tables.x[i]); - } - - return tables; -} - -const norm_r = 3.6541528853610088; -const norm_v = 0.00492867323399; - -fn norm_f(x: f64) f64 { - return math.exp(-x * x / 2.0); -} -fn norm_f_inv(y: f64) f64 { - return math.sqrt(-2.0 * math.ln(y)); -} -fn norm_zero_case(random: *Random, u: f64) f64 { - return 0.0; -} - -const NormalDist = blk: { - @setEvalBranchQuota(30000); - break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); -}; - -test "bug 920 fixed" { - const NormalDist1 = blk: { - break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); - }; - - for (NormalDist1.f) |_, i| { - std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]); - } -} diff --git a/test/cases/byval_arg_var.zig b/test/cases/byval_arg_var.zig deleted file mode 100644 index 826b9cc9e5..0000000000 --- a/test/cases/byval_arg_var.zig +++ /dev/null @@ -1,27 +0,0 @@ -const std = @import("std"); - -var result: []const u8 = "wrong"; - -test "aoeu" { - start(); - blowUpStack(10); - - std.debug.assert(std.mem.eql(u8, result, "string literal")); -} - -fn start() void { - foo("string literal"); -} - -fn foo(x: var) void { - bar(x); -} - -fn bar(x: var) void { - result = x; -} - -fn blowUpStack(x: u32) void { - if (x == 0) return; - blowUpStack(x - 1); -} diff --git a/test/cases/cancel.zig b/test/cases/cancel.zig deleted file mode 100644 index c0f74fd34f..0000000000 --- a/test/cases/cancel.zig +++ /dev/null @@ -1,92 +0,0 @@ -const std = @import("std"); - -var defer_f1: bool = false; -var defer_f2: bool = false; -var defer_f3: bool = false; - -test "cancel forwards" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const p = async<&da.allocator> f1() catch unreachable; - cancel p; - std.debug.assert(defer_f1); - std.debug.assert(defer_f2); - std.debug.assert(defer_f3); -} - -async fn f1() void { - defer { - defer_f1 = true; - } - await (async f2() catch unreachable); -} - -async fn f2() void { - defer { - defer_f2 = true; - } - await (async f3() catch unreachable); -} - -async fn f3() void { - defer { - defer_f3 = true; - } - suspend; -} - -var defer_b1: bool = false; -var defer_b2: bool = false; -var defer_b3: bool = false; -var defer_b4: bool = false; - -test "cancel backwards" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const p = async<&da.allocator> b1() catch unreachable; - cancel p; - std.debug.assert(defer_b1); - std.debug.assert(defer_b2); - std.debug.assert(defer_b3); - std.debug.assert(defer_b4); -} - -async fn b1() void { - defer { - defer_b1 = true; - } - await (async b2() catch unreachable); -} - -var b4_handle: promise = undefined; - -async fn b2() void { - const b3_handle = async b3() catch unreachable; - resume b4_handle; - cancel b4_handle; - defer { - defer_b2 = true; - } - const value = await b3_handle; - @panic("unreachable"); -} - -async fn b3() i32 { - defer { - defer_b3 = true; - } - await (async b4() catch unreachable); - return 1234; -} - -async fn b4() void { - defer { - defer_b4 = true; - } - suspend { - b4_handle = @handle(); - } - suspend; -} diff --git a/test/cases/cast.zig b/test/cases/cast.zig deleted file mode 100644 index bd45bbc00f..0000000000 --- a/test/cases/cast.zig +++ /dev/null @@ -1,472 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; -const maxInt = std.math.maxInt; - -test "int to ptr cast" { - const x = usize(13); - const y = @intToPtr(*u8, x); - const z = @ptrToInt(y); - assert(z == 13); -} - -test "integer literal to pointer cast" { - const vga_mem = @intToPtr(*u16, 0xB8000); - assert(@ptrToInt(vga_mem) == 0xB8000); -} - -test "pointer reinterpret const float to int" { - const float: f64 = 5.99999999999994648725e-01; - const float_ptr = &float; - const int_ptr = @ptrCast(*const i32, float_ptr); - const int_val = int_ptr.*; - assert(int_val == 858993411); -} - -test "implicitly cast indirect pointer to maybe-indirect pointer" { - const S = struct { - const Self = @This(); - x: u8, - fn constConst(p: *const *const Self) u8 { - return p.*.x; - } - fn maybeConstConst(p: ?*const *const Self) u8 { - return p.?.*.x; - } - fn constConstConst(p: *const *const *const Self) u8 { - return p.*.*.x; - } - fn maybeConstConstConst(p: ?*const *const *const Self) u8 { - return p.?.*.*.x; - } - }; - const s = S{ .x = 42 }; - const p = &s; - const q = &p; - const r = &q; - assert(42 == S.constConst(q)); - assert(42 == S.maybeConstConst(q)); - assert(42 == S.constConstConst(r)); - assert(42 == S.maybeConstConstConst(r)); -} - -test "explicit cast from integer to error type" { - testCastIntToErr(error.ItBroke); - comptime testCastIntToErr(error.ItBroke); -} -fn testCastIntToErr(err: anyerror) void { - const x = @errorToInt(err); - const y = @intToError(x); - assert(error.ItBroke == y); -} - -test "peer resolve arrays of different size to const slice" { - assert(mem.eql(u8, boolToStr(true), "true")); - assert(mem.eql(u8, boolToStr(false), "false")); - comptime assert(mem.eql(u8, boolToStr(true), "true")); - comptime assert(mem.eql(u8, boolToStr(false), "false")); -} -fn boolToStr(b: bool) []const u8 { - return if (b) "true" else "false"; -} - -test "peer resolve array and const slice" { - testPeerResolveArrayConstSlice(true); - comptime testPeerResolveArrayConstSlice(true); -} -fn testPeerResolveArrayConstSlice(b: bool) void { - const value1 = if (b) "aoeu" else ([]const u8)("zz"); - const value2 = if (b) ([]const u8)("zz") else "aoeu"; - assert(mem.eql(u8, value1, "aoeu")); - assert(mem.eql(u8, value2, "zz")); -} - -test "implicitly cast from T to anyerror!?T" { - castToOptionalTypeError(1); - comptime castToOptionalTypeError(1); -} -const A = struct { - a: i32, -}; -fn castToOptionalTypeError(z: i32) void { - const x = i32(1); - const y: anyerror!?i32 = x; - assert((try y).? == 1); - - const f = z; - const g: anyerror!?i32 = f; - - const a = A{ .a = z }; - const b: anyerror!?A = a; - assert((b catch unreachable).?.a == 1); -} - -test "implicitly cast from int to anyerror!?T" { - implicitIntLitToOptional(); - comptime implicitIntLitToOptional(); -} -fn implicitIntLitToOptional() void { - const f: ?i32 = 1; - const g: anyerror!?i32 = 1; -} - -test "return null from fn() anyerror!?&T" { - const a = returnNullFromOptionalTypeErrorRef(); - const b = returnNullLitFromOptionalTypeErrorRef(); - assert((try a) == null and (try b) == null); -} -fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { - const a: ?*A = null; - return a; -} -fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { - return null; -} - -test "peer type resolution: ?T and T" { - assert(peerTypeTAndOptionalT(true, false).? == 0); - assert(peerTypeTAndOptionalT(false, false).? == 3); - comptime { - assert(peerTypeTAndOptionalT(true, false).? == 0); - assert(peerTypeTAndOptionalT(false, false).? == 3); - } -} -fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { - if (c) { - return if (b) null else usize(0); - } - - return usize(3); -} - -test "peer type resolution: [0]u8 and []const u8" { - assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); - comptime { - assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); - } -} -fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { - if (a) { - return []const u8{}; - } - - return slice[0..1]; -} - -test "implicitly cast from [N]T to ?[]const T" { - assert(mem.eql(u8, castToOptionalSlice().?, "hi")); - comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi")); -} - -fn castToOptionalSlice() ?[]const u8 { - return "hi"; -} - -test "implicitly cast from [0]T to anyerror![]T" { - testCastZeroArrayToErrSliceMut(); - comptime testCastZeroArrayToErrSliceMut(); -} - -fn testCastZeroArrayToErrSliceMut() void { - assert((gimmeErrOrSlice() catch unreachable).len == 0); -} - -fn gimmeErrOrSlice() anyerror![]u8 { - return []u8{}; -} - -test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - { - var data = "hi"; - const slice = data[0..]; - assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - comptime { - var data = "hi"; - const slice = data[0..]; - assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } -} -fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { - if (a) { - return []u8{}; - } - - return slice[0..1]; -} - -test "resolve undefined with integer" { - testResolveUndefWithInt(true, 1234); - comptime testResolveUndefWithInt(true, 1234); -} -fn testResolveUndefWithInt(b: bool, x: i32) void { - const value = if (b) x else undefined; - if (b) { - assert(value == x); - } -} - -test "implicit cast from &const [N]T to []const T" { - testCastConstArrayRefToConstSlice(); - comptime testCastConstArrayRefToConstSlice(); -} - -fn testCastConstArrayRefToConstSlice() void { - const blah = "aoeu"; - const const_array_ref = &blah; - assert(@typeOf(const_array_ref) == *const [4]u8); - const slice: []const u8 = const_array_ref; - assert(mem.eql(u8, slice, "aoeu")); -} - -test "peer type resolution: error and [N]T" { - // TODO: implicit error!T to error!U where T can implicitly cast to U - //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); - comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); -} - -//fn testPeerErrorAndArray(x: u8) error![]const u8 { -// return switch (x) { -// 0x00 => "OK", -// else => error.BadValue, -// }; -//} -fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { - return switch (x) { - 0x00 => "OK", - 0x01 => "OKK", - else => error.BadValue, - }; -} - -test "@floatToInt" { - testFloatToInts(); - comptime testFloatToInts(); -} - -fn testFloatToInts() void { - const x = i32(1e4); - assert(x == 10000); - const y = @floatToInt(i32, f32(1e4)); - assert(y == 10000); - expectFloatToInt(f16, 255.1, u8, 255); - expectFloatToInt(f16, 127.2, i8, 127); - expectFloatToInt(f16, -128.2, i8, -128); - expectFloatToInt(f32, 255.1, u8, 255); - expectFloatToInt(f32, 127.2, i8, 127); - expectFloatToInt(f32, -128.2, i8, -128); - expectFloatToInt(comptime_int, 1234, i16, 1234); -} - -fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { - assert(@floatToInt(I, f) == i); -} - -test "cast u128 to f128 and back" { - comptime testCast128(); - testCast128(); -} - -fn testCast128() void { - assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); -} - -fn cast128Int(x: f128) u128 { - return @bitCast(u128, x); -} - -fn cast128Float(x: u128) f128 { - return @bitCast(f128, x); -} - -test "const slice widen cast" { - const bytes align(4) = []u8{ - 0x12, - 0x12, - 0x12, - 0x12, - }; - - const u32_value = @bytesToSlice(u32, bytes[0..])[0]; - assert(u32_value == 0x12121212); - - assert(@bitCast(u32, bytes) == 0x12121212); -} - -test "single-item pointer of array to slice and to unknown length pointer" { - testCastPtrOfArrayToSliceAndPtr(); - comptime testCastPtrOfArrayToSliceAndPtr(); -} - -fn testCastPtrOfArrayToSliceAndPtr() void { - var array = "aoeu"; - const x: [*]u8 = &array; - x[0] += 1; - assert(mem.eql(u8, array[0..], "boeu")); - const y: []u8 = &array; - y[0] += 1; - assert(mem.eql(u8, array[0..], "coeu")); -} - -test "cast *[1][*]const u8 to [*]const ?[*]const u8" { - const window_name = [1][*]const u8{c"window name"}; - const x: [*]const ?[*]const u8 = &window_name; - assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); -} - -test "@intCast comptime_int" { - const result = @intCast(i32, 1234); - assert(@typeOf(result) == i32); - assert(result == 1234); -} - -test "@floatCast comptime_int and comptime_float" { - { - const result = @floatCast(f16, 1234); - assert(@typeOf(result) == f16); - assert(result == 1234.0); - } - { - const result = @floatCast(f16, 1234.0); - assert(@typeOf(result) == f16); - assert(result == 1234.0); - } - { - const result = @floatCast(f32, 1234); - assert(@typeOf(result) == f32); - assert(result == 1234.0); - } - { - const result = @floatCast(f32, 1234.0); - assert(@typeOf(result) == f32); - assert(result == 1234.0); - } -} - -test "comptime_int @intToFloat" { - { - const result = @intToFloat(f16, 1234); - assert(@typeOf(result) == f16); - assert(result == 1234.0); - } - { - const result = @intToFloat(f32, 1234); - assert(@typeOf(result) == f32); - assert(result == 1234.0); - } -} - -test "@bytesToSlice keeps pointer alignment" { - var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; - const numbers = @bytesToSlice(u32, bytes[0..]); - comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); -} - -test "@intCast i32 to u7" { - var x: u128 = maxInt(u128); - var y: i32 = 120; - var z = x >> @intCast(u7, y); - assert(z == 0xff); -} - -test "implicit cast undefined to optional" { - assert(MakeType(void).getNull() == null); - assert(MakeType(void).getNonNull() != null); -} - -fn MakeType(comptime T: type) type { - return struct { - fn getNull() ?T { - return null; - } - - fn getNonNull() ?T { - return T(undefined); - } - }; -} - -test "implicit cast from *[N]T to ?[*]T" { - var x: ?[*]u16 = null; - var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; - - x = &y; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); - x.?[0] = 8; - y[3] = 6; - assert(std.mem.eql(u16, x.?[0..4], y[0..4])); -} - -test "implicit cast from *T to ?*c_void" { - var a: u8 = 1; - incrementVoidPtrValue(&a); - std.debug.assert(a == 2); -} - -fn incrementVoidPtrValue(value: ?*c_void) void { - @ptrCast(*u8, value.?).* += 1; -} - -test "implicit cast from [*]T to ?*c_void" { - var a = []u8{ 3, 2, 1 }; - incrementVoidPtrArray(a[0..].ptr, 3); - assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); -} - -fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { - var n: usize = 0; - while (n < len) : (n += 1) { - @ptrCast([*]u8, array.?)[n] += 1; - } -} - -test "*usize to *void" { - var i = usize(0); - var v = @ptrCast(*void, &i); - v.* = {}; -} - -test "compile time int to ptr of function" { - foobar(FUNCTION_CONSTANT); -} - -pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); -pub const PFN_void = extern fn (*c_void) void; - -fn foobar(func: PFN_void) void { - std.debug.assert(@ptrToInt(func) == maxInt(usize)); -} - -test "implicit ptr to *c_void" { - var a: u32 = 1; - var ptr: *c_void = &a; - var b: *u32 = @ptrCast(*u32, ptr); - assert(b.* == 1); - var ptr2: ?*c_void = &a; - var c: *u32 = @ptrCast(*u32, ptr2.?); - assert(c.* == 1); -} - -test "@intCast to comptime_int" { - assert(@intCast(comptime_int, 0) == 0); -} - -test "implicit cast comptime numbers to any type when the value fits" { - const a: u64 = 255; - var b: u8 = a; - assert(b == 255); -} - -test "@intToEnum passed a comptime_int to an enum with one item" { - const E = enum { - A, - }; - const x = @intToEnum(E, 0); - assert(x == E.A); -} diff --git a/test/cases/const_slice_child.zig b/test/cases/const_slice_child.zig deleted file mode 100644 index 07d02d5df0..0000000000 --- a/test/cases/const_slice_child.zig +++ /dev/null @@ -1,45 +0,0 @@ -const debug = @import("std").debug; -const assert = debug.assert; - -var argv: [*]const [*]const u8 = undefined; - -test "const slice child" { - const strs = ([][*]const u8){ - c"one", - c"two", - c"three", - }; - // TODO this should implicitly cast - argv = @ptrCast([*]const [*]const u8, &strs); - bar(strs.len); -} - -fn foo(args: [][]const u8) void { - assert(args.len == 3); - assert(streql(args[0], "one")); - assert(streql(args[1], "two")); - assert(streql(args[2], "three")); -} - -fn bar(argc: usize) void { - const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable; - for (args) |_, i| { - const ptr = argv[i]; - args[i] = ptr[0..strlen(ptr)]; - } - foo(args); -} - -fn strlen(ptr: [*]const u8) usize { - var count: usize = 0; - while (ptr[count] != 0) : (count += 1) {} - return count; -} - -fn streql(a: []const u8, b: []const u8) bool { - if (a.len != b.len) return false; - for (a) |item, index| { - if (b[index] != item) return false; - } - return true; -} diff --git a/test/cases/coroutine_await_struct.zig b/test/cases/coroutine_await_struct.zig deleted file mode 100644 index 79168715d8..0000000000 --- a/test/cases/coroutine_await_struct.zig +++ /dev/null @@ -1,47 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -const Foo = struct { - x: i32, -}; - -var await_a_promise: promise = undefined; -var await_final_result = Foo{ .x = 0 }; - -test "coroutine await struct" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - await_seq('a'); - const p = async<&da.allocator> await_amain() catch unreachable; - await_seq('f'); - resume await_a_promise; - await_seq('i'); - assert(await_final_result.x == 1234); - assert(std.mem.eql(u8, await_points, "abcdefghi")); -} -async fn await_amain() void { - await_seq('b'); - const p = async await_another() catch unreachable; - await_seq('e'); - await_final_result = await p; - await_seq('h'); -} -async fn await_another() Foo { - await_seq('c'); - suspend { - await_seq('d'); - await_a_promise = @handle(); - } - await_seq('g'); - return Foo{ .x = 1234 }; -} - -var await_points = []u8{0} ** "abcdefghi".len; -var await_seq_index: usize = 0; - -fn await_seq(c: u8) void { - await_points[await_seq_index] = c; - await_seq_index += 1; -} diff --git a/test/cases/coroutines.zig b/test/cases/coroutines.zig deleted file mode 100644 index 89490ebc2c..0000000000 --- a/test/cases/coroutines.zig +++ /dev/null @@ -1,258 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -var x: i32 = 1; - -test "create a coroutine and cancel it" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const p = try async<&da.allocator> simpleAsyncFn(); - comptime assert(@typeOf(p) == promise->void); - cancel p; - assert(x == 2); -} -async fn simpleAsyncFn() void { - x += 1; - suspend; - x += 1; -} - -test "coroutine suspend, resume, cancel" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - seq('a'); - const p = try async<&da.allocator> testAsyncSeq(); - seq('c'); - resume p; - seq('f'); - cancel p; - seq('g'); - - assert(std.mem.eql(u8, points, "abcdefg")); -} -async fn testAsyncSeq() void { - defer seq('e'); - - seq('b'); - suspend; - seq('d'); -} -var points = []u8{0} ** "abcdefg".len; -var index: usize = 0; - -fn seq(c: u8) void { - points[index] = c; - index += 1; -} - -test "coroutine suspend with block" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - const p = try async<&da.allocator> testSuspendBlock(); - std.debug.assert(!result); - resume a_promise; - std.debug.assert(result); - cancel p; -} - -var a_promise: promise = undefined; -var result = false; -async fn testSuspendBlock() void { - suspend { - comptime assert(@typeOf(@handle()) == promise->void); - a_promise = @handle(); - } - - //Test to make sure that @handle() works as advertised (issue #1296) - //var our_handle: promise = @handle(); - assert( a_promise == @handle() ); - - result = true; -} - -var await_a_promise: promise = undefined; -var await_final_result: i32 = 0; - -test "coroutine await" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - await_seq('a'); - const p = async<&da.allocator> await_amain() catch unreachable; - await_seq('f'); - resume await_a_promise; - await_seq('i'); - assert(await_final_result == 1234); - assert(std.mem.eql(u8, await_points, "abcdefghi")); -} -async fn await_amain() void { - await_seq('b'); - const p = async await_another() catch unreachable; - await_seq('e'); - await_final_result = await p; - await_seq('h'); -} -async fn await_another() i32 { - await_seq('c'); - suspend { - await_seq('d'); - await_a_promise = @handle(); - } - await_seq('g'); - return 1234; -} - -var await_points = []u8{0} ** "abcdefghi".len; -var await_seq_index: usize = 0; - -fn await_seq(c: u8) void { - await_points[await_seq_index] = c; - await_seq_index += 1; -} - -var early_final_result: i32 = 0; - -test "coroutine await early return" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - - early_seq('a'); - const p = async<&da.allocator> early_amain() catch @panic("out of memory"); - early_seq('f'); - assert(early_final_result == 1234); - assert(std.mem.eql(u8, early_points, "abcdef")); -} -async fn early_amain() void { - early_seq('b'); - const p = async early_another() catch @panic("out of memory"); - early_seq('d'); - early_final_result = await p; - early_seq('e'); -} -async fn early_another() i32 { - early_seq('c'); - return 1234; -} - -var early_points = []u8{0} ** "abcdef".len; -var early_seq_index: usize = 0; - -fn early_seq(c: u8) void { - early_points[early_seq_index] = c; - early_seq_index += 1; -} - -test "coro allocation failure" { - var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); - if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { - @panic("expected allocation failure"); - } else |err| switch (err) { - error.OutOfMemory => {}, - } -} -async fn asyncFuncThatNeverGetsRun() void { - @panic("coro frame allocation should fail"); -} - -test "async function with dot syntax" { - const S = struct { - var y: i32 = 1; - async fn foo() void { - y += 1; - suspend; - } - }; - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - const p = try async<&da.allocator> S.foo(); - cancel p; - assert(S.y == 2); -} - -test "async fn pointer in a struct field" { - var data: i32 = 1; - const Foo = struct { - bar: async<*std.mem.Allocator> fn (*i32) void, - }; - var foo = Foo{ .bar = simpleAsyncFn2 }; - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; - assert(data == 2); - cancel p; - assert(data == 4); -} -async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { - defer y.* += 2; - y.* += 1; - suspend; -} - -test "async fn with inferred error set" { - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - const p = (async<&da.allocator> failing()) catch unreachable; - resume p; - cancel p; -} -async fn failing() !void { - suspend; - return error.Fail; -} - -test "error return trace across suspend points - early return" { - const p = nonFailing(); - resume p; - var da = std.heap.DirectAllocator.init(); - defer da.deinit(); - const p2 = try async<&da.allocator> printTrace(p); - cancel p2; -} - -test "error return trace across suspend points - async return" { - const p = nonFailing(); - const p2 = try async printTrace(p); - resume p; - cancel p2; -} - -// TODO https://github.com/ziglang/zig/issues/760 -fn nonFailing() promise->(anyerror!void) { - return async suspendThenFail() catch unreachable; -} -async fn suspendThenFail() anyerror!void { - suspend; - return error.Fail; -} -async fn printTrace(p: promise->(anyerror!void)) void { - (await p) catch |e| { - std.debug.assert(e == error.Fail); - if (@errorReturnTrace()) |trace| { - assert(trace.index == 1); - } else switch (builtin.mode) { - builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), - builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, - } - }; -} - -test "break from suspend" { - var buf: [500]u8 = undefined; - var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; - var my_result: i32 = 1; - const p = try async testBreakFromSuspend(&my_result); - cancel p; - std.debug.assert(my_result == 2); -} -async fn testBreakFromSuspend(my_result: *i32) void { - suspend { - resume @handle(); - } - my_result.* += 1; - suspend; - my_result.* += 1; -} diff --git a/test/cases/defer.zig b/test/cases/defer.zig deleted file mode 100644 index f9a2b69cd9..0000000000 --- a/test/cases/defer.zig +++ /dev/null @@ -1,78 +0,0 @@ -const assert = @import("std").debug.assert; - -var result: [3]u8 = undefined; -var index: usize = undefined; - -fn runSomeErrorDefers(x: bool) !bool { - index = 0; - defer { - result[index] = 'a'; - index += 1; - } - errdefer { - result[index] = 'b'; - index += 1; - } - defer { - result[index] = 'c'; - index += 1; - } - return if (x) x else error.FalseNotAllowed; -} - -test "mixing normal and error defers" { - assert(runSomeErrorDefers(true) catch unreachable); - assert(result[0] == 'c'); - assert(result[1] == 'a'); - - const ok = runSomeErrorDefers(false) catch |err| x: { - assert(err == error.FalseNotAllowed); - break :x true; - }; - assert(ok); - assert(result[0] == 'c'); - assert(result[1] == 'b'); - assert(result[2] == 'a'); -} - -test "break and continue inside loop inside defer expression" { - testBreakContInDefer(10); - comptime testBreakContInDefer(10); -} - -fn testBreakContInDefer(x: usize) void { - defer { - var i: usize = 0; - while (i < x) : (i += 1) { - if (i < 5) continue; - if (i == 5) break; - } - assert(i == 5); - } -} - -test "defer and labeled break" { - var i = usize(0); - - blk: { - defer i += 1; - break :blk; - } - - assert(i == 1); -} - -test "errdefer does not apply to fn inside fn" { - if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad); -} - -fn testNestedFnErrDefer() anyerror!void { - var a: i32 = 0; - errdefer a += 1; - const S = struct { - fn baz() anyerror { - return error.Bad; - } - }; - return S.baz(); -} diff --git a/test/cases/enum.zig b/test/cases/enum.zig deleted file mode 100644 index 2dd552488c..0000000000 --- a/test/cases/enum.zig +++ /dev/null @@ -1,894 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -test "enum type" { - const foo1 = Foo{ .One = 13 }; - const foo2 = Foo{ - .Two = Point{ - .x = 1234, - .y = 5678, - }, - }; - const bar = Bar.B; - - assert(bar == Bar.B); - assert(@memberCount(Foo) == 3); - assert(@memberCount(Bar) == 4); - assert(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - assert(@sizeOf(Bar) == 1); -} - -test "enum as return value" { - switch (returnAnInt(13)) { - Foo.One => |value| assert(value == 13), - else => unreachable, - } -} - -const Point = struct { - x: u64, - y: u64, -}; -const Foo = union(enum) { - One: i32, - Two: Point, - Three: void, -}; -const FooNoVoid = union(enum) { - One: i32, - Two: Point, -}; -const Bar = enum { - A, - B, - C, - D, -}; - -fn returnAnInt(x: i32) Foo { - return Foo{ .One = x }; -} - -test "constant enum with payload" { - var empty = AnEnumWithPayload{ .Empty = {} }; - var full = AnEnumWithPayload{ .Full = 13 }; - shouldBeEmpty(empty); - shouldBeNotEmpty(full); -} - -fn shouldBeEmpty(x: AnEnumWithPayload) void { - switch (x) { - AnEnumWithPayload.Empty => {}, - else => unreachable, - } -} - -fn shouldBeNotEmpty(x: AnEnumWithPayload) void { - switch (x) { - AnEnumWithPayload.Empty => unreachable, - else => {}, - } -} - -const AnEnumWithPayload = union(enum) { - Empty: void, - Full: i32, -}; - -const Number = enum { - Zero, - One, - Two, - Three, - Four, -}; - -test "enum to int" { - shouldEqual(Number.Zero, 0); - shouldEqual(Number.One, 1); - shouldEqual(Number.Two, 2); - shouldEqual(Number.Three, 3); - shouldEqual(Number.Four, 4); -} - -fn shouldEqual(n: Number, expected: u3) void { - assert(@enumToInt(n) == expected); -} - -test "int to enum" { - testIntToEnumEval(3); -} -fn testIntToEnumEval(x: i32) void { - assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); -} -const IntToEnumNumber = enum { - Zero, - One, - Two, - Three, - Four, -}; - -test "@tagName" { - assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); - comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); -} - -fn testEnumTagNameBare(n: BareNumber) []const u8 { - return @tagName(n); -} - -const BareNumber = enum { - One, - Two, - Three, -}; - -test "enum alignment" { - comptime { - assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); - assert(@alignOf(AlignTestEnum) >= @alignOf(u64)); - } -} - -const AlignTestEnum = union(enum) { - A: [9]u8, - B: u64, -}; - -const ValueCount1 = enum { - I0, -}; -const ValueCount2 = enum { - I0, - I1, -}; -const ValueCount256 = enum { - I0, - I1, - I2, - I3, - I4, - I5, - I6, - I7, - I8, - I9, - I10, - I11, - I12, - I13, - I14, - I15, - I16, - I17, - I18, - I19, - I20, - I21, - I22, - I23, - I24, - I25, - I26, - I27, - I28, - I29, - I30, - I31, - I32, - I33, - I34, - I35, - I36, - I37, - I38, - I39, - I40, - I41, - I42, - I43, - I44, - I45, - I46, - I47, - I48, - I49, - I50, - I51, - I52, - I53, - I54, - I55, - I56, - I57, - I58, - I59, - I60, - I61, - I62, - I63, - I64, - I65, - I66, - I67, - I68, - I69, - I70, - I71, - I72, - I73, - I74, - I75, - I76, - I77, - I78, - I79, - I80, - I81, - I82, - I83, - I84, - I85, - I86, - I87, - I88, - I89, - I90, - I91, - I92, - I93, - I94, - I95, - I96, - I97, - I98, - I99, - I100, - I101, - I102, - I103, - I104, - I105, - I106, - I107, - I108, - I109, - I110, - I111, - I112, - I113, - I114, - I115, - I116, - I117, - I118, - I119, - I120, - I121, - I122, - I123, - I124, - I125, - I126, - I127, - I128, - I129, - I130, - I131, - I132, - I133, - I134, - I135, - I136, - I137, - I138, - I139, - I140, - I141, - I142, - I143, - I144, - I145, - I146, - I147, - I148, - I149, - I150, - I151, - I152, - I153, - I154, - I155, - I156, - I157, - I158, - I159, - I160, - I161, - I162, - I163, - I164, - I165, - I166, - I167, - I168, - I169, - I170, - I171, - I172, - I173, - I174, - I175, - I176, - I177, - I178, - I179, - I180, - I181, - I182, - I183, - I184, - I185, - I186, - I187, - I188, - I189, - I190, - I191, - I192, - I193, - I194, - I195, - I196, - I197, - I198, - I199, - I200, - I201, - I202, - I203, - I204, - I205, - I206, - I207, - I208, - I209, - I210, - I211, - I212, - I213, - I214, - I215, - I216, - I217, - I218, - I219, - I220, - I221, - I222, - I223, - I224, - I225, - I226, - I227, - I228, - I229, - I230, - I231, - I232, - I233, - I234, - I235, - I236, - I237, - I238, - I239, - I240, - I241, - I242, - I243, - I244, - I245, - I246, - I247, - I248, - I249, - I250, - I251, - I252, - I253, - I254, - I255, -}; -const ValueCount257 = enum { - I0, - I1, - I2, - I3, - I4, - I5, - I6, - I7, - I8, - I9, - I10, - I11, - I12, - I13, - I14, - I15, - I16, - I17, - I18, - I19, - I20, - I21, - I22, - I23, - I24, - I25, - I26, - I27, - I28, - I29, - I30, - I31, - I32, - I33, - I34, - I35, - I36, - I37, - I38, - I39, - I40, - I41, - I42, - I43, - I44, - I45, - I46, - I47, - I48, - I49, - I50, - I51, - I52, - I53, - I54, - I55, - I56, - I57, - I58, - I59, - I60, - I61, - I62, - I63, - I64, - I65, - I66, - I67, - I68, - I69, - I70, - I71, - I72, - I73, - I74, - I75, - I76, - I77, - I78, - I79, - I80, - I81, - I82, - I83, - I84, - I85, - I86, - I87, - I88, - I89, - I90, - I91, - I92, - I93, - I94, - I95, - I96, - I97, - I98, - I99, - I100, - I101, - I102, - I103, - I104, - I105, - I106, - I107, - I108, - I109, - I110, - I111, - I112, - I113, - I114, - I115, - I116, - I117, - I118, - I119, - I120, - I121, - I122, - I123, - I124, - I125, - I126, - I127, - I128, - I129, - I130, - I131, - I132, - I133, - I134, - I135, - I136, - I137, - I138, - I139, - I140, - I141, - I142, - I143, - I144, - I145, - I146, - I147, - I148, - I149, - I150, - I151, - I152, - I153, - I154, - I155, - I156, - I157, - I158, - I159, - I160, - I161, - I162, - I163, - I164, - I165, - I166, - I167, - I168, - I169, - I170, - I171, - I172, - I173, - I174, - I175, - I176, - I177, - I178, - I179, - I180, - I181, - I182, - I183, - I184, - I185, - I186, - I187, - I188, - I189, - I190, - I191, - I192, - I193, - I194, - I195, - I196, - I197, - I198, - I199, - I200, - I201, - I202, - I203, - I204, - I205, - I206, - I207, - I208, - I209, - I210, - I211, - I212, - I213, - I214, - I215, - I216, - I217, - I218, - I219, - I220, - I221, - I222, - I223, - I224, - I225, - I226, - I227, - I228, - I229, - I230, - I231, - I232, - I233, - I234, - I235, - I236, - I237, - I238, - I239, - I240, - I241, - I242, - I243, - I244, - I245, - I246, - I247, - I248, - I249, - I250, - I251, - I252, - I253, - I254, - I255, - I256, -}; - -test "enum sizes" { - comptime { - assert(@sizeOf(ValueCount1) == 0); - assert(@sizeOf(ValueCount2) == 1); - assert(@sizeOf(ValueCount256) == 1); - assert(@sizeOf(ValueCount257) == 2); - } -} - -const Small2 = enum(u2) { - One, - Two, -}; -const Small = enum(u2) { - One, - Two, - Three, - Four, -}; - -test "set enum tag type" { - { - var x = Small.One; - x = Small.Two; - comptime assert(@TagType(Small) == u2); - } - { - var x = Small2.One; - x = Small2.Two; - comptime assert(@TagType(Small2) == u2); - } -} - -const A = enum(u3) { - One, - Two, - Three, - Four, - One2, - Two2, - Three2, - Four2, -}; - -const B = enum(u3) { - One3, - Two3, - Three3, - Four3, - One23, - Two23, - Three23, - Four23, -}; - -const C = enum(u2) { - One4, - Two4, - Three4, - Four4, -}; - -const BitFieldOfEnums = packed struct { - a: A, - b: B, - c: C, -}; - -const bit_field_1 = BitFieldOfEnums{ - .a = A.Two, - .b = B.Three3, - .c = C.Four4, -}; - -test "bit field access with enum fields" { - var data = bit_field_1; - assert(getA(&data) == A.Two); - assert(getB(&data) == B.Three3); - assert(getC(&data) == C.Four4); - comptime assert(@sizeOf(BitFieldOfEnums) == 1); - - data.b = B.Four3; - assert(data.b == B.Four3); - - data.a = A.Three; - assert(data.a == A.Three); - assert(data.b == B.Four3); -} - -fn getA(data: *const BitFieldOfEnums) A { - return data.a; -} - -fn getB(data: *const BitFieldOfEnums) B { - return data.b; -} - -fn getC(data: *const BitFieldOfEnums) C { - return data.c; -} - -test "casting enum to its tag type" { - testCastEnumToTagType(Small2.Two); - comptime testCastEnumToTagType(Small2.Two); -} - -fn testCastEnumToTagType(value: Small2) void { - assert(@enumToInt(value) == 1); -} - -const MultipleChoice = enum(u32) { - A = 20, - B = 40, - C = 60, - D = 1000, -}; - -test "enum with specified tag values" { - testEnumWithSpecifiedTagValues(MultipleChoice.C); - comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); -} - -fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { - assert(@enumToInt(x) == 60); - assert(1234 == switch (x) { - MultipleChoice.A => 1, - MultipleChoice.B => 2, - MultipleChoice.C => u32(1234), - MultipleChoice.D => 4, - }); -} - -const MultipleChoice2 = enum(u32) { - Unspecified1, - A = 20, - Unspecified2, - B = 40, - Unspecified3, - C = 60, - Unspecified4, - D = 1000, - Unspecified5, -}; - -test "enum with specified and unspecified tag values" { - testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); - comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); -} - -fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assert(@enumToInt(x) == 1000); - assert(1234 == switch (x) { - MultipleChoice2.A => 1, - MultipleChoice2.B => 2, - MultipleChoice2.C => 3, - MultipleChoice2.D => u32(1234), - MultipleChoice2.Unspecified1 => 5, - MultipleChoice2.Unspecified2 => 6, - MultipleChoice2.Unspecified3 => 7, - MultipleChoice2.Unspecified4 => 8, - MultipleChoice2.Unspecified5 => 9, - }); -} - -test "cast integer literal to enum" { - assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); - assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); -} - -const EnumWithOneMember = enum { - Eof, -}; - -fn doALoopThing(id: EnumWithOneMember) void { - while (true) { - if (id == EnumWithOneMember.Eof) { - break; - } - @compileError("above if condition should be comptime"); - } -} - -test "comparison operator on enum with one member is comptime known" { - doALoopThing(EnumWithOneMember.Eof); -} - -const State = enum { - Start, -}; -test "switch on enum with one member is comptime known" { - var state = State.Start; - switch (state) { - State.Start => return, - } - @compileError("analysis should not reach here"); -} - -const EnumWithTagValues = enum(u4) { - A = 1 << 0, - B = 1 << 1, - C = 1 << 2, - D = 1 << 3, -}; -test "enum with tag values don't require parens" { - assert(@enumToInt(EnumWithTagValues.C) == 0b0100); -} - -test "enum with 1 field but explicit tag type should still have the tag type" { - const Enum = enum(u8) { - B = 2, - }; - comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8)); -} - -test "empty extern enum with members" { - const E = extern enum { - A, - B, - C, - }; - assert(@sizeOf(E) == @sizeOf(c_int)); -} - -test "aoeu" { - const LocalFoo = enum { - A = 1, - B = 0, - }; - var b = LocalFoo.B; - assert(mem.eql(u8, @tagName(b), "B")); -} diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig deleted file mode 100644 index 088496bd2f..0000000000 --- a/test/cases/enum_with_members.zig +++ /dev/null @@ -1,27 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const fmt = @import("std").fmt; - -const ET = union(enum) { - SINT: i32, - UINT: u32, - - pub fn print(a: *const ET, buf: []u8) anyerror!usize { - return switch (a.*) { - ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), - ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), - }; - } -}; - -test "enum with members" { - const a = ET{ .SINT = -42 }; - const b = ET{ .UINT = 42 }; - var buf: [20]u8 = undefined; - - assert((a.print(buf[0..]) catch unreachable) == 3); - assert(mem.eql(u8, buf[0..3], "-42")); - - assert((b.print(buf[0..]) catch unreachable) == 2); - assert(mem.eql(u8, buf[0..2], "42")); -} diff --git a/test/cases/error.zig b/test/cases/error.zig deleted file mode 100644 index a731f39021..0000000000 --- a/test/cases/error.zig +++ /dev/null @@ -1,245 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; -const builtin = @import("builtin"); - -pub fn foo() anyerror!i32 { - const x = try bar(); - return x + 1; -} - -pub fn bar() anyerror!i32 { - return 13; -} - -pub fn baz() anyerror!i32 { - const y = foo() catch 1234; - return y + 1; -} - -test "error wrapping" { - assert((baz() catch unreachable) == 15); -} - -fn gimmeItBroke() []const u8 { - return @errorName(error.ItBroke); -} - -test "@errorName" { - assert(mem.eql(u8, @errorName(error.AnError), "AnError")); - assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); -} - -test "error values" { - const a = @errorToInt(error.err1); - const b = @errorToInt(error.err2); - assert(a != b); -} - -test "redefinition of error values allowed" { - shouldBeNotEqual(error.AnError, error.SecondError); -} -fn shouldBeNotEqual(a: anyerror, b: anyerror) void { - if (a == b) unreachable; -} - -test "error binary operator" { - const a = errBinaryOperatorG(true) catch 3; - const b = errBinaryOperatorG(false) catch 3; - assert(a == 3); - assert(b == 10); -} -fn errBinaryOperatorG(x: bool) anyerror!isize { - return if (x) error.ItBroke else isize(10); -} - -test "unwrap simple value from error" { - const i = unwrapSimpleValueFromErrorDo() catch unreachable; - assert(i == 13); -} -fn unwrapSimpleValueFromErrorDo() anyerror!isize { - return 13; -} - -test "error return in assignment" { - doErrReturnInAssignment() catch unreachable; -} - -fn doErrReturnInAssignment() anyerror!void { - var x: i32 = undefined; - x = try makeANonErr(); -} - -fn makeANonErr() anyerror!i32 { - return 1; -} - -test "error union type " { - testErrorUnionType(); - comptime testErrorUnionType(); -} - -fn testErrorUnionType() void { - const x: anyerror!i32 = 1234; - if (x) |value| assert(value == 1234) else |_| unreachable; - assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); - assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); - assert(@typeOf(x).ErrorSet == anyerror); -} - -test "error set type " { - testErrorSetType(); - comptime testErrorSetType(); -} - -const MyErrSet = error{ - OutOfMemory, - FileNotFound, -}; - -fn testErrorSetType() void { - assert(@memberCount(MyErrSet) == 2); - - const a: MyErrSet!i32 = 5678; - const b: MyErrSet!i32 = MyErrSet.OutOfMemory; - - if (a) |value| assert(value == 5678) else |err| switch (err) { - error.OutOfMemory => unreachable, - error.FileNotFound => unreachable, - } -} - -test "explicit error set cast" { - testExplicitErrorSetCast(Set1.A); - comptime testExplicitErrorSetCast(Set1.A); -} - -const Set1 = error{ - A, - B, -}; -const Set2 = error{ - A, - C, -}; - -fn testExplicitErrorSetCast(set1: Set1) void { - var x = @errSetCast(Set2, set1); - var y = @errSetCast(Set1, x); - assert(y == error.A); -} - -test "comptime test error for empty error set" { - testComptimeTestErrorEmptySet(1234); - comptime testComptimeTestErrorEmptySet(1234); -} - -const EmptyErrorSet = error{}; - -fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { - if (x) |v| assert(v == 1234) else |err| @compileError("bad"); -} - -test "syntax: optional operator in front of error union operator" { - comptime { - assert(?(anyerror!i32) == ?(anyerror!i32)); - } -} - -test "comptime err to int of error set with only 1 possible value" { - testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); - comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); -} -fn testErrToIntWithOnePossibleValue( - x: error{A}, - comptime value: u32, -) void { - if (@errorToInt(x) != value) { - @compileError("bad"); - } -} - -test "error union peer type resolution" { - testErrorUnionPeerTypeResolution(1); - comptime testErrorUnionPeerTypeResolution(1); -} - -fn testErrorUnionPeerTypeResolution(x: i32) void { - const y = switch (x) { - 1 => bar_1(), - 2 => baz_1(), - else => quux_1(), - }; -} - -fn bar_1() anyerror { - return error.A; -} - -fn baz_1() !i32 { - return error.B; -} - -fn quux_1() !i32 { - return error.C; -} - -test "error: fn returning empty error set can be passed as fn returning any error" { - entry(); - comptime entry(); -} - -fn entry() void { - foo2(bar2); -} - -fn foo2(f: fn () anyerror!void) void { - const x = f(); -} - -fn bar2() (error{}!void) {} - -test "error: Zero sized error set returned with value payload crash" { - _ = foo3(0); - _ = comptime foo3(0); -} - -const Error = error{}; -fn foo3(b: usize) Error!usize { - return b; -} - -test "error: Infer error set from literals" { - _ = nullLiteral("n") catch |err| handleErrors(err); - _ = floatLiteral("n") catch |err| handleErrors(err); - _ = intLiteral("n") catch |err| handleErrors(err); - _ = comptime nullLiteral("n") catch |err| handleErrors(err); - _ = comptime floatLiteral("n") catch |err| handleErrors(err); - _ = comptime intLiteral("n") catch |err| handleErrors(err); -} - -fn handleErrors(err: var) noreturn { - switch (err) { - error.T => {}, - } - - unreachable; -} - -fn nullLiteral(str: []const u8) !?i64 { - if (str[0] == 'n') return null; - - return error.T; -} - -fn floatLiteral(str: []const u8) !?f64 { - if (str[0] == 'n') return 1.0; - - return error.T; -} - -fn intLiteral(str: []const u8) !?i64 { - if (str[0] == 'n') return 1; - - return error.T; -} diff --git a/test/cases/eval.zig b/test/cases/eval.zig deleted file mode 100644 index a9eded151e..0000000000 --- a/test/cases/eval.zig +++ /dev/null @@ -1,782 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const builtin = @import("builtin"); - -test "compile time recursion" { - assert(some_data.len == 21); -} -var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; -fn fibonacci(x: i32) i32 { - if (x <= 1) return 1; - return fibonacci(x - 1) + fibonacci(x - 2); -} - -fn unwrapAndAddOne(blah: ?i32) i32 { - return blah.? + 1; -} -const should_be_1235 = unwrapAndAddOne(1234); -test "static add one" { - assert(should_be_1235 == 1235); -} - -test "inlined loop" { - comptime var i = 0; - comptime var sum = 0; - inline while (i <= 5) : (i += 1) - sum += i; - assert(sum == 15); -} - -fn gimme1or2(comptime a: bool) i32 { - const x: i32 = 1; - const y: i32 = 2; - comptime var z: i32 = if (a) x else y; - return z; -} -test "inline variable gets result of const if" { - assert(gimme1or2(true) == 1); - assert(gimme1or2(false) == 2); -} - -test "static function evaluation" { - assert(statically_added_number == 3); -} -const statically_added_number = staticAdd(1, 2); -fn staticAdd(a: i32, b: i32) i32 { - return a + b; -} - -test "const expr eval on single expr blocks" { - assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3); -} - -fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { - const literal = 3; - - const result = if (b) b: { - break :b literal; - } else b: { - break :b x; - }; - - return result; -} - -test "statically initialized list" { - assert(static_point_list[0].x == 1); - assert(static_point_list[0].y == 2); - assert(static_point_list[1].x == 3); - assert(static_point_list[1].y == 4); -} -const Point = struct { - x: i32, - y: i32, -}; -const static_point_list = []Point{ - makePoint(1, 2), - makePoint(3, 4), -}; -fn makePoint(x: i32, y: i32) Point { - return Point{ - .x = x, - .y = y, - }; -} - -test "static eval list init" { - assert(static_vec3.data[2] == 1.0); - assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0); -} -const static_vec3 = vec3(0.0, 0.0, 1.0); -pub const Vec3 = struct { - data: [3]f32, -}; -pub fn vec3(x: f32, y: f32, z: f32) Vec3 { - return Vec3{ .data = []f32{ - x, - y, - z, - } }; -} - -test "constant expressions" { - var array: [array_size]u8 = undefined; - assert(@sizeOf(@typeOf(array)) == 20); -} -const array_size: u8 = 20; - -test "constant struct with negation" { - assert(vertices[0].x == -0.6); -} -const Vertex = struct { - x: f32, - y: f32, - r: f32, - g: f32, - b: f32, -}; -const vertices = []Vertex{ - Vertex{ - .x = -0.6, - .y = -0.4, - .r = 1.0, - .g = 0.0, - .b = 0.0, - }, - Vertex{ - .x = 0.6, - .y = -0.4, - .r = 0.0, - .g = 1.0, - .b = 0.0, - }, - Vertex{ - .x = 0.0, - .y = 0.6, - .r = 0.0, - .g = 0.0, - .b = 1.0, - }, -}; - -test "statically initialized struct" { - st_init_str_foo.x += 1; - assert(st_init_str_foo.x == 14); -} -const StInitStrFoo = struct { - x: i32, - y: bool, -}; -var st_init_str_foo = StInitStrFoo{ - .x = 13, - .y = true, -}; - -test "statically initalized array literal" { - const y: [4]u8 = st_init_arr_lit_x; - assert(y[3] == 4); -} -const st_init_arr_lit_x = []u8{ - 1, - 2, - 3, - 4, -}; - -test "const slice" { - comptime { - const a = "1234567890"; - assert(a.len == 10); - const b = a[1..2]; - assert(b.len == 1); - assert(b[0] == '2'); - } -} - -test "try to trick eval with runtime if" { - assert(testTryToTrickEvalWithRuntimeIf(true) == 10); -} - -fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { - comptime var i: usize = 0; - inline while (i < 10) : (i += 1) { - const result = if (b) false else true; - } - comptime { - return i; - } -} - -fn max(comptime T: type, a: T, b: T) T { - if (T == bool) { - return a or b; - } else if (a > b) { - return a; - } else { - return b; - } -} -fn letsTryToCompareBools(a: bool, b: bool) bool { - return max(bool, a, b); -} -test "inlined block and runtime block phi" { - assert(letsTryToCompareBools(true, true)); - assert(letsTryToCompareBools(true, false)); - assert(letsTryToCompareBools(false, true)); - assert(!letsTryToCompareBools(false, false)); - - comptime { - assert(letsTryToCompareBools(true, true)); - assert(letsTryToCompareBools(true, false)); - assert(letsTryToCompareBools(false, true)); - assert(!letsTryToCompareBools(false, false)); - } -} - -const CmdFn = struct { - name: []const u8, - func: fn (i32) i32, -}; - -const cmd_fns = []CmdFn{ - CmdFn{ - .name = "one", - .func = one, - }, - CmdFn{ - .name = "two", - .func = two, - }, - CmdFn{ - .name = "three", - .func = three, - }, -}; -fn one(value: i32) i32 { - return value + 1; -} -fn two(value: i32) i32 { - return value + 2; -} -fn three(value: i32) i32 { - return value + 3; -} - -fn performFn(comptime prefix_char: u8, start_value: i32) i32 { - var result: i32 = start_value; - comptime var i = 0; - inline while (i < cmd_fns.len) : (i += 1) { - if (cmd_fns[i].name[0] == prefix_char) { - result = cmd_fns[i].func(result); - } - } - return result; -} - -test "comptime iterate over fn ptr list" { - assert(performFn('t', 1) == 6); - assert(performFn('o', 0) == 1); - assert(performFn('w', 99) == 99); -} - -test "eval @setRuntimeSafety at compile-time" { - const result = comptime fnWithSetRuntimeSafety(); - assert(result == 1234); -} - -fn fnWithSetRuntimeSafety() i32 { - @setRuntimeSafety(true); - return 1234; -} - -test "eval @setFloatMode at compile-time" { - const result = comptime fnWithFloatMode(); - assert(result == 1234.0); -} - -fn fnWithFloatMode() f32 { - @setFloatMode(builtin.FloatMode.Strict); - return 1234.0; -} - -const SimpleStruct = struct { - field: i32, - - fn method(self: *const SimpleStruct) i32 { - return self.field + 3; - } -}; - -var simple_struct = SimpleStruct{ .field = 1234 }; - -const bound_fn = simple_struct.method; - -test "call method on bound fn referring to var instance" { - assert(bound_fn() == 1237); -} - -test "ptr to local array argument at comptime" { - comptime { - var bytes: [10]u8 = undefined; - modifySomeBytes(bytes[0..]); - assert(bytes[0] == 'a'); - assert(bytes[9] == 'b'); - } -} - -fn modifySomeBytes(bytes: []u8) void { - bytes[0] = 'a'; - bytes[9] = 'b'; -} - -test "comparisons 0 <= uint and 0 > uint should be comptime" { - testCompTimeUIntComparisons(1234); -} -fn testCompTimeUIntComparisons(x: u32) void { - if (!(0 <= x)) { - @compileError("this condition should be comptime known"); - } - if (0 > x) { - @compileError("this condition should be comptime known"); - } - if (!(x >= 0)) { - @compileError("this condition should be comptime known"); - } - if (x < 0) { - @compileError("this condition should be comptime known"); - } -} - -test "const ptr to variable data changes at runtime" { - assert(foo_ref.name[0] == 'a'); - foo_ref.name = "b"; - assert(foo_ref.name[0] == 'b'); -} - -const Foo = struct { - name: []const u8, -}; - -var foo_contents = Foo{ .name = "a" }; -const foo_ref = &foo_contents; - -test "create global array with for loop" { - assert(global_array[5] == 5 * 5); - assert(global_array[9] == 9 * 9); -} - -const global_array = x: { - var result: [10]usize = undefined; - for (result) |*item, index| { - item.* = index * index; - } - break :x result; -}; - -test "compile-time downcast when the bits fit" { - comptime { - const spartan_count: u16 = 255; - const byte = @intCast(u8, spartan_count); - assert(byte == 255); - } -} - -const hi1 = "hi"; -const hi2 = hi1; -test "const global shares pointer with other same one" { - assertEqualPtrs(&hi1[0], &hi2[0]); - comptime assert(&hi1[0] == &hi2[0]); -} -fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { - assert(ptr1 == ptr2); -} - -test "@setEvalBranchQuota" { - comptime { - // 1001 for the loop and then 1 more for the assert fn call - @setEvalBranchQuota(1002); - var i = 0; - var sum = 0; - while (i < 1001) : (i += 1) { - sum += i; - } - assert(sum == 500500); - } -} - -// TODO test "float literal at compile time not lossy" { -// TODO assert(16777216.0 + 1.0 == 16777217.0); -// TODO assert(9007199254740992.0 + 1.0 == 9007199254740993.0); -// TODO } - -test "f32 at compile time is lossy" { - assert(f32(1 << 24) + 1 == 1 << 24); -} - -test "f64 at compile time is lossy" { - assert(f64(1 << 53) + 1 == 1 << 53); -} - -test "f128 at compile time is lossy" { - assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); -} - -// TODO need a better implementation of bigfloat_init_bigint -// assert(f128(1 << 113) == 10384593717069655257060992658440192); - -pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { - return struct { - pub const Node = struct {}; - }; -} - -test "string literal used as comptime slice is memoized" { - const a = "link"; - const b = "link"; - comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); - comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); -} - -test "comptime slice of undefined pointer of length 0" { - const slice1 = ([*]i32)(undefined)[0..0]; - assert(slice1.len == 0); - const slice2 = ([*]i32)(undefined)[100..100]; - assert(slice2.len == 0); -} - -fn copyWithPartialInline(s: []u32, b: []u8) void { - comptime var i: usize = 0; - inline while (i < 4) : (i += 1) { - s[i] = 0; - s[i] |= u32(b[i * 4 + 0]) << 24; - s[i] |= u32(b[i * 4 + 1]) << 16; - s[i] |= u32(b[i * 4 + 2]) << 8; - s[i] |= u32(b[i * 4 + 3]) << 0; - } -} - -test "binary math operator in partially inlined function" { - var s: [4]u32 = undefined; - var b: [16]u8 = undefined; - - for (b) |*r, i| - r.* = @intCast(u8, i + 1); - - copyWithPartialInline(s[0..], b[0..]); - assert(s[0] == 0x1020304); - assert(s[1] == 0x5060708); - assert(s[2] == 0x90a0b0c); - assert(s[3] == 0xd0e0f10); -} - -test "comptime function with the same args is memoized" { - comptime { - assert(MakeType(i32) == MakeType(i32)); - assert(MakeType(i32) != MakeType(f64)); - } -} - -fn MakeType(comptime T: type) type { - return struct { - field: T, - }; -} - -test "comptime function with mutable pointer is not memoized" { - comptime { - var x: i32 = 1; - const ptr = &x; - increment(ptr); - increment(ptr); - assert(x == 3); - } -} - -fn increment(value: *i32) void { - value.* += 1; -} - -fn generateTable(comptime T: type) [1010]T { - var res: [1010]T = undefined; - var i: usize = 0; - while (i < 1010) : (i += 1) { - res[i] = @intCast(T, i); - } - return res; -} - -fn doesAlotT(comptime T: type, value: usize) T { - @setEvalBranchQuota(5000); - const table = comptime blk: { - break :blk generateTable(T); - }; - return table[value]; -} - -test "@setEvalBranchQuota at same scope as generic function call" { - assert(doesAlotT(u32, 2) == 2); -} - -test "comptime slice of slice preserves comptime var" { - comptime { - var buff: [10]u8 = undefined; - buff[0..][0..][0] = 1; - assert(buff[0..][0..][0] == 1); - } -} - -test "comptime slice of pointer preserves comptime var" { - comptime { - var buff: [10]u8 = undefined; - var a = buff[0..].ptr; - a[0..1][0] = 1; - assert(buff[0..][0..][0] == 1); - } -} - -const SingleFieldStruct = struct { - x: i32, - - fn read_x(self: *const SingleFieldStruct) i32 { - return self.x; - } -}; -test "const ptr to comptime mutable data is not memoized" { - comptime { - var foo = SingleFieldStruct{ .x = 1 }; - assert(foo.read_x() == 1); - foo.x = 2; - assert(foo.read_x() == 2); - } -} - -test "array concat of slices gives slice" { - comptime { - var a: []const u8 = "aoeu"; - var b: []const u8 = "asdf"; - const c = a ++ b; - assert(std.mem.eql(u8, c, "aoeuasdf")); - } -} - -test "comptime shlWithOverflow" { - const ct_shifted: u64 = comptime amt: { - var amt = u64(0); - _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); - break :amt amt; - }; - - const rt_shifted: u64 = amt: { - var amt = u64(0); - _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); - break :amt amt; - }; - - assert(ct_shifted == rt_shifted); -} - -test "runtime 128 bit integer division" { - var a: u128 = 152313999999999991610955792383; - var b: u128 = 10000000000000000000; - var c = a / b; - assert(c == 15231399999); -} - -pub const Info = struct { - version: u8, -}; - -pub const diamond_info = Info{ .version = 0 }; - -test "comptime modification of const struct field" { - comptime { - var res = diamond_info; - res.version = 1; - assert(diamond_info.version == 0); - assert(res.version == 1); - } -} - -test "pointer to type" { - comptime { - var T: type = i32; - assert(T == i32); - var ptr = &T; - assert(@typeOf(ptr) == *type); - ptr.* = f32; - assert(T == f32); - assert(*T == *f32); - } -} - -test "slice of type" { - comptime { - var types_array = []type{ i32, f64, type }; - for (types_array) |T, i| { - switch (i) { - 0 => assert(T == i32), - 1 => assert(T == f64), - 2 => assert(T == type), - else => unreachable, - } - } - for (types_array[0..]) |T, i| { - switch (i) { - 0 => assert(T == i32), - 1 => assert(T == f64), - 2 => assert(T == type), - else => unreachable, - } - } - } -} - -const Wrapper = struct { - T: type, -}; - -fn wrap(comptime T: type) Wrapper { - return Wrapper{ .T = T }; -} - -test "function which returns struct with type field causes implicit comptime" { - const ty = wrap(i32).T; - assert(ty == i32); -} - -test "call method with comptime pass-by-non-copying-value self parameter" { - const S = struct { - a: u8, - - fn b(comptime s: @This()) u8 { - return s.a; - } - }; - - const s = S{ .a = 2 }; - var b = s.b(); - assert(b == 2); -} - -test "@tagName of @typeId" { - const str = @tagName(@typeId(u8)); - assert(std.mem.eql(u8, str, "Int")); -} - -test "setting backward branch quota just before a generic fn call" { - @setEvalBranchQuota(1001); - loopNTimes(1001); -} - -fn loopNTimes(comptime n: usize) void { - comptime var i = 0; - inline while (i < n) : (i += 1) {} -} - -test "variable inside inline loop that has different types on different iterations" { - testVarInsideInlineLoop(true, u32(42)); -} - -fn testVarInsideInlineLoop(args: ...) void { - comptime var i = 0; - inline while (i < args.len) : (i += 1) { - const x = args[i]; - if (i == 0) assert(x); - if (i == 1) assert(x == 42); - } -} - -test "inline for with same type but different values" { - var res: usize = 0; - inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| { - var a: T = undefined; - res += a.len; - } - assert(res == 5); -} - -test "refer to the type of a generic function" { - const Func = fn (type) void; - const f: Func = doNothingWithType; - f(i32); -} - -fn doNothingWithType(comptime T: type) void {} - -test "zero extend from u0 to u1" { - var zero_u0: u0 = 0; - var zero_u1: u1 = zero_u0; - assert(zero_u1 == 0); -} - -test "bit shift a u1" { - var x: u1 = 1; - var y = x << 0; - assert(y == 1); -} - -test "@intCast to a u0" { - var x: u8 = 0; - var y: u0 = @intCast(u0, x); - assert(y == 0); -} - -test "@bytesToslice on a packed struct" { - const F = packed struct { - a: u8, - }; - - var b = [1]u8{9}; - var f = @bytesToSlice(F, b); - assert(f[0].a == 9); -} - -test "comptime pointer cast array and then slice" { - const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; - - const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); - const sliceA: []const u8 = ptrA[0..2]; - - const ptrB: [*]const u8 = &array; - const sliceB: []const u8 = ptrB[0..2]; - - assert(sliceA[1] == 2); - assert(sliceB[1] == 2); -} - -test "slice bounds in comptime concatenation" { - const bs = comptime blk: { - const b = c"11"; - break :blk b[0..1]; - }; - const str = "" ++ bs; - assert(str.len == 1); - assert(std.mem.eql(u8, str, "1")); - - const str2 = bs ++ ""; - assert(str2.len == 1); - assert(std.mem.eql(u8, str2, "1")); -} - -test "comptime bitwise operators" { - comptime { - assert(3 & 1 == 1); - assert(3 & -1 == 3); - assert(-3 & -1 == -3); - assert(3 | -1 == -1); - assert(-3 | -1 == -1); - assert(3 ^ -1 == -4); - assert(-3 ^ -1 == 2); - assert(~i8(-1) == 0); - assert(~i128(-1) == 0); - assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611); - assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); - assert(~u128(0) == 0xffffffffffffffffffffffffffffffff); - } -} - -test "*align(1) u16 is the same as *align(1:0:2) u16" { - comptime { - assert(*align(1:0:2) u16 == *align(1) u16); - // TODO add parsing support for this syntax - //assert(*align(:0:2) u16 == *u16); - } -} - -test "array concatenation forces comptime" { - var a = oneItem(3) ++ oneItem(4); - assert(std.mem.eql(i32, a, []i32{3, 4})); -} - -test "array multiplication forces comptime" { - var a = oneItem(3) ** scalar(2); - assert(std.mem.eql(i32, a, []i32{3, 3})); -} - -fn oneItem(x: i32) [1]i32 { - return []i32{x}; -} - -fn scalar(x: u32) u32 { - return x; -} diff --git a/test/cases/field_parent_ptr.zig b/test/cases/field_parent_ptr.zig deleted file mode 100644 index 00d4e0f367..0000000000 --- a/test/cases/field_parent_ptr.zig +++ /dev/null @@ -1,41 +0,0 @@ -const assert = @import("std").debug.assert; - -test "@fieldParentPtr non-first field" { - testParentFieldPtr(&foo.c); - comptime testParentFieldPtr(&foo.c); -} - -test "@fieldParentPtr first field" { - testParentFieldPtrFirst(&foo.a); - comptime testParentFieldPtrFirst(&foo.a); -} - -const Foo = struct { - a: bool, - b: f32, - c: i32, - d: i32, -}; - -const foo = Foo{ - .a = true, - .b = 0.123, - .c = 1234, - .d = -10, -}; - -fn testParentFieldPtr(c: *const i32) void { - assert(c == &foo.c); - - const base = @fieldParentPtr(Foo, "c", c); - assert(base == &foo); - assert(&base.c == c); -} - -fn testParentFieldPtrFirst(a: *const bool) void { - assert(a == &foo.a); - - const base = @fieldParentPtr(Foo, "a", a); - assert(base == &foo); - assert(&base.a == a); -} diff --git a/test/cases/fn.zig b/test/cases/fn.zig deleted file mode 100644 index 8908bd7854..0000000000 --- a/test/cases/fn.zig +++ /dev/null @@ -1,207 +0,0 @@ -const assert = @import("std").debug.assert; - -test "params" { - assert(testParamsAdd(22, 11) == 33); -} -fn testParamsAdd(a: i32, b: i32) i32 { - return a + b; -} - -test "local variables" { - testLocVars(2); -} -fn testLocVars(b: i32) void { - const a: i32 = 1; - if (a + b != 3) unreachable; -} - -test "void parameters" { - voidFun(1, void{}, 2, {}); -} -fn voidFun(a: i32, b: void, c: i32, d: void) void { - const v = b; - const vv: void = if (a == 1) v else {}; - assert(a + c == 3); - return vv; -} - -test "mutable local variables" { - var zero: i32 = 0; - assert(zero == 0); - - var i = i32(0); - while (i != 3) { - i += 1; - } - assert(i == 3); -} - -test "separate block scopes" { - { - const no_conflict: i32 = 5; - assert(no_conflict == 5); - } - - const c = x: { - const no_conflict = i32(10); - break :x no_conflict; - }; - assert(c == 10); -} - -test "call function with empty string" { - acceptsString(""); -} - -fn acceptsString(foo: []u8) void {} - -fn @"weird function name"() i32 { - return 1234; -} -test "weird function name" { - assert(@"weird function name"() == 1234); -} - -test "implicit cast function unreachable return" { - wantsFnWithVoid(fnWithUnreachable); -} - -fn wantsFnWithVoid(f: fn () void) void {} - -fn fnWithUnreachable() noreturn { - unreachable; -} - -test "function pointers" { - const fns = []@typeOf(fn1){ - fn1, - fn2, - fn3, - fn4, - }; - for (fns) |f, i| { - assert(f() == @intCast(u32, i) + 5); - } -} -fn fn1() u32 { - return 5; -} -fn fn2() u32 { - return 6; -} -fn fn3() u32 { - return 7; -} -fn fn4() u32 { - return 8; -} - -test "inline function call" { - assert(@inlineCall(add, 3, 9) == 12); -} - -fn add(a: i32, b: i32) i32 { - return a + b; -} - -test "number literal as an argument" { - numberLiteralArg(3); - comptime numberLiteralArg(3); -} - -fn numberLiteralArg(a: var) void { - assert(a == 3); -} - -test "assign inline fn to const variable" { - const a = inlineFn; - a(); -} - -inline fn inlineFn() void {} - -test "pass by non-copying value" { - assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); -} - -const Point = struct { - x: i32, - y: i32, -}; - -fn addPointCoords(pt: Point) i32 { - return pt.x + pt.y; -} - -test "pass by non-copying value through var arg" { - assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); -} - -fn addPointCoordsVar(pt: var) i32 { - comptime assert(@typeOf(pt) == Point); - return pt.x + pt.y; -} - -test "pass by non-copying value as method" { - var pt = Point2{ .x = 1, .y = 2 }; - assert(pt.addPointCoords() == 3); -} - -const Point2 = struct { - x: i32, - y: i32, - - fn addPointCoords(self: Point2) i32 { - return self.x + self.y; - } -}; - -test "pass by non-copying value as method, which is generic" { - var pt = Point3{ .x = 1, .y = 2 }; - assert(pt.addPointCoords(i32) == 3); -} - -const Point3 = struct { - x: i32, - y: i32, - - fn addPointCoords(self: Point3, comptime T: type) i32 { - return self.x + self.y; - } -}; - -test "pass by non-copying value as method, at comptime" { - comptime { - var pt = Point2{ .x = 1, .y = 2 }; - assert(pt.addPointCoords() == 3); - } -} - -fn outer(y: u32) fn (u32) u32 { - const Y = @typeOf(y); - const st = struct { - fn get(z: u32) u32 { - return z + @sizeOf(Y); - } - }; - return st.get; -} - -test "return inner function which references comptime variable of outer function" { - var func = outer(10); - assert(func(3) == 7); -} - -test "extern struct with stdcallcc fn pointer" { - const S = extern struct { - ptr: stdcallcc fn () i32, - - stdcallcc fn foo() i32 { - return 1234; - } - }; - - var s: S = undefined; - s.ptr = S.foo; - assert(s.ptr() == 1234); -} diff --git a/test/cases/fn_in_struct_in_comptime.zig b/test/cases/fn_in_struct_in_comptime.zig deleted file mode 100644 index fabb57e9cb..0000000000 --- a/test/cases/fn_in_struct_in_comptime.zig +++ /dev/null @@ -1,17 +0,0 @@ -const assert = @import("std").debug.assert; - -fn get_foo() fn (*u8) usize { - comptime { - return struct { - fn func(ptr: *u8) usize { - var u = @ptrToInt(ptr); - return u; - } - }.func; - } -} - -test "define a function in an anonymous struct in comptime" { - const foo = get_foo(); - assert(foo(@intToPtr(*u8, 12345)) == 12345); -} diff --git a/test/cases/for.zig b/test/cases/for.zig deleted file mode 100644 index aecd8b9a07..0000000000 --- a/test/cases/for.zig +++ /dev/null @@ -1,106 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; - -test "continue in for loop" { - const array = []i32{ - 1, - 2, - 3, - 4, - 5, - }; - var sum: i32 = 0; - for (array) |x| { - sum += x; - if (x < 3) { - continue; - } - break; - } - if (sum != 6) unreachable; -} - -test "for loop with pointer elem var" { - const source = "abcdefg"; - var target: [source.len]u8 = undefined; - mem.copy(u8, target[0..], source); - mangleString(target[0..]); - assert(mem.eql(u8, target, "bcdefgh")); -} -fn mangleString(s: []u8) void { - for (s) |*c| { - c.* += 1; - } -} - -test "basic for loop" { - const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; - - var buffer: [expected_result.len]u8 = undefined; - var buf_index: usize = 0; - - const array = []u8{ 9, 8, 7, 6 }; - for (array) |item| { - buffer[buf_index] = item; - buf_index += 1; - } - for (array) |item, index| { - buffer[buf_index] = @intCast(u8, index); - buf_index += 1; - } - const array_ptr = &array; - for (array_ptr) |item| { - buffer[buf_index] = item; - buf_index += 1; - } - for (array_ptr) |item, index| { - buffer[buf_index] = @intCast(u8, index); - buf_index += 1; - } - const unknown_size: []const u8 = array; - for (unknown_size) |item| { - buffer[buf_index] = item; - buf_index += 1; - } - for (unknown_size) |item, index| { - buffer[buf_index] = @intCast(u8, index); - buf_index += 1; - } - - assert(mem.eql(u8, buffer[0..buf_index], expected_result)); -} - -test "break from outer for loop" { - testBreakOuter(); - comptime testBreakOuter(); -} - -fn testBreakOuter() void { - var array = "aoeu"; - var count: usize = 0; - outer: for (array) |_| { - for (array) |_| { - count += 1; - break :outer; - } - } - assert(count == 1); -} - -test "continue outer for loop" { - testContinueOuter(); - comptime testContinueOuter(); -} - -fn testContinueOuter() void { - var array = "aoeu"; - var counter: usize = 0; - outer: for (array) |_| { - for (array) |_| { - counter += 1; - continue :outer; - } - } - assert(counter == array.len); -} diff --git a/test/cases/generics.zig b/test/cases/generics.zig deleted file mode 100644 index 52aa013989..0000000000 --- a/test/cases/generics.zig +++ /dev/null @@ -1,151 +0,0 @@ -const assert = @import("std").debug.assert; - -test "simple generic fn" { - assert(max(i32, 3, -1) == 3); - assert(max(f32, 0.123, 0.456) == 0.456); - assert(add(2, 3) == 5); -} - -fn max(comptime T: type, a: T, b: T) T { - return if (a > b) a else b; -} - -fn add(comptime a: i32, b: i32) i32 { - return (comptime a) + b; -} - -const the_max = max(u32, 1234, 5678); -test "compile time generic eval" { - assert(the_max == 5678); -} - -fn gimmeTheBigOne(a: u32, b: u32) u32 { - return max(u32, a, b); -} - -fn shouldCallSameInstance(a: u32, b: u32) u32 { - return max(u32, a, b); -} - -fn sameButWithFloats(a: f64, b: f64) f64 { - return max(f64, a, b); -} - -test "fn with comptime args" { - assert(gimmeTheBigOne(1234, 5678) == 5678); - assert(shouldCallSameInstance(34, 12) == 34); - assert(sameButWithFloats(0.43, 0.49) == 0.49); -} - -test "var params" { - assert(max_i32(12, 34) == 34); - assert(max_f64(1.2, 3.4) == 3.4); -} - -comptime { - assert(max_i32(12, 34) == 34); - assert(max_f64(1.2, 3.4) == 3.4); -} - -fn max_var(a: var, b: var) @typeOf(a + b) { - return if (a > b) a else b; -} - -fn max_i32(a: i32, b: i32) i32 { - return max_var(a, b); -} - -fn max_f64(a: f64, b: f64) f64 { - return max_var(a, b); -} - -pub fn List(comptime T: type) type { - return SmallList(T, 8); -} - -pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { - return struct { - items: []T, - length: usize, - prealloc_items: [STATIC_SIZE]T, - }; -} - -test "function with return type type" { - var list: List(i32) = undefined; - var list2: List(i32) = undefined; - list.length = 10; - list2.length = 10; - assert(list.prealloc_items.len == 8); - assert(list2.prealloc_items.len == 8); -} - -test "generic struct" { - var a1 = GenNode(i32){ - .value = 13, - .next = null, - }; - var b1 = GenNode(bool){ - .value = true, - .next = null, - }; - assert(a1.value == 13); - assert(a1.value == a1.getVal()); - assert(b1.getVal()); -} -fn GenNode(comptime T: type) type { - return struct { - value: T, - next: ?*GenNode(T), - fn getVal(n: *const GenNode(T)) T { - return n.value; - } - }; -} - -test "const decls in struct" { - assert(GenericDataThing(3).count_plus_one == 4); -} -fn GenericDataThing(comptime count: isize) type { - return struct { - const count_plus_one = count + 1; - }; -} - -test "use generic param in generic param" { - assert(aGenericFn(i32, 3, 4) == 7); -} -fn aGenericFn(comptime T: type, comptime a: T, b: T) T { - return a + b; -} - -test "generic fn with implicit cast" { - assert(getFirstByte(u8, []u8{13}) == 13); - assert(getFirstByte(u16, []u16{ - 0, - 13, - }) == 0); -} -fn getByte(ptr: ?*const u8) u8 { - return ptr.?.*; -} -fn getFirstByte(comptime T: type, mem: []const T) u8 { - return getByte(@ptrCast(*const u8, &mem[0])); -} - -const foos = []fn (var) bool{ - foo1, - foo2, -}; - -fn foo1(arg: var) bool { - return arg; -} -fn foo2(arg: var) bool { - return !arg; -} - -test "array of generic fns" { - assert(foos[0](true)); - assert(!foos[1](true)); -} diff --git a/test/cases/if.zig b/test/cases/if.zig deleted file mode 100644 index 808936bfa5..0000000000 --- a/test/cases/if.zig +++ /dev/null @@ -1,37 +0,0 @@ -const assert = @import("std").debug.assert; - -test "if statements" { - shouldBeEqual(1, 1); - firstEqlThird(2, 1, 2); -} -fn shouldBeEqual(a: i32, b: i32) void { - if (a != b) { - unreachable; - } else { - return; - } -} -fn firstEqlThird(a: i32, b: i32, c: i32) void { - if (a == b) { - unreachable; - } else if (b == c) { - unreachable; - } else if (a == c) { - return; - } else { - unreachable; - } -} - -test "else if expression" { - assert(elseIfExpressionF(1) == 1); -} -fn elseIfExpressionF(c: u8) u8 { - if (c == 0) { - return 0; - } else if (c == 1) { - return 1; - } else { - return u8(2); - } -} diff --git a/test/cases/import.zig b/test/cases/import.zig deleted file mode 100644 index 6d6d4b0208..0000000000 --- a/test/cases/import.zig +++ /dev/null @@ -1,10 +0,0 @@ -const assert = @import("std").debug.assert; -const a_namespace = @import("import/a_namespace.zig"); - -test "call fn via namespace lookup" { - assert(a_namespace.foo() == 1234); -} - -test "importing the same thing gives the same import" { - assert(@import("std") == @import("std")); -} diff --git a/test/cases/import/a_namespace.zig b/test/cases/import/a_namespace.zig deleted file mode 100644 index 042f1867a5..0000000000 --- a/test/cases/import/a_namespace.zig +++ /dev/null @@ -1,3 +0,0 @@ -pub fn foo() i32 { - return 1234; -} diff --git a/test/cases/incomplete_struct_param_tld.zig b/test/cases/incomplete_struct_param_tld.zig deleted file mode 100644 index f1ac03a292..0000000000 --- a/test/cases/incomplete_struct_param_tld.zig +++ /dev/null @@ -1,30 +0,0 @@ -const assert = @import("std").debug.assert; - -const A = struct { - b: B, -}; - -const B = struct { - c: C, -}; - -const C = struct { - x: i32, - - fn d(c: *const C) i32 { - return c.x; - } -}; - -fn foo(a: A) i32 { - return a.b.c.d(); -} - -test "incomplete struct param top level declaration" { - const a = A{ - .b = B{ - .c = C{ .x = 13 }, - }, - }; - assert(foo(a) == 13); -} diff --git a/test/cases/inttoptr.zig b/test/cases/inttoptr.zig deleted file mode 100644 index ba3cc52f09..0000000000 --- a/test/cases/inttoptr.zig +++ /dev/null @@ -1,27 +0,0 @@ -const builtin = @import("builtin"); -const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; - -test "casting random address to function pointer" { - randomAddressToFunction(); - comptime randomAddressToFunction(); -} - -fn randomAddressToFunction() void { - var addr: usize = 0xdeadbeef; - var ptr = @intToPtr(fn () void, addr); -} - -test "mutate through ptr initialized with constant intToPtr value" { - forceCompilerAnalyzeBranchHardCodedPtrDereference(false); -} - -fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { - const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); - if (x) { - hardCodedP.* = hardCodedP.* | 10; - } else { - return; - } -} - diff --git a/test/cases/ir_block_deps.zig b/test/cases/ir_block_deps.zig deleted file mode 100644 index 5c1b18c00e..0000000000 --- a/test/cases/ir_block_deps.zig +++ /dev/null @@ -1,21 +0,0 @@ -const assert = @import("std").debug.assert; - -fn foo(id: u64) !i32 { - return switch (id) { - 1 => getErrInt(), - 2 => { - const size = try getErrInt(); - return try getErrInt(); - }, - else => error.ItBroke, - }; -} - -fn getErrInt() anyerror!i32 { - return 0; -} - -test "ir block deps" { - assert((foo(1) catch unreachable) == 0); - assert((foo(2) catch unreachable) == 0); -} diff --git a/test/cases/math.zig b/test/cases/math.zig deleted file mode 100644 index 7d6b1bd9ac..0000000000 --- a/test/cases/math.zig +++ /dev/null @@ -1,500 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const maxInt = std.math.maxInt; -const minInt = std.math.minInt; - -test "division" { - testDivision(); - comptime testDivision(); -} -fn testDivision() void { - assert(div(u32, 13, 3) == 4); - assert(div(f16, 1.0, 2.0) == 0.5); - assert(div(f32, 1.0, 2.0) == 0.5); - - assert(divExact(u32, 55, 11) == 5); - assert(divExact(i32, -55, 11) == -5); - assert(divExact(f16, 55.0, 11.0) == 5.0); - assert(divExact(f16, -55.0, 11.0) == -5.0); - assert(divExact(f32, 55.0, 11.0) == 5.0); - assert(divExact(f32, -55.0, 11.0) == -5.0); - - assert(divFloor(i32, 5, 3) == 1); - assert(divFloor(i32, -5, 3) == -2); - assert(divFloor(f16, 5.0, 3.0) == 1.0); - assert(divFloor(f16, -5.0, 3.0) == -2.0); - assert(divFloor(f32, 5.0, 3.0) == 1.0); - assert(divFloor(f32, -5.0, 3.0) == -2.0); - assert(divFloor(i32, -0x80000000, -2) == 0x40000000); - assert(divFloor(i32, 0, -0x80000000) == 0); - assert(divFloor(i32, -0x40000001, 0x40000000) == -2); - assert(divFloor(i32, -0x80000000, 1) == -0x80000000); - - assert(divTrunc(i32, 5, 3) == 1); - assert(divTrunc(i32, -5, 3) == -1); - assert(divTrunc(f16, 5.0, 3.0) == 1.0); - assert(divTrunc(f16, -5.0, 3.0) == -1.0); - assert(divTrunc(f32, 5.0, 3.0) == 1.0); - assert(divTrunc(f32, -5.0, 3.0) == -1.0); - assert(divTrunc(f64, 5.0, 3.0) == 1.0); - assert(divTrunc(f64, -5.0, 3.0) == -1.0); - - comptime { - assert( - 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, - ); - assert( - @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, - ); - assert( - 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, - ); - assert( - @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, - ); - assert( - @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, - ); - assert( - @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, - ); - assert( - 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, - ); - } -} -fn div(comptime T: type, a: T, b: T) T { - return a / b; -} -fn divExact(comptime T: type, a: T, b: T) T { - return @divExact(a, b); -} -fn divFloor(comptime T: type, a: T, b: T) T { - return @divFloor(a, b); -} -fn divTrunc(comptime T: type, a: T, b: T) T { - return @divTrunc(a, b); -} - -test "@addWithOverflow" { - var result: u8 = undefined; - assert(@addWithOverflow(u8, 250, 100, &result)); - assert(!@addWithOverflow(u8, 100, 150, &result)); - assert(result == 250); -} - -// TODO test mulWithOverflow -// TODO test subWithOverflow - -test "@shlWithOverflow" { - var result: u16 = undefined; - assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - assert(result == 0b1011111111111100); -} - -test "@clz" { - testClz(); - comptime testClz(); -} - -fn testClz() void { - assert(clz(u8(0b00001010)) == 4); - assert(clz(u8(0b10001010)) == 0); - assert(clz(u8(0b00000000)) == 8); - assert(clz(u128(0xffffffffffffffff)) == 64); - assert(clz(u128(0x10000000000000000)) == 63); -} - -fn clz(x: var) usize { - return @clz(x); -} - -test "@ctz" { - testCtz(); - comptime testCtz(); -} - -fn testCtz() void { - assert(ctz(u8(0b10100000)) == 5); - assert(ctz(u8(0b10001010)) == 1); - assert(ctz(u8(0b00000000)) == 8); -} - -fn ctz(x: var) usize { - return @ctz(x); -} - -test "assignment operators" { - var i: u32 = 0; - i += 5; - assert(i == 5); - i -= 2; - assert(i == 3); - i *= 20; - assert(i == 60); - i /= 3; - assert(i == 20); - i %= 11; - assert(i == 9); - i <<= 1; - assert(i == 18); - i >>= 2; - assert(i == 4); - i = 6; - i &= 5; - assert(i == 4); - i ^= 6; - assert(i == 2); - i = 6; - i |= 3; - assert(i == 7); -} - -test "three expr in a row" { - testThreeExprInARow(false, true); - comptime testThreeExprInARow(false, true); -} -fn testThreeExprInARow(f: bool, t: bool) void { - assertFalse(f or f or f); - assertFalse(t and t and f); - assertFalse(1 | 2 | 4 != 7); - assertFalse(3 ^ 6 ^ 8 != 13); - assertFalse(7 & 14 & 28 != 4); - assertFalse(9 << 1 << 2 != 9 << 3); - assertFalse(90 >> 1 >> 2 != 90 >> 3); - assertFalse(100 - 1 + 1000 != 1099); - assertFalse(5 * 4 / 2 % 3 != 1); - assertFalse(i32(i32(5)) != 5); - assertFalse(!!false); - assertFalse(i32(7) != --(i32(7))); -} -fn assertFalse(b: bool) void { - assert(!b); -} - -test "const number literal" { - const one = 1; - const eleven = ten + one; - - assert(eleven == 11); -} -const ten = 10; - -test "unsigned wrapping" { - testUnsignedWrappingEval(maxInt(u32)); - comptime testUnsignedWrappingEval(maxInt(u32)); -} -fn testUnsignedWrappingEval(x: u32) void { - const zero = x +% 1; - assert(zero == 0); - const orig = zero -% 1; - assert(orig == maxInt(u32)); -} - -test "signed wrapping" { - testSignedWrappingEval(maxInt(i32)); - comptime testSignedWrappingEval(maxInt(i32)); -} -fn testSignedWrappingEval(x: i32) void { - const min_val = x +% 1; - assert(min_val == minInt(i32)); - const max_val = min_val -% 1; - assert(max_val == maxInt(i32)); -} - -test "negation wrapping" { - testNegationWrappingEval(minInt(i16)); - comptime testNegationWrappingEval(minInt(i16)); -} -fn testNegationWrappingEval(x: i16) void { - assert(x == -32768); - const neg = -%x; - assert(neg == -32768); -} - -test "unsigned 64-bit division" { - test_u64_div(); - comptime test_u64_div(); -} -fn test_u64_div() void { - const result = divWithResult(1152921504606846976, 34359738365); - assert(result.quotient == 33554432); - assert(result.remainder == 100663296); -} -fn divWithResult(a: u64, b: u64) DivResult { - return DivResult{ - .quotient = a / b, - .remainder = a % b, - }; -} -const DivResult = struct { - quotient: u64, - remainder: u64, -}; - -test "binary not" { - assert(comptime x: { - break :x ~u16(0b1010101010101010) == 0b0101010101010101; - }); - assert(comptime x: { - break :x ~u64(2147483647) == 18446744071562067968; - }); - testBinaryNot(0b1010101010101010); -} - -fn testBinaryNot(x: u16) void { - assert(~x == 0b0101010101010101); -} - -test "small int addition" { - var x: @IntType(false, 2) = 0; - assert(x == 0); - - x += 1; - assert(x == 1); - - x += 1; - assert(x == 2); - - x += 1; - assert(x == 3); - - var result: @typeOf(x) = 3; - assert(@addWithOverflow(@typeOf(x), x, 1, &result)); - - assert(result == 0); -} - -test "float equality" { - const x: f64 = 0.012; - const y: f64 = x + 1.0; - - testFloatEqualityImpl(x, y); - comptime testFloatEqualityImpl(x, y); -} - -fn testFloatEqualityImpl(x: f64, y: f64) void { - const y2 = x + 1.0; - assert(y == y2); -} - -test "allow signed integer division/remainder when values are comptime known and positive or exact" { - assert(5 / 3 == 1); - assert(-5 / -3 == 1); - assert(-6 / 3 == -2); - - assert(5 % 3 == 2); - assert(-6 % 3 == 0); -} - -test "hex float literal parsing" { - comptime assert(0x1.0 == 1.0); -} - -test "quad hex float literal parsing in range" { - const a = 0x1.af23456789bbaaab347645365cdep+5; - const b = 0x1.dedafcff354b6ae9758763545432p-9; - const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; - const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; -} - -test "quad hex float literal parsing accurate" { - const a: f128 = 0x1.1111222233334444555566667777p+0; - - // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. - const expected: u128 = 0x3fff1111222233334444555566667777; - assert(@bitCast(u128, a) == expected); -} - -test "hex float literal within range" { - const a = 0x1.0p16383; - const b = 0x0.1p16387; - const c = 0x1.0p-16382; -} - -test "truncating shift left" { - testShlTrunc(maxInt(u16)); - comptime testShlTrunc(maxInt(u16)); -} -fn testShlTrunc(x: u16) void { - const shifted = x << 1; - assert(shifted == 65534); -} - -test "truncating shift right" { - testShrTrunc(maxInt(u16)); - comptime testShrTrunc(maxInt(u16)); -} -fn testShrTrunc(x: u16) void { - const shifted = x >> 1; - assert(shifted == 32767); -} - -test "exact shift left" { - testShlExact(0b00110101); - comptime testShlExact(0b00110101); -} -fn testShlExact(x: u8) void { - const shifted = @shlExact(x, 2); - assert(shifted == 0b11010100); -} - -test "exact shift right" { - testShrExact(0b10110100); - comptime testShrExact(0b10110100); -} -fn testShrExact(x: u8) void { - const shifted = @shrExact(x, 2); - assert(shifted == 0b00101101); -} - -test "comptime_int addition" { - comptime { - assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); - assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); - } -} - -test "comptime_int multiplication" { - comptime { - assert( - 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, - ); - assert( - 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, - ); - } -} - -test "comptime_int shifting" { - comptime { - assert((u128(1) << 127) == 0x80000000000000000000000000000000); - } -} - -test "comptime_int multi-limb shift and mask" { - comptime { - var a = 0xefffffffa0000001eeeeeeefaaaaaaab; - - assert(u32(a & 0xffffffff) == 0xaaaaaaab); - a >>= 32; - assert(u32(a & 0xffffffff) == 0xeeeeeeef); - a >>= 32; - assert(u32(a & 0xffffffff) == 0xa0000001); - a >>= 32; - assert(u32(a & 0xffffffff) == 0xefffffff); - a >>= 32; - - assert(a == 0); - } -} - -test "comptime_int multi-limb partial shift right" { - comptime { - var a = 0x1ffffffffeeeeeeee; - a >>= 16; - assert(a == 0x1ffffffffeeee); - } -} - -test "xor" { - test_xor(); - comptime test_xor(); -} - -fn test_xor() void { - assert(0xFF ^ 0x00 == 0xFF); - assert(0xF0 ^ 0x0F == 0xFF); - assert(0xFF ^ 0xF0 == 0x0F); - assert(0xFF ^ 0x0F == 0xF0); - assert(0xFF ^ 0xFF == 0x00); -} - -test "comptime_int xor" { - comptime { - assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); - assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); - assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); - assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); - assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); - } -} - -test "f128" { - test_f128(); - comptime test_f128(); -} - -fn make_f128(x: f128) f128 { - return x; -} - -fn test_f128() void { - assert(@sizeOf(f128) == 16); - assert(make_f128(1.0) == 1.0); - assert(make_f128(1.0) != 1.1); - assert(make_f128(1.0) > 0.9); - assert(make_f128(1.0) >= 0.9); - assert(make_f128(1.0) >= 1.0); - should_not_be_zero(1.0); -} - -fn should_not_be_zero(x: f128) void { - assert(x != 0.0); -} - -test "comptime float rem int" { - comptime { - var x = f32(1) % 2; - assert(x == 1.0); - } -} - -test "remainder division" { - comptime remdiv(f16); - comptime remdiv(f32); - comptime remdiv(f64); - comptime remdiv(f128); - remdiv(f16); - remdiv(f64); - remdiv(f128); -} - -fn remdiv(comptime T: type) void { - assert(T(1) == T(1) % T(2)); - assert(T(1) == T(7) % T(3)); -} - -test "@sqrt" { - testSqrt(f64, 12.0); - comptime testSqrt(f64, 12.0); - testSqrt(f32, 13.0); - comptime testSqrt(f32, 13.0); - testSqrt(f16, 13.0); - comptime testSqrt(f16, 13.0); - - const x = 14.0; - const y = x * x; - const z = @sqrt(@typeOf(y), y); - comptime assert(z == x); -} - -fn testSqrt(comptime T: type, x: T) void { - assert(@sqrt(T, x * x) == x); -} - -test "comptime_int param and return" { - const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); - assert(a == 137114567242441932203689521744947848950); - - const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); - assert(b == 985095453608931032642182098849559179469148836107390954364380); -} - -fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { - return a + b; -} diff --git a/test/cases/merge_error_sets.zig b/test/cases/merge_error_sets.zig deleted file mode 100644 index 147b580232..0000000000 --- a/test/cases/merge_error_sets.zig +++ /dev/null @@ -1,21 +0,0 @@ -const A = error{ - FileNotFound, - NotDir, -}; -const B = error{OutOfMemory}; - -const C = A || B; - -fn foo() C!void { - return error.NotDir; -} - -test "merge error sets" { - if (foo()) { - @panic("unexpected"); - } else |err| switch (err) { - error.OutOfMemory => @panic("unexpected"), - error.FileNotFound => @panic("unexpected"), - error.NotDir => {}, - } -} diff --git a/test/cases/misc.zig b/test/cases/misc.zig deleted file mode 100644 index 1a34d54e9e..0000000000 --- a/test/cases/misc.zig +++ /dev/null @@ -1,681 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; -const cstr = std.cstr; -const builtin = @import("builtin"); -const maxInt = std.math.maxInt; - -// normal comment - -/// this is a documentation comment -/// doc comment line 2 -fn emptyFunctionWithComments() void {} - -test "empty function with comments" { - emptyFunctionWithComments(); -} - -comptime { - @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); -} - -extern fn disabledExternFn() void {} - -test "call disabled extern fn" { - disabledExternFn(); -} - -test "@IntType builtin" { - assert(@IntType(true, 8) == i8); - assert(@IntType(true, 16) == i16); - assert(@IntType(true, 32) == i32); - assert(@IntType(true, 64) == i64); - - assert(@IntType(false, 8) == u8); - assert(@IntType(false, 16) == u16); - assert(@IntType(false, 32) == u32); - assert(@IntType(false, 64) == u64); - - assert(i8.bit_count == 8); - assert(i16.bit_count == 16); - assert(i32.bit_count == 32); - assert(i64.bit_count == 64); - - assert(i8.is_signed); - assert(i16.is_signed); - assert(i32.is_signed); - assert(i64.is_signed); - assert(isize.is_signed); - - assert(!u8.is_signed); - assert(!u16.is_signed); - assert(!u32.is_signed); - assert(!u64.is_signed); - assert(!usize.is_signed); -} - -test "floating point primitive bit counts" { - assert(f16.bit_count == 16); - assert(f32.bit_count == 32); - assert(f64.bit_count == 64); -} - -test "short circuit" { - testShortCircuit(false, true); - comptime testShortCircuit(false, true); -} - -fn testShortCircuit(f: bool, t: bool) void { - var hit_1 = f; - var hit_2 = f; - var hit_3 = f; - var hit_4 = f; - - if (t or x: { - assert(f); - break :x f; - }) { - hit_1 = t; - } - if (f or x: { - hit_2 = t; - break :x f; - }) { - assert(f); - } - - if (t and x: { - hit_3 = t; - break :x f; - }) { - assert(f); - } - if (f and x: { - assert(f); - break :x f; - }) { - assert(f); - } else { - hit_4 = t; - } - assert(hit_1); - assert(hit_2); - assert(hit_3); - assert(hit_4); -} - -test "truncate" { - assert(testTruncate(0x10fd) == 0xfd); -} -fn testTruncate(x: u32) u8 { - return @truncate(u8, x); -} - -fn first4KeysOfHomeRow() []const u8 { - return "aoeu"; -} - -test "return string from function" { - assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); -} - -const g1: i32 = 1233 + 1; -var g2: i32 = 0; - -test "global variables" { - assert(g2 == 0); - g2 = g1; - assert(g2 == 1234); -} - -test "memcpy and memset intrinsics" { - var foo: [20]u8 = undefined; - var bar: [20]u8 = undefined; - - @memset(foo[0..].ptr, 'A', foo.len); - @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); - - if (bar[11] != 'A') unreachable; -} - -test "builtin static eval" { - const x: i32 = comptime x: { - break :x 1 + 2 + 3; - }; - assert(x == comptime 6); -} - -test "slicing" { - var array: [20]i32 = undefined; - - array[5] = 1234; - - var slice = array[5..10]; - - if (slice.len != 5) unreachable; - - const ptr = &slice[0]; - if (ptr.* != 1234) unreachable; - - var slice_rest = array[10..]; - if (slice_rest.len != 10) unreachable; -} - -test "constant equal function pointers" { - const alias = emptyFn; - assert(comptime x: { - break :x emptyFn == alias; - }); -} - -fn emptyFn() void {} - -test "hex escape" { - assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); -} - -test "string concatenation" { - assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); -} - -test "array mult operator" { - assert(mem.eql(u8, "ab" ** 5, "ababababab")); -} - -test "string escapes" { - assert(mem.eql(u8, "\"", "\x22")); - assert(mem.eql(u8, "\'", "\x27")); - assert(mem.eql(u8, "\n", "\x0a")); - assert(mem.eql(u8, "\r", "\x0d")); - assert(mem.eql(u8, "\t", "\x09")); - assert(mem.eql(u8, "\\", "\x5c")); - assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); -} - -test "multiline string" { - const s1 = - \\one - \\two) - \\three - ; - const s2 = "one\ntwo)\nthree"; - assert(mem.eql(u8, s1, s2)); -} - -test "multiline C string" { - const s1 = - c\\one - c\\two) - c\\three - ; - const s2 = c"one\ntwo)\nthree"; - assert(cstr.cmp(s1, s2) == 0); -} - -test "type equality" { - assert(*const u8 != *u8); -} - -const global_a: i32 = 1234; -const global_b: *const i32 = &global_a; -const global_c: *const f32 = @ptrCast(*const f32, global_b); -test "compile time global reinterpret" { - const d = @ptrCast(*const i32, global_c); - assert(d.* == 1234); -} - -test "explicit cast maybe pointers" { - const a: ?*i32 = undefined; - const b: ?*f32 = @ptrCast(?*f32, a); -} - -test "generic malloc free" { - const a = memAlloc(u8, 10) catch unreachable; - memFree(u8, a); -} -var some_mem: [100]u8 = undefined; -fn memAlloc(comptime T: type, n: usize) anyerror![]T { - return @ptrCast([*]T, &some_mem[0])[0..n]; -} -fn memFree(comptime T: type, memory: []T) void {} - -test "cast undefined" { - const array: [100]u8 = undefined; - const slice = ([]const u8)(array); - testCastUndefined(slice); -} -fn testCastUndefined(x: []const u8) void {} - -test "cast small unsigned to larger signed" { - assert(castSmallUnsignedToLargerSigned1(200) == i16(200)); - assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); -} -fn castSmallUnsignedToLargerSigned1(x: u8) i16 { - return x; -} -fn castSmallUnsignedToLargerSigned2(x: u16) i64 { - return x; -} - -test "implicit cast after unreachable" { - assert(outer() == 1234); -} -fn inner() i32 { - return 1234; -} -fn outer() i64 { - return inner(); -} - -test "pointer dereferencing" { - var x = i32(3); - const y = &x; - - y.* += 1; - - assert(x == 4); - assert(y.* == 4); -} - -test "call result of if else expression" { - assert(mem.eql(u8, f2(true), "a")); - assert(mem.eql(u8, f2(false), "b")); -} -fn f2(x: bool) []const u8 { - return (if (x) fA else fB)(); -} -fn fA() []const u8 { - return "a"; -} -fn fB() []const u8 { - return "b"; -} - -test "const expression eval handling of variables" { - var x = true; - while (x) { - x = false; - } -} - -test "constant enum initialization with differing sizes" { - test3_1(test3_foo); - test3_2(test3_bar); -} -const Test3Foo = union(enum) { - One: void, - Two: f32, - Three: Test3Point, -}; -const Test3Point = struct { - x: i32, - y: i32, -}; -const test3_foo = Test3Foo{ - .Three = Test3Point{ - .x = 3, - .y = 4, - }, -}; -const test3_bar = Test3Foo{ .Two = 13 }; -fn test3_1(f: Test3Foo) void { - switch (f) { - Test3Foo.Three => |pt| { - assert(pt.x == 3); - assert(pt.y == 4); - }, - else => unreachable, - } -} -fn test3_2(f: Test3Foo) void { - switch (f) { - Test3Foo.Two => |x| { - assert(x == 13); - }, - else => unreachable, - } -} - -test "character literals" { - assert('\'' == single_quote); -} -const single_quote = '\''; - -test "take address of parameter" { - testTakeAddressOfParameter(12.34); -} -fn testTakeAddressOfParameter(f: f32) void { - const f_ptr = &f; - assert(f_ptr.* == 12.34); -} - -test "pointer comparison" { - const a = ([]const u8)("a"); - const b = &a; - assert(ptrEql(b, b)); -} -fn ptrEql(a: *const []const u8, b: *const []const u8) bool { - return a == b; -} - -test "C string concatenation" { - const a = c"OK" ++ c" IT " ++ c"WORKED"; - const b = c"OK IT WORKED"; - - const len = cstr.len(b); - const len_with_null = len + 1; - { - var i: u32 = 0; - while (i < len_with_null) : (i += 1) { - assert(a[i] == b[i]); - } - } - assert(a[len] == 0); - assert(b[len] == 0); -} - -test "cast slice to u8 slice" { - assert(@sizeOf(i32) == 4); - var big_thing_array = []i32{ - 1, - 2, - 3, - 4, - }; - const big_thing_slice: []i32 = big_thing_array[0..]; - const bytes = @sliceToBytes(big_thing_slice); - assert(bytes.len == 4 * 4); - bytes[4] = 0; - bytes[5] = 0; - bytes[6] = 0; - bytes[7] = 0; - assert(big_thing_slice[1] == 0); - const big_thing_again = @bytesToSlice(i32, bytes); - assert(big_thing_again[2] == 3); - big_thing_again[2] = -1; - assert(bytes[8] == maxInt(u8)); - assert(bytes[9] == maxInt(u8)); - assert(bytes[10] == maxInt(u8)); - assert(bytes[11] == maxInt(u8)); -} - -test "pointer to void return type" { - testPointerToVoidReturnType() catch unreachable; -} -fn testPointerToVoidReturnType() anyerror!void { - const a = testPointerToVoidReturnType2(); - return a.*; -} -const test_pointer_to_void_return_type_x = void{}; -fn testPointerToVoidReturnType2() *const void { - return &test_pointer_to_void_return_type_x; -} - -test "non const ptr to aliased type" { - const int = i32; - assert(?*int == ?*i32); -} - -test "array 2D const double ptr" { - const rect_2d_vertexes = [][1]f32{ - []f32{1.0}, - []f32{2.0}, - }; - testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); -} - -fn testArray2DConstDoublePtr(ptr: *const f32) void { - const ptr2 = @ptrCast([*]const f32, ptr); - assert(ptr2[0] == 1.0); - assert(ptr2[1] == 2.0); -} - -const Tid = builtin.TypeId; -const AStruct = struct { - x: i32, -}; -const AnEnum = enum { - One, - Two, -}; -const AUnionEnum = union(enum) { - One: i32, - Two: void, -}; -const AUnion = union { - One: void, - Two: void, -}; - -test "@typeId" { - comptime { - assert(@typeId(type) == Tid.Type); - assert(@typeId(void) == Tid.Void); - assert(@typeId(bool) == Tid.Bool); - assert(@typeId(noreturn) == Tid.NoReturn); - assert(@typeId(i8) == Tid.Int); - assert(@typeId(u8) == Tid.Int); - assert(@typeId(i64) == Tid.Int); - assert(@typeId(u64) == Tid.Int); - assert(@typeId(f32) == Tid.Float); - assert(@typeId(f64) == Tid.Float); - assert(@typeId(*f32) == Tid.Pointer); - assert(@typeId([2]u8) == Tid.Array); - assert(@typeId(AStruct) == Tid.Struct); - assert(@typeId(@typeOf(1)) == Tid.ComptimeInt); - assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); - assert(@typeId(@typeOf(undefined)) == Tid.Undefined); - assert(@typeId(@typeOf(null)) == Tid.Null); - assert(@typeId(?i32) == Tid.Optional); - assert(@typeId(anyerror!i32) == Tid.ErrorUnion); - assert(@typeId(anyerror) == Tid.ErrorSet); - assert(@typeId(AnEnum) == Tid.Enum); - assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); - assert(@typeId(AUnionEnum) == Tid.Union); - assert(@typeId(AUnion) == Tid.Union); - assert(@typeId(fn () void) == Tid.Fn); - assert(@typeId(@typeOf(builtin)) == Tid.Namespace); - // TODO bound fn - // TODO arg tuple - // TODO opaque - } -} - -test "@typeName" { - const Struct = struct {}; - const Union = union { - unused: u8, - }; - const Enum = enum { - Unused, - }; - comptime { - assert(mem.eql(u8, @typeName(i64), "i64")); - assert(mem.eql(u8, @typeName(*usize), "*usize")); - // https://github.com/ziglang/zig/issues/675 - assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); - assert(mem.eql(u8, @typeName(Struct), "Struct")); - assert(mem.eql(u8, @typeName(Union), "Union")); - assert(mem.eql(u8, @typeName(Enum), "Enum")); - } -} - -fn TypeFromFn(comptime T: type) type { - return struct {}; -} - -test "volatile load and store" { - var number: i32 = 1234; - const ptr = (*volatile i32)(&number); - ptr.* += 1; - assert(ptr.* == 1235); -} - -test "slice string literal has type []const u8" { - comptime { - assert(@typeOf("aoeu"[0..]) == []const u8); - const array = []i32{ - 1, - 2, - 3, - 4, - }; - assert(@typeOf(array[0..]) == []const i32); - } -} - -test "global variable initialized to global variable array element" { - assert(global_ptr == &gdt[0]); -} -const GDTEntry = struct { - field: i32, -}; -var gdt = []GDTEntry{ - GDTEntry{ .field = 1 }, - GDTEntry{ .field = 2 }, -}; -var global_ptr = &gdt[0]; - -// can't really run this test but we can make sure it has no compile error -// and generates code -const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; -export fn writeToVRam() void { - vram[0] = 'X'; -} - -test "pointer child field" { - assert((*u32).Child == u32); -} - -const OpaqueA = @OpaqueType(); -const OpaqueB = @OpaqueType(); -test "@OpaqueType" { - assert(*OpaqueA != *OpaqueB); - assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); - assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); -} - -test "variable is allowed to be a pointer to an opaque type" { - var x: i32 = 1234; - _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); -} -fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { - var a = ptr; - return a; -} - -test "comptime if inside runtime while which unconditionally breaks" { - testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); - comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); -} -fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { - while (cond) { - if (false) {} - break; - } -} - -test "implicit comptime while" { - while (false) { - @compileError("bad"); - } -} - -test "struct inside function" { - testStructInFn(); - comptime testStructInFn(); -} - -fn testStructInFn() void { - const BlockKind = u32; - - const Block = struct { - kind: BlockKind, - }; - - var block = Block{ .kind = 1234 }; - - block.kind += 1; - - assert(block.kind == 1235); -} - -fn fnThatClosesOverLocalConst() type { - const c = 1; - return struct { - fn g() i32 { - return c; - } - }; -} - -test "function closes over local const" { - const x = fnThatClosesOverLocalConst().g(); - assert(x == 1); -} - -test "cold function" { - thisIsAColdFn(); - comptime thisIsAColdFn(); -} - -fn thisIsAColdFn() void { - @setCold(true); -} - -const PackedStruct = packed struct { - a: u8, - b: u8, -}; -const PackedUnion = packed union { - a: u8, - b: u32, -}; -const PackedEnum = packed enum { - A, - B, -}; - -test "packed struct, enum, union parameters in extern function" { - testPackedStuff(&(PackedStruct{ - .a = 1, - .b = 2, - }), &(PackedUnion{ .a = 1 }), PackedEnum.A); -} - -export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} - -test "slicing zero length array" { - const s1 = ""[0..]; - const s2 = ([]u32{})[0..]; - assert(s1.len == 0); - assert(s2.len == 0); - assert(mem.eql(u8, s1, "")); - assert(mem.eql(u32, s2, []u32{})); -} - -const addr1 = @ptrCast(*const u8, emptyFn); -test "comptime cast fn to ptr" { - const addr2 = @ptrCast(*const u8, emptyFn); - comptime assert(addr1 == addr2); -} - -test "equality compare fn ptrs" { - var a = emptyFn; - assert(a == a); -} - -test "self reference through fn ptr field" { - const S = struct { - const A = struct { - f: fn (A) u8, - }; - - fn foo(a: A) u8 { - return 12; - } - }; - var a: S.A = undefined; - a.f = S.foo; - assert(a.f(a) == 12); -} diff --git a/test/cases/namespace_depends_on_compile_var/a.zig b/test/cases/namespace_depends_on_compile_var/a.zig deleted file mode 100644 index 5ce0e94f8b..0000000000 --- a/test/cases/namespace_depends_on_compile_var/a.zig +++ /dev/null @@ -1 +0,0 @@ -pub const a_bool = true; diff --git a/test/cases/namespace_depends_on_compile_var/b.zig b/test/cases/namespace_depends_on_compile_var/b.zig deleted file mode 100644 index a12a54b589..0000000000 --- a/test/cases/namespace_depends_on_compile_var/b.zig +++ /dev/null @@ -1 +0,0 @@ -pub const a_bool = false; diff --git a/test/cases/namespace_depends_on_compile_var/index.zig b/test/cases/namespace_depends_on_compile_var/index.zig deleted file mode 100644 index ccc49d9367..0000000000 --- a/test/cases/namespace_depends_on_compile_var/index.zig +++ /dev/null @@ -1,14 +0,0 @@ -const builtin = @import("builtin"); -const assert = @import("std").debug.assert; - -test "namespace depends on compile var" { - if (some_namespace.a_bool) { - assert(some_namespace.a_bool); - } else { - assert(!some_namespace.a_bool); - } -} -const some_namespace = switch (builtin.os) { - builtin.Os.linux => @import("a.zig"), - else => @import("b.zig"), -}; diff --git a/test/cases/new_stack_call.zig b/test/cases/new_stack_call.zig deleted file mode 100644 index 5912550d54..0000000000 --- a/test/cases/new_stack_call.zig +++ /dev/null @@ -1,26 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -var new_stack_bytes: [1024]u8 = undefined; - -test "calling a function with a new stack" { - const arg = 1234; - - const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); - const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); - _ = targetFunction(arg); - - assert(arg == 1234); - assert(a < b); -} - -fn targetFunction(x: i32) usize { - assert(x == 1234); - - var local_variable: i32 = 42; - const ptr = &local_variable; - ptr.* += 1; - - assert(local_variable == 43); - return @ptrToInt(ptr); -} diff --git a/test/cases/null.zig b/test/cases/null.zig deleted file mode 100644 index 825db88b1e..0000000000 --- a/test/cases/null.zig +++ /dev/null @@ -1,162 +0,0 @@ -const assert = @import("std").debug.assert; - -test "optional type" { - const x: ?bool = true; - - if (x) |y| { - if (y) { - // OK - } else { - unreachable; - } - } else { - unreachable; - } - - const next_x: ?i32 = null; - - const z = next_x orelse 1234; - - assert(z == 1234); - - const final_x: ?i32 = 13; - - const num = final_x orelse unreachable; - - assert(num == 13); -} - -test "test maybe object and get a pointer to the inner value" { - var maybe_bool: ?bool = true; - - if (maybe_bool) |*b| { - b.* = false; - } - - assert(maybe_bool.? == false); -} - -test "rhs maybe unwrap return" { - const x: ?bool = true; - const y = x orelse return; -} - -test "maybe return" { - maybeReturnImpl(); - comptime maybeReturnImpl(); -} - -fn maybeReturnImpl() void { - assert(foo(1235).?); - if (foo(null) != null) unreachable; - assert(!foo(1234).?); -} - -fn foo(x: ?i32) ?bool { - const value = x orelse return null; - return value > 1234; -} - -test "if var maybe pointer" { - assert(shouldBeAPlus1(Particle{ - .a = 14, - .b = 1, - .c = 1, - .d = 1, - }) == 15); -} -fn shouldBeAPlus1(p: Particle) u64 { - var maybe_particle: ?Particle = p; - if (maybe_particle) |*particle| { - particle.a += 1; - } - if (maybe_particle) |particle| { - return particle.a; - } - return 0; -} -const Particle = struct { - a: u64, - b: u64, - c: u64, - d: u64, -}; - -test "null literal outside function" { - const is_null = here_is_a_null_literal.context == null; - assert(is_null); - - const is_non_null = here_is_a_null_literal.context != null; - assert(!is_non_null); -} -const SillyStruct = struct { - context: ?i32, -}; -const here_is_a_null_literal = SillyStruct{ .context = null }; - -test "test null runtime" { - testTestNullRuntime(null); -} -fn testTestNullRuntime(x: ?i32) void { - assert(x == null); - assert(!(x != null)); -} - -test "optional void" { - optionalVoidImpl(); - comptime optionalVoidImpl(); -} - -fn optionalVoidImpl() void { - assert(bar(null) == null); - assert(bar({}) != null); -} - -fn bar(x: ?void) ?void { - if (x) |_| { - return {}; - } else { - return null; - } -} - -const StructWithOptional = struct { - field: ?i32, -}; - -var struct_with_optional: StructWithOptional = undefined; - -test "unwrap optional which is field of global var" { - struct_with_optional.field = null; - if (struct_with_optional.field) |payload| { - unreachable; - } - struct_with_optional.field = 1234; - if (struct_with_optional.field) |payload| { - assert(payload == 1234); - } else { - unreachable; - } -} - -test "null with default unwrap" { - const x: i32 = null orelse 1; - assert(x == 1); -} - -test "optional types" { - comptime { - const opt_type_struct = StructWithOptionalType{ .t = u8 }; - assert(opt_type_struct.t != null and opt_type_struct.t.? == u8); - } -} - -const StructWithOptionalType = struct { - t: ?type, -}; - -test "optional pointer to 0 bit type null value at runtime" { - const EmptyStruct = struct {}; - var x: ?*EmptyStruct = null; - assert(x == null); -} diff --git a/test/cases/optional.zig b/test/cases/optional.zig deleted file mode 100644 index d43682bbec..0000000000 --- a/test/cases/optional.zig +++ /dev/null @@ -1,30 +0,0 @@ -const assert = @import("std").debug.assert; - -pub const EmptyStruct = struct {}; - -test "optional pointer to size zero struct" { - var e = EmptyStruct{}; - var o: ?*EmptyStruct = &e; - assert(o != null); -} - -test "equality compare nullable pointers" { - testNullPtrsEql(); - comptime testNullPtrsEql(); -} - -fn testNullPtrsEql() void { - var number: i32 = 1234; - - var x: ?*i32 = null; - var y: ?*i32 = null; - assert(x == y); - y = &number; - assert(x != y); - assert(x != &number); - assert(&number != x); - x = &number; - assert(x == y); - assert(x == &number); - assert(&number == x); -} diff --git a/test/cases/pointers.zig b/test/cases/pointers.zig deleted file mode 100644 index 47afb60a2e..0000000000 --- a/test/cases/pointers.zig +++ /dev/null @@ -1,44 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "dereference pointer" { - comptime testDerefPtr(); - testDerefPtr(); -} - -fn testDerefPtr() void { - var x: i32 = 1234; - var y = &x; - y.* += 1; - assert(x == 1235); -} - -test "pointer arithmetic" { - var ptr = c"abcd"; - - assert(ptr[0] == 'a'); - ptr += 1; - assert(ptr[0] == 'b'); - ptr += 1; - assert(ptr[0] == 'c'); - ptr += 1; - assert(ptr[0] == 'd'); - ptr += 1; - assert(ptr[0] == 0); - ptr -= 1; - assert(ptr[0] == 'd'); - ptr -= 1; - assert(ptr[0] == 'c'); - ptr -= 1; - assert(ptr[0] == 'b'); - ptr -= 1; - assert(ptr[0] == 'a'); -} - -test "double pointer parsing" { - comptime assert(PtrOf(PtrOf(i32)) == **i32); -} - -fn PtrOf(comptime T: type) type { - return *T; -} diff --git a/test/cases/popcount.zig b/test/cases/popcount.zig deleted file mode 100644 index 7dc7f28c0e..0000000000 --- a/test/cases/popcount.zig +++ /dev/null @@ -1,24 +0,0 @@ -const assert = @import("std").debug.assert; - -test "@popCount" { - comptime testPopCount(); - testPopCount(); -} - -fn testPopCount() void { - { - var x: u32 = 0xaa; - assert(@popCount(x) == 4); - } - { - var x: u32 = 0xaaaaaaaa; - assert(@popCount(x) == 16); - } - { - var x: i16 = -1; - assert(@popCount(x) == 16); - } - comptime { - assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); - } -} diff --git a/test/cases/ptrcast.zig b/test/cases/ptrcast.zig deleted file mode 100644 index 54c3dda849..0000000000 --- a/test/cases/ptrcast.zig +++ /dev/null @@ -1,52 +0,0 @@ -const builtin = @import("builtin"); -const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; - -test "reinterpret bytes as integer with nonzero offset" { - testReinterpretBytesAsInteger(); - comptime testReinterpretBytesAsInteger(); -} - -fn testReinterpretBytesAsInteger() void { - const bytes = "\x12\x34\x56\x78\xab"; - const expected = switch (builtin.endian) { - builtin.Endian.Little => 0xab785634, - builtin.Endian.Big => 0x345678ab, - }; - assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); -} - -test "reinterpret bytes of an array into an extern struct" { - testReinterpretBytesAsExternStruct(); - comptime testReinterpretBytesAsExternStruct(); -} - -fn testReinterpretBytesAsExternStruct() void { - var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; - - const S = extern struct { - a: u8, - b: u16, - c: u8, - }; - - var ptr = @ptrCast(*const S, &bytes); - var val = ptr.c; - assertOrPanic(val == 5); -} - -test "reinterpret struct field at comptime" { - const numLittle = comptime Bytes.init(0x12345678); - assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); -} - -const Bytes = struct { - bytes: [4]u8, - - pub fn init(v: u32) Bytes { - var res: Bytes = undefined; - @ptrCast(*align(1) u32, &res.bytes).* = v; - - return res; - } -}; diff --git a/test/cases/pub_enum/index.zig b/test/cases/pub_enum/index.zig deleted file mode 100644 index 7fdd07b8a3..0000000000 --- a/test/cases/pub_enum/index.zig +++ /dev/null @@ -1,13 +0,0 @@ -const other = @import("other.zig"); -const assert = @import("std").debug.assert; - -test "pub enum" { - pubEnumTest(other.APubEnum.Two); -} -fn pubEnumTest(foo: other.APubEnum) void { - assert(foo == other.APubEnum.Two); -} - -test "cast with imported symbol" { - assert(other.size_t(42) == 42); -} diff --git a/test/cases/pub_enum/other.zig b/test/cases/pub_enum/other.zig deleted file mode 100644 index c663950383..0000000000 --- a/test/cases/pub_enum/other.zig +++ /dev/null @@ -1,6 +0,0 @@ -pub const APubEnum = enum { - One, - Two, - Three, -}; -pub const size_t = u64; diff --git a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig deleted file mode 100644 index 3c94bb0d49..0000000000 --- a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig +++ /dev/null @@ -1,37 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -var ok: bool = false; -test "reference a variable in an if after an if in the 2nd switch prong" { - foo(true, Num.Two, false, "aoeu"); - assert(!ok); - foo(false, Num.One, false, "aoeu"); - assert(!ok); - foo(true, Num.One, false, "aoeu"); - assert(ok); -} - -const Num = enum { - One, - Two, -}; - -fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { - switch (k) { - Num.Two => {}, - Num.One => { - if (c) { - const output_path = b; - - if (c2) {} - - a(output_path); - } - }, - } -} - -fn a(x: []const u8) void { - assert(mem.eql(u8, x, "aoeu")); - ok = true; -} diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig deleted file mode 100644 index b9b8aff4e1..0000000000 --- a/test/cases/reflection.zig +++ /dev/null @@ -1,95 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const reflection = @This(); - -test "reflection: array, pointer, optional, error union type child" { - comptime { - assert(([10]u8).Child == u8); - assert((*u8).Child == u8); - assert((anyerror!u8).Payload == u8); - assert((?u8).Child == u8); - } -} - -test "reflection: function return type, var args, and param types" { - comptime { - assert(@typeOf(dummy).ReturnType == i32); - assert(!@typeOf(dummy).is_var_args); - assert(@typeOf(dummy_varargs).is_var_args); - assert(@typeOf(dummy).arg_count == 3); - assert(@ArgType(@typeOf(dummy), 0) == bool); - assert(@ArgType(@typeOf(dummy), 1) == i32); - assert(@ArgType(@typeOf(dummy), 2) == f32); - } -} - -fn dummy(a: bool, b: i32, c: f32) i32 { - return 1234; -} -fn dummy_varargs(args: ...) void {} - -test "reflection: struct member types and names" { - comptime { - assert(@memberCount(Foo) == 3); - - assert(@memberType(Foo, 0) == i32); - assert(@memberType(Foo, 1) == bool); - assert(@memberType(Foo, 2) == void); - - assert(mem.eql(u8, @memberName(Foo, 0), "one")); - assert(mem.eql(u8, @memberName(Foo, 1), "two")); - assert(mem.eql(u8, @memberName(Foo, 2), "three")); - } -} - -test "reflection: enum member types and names" { - comptime { - assert(@memberCount(Bar) == 4); - - assert(@memberType(Bar, 0) == void); - assert(@memberType(Bar, 1) == i32); - assert(@memberType(Bar, 2) == bool); - assert(@memberType(Bar, 3) == f64); - - assert(mem.eql(u8, @memberName(Bar, 0), "One")); - assert(mem.eql(u8, @memberName(Bar, 1), "Two")); - assert(mem.eql(u8, @memberName(Bar, 2), "Three")); - assert(mem.eql(u8, @memberName(Bar, 3), "Four")); - } -} - -test "reflection: @field" { - var f = Foo{ - .one = 42, - .two = true, - .three = void{}, - }; - - assert(f.one == f.one); - assert(@field(f, "o" ++ "ne") == f.one); - assert(@field(f, "t" ++ "wo") == f.two); - assert(@field(f, "th" ++ "ree") == f.three); - assert(@field(Foo, "const" ++ "ant") == Foo.constant); - assert(@field(Bar, "O" ++ "ne") == Bar.One); - assert(@field(Bar, "T" ++ "wo") == Bar.Two); - assert(@field(Bar, "Th" ++ "ree") == Bar.Three); - assert(@field(Bar, "F" ++ "our") == Bar.Four); - assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); - @field(f, "o" ++ "ne") = 4; - assert(f.one == 4); -} - -const Foo = struct { - const constant = 52; - - one: i32, - two: bool, - three: void, -}; - -const Bar = union(enum) { - One: void, - Two: i32, - Three: bool, - Four: f64, -}; diff --git a/test/cases/sizeof_and_typeof.zig b/test/cases/sizeof_and_typeof.zig deleted file mode 100644 index 11c6b2f6ba..0000000000 --- a/test/cases/sizeof_and_typeof.zig +++ /dev/null @@ -1,69 +0,0 @@ -const builtin = @import("builtin"); -const assert = @import("std").debug.assert; - -test "@sizeOf and @typeOf" { - const y: @typeOf(x) = 120; - assert(@sizeOf(@typeOf(y)) == 2); -} -const x: u16 = 13; -const z: @typeOf(x) = 19; - -const A = struct { - a: u8, - b: u32, - c: u8, - d: u3, - e: u5, - f: u16, - g: u16, -}; - -const P = packed struct { - a: u8, - b: u32, - c: u8, - d: u3, - e: u5, - f: u16, - g: u16, -}; - -test "@byteOffsetOf" { - // Packed structs have fixed memory layout - assert(@byteOffsetOf(P, "a") == 0); - assert(@byteOffsetOf(P, "b") == 1); - assert(@byteOffsetOf(P, "c") == 5); - assert(@byteOffsetOf(P, "d") == 6); - assert(@byteOffsetOf(P, "e") == 6); - assert(@byteOffsetOf(P, "f") == 7); - assert(@byteOffsetOf(P, "g") == 9); - - // Normal struct fields can be moved/padded - var a: A = undefined; - assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); - assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); - assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); - assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); - assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); - assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); - assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); -} - -test "@bitOffsetOf" { - // Packed structs have fixed memory layout - assert(@bitOffsetOf(P, "a") == 0); - assert(@bitOffsetOf(P, "b") == 8); - assert(@bitOffsetOf(P, "c") == 40); - assert(@bitOffsetOf(P, "d") == 48); - assert(@bitOffsetOf(P, "e") == 51); - assert(@bitOffsetOf(P, "f") == 56); - assert(@bitOffsetOf(P, "g") == 72); - - assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); - assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); - assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); - assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); - assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); - assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); - assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); -} diff --git a/test/cases/slice.zig b/test/cases/slice.zig deleted file mode 100644 index b4b43bdd19..0000000000 --- a/test/cases/slice.zig +++ /dev/null @@ -1,40 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -const x = @intToPtr([*]i32, 0x1000)[0..0x500]; -const y = x[0x100..]; -test "compile time slice of pointer to hard coded address" { - assert(@ptrToInt(x.ptr) == 0x1000); - assert(x.len == 0x500); - - assert(@ptrToInt(y.ptr) == 0x1100); - assert(y.len == 0x400); -} - -test "slice child property" { - var array: [5]i32 = undefined; - var slice = array[0..]; - assert(@typeOf(slice).Child == i32); -} - -test "runtime safety lets us slice from len..len" { - var an_array = []u8{ - 1, - 2, - 3, - }; - assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); -} - -fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { - return a_slice[start..end]; -} - -test "implicitly cast array of size 0 to slice" { - var msg = []u8{}; - assertLenIsZero(msg); -} - -fn assertLenIsZero(msg: []const u8) void { - assert(msg.len == 0); -} diff --git a/test/cases/struct.zig b/test/cases/struct.zig deleted file mode 100644 index bbbd21912c..0000000000 --- a/test/cases/struct.zig +++ /dev/null @@ -1,470 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const builtin = @import("builtin"); -const maxInt = std.math.maxInt; - -const StructWithNoFields = struct { - fn add(a: i32, b: i32) i32 { - return a + b; - } -}; -const empty_global_instance = StructWithNoFields{}; - -test "call struct static method" { - const result = StructWithNoFields.add(3, 4); - assert(result == 7); -} - -test "return empty struct instance" { - _ = returnEmptyStructInstance(); -} -fn returnEmptyStructInstance() StructWithNoFields { - return empty_global_instance; -} - -const should_be_11 = StructWithNoFields.add(5, 6); - -test "invake static method in global scope" { - assert(should_be_11 == 11); -} - -test "void struct fields" { - const foo = VoidStructFieldsFoo{ - .a = void{}, - .b = 1, - .c = void{}, - }; - assert(foo.b == 1); - assert(@sizeOf(VoidStructFieldsFoo) == 4); -} -const VoidStructFieldsFoo = struct { - a: void, - b: i32, - c: void, -}; - -test "structs" { - var foo: StructFoo = undefined; - @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); - foo.a += 1; - foo.b = foo.a == 1; - testFoo(foo); - testMutation(&foo); - assert(foo.c == 100); -} -const StructFoo = struct { - a: i32, - b: bool, - c: f32, -}; -fn testFoo(foo: StructFoo) void { - assert(foo.b); -} -fn testMutation(foo: *StructFoo) void { - foo.c = 100; -} - -const Node = struct { - val: Val, - next: *Node, -}; - -const Val = struct { - x: i32, -}; - -test "struct point to self" { - var root: Node = undefined; - root.val.x = 1; - - var node: Node = undefined; - node.next = &root; - node.val.x = 2; - - root.next = &node; - - assert(node.next.next.next.val.x == 1); -} - -test "struct byval assign" { - var foo1: StructFoo = undefined; - var foo2: StructFoo = undefined; - - foo1.a = 1234; - foo2.a = 0; - assert(foo2.a == 0); - foo2 = foo1; - assert(foo2.a == 1234); -} - -fn structInitializer() void { - const val = Val{ .x = 42 }; - assert(val.x == 42); -} - -test "fn call of struct field" { - assert(callStructField(Foo{ .ptr = aFunc }) == 13); -} - -const Foo = struct { - ptr: fn () i32, -}; - -fn aFunc() i32 { - return 13; -} - -fn callStructField(foo: Foo) i32 { - return foo.ptr(); -} - -test "store member function in variable" { - const instance = MemberFnTestFoo{ .x = 1234 }; - const memberFn = MemberFnTestFoo.member; - const result = memberFn(instance); - assert(result == 1234); -} -const MemberFnTestFoo = struct { - x: i32, - fn member(foo: MemberFnTestFoo) i32 { - return foo.x; - } -}; - -test "call member function directly" { - const instance = MemberFnTestFoo{ .x = 1234 }; - const result = MemberFnTestFoo.member(instance); - assert(result == 1234); -} - -test "member functions" { - const r = MemberFnRand{ .seed = 1234 }; - assert(r.getSeed() == 1234); -} -const MemberFnRand = struct { - seed: u32, - pub fn getSeed(r: *const MemberFnRand) u32 { - return r.seed; - } -}; - -test "return struct byval from function" { - const bar = makeBar(1234, 5678); - assert(bar.y == 5678); -} -const Bar = struct { - x: i32, - y: i32, -}; -fn makeBar(x: i32, y: i32) Bar { - return Bar{ - .x = x, - .y = y, - }; -} - -test "empty struct method call" { - const es = EmptyStruct{}; - assert(es.method() == 1234); -} -const EmptyStruct = struct { - fn method(es: *const EmptyStruct) i32 { - return 1234; - } -}; - -test "return empty struct from fn" { - _ = testReturnEmptyStructFromFn(); -} -const EmptyStruct2 = struct {}; -fn testReturnEmptyStructFromFn() EmptyStruct2 { - return EmptyStruct2{}; -} - -test "pass slice of empty struct to fn" { - assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); -} -fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { - return slice.len; -} - -const APackedStruct = packed struct { - x: u8, - y: u8, -}; - -test "packed struct" { - var foo = APackedStruct{ - .x = 1, - .y = 2, - }; - foo.y += 1; - const four = foo.x + foo.y; - assert(four == 4); -} - -const BitField1 = packed struct { - a: u3, - b: u3, - c: u2, -}; - -const bit_field_1 = BitField1{ - .a = 1, - .b = 2, - .c = 3, -}; - -test "bit field access" { - var data = bit_field_1; - assert(getA(&data) == 1); - assert(getB(&data) == 2); - assert(getC(&data) == 3); - comptime assert(@sizeOf(BitField1) == 1); - - data.b += 1; - assert(data.b == 3); - - data.a += 1; - assert(data.a == 2); - assert(data.b == 3); -} - -fn getA(data: *const BitField1) u3 { - return data.a; -} - -fn getB(data: *const BitField1) u3 { - return data.b; -} - -fn getC(data: *const BitField1) u2 { - return data.c; -} - -const Foo24Bits = packed struct { - field: u24, -}; -const Foo96Bits = packed struct { - a: u24, - b: u24, - c: u24, - d: u24, -}; - -test "packed struct 24bits" { - comptime { - assert(@sizeOf(Foo24Bits) == 3); - assert(@sizeOf(Foo96Bits) == 12); - } - - var value = Foo96Bits{ - .a = 0, - .b = 0, - .c = 0, - .d = 0, - }; - value.a += 1; - assert(value.a == 1); - assert(value.b == 0); - assert(value.c == 0); - assert(value.d == 0); - - value.b += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 0); - assert(value.d == 0); - - value.c += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 1); - assert(value.d == 0); - - value.d += 1; - assert(value.a == 1); - assert(value.b == 1); - assert(value.c == 1); - assert(value.d == 1); -} - -const FooArray24Bits = packed struct { - a: u16, - b: [2]Foo24Bits, - c: u16, -}; - -test "packed array 24bits" { - comptime { - assert(@sizeOf([9]Foo24Bits) == 9 * 3); - assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); - } - - var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); - bytes[bytes.len - 1] = 0xaa; - const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; - assert(ptr.a == 0); - assert(ptr.b[0].field == 0); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); - - ptr.a = maxInt(u16); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == 0); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); - - ptr.b[0].field = maxInt(u24); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == 0); - assert(ptr.c == 0); - - ptr.b[1].field = maxInt(u24); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == maxInt(u24)); - assert(ptr.c == 0); - - ptr.c = maxInt(u16); - assert(ptr.a == maxInt(u16)); - assert(ptr.b[0].field == maxInt(u24)); - assert(ptr.b[1].field == maxInt(u24)); - assert(ptr.c == maxInt(u16)); - - assert(bytes[bytes.len - 1] == 0xaa); -} - -const FooStructAligned = packed struct { - a: u8, - b: u8, -}; - -const FooArrayOfAligned = packed struct { - a: [2]FooStructAligned, -}; - -test "aligned array of packed struct" { - comptime { - assert(@sizeOf(FooStructAligned) == 2); - assert(@sizeOf(FooArrayOfAligned) == 2 * 2); - } - - var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); - const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; - - assert(ptr.a[0].a == 0xbb); - assert(ptr.a[0].b == 0xbb); - assert(ptr.a[1].a == 0xbb); - assert(ptr.a[1].b == 0xbb); -} - -test "runtime struct initialization of bitfield" { - const s1 = Nibbles{ - .x = x1, - .y = x1, - }; - const s2 = Nibbles{ - .x = @intCast(u4, x2), - .y = @intCast(u4, x2), - }; - - assert(s1.x == x1); - assert(s1.y == x1); - assert(s2.x == @intCast(u4, x2)); - assert(s2.y == @intCast(u4, x2)); -} - -var x1 = u4(1); -var x2 = u8(2); - -const Nibbles = packed struct { - x: u4, - y: u4, -}; - -const Bitfields = packed struct { - f1: u16, - f2: u16, - f3: u8, - f4: u8, - f5: u4, - f6: u4, - f7: u8, -}; - -test "native bit field understands endianness" { - var all: u64 = 0x7765443322221111; - var bytes: [8]u8 = undefined; - @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); - var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; - - assert(bitfields.f1 == 0x1111); - assert(bitfields.f2 == 0x2222); - assert(bitfields.f3 == 0x33); - assert(bitfields.f4 == 0x44); - assert(bitfields.f5 == 0x5); - assert(bitfields.f6 == 0x6); - assert(bitfields.f7 == 0x77); -} - -test "align 1 field before self referential align 8 field as slice return type" { - const result = alloc(Expr); - assert(result.len == 0); -} - -const Expr = union(enum) { - Literal: u8, - Question: *Expr, -}; - -fn alloc(comptime T: type) []T { - return []T{}; -} - -test "call method with mutable reference to struct with no fields" { - const S = struct { - fn doC(s: *const @This()) bool { - return true; - } - fn do(s: *@This()) bool { - return true; - } - }; - - var s = S{}; - assert(S.doC(&s)); - assert(s.doC()); - assert(S.do(&s)); - assert(s.do()); -} - -test "implicit cast packed struct field to const ptr" { - const LevelUpMove = packed struct { - move_id: u9, - level: u7, - - fn toInt(value: u7) u7 { - return value; - } - }; - - var lup: LevelUpMove = undefined; - lup.level = 12; - const res = LevelUpMove.toInt(lup.level); - assert(res == 12); -} - -test "pointer to packed struct member in a stack variable" { - const S = packed struct { - a: u2, - b: u2, - }; - - var s = S{ .a = 2, .b = 0 }; - var b_ptr = &s.b; - assert(s.b == 0); - b_ptr.* = 2; - assert(s.b == 2); -} diff --git a/test/cases/struct_contains_null_ptr_itself.zig b/test/cases/struct_contains_null_ptr_itself.zig deleted file mode 100644 index 21175974b3..0000000000 --- a/test/cases/struct_contains_null_ptr_itself.zig +++ /dev/null @@ -1,21 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "struct contains null pointer which contains original struct" { - var x: ?*NodeLineComment = null; - assert(x == null); -} - -pub const Node = struct { - id: Id, - comment: ?*NodeLineComment, - - pub const Id = enum { - Root, - LineComment, - }; -}; - -pub const NodeLineComment = struct { - base: Node, -}; diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases/struct_contains_slice_of_itself.zig deleted file mode 100644 index aa3075312c..0000000000 --- a/test/cases/struct_contains_slice_of_itself.zig +++ /dev/null @@ -1,85 +0,0 @@ -const assert = @import("std").debug.assert; - -const Node = struct { - payload: i32, - children: []Node, -}; - -const NodeAligned = struct { - payload: i32, - children: []align(@alignOf(NodeAligned)) NodeAligned, -}; - -test "struct contains slice of itself" { - var other_nodes = []Node{ - Node{ - .payload = 31, - .children = []Node{}, - }, - Node{ - .payload = 32, - .children = []Node{}, - }, - }; - var nodes = []Node{ - Node{ - .payload = 1, - .children = []Node{}, - }, - Node{ - .payload = 2, - .children = []Node{}, - }, - Node{ - .payload = 3, - .children = other_nodes[0..], - }, - }; - const root = Node{ - .payload = 1234, - .children = nodes[0..], - }; - assert(root.payload == 1234); - assert(root.children[0].payload == 1); - assert(root.children[1].payload == 2); - assert(root.children[2].payload == 3); - assert(root.children[2].children[0].payload == 31); - assert(root.children[2].children[1].payload == 32); -} - -test "struct contains aligned slice of itself" { - var other_nodes = []NodeAligned{ - NodeAligned{ - .payload = 31, - .children = []NodeAligned{}, - }, - NodeAligned{ - .payload = 32, - .children = []NodeAligned{}, - }, - }; - var nodes = []NodeAligned{ - NodeAligned{ - .payload = 1, - .children = []NodeAligned{}, - }, - NodeAligned{ - .payload = 2, - .children = []NodeAligned{}, - }, - NodeAligned{ - .payload = 3, - .children = other_nodes[0..], - }, - }; - const root = NodeAligned{ - .payload = 1234, - .children = nodes[0..], - }; - assert(root.payload == 1234); - assert(root.children[0].payload == 1); - assert(root.children[1].payload == 2); - assert(root.children[2].payload == 3); - assert(root.children[2].children[0].payload == 31); - assert(root.children[2].children[1].payload == 32); -} diff --git a/test/cases/switch.zig b/test/cases/switch.zig deleted file mode 100644 index 1162fdd4b2..0000000000 --- a/test/cases/switch.zig +++ /dev/null @@ -1,271 +0,0 @@ -const assert = @import("std").debug.assert; - -test "switch with numbers" { - testSwitchWithNumbers(13); -} - -fn testSwitchWithNumbers(x: u32) void { - const result = switch (x) { - 1, 2, 3, 4...8 => false, - 13 => true, - else => false, - }; - assert(result); -} - -test "switch with all ranges" { - assert(testSwitchWithAllRanges(50, 3) == 1); - assert(testSwitchWithAllRanges(101, 0) == 2); - assert(testSwitchWithAllRanges(300, 5) == 3); - assert(testSwitchWithAllRanges(301, 6) == 6); -} - -fn testSwitchWithAllRanges(x: u32, y: u32) u32 { - return switch (x) { - 0...100 => 1, - 101...200 => 2, - 201...300 => 3, - else => y, - }; -} - -test "implicit comptime switch" { - const x = 3 + 4; - const result = switch (x) { - 3 => 10, - 4 => 11, - 5, 6 => 12, - 7, 8 => 13, - else => 14, - }; - - comptime { - assert(result + 1 == 14); - } -} - -test "switch on enum" { - const fruit = Fruit.Orange; - nonConstSwitchOnEnum(fruit); -} -const Fruit = enum { - Apple, - Orange, - Banana, -}; -fn nonConstSwitchOnEnum(fruit: Fruit) void { - switch (fruit) { - Fruit.Apple => unreachable, - Fruit.Orange => {}, - Fruit.Banana => unreachable, - } -} - -test "switch statement" { - nonConstSwitch(SwitchStatmentFoo.C); -} -fn nonConstSwitch(foo: SwitchStatmentFoo) void { - const val = switch (foo) { - SwitchStatmentFoo.A => i32(1), - SwitchStatmentFoo.B => 2, - SwitchStatmentFoo.C => 3, - SwitchStatmentFoo.D => 4, - }; - assert(val == 3); -} -const SwitchStatmentFoo = enum { - A, - B, - C, - D, -}; - -test "switch prong with variable" { - switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); - switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); - switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); -} -const SwitchProngWithVarEnum = union(enum) { - One: i32, - Two: f32, - Meh: void, -}; -fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { - switch (a) { - SwitchProngWithVarEnum.One => |x| { - assert(x == 13); - }, - SwitchProngWithVarEnum.Two => |x| { - assert(x == 13.0); - }, - SwitchProngWithVarEnum.Meh => |x| { - const v: void = x; - }, - } -} - -test "switch on enum using pointer capture" { - testSwitchEnumPtrCapture(); - comptime testSwitchEnumPtrCapture(); -} - -fn testSwitchEnumPtrCapture() void { - var value = SwitchProngWithVarEnum{ .One = 1234 }; - switch (value) { - SwitchProngWithVarEnum.One => |*x| x.* += 1, - else => unreachable, - } - switch (value) { - SwitchProngWithVarEnum.One => |x| assert(x == 1235), - else => unreachable, - } -} - -test "switch with multiple expressions" { - const x = switch (returnsFive()) { - 1, 2, 3 => 1, - 4, 5, 6 => 2, - else => i32(3), - }; - assert(x == 2); -} -fn returnsFive() i32 { - return 5; -} - -const Number = union(enum) { - One: u64, - Two: u8, - Three: f32, -}; - -const number = Number{ .Three = 1.23 }; - -fn returnsFalse() bool { - switch (number) { - Number.One => |x| return x > 1234, - Number.Two => |x| return x == 'a', - Number.Three => |x| return x > 12.34, - } -} -test "switch on const enum with var" { - assert(!returnsFalse()); -} - -test "switch on type" { - assert(trueIfBoolFalseOtherwise(bool)); - assert(!trueIfBoolFalseOtherwise(i32)); -} - -fn trueIfBoolFalseOtherwise(comptime T: type) bool { - return switch (T) { - bool => true, - else => false, - }; -} - -test "switch handles all cases of number" { - testSwitchHandleAllCases(); - comptime testSwitchHandleAllCases(); -} - -fn testSwitchHandleAllCases() void { - assert(testSwitchHandleAllCasesExhaustive(0) == 3); - assert(testSwitchHandleAllCasesExhaustive(1) == 2); - assert(testSwitchHandleAllCasesExhaustive(2) == 1); - assert(testSwitchHandleAllCasesExhaustive(3) == 0); - - assert(testSwitchHandleAllCasesRange(100) == 0); - assert(testSwitchHandleAllCasesRange(200) == 1); - assert(testSwitchHandleAllCasesRange(201) == 2); - assert(testSwitchHandleAllCasesRange(202) == 4); - assert(testSwitchHandleAllCasesRange(230) == 3); -} - -fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { - return switch (x) { - 0 => u2(3), - 1 => 2, - 2 => 1, - 3 => 0, - }; -} - -fn testSwitchHandleAllCasesRange(x: u8) u8 { - return switch (x) { - 0...100 => u8(0), - 101...200 => 1, - 201, 203 => 2, - 202 => 4, - 204...255 => 3, - }; -} - -test "switch all prongs unreachable" { - testAllProngsUnreachable(); - comptime testAllProngsUnreachable(); -} - -fn testAllProngsUnreachable() void { - assert(switchWithUnreachable(1) == 2); - assert(switchWithUnreachable(2) == 10); -} - -fn switchWithUnreachable(x: i32) i32 { - while (true) { - switch (x) { - 1 => return 2, - 2 => break, - else => continue, - } - } - return 10; -} - -fn return_a_number() anyerror!i32 { - return 1; -} - -test "capture value of switch with all unreachable prongs" { - const x = return_a_number() catch |err| switch (err) { - else => unreachable, - }; - assert(x == 1); -} - -test "switching on booleans" { - testSwitchOnBools(); - comptime testSwitchOnBools(); -} - -fn testSwitchOnBools() void { - assert(testSwitchOnBoolsTrueAndFalse(true) == false); - assert(testSwitchOnBoolsTrueAndFalse(false) == true); - - assert(testSwitchOnBoolsTrueWithElse(true) == false); - assert(testSwitchOnBoolsTrueWithElse(false) == true); - - assert(testSwitchOnBoolsFalseWithElse(true) == false); - assert(testSwitchOnBoolsFalseWithElse(false) == true); -} - -fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { - return switch (x) { - true => false, - false => true, - }; -} - -fn testSwitchOnBoolsTrueWithElse(x: bool) bool { - return switch (x) { - true => false, - else => true, - }; -} - -fn testSwitchOnBoolsFalseWithElse(x: bool) bool { - return switch (x) { - false => true, - else => false, - }; -} diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig deleted file mode 100644 index 89060690fc..0000000000 --- a/test/cases/switch_prong_err_enum.zig +++ /dev/null @@ -1,30 +0,0 @@ -const assert = @import("std").debug.assert; - -var read_count: u64 = 0; - -fn readOnce() anyerror!u64 { - read_count += 1; - return read_count; -} - -const FormValue = union(enum) { - Address: u64, - Other: bool, -}; - -fn doThing(form_id: u64) anyerror!FormValue { - return switch (form_id) { - 17 => FormValue{ .Address = try readOnce() }, - else => error.InvalidDebugInfo, - }; -} - -test "switch prong returns error enum" { - switch (doThing(17) catch unreachable) { - FormValue.Address => |payload| { - assert(payload == 1); - }, - else => unreachable, - } - assert(read_count == 1); -} diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/cases/switch_prong_implicit_cast.zig deleted file mode 100644 index 56d37e290f..0000000000 --- a/test/cases/switch_prong_implicit_cast.zig +++ /dev/null @@ -1,22 +0,0 @@ -const assert = @import("std").debug.assert; - -const FormValue = union(enum) { - One: void, - Two: bool, -}; - -fn foo(id: u64) !FormValue { - return switch (id) { - 2 => FormValue{ .Two = true }, - 1 => FormValue{ .One = {} }, - else => return error.Whatever, - }; -} - -test "switch prong implicit cast" { - const result = switch (foo(2) catch unreachable) { - FormValue.One => false, - FormValue.Two => |x| x, - }; - assert(result); -} diff --git a/test/cases/syntax.zig b/test/cases/syntax.zig deleted file mode 100644 index 0c8c3c5ed3..0000000000 --- a/test/cases/syntax.zig +++ /dev/null @@ -1,59 +0,0 @@ -// Test trailing comma syntax -// zig fmt: off - -const struct_trailing_comma = struct { x: i32, y: i32, }; -const struct_no_comma = struct { x: i32, y: i32 }; -const struct_fn_no_comma = struct { fn m() void {} y: i32 }; - -const enum_no_comma = enum { A, B }; - -fn container_init() void { - const S = struct { x: i32, y: i32 }; - _ = S { .x = 1, .y = 2 }; - _ = S { .x = 1, .y = 2, }; -} - -fn type_expr_return1() if (true) A {} -fn type_expr_return2() for (true) |_| A {} -fn type_expr_return3() while (true) A {} -fn type_expr_return4() comptime A {} - -fn switch_cases(x: i32) void { - switch (x) { - 1,2,3 => {}, - 4,5, => {}, - 6...8, => {}, - else => {}, - } -} - -fn switch_prongs(x: i32) void { - switch (x) { - 0 => {}, - else => {}, - } - switch (x) { - 0 => {}, - else => {} - } -} - -const fn_no_comma = fn(i32, i32)void; -const fn_trailing_comma = fn(i32, i32,)void; - -fn fn_calls() void { - fn add(x: i32, y: i32,) i32 { x + y }; - _ = add(1, 2); - _ = add(1, 2,); -} - -fn asm_lists() void { - if (false) { // Build AST but don't analyze - asm ("not real assembly" - :[a] "x" (x),); - asm ("not real assembly" - :[a] "x" (->i32),:[a] "x" (1),); - asm ("still not real assembly" - :::"a","b",); - } -} diff --git a/test/cases/this.zig b/test/cases/this.zig deleted file mode 100644 index c7be074f36..0000000000 --- a/test/cases/this.zig +++ /dev/null @@ -1,34 +0,0 @@ -const assert = @import("std").debug.assert; - -const module = @This(); - -fn Point(comptime T: type) type { - return struct { - const Self = @This(); - x: T, - y: T, - - fn addOne(self: *Self) void { - self.x += 1; - self.y += 1; - } - }; -} - -fn add(x: i32, y: i32) i32 { - return x + y; -} - -test "this refer to module call private fn" { - assert(module.add(1, 2) == 3); -} - -test "this refer to container" { - var pt = Point(i32){ - .x = 12, - .y = 34, - }; - pt.addOne(); - assert(pt.x == 13); - assert(pt.y == 35); -} diff --git a/test/cases/truncate.zig b/test/cases/truncate.zig deleted file mode 100644 index 02b5085ccd..0000000000 --- a/test/cases/truncate.zig +++ /dev/null @@ -1,8 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "truncate u0 to larger integer allowed and has comptime known result" { - var x: u0 = 0; - const y = @truncate(u8, x); - comptime assert(y == 0); -} diff --git a/test/cases/try.zig b/test/cases/try.zig deleted file mode 100644 index 450a9af6ac..0000000000 --- a/test/cases/try.zig +++ /dev/null @@ -1,43 +0,0 @@ -const assert = @import("std").debug.assert; - -test "try on error union" { - tryOnErrorUnionImpl(); - comptime tryOnErrorUnionImpl(); -} - -fn tryOnErrorUnionImpl() void { - const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { - error.ItBroke, error.NoMem => 1, - error.CrappedOut => i32(2), - else => unreachable, - }; - assert(x == 11); -} - -fn returnsTen() anyerror!i32 { - return 10; -} - -test "try without vars" { - const result1 = if (failIfTrue(true)) 1 else |_| i32(2); - assert(result1 == 2); - - const result2 = if (failIfTrue(false)) 1 else |_| i32(2); - assert(result2 == 1); -} - -fn failIfTrue(ok: bool) anyerror!void { - if (ok) { - return error.ItBroke; - } else { - return; - } -} - -test "try then not executed with assignment" { - if (failIfTrue(true)) { - unreachable; - } else |err| { - assert(err == error.ItBroke); - } -} diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig deleted file mode 100644 index cec532d5d3..0000000000 --- a/test/cases/type_info.zig +++ /dev/null @@ -1,264 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const TypeInfo = @import("builtin").TypeInfo; -const TypeId = @import("builtin").TypeId; - -test "type info: tag type, void info" { - testBasic(); - comptime testBasic(); -} - -fn testBasic() void { - assert(@TagType(TypeInfo) == TypeId); - const void_info = @typeInfo(void); - assert(TypeId(void_info) == TypeId.Void); - assert(void_info.Void == {}); -} - -test "type info: integer, floating point type info" { - testIntFloat(); - comptime testIntFloat(); -} - -fn testIntFloat() void { - const u8_info = @typeInfo(u8); - assert(TypeId(u8_info) == TypeId.Int); - assert(!u8_info.Int.is_signed); - assert(u8_info.Int.bits == 8); - - const f64_info = @typeInfo(f64); - assert(TypeId(f64_info) == TypeId.Float); - assert(f64_info.Float.bits == 64); -} - -test "type info: pointer type info" { - testPointer(); - comptime testPointer(); -} - -fn testPointer() void { - const u32_ptr_info = @typeInfo(*u32); - assert(TypeId(u32_ptr_info) == TypeId.Pointer); - assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); - assert(u32_ptr_info.Pointer.is_const == false); - assert(u32_ptr_info.Pointer.is_volatile == false); - assert(u32_ptr_info.Pointer.alignment == @alignOf(u32)); - assert(u32_ptr_info.Pointer.child == u32); -} - -test "type info: unknown length pointer type info" { - testUnknownLenPtr(); - comptime testUnknownLenPtr(); -} - -fn testUnknownLenPtr() void { - const u32_ptr_info = @typeInfo([*]const volatile f64); - assert(TypeId(u32_ptr_info) == TypeId.Pointer); - assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); - assert(u32_ptr_info.Pointer.is_const == true); - assert(u32_ptr_info.Pointer.is_volatile == true); - assert(u32_ptr_info.Pointer.alignment == @alignOf(f64)); - assert(u32_ptr_info.Pointer.child == f64); -} - -test "type info: slice type info" { - testSlice(); - comptime testSlice(); -} - -fn testSlice() void { - const u32_slice_info = @typeInfo([]u32); - assert(TypeId(u32_slice_info) == TypeId.Pointer); - assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); - assert(u32_slice_info.Pointer.is_const == false); - assert(u32_slice_info.Pointer.is_volatile == false); - assert(u32_slice_info.Pointer.alignment == 4); - assert(u32_slice_info.Pointer.child == u32); -} - -test "type info: array type info" { - testArray(); - comptime testArray(); -} - -fn testArray() void { - const arr_info = @typeInfo([42]bool); - assert(TypeId(arr_info) == TypeId.Array); - assert(arr_info.Array.len == 42); - assert(arr_info.Array.child == bool); -} - -test "type info: optional type info" { - testOptional(); - comptime testOptional(); -} - -fn testOptional() void { - const null_info = @typeInfo(?void); - assert(TypeId(null_info) == TypeId.Optional); - assert(null_info.Optional.child == void); -} - -test "type info: promise info" { - testPromise(); - comptime testPromise(); -} - -fn testPromise() void { - const null_promise_info = @typeInfo(promise); - assert(TypeId(null_promise_info) == TypeId.Promise); - assert(null_promise_info.Promise.child == null); - - const promise_info = @typeInfo(promise->usize); - assert(TypeId(promise_info) == TypeId.Promise); - assert(promise_info.Promise.child.? == usize); -} - -test "type info: error set, error union info" { - testErrorSet(); - comptime testErrorSet(); -} - -fn testErrorSet() void { - const TestErrorSet = error{ - First, - Second, - Third, - }; - - const error_set_info = @typeInfo(TestErrorSet); - assert(TypeId(error_set_info) == TypeId.ErrorSet); - assert(error_set_info.ErrorSet.errors.len == 3); - assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); - assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); - - const error_union_info = @typeInfo(TestErrorSet!usize); - assert(TypeId(error_union_info) == TypeId.ErrorUnion); - assert(error_union_info.ErrorUnion.error_set == TestErrorSet); - assert(error_union_info.ErrorUnion.payload == usize); -} - -test "type info: enum info" { - testEnum(); - comptime testEnum(); -} - -fn testEnum() void { - const Os = enum { - Windows, - Macos, - Linux, - FreeBSD, - }; - - const os_info = @typeInfo(Os); - assert(TypeId(os_info) == TypeId.Enum); - assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assert(os_info.Enum.fields.len == 4); - assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); - assert(os_info.Enum.fields[3].value == 3); - assert(os_info.Enum.tag_type == u2); - assert(os_info.Enum.defs.len == 0); -} - -test "type info: union info" { - testUnion(); - comptime testUnion(); -} - -fn testUnion() void { - const typeinfo_info = @typeInfo(TypeInfo); - assert(TypeId(typeinfo_info) == TypeId.Union); - assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(typeinfo_info.Union.tag_type.? == TypeId); - assert(typeinfo_info.Union.fields.len == 24); - assert(typeinfo_info.Union.fields[4].enum_field != null); - assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4); - assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assert(typeinfo_info.Union.defs.len == 20); - - const TestNoTagUnion = union { - Foo: void, - Bar: u32, - }; - - const notag_union_info = @typeInfo(TestNoTagUnion); - assert(TypeId(notag_union_info) == TypeId.Union); - assert(notag_union_info.Union.tag_type == null); - assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assert(notag_union_info.Union.fields.len == 2); - assert(notag_union_info.Union.fields[0].enum_field == null); - assert(notag_union_info.Union.fields[1].field_type == u32); - - const TestExternUnion = extern union { - foo: *c_void, - }; - - const extern_union_info = @typeInfo(TestExternUnion); - assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); - assert(extern_union_info.Union.tag_type == null); - assert(extern_union_info.Union.fields[0].enum_field == null); - assert(extern_union_info.Union.fields[0].field_type == *c_void); -} - -test "type info: struct info" { - testStruct(); - comptime testStruct(); -} - -fn testStruct() void { - const struct_info = @typeInfo(TestStruct); - assert(TypeId(struct_info) == TypeId.Struct); - assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); - assert(struct_info.Struct.fields.len == 3); - assert(struct_info.Struct.fields[1].offset == null); - assert(struct_info.Struct.fields[2].field_type == *TestStruct); - assert(struct_info.Struct.defs.len == 2); - assert(struct_info.Struct.defs[0].is_pub); - assert(!struct_info.Struct.defs[0].data.Fn.is_extern); - assert(struct_info.Struct.defs[0].data.Fn.lib_name == null); - assert(struct_info.Struct.defs[0].data.Fn.return_type == void); - assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); -} - -const TestStruct = packed struct { - const Self = @This(); - - fieldA: usize, - fieldB: void, - fieldC: *Self, - - pub fn foo(self: *const Self) void {} -}; - -test "type info: function type info" { - testFunction(); - comptime testFunction(); -} - -fn testFunction() void { - const fn_info = @typeInfo(@typeOf(foo)); - assert(TypeId(fn_info) == TypeId.Fn); - assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); - assert(fn_info.Fn.is_generic); - assert(fn_info.Fn.args.len == 2); - assert(fn_info.Fn.is_var_args); - assert(fn_info.Fn.return_type == null); - assert(fn_info.Fn.async_allocator_type == null); - - const test_instance: TestStruct = undefined; - const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); - assert(TypeId(bound_fn_info) == TypeId.BoundFn); - assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); -} - -fn foo(comptime a: usize, b: bool, args: ...) usize { - return 0; -} - -test "typeInfo with comptime parameter in struct fn def" { - const S = struct { - pub fn func(comptime x: f32) void {} - }; - comptime var info = @typeInfo(S); -} diff --git a/test/cases/undefined.zig b/test/cases/undefined.zig deleted file mode 100644 index 83c620d211..0000000000 --- a/test/cases/undefined.zig +++ /dev/null @@ -1,68 +0,0 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; - -fn initStaticArray() [10]i32 { - var array: [10]i32 = undefined; - array[0] = 1; - array[4] = 2; - array[7] = 3; - array[9] = 4; - return array; -} -const static_array = initStaticArray(); -test "init static array to undefined" { - assert(static_array[0] == 1); - assert(static_array[4] == 2); - assert(static_array[7] == 3); - assert(static_array[9] == 4); - - comptime { - assert(static_array[0] == 1); - assert(static_array[4] == 2); - assert(static_array[7] == 3); - assert(static_array[9] == 4); - } -} - -const Foo = struct { - x: i32, - - fn setFooXMethod(foo: *Foo) void { - foo.x = 3; - } -}; - -fn setFooX(foo: *Foo) void { - foo.x = 2; -} - -test "assign undefined to struct" { - comptime { - var foo: Foo = undefined; - setFooX(&foo); - assert(foo.x == 2); - } - { - var foo: Foo = undefined; - setFooX(&foo); - assert(foo.x == 2); - } -} - -test "assign undefined to struct with method" { - comptime { - var foo: Foo = undefined; - foo.setFooXMethod(); - assert(foo.x == 3); - } - { - var foo: Foo = undefined; - foo.setFooXMethod(); - assert(foo.x == 3); - } -} - -test "type name of undefined" { - const x = undefined; - assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); -} diff --git a/test/cases/underscore.zig b/test/cases/underscore.zig deleted file mode 100644 index da1c97659c..0000000000 --- a/test/cases/underscore.zig +++ /dev/null @@ -1,28 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; - -test "ignore lval with underscore" { - _ = false; -} - -test "ignore lval with underscore (for loop)" { - for ([]void{}) |_, i| { - for ([]void{}) |_, j| { - break; - } - break; - } -} - -test "ignore lval with underscore (while loop)" { - while (optionalReturnError()) |_| { - while (optionalReturnError()) |_| { - break; - } else |_| {} - break; - } else |_| {} -} - -fn optionalReturnError() !?u32 { - return error.optionalReturnError; -} diff --git a/test/cases/union.zig b/test/cases/union.zig deleted file mode 100644 index 019a7012da..0000000000 --- a/test/cases/union.zig +++ /dev/null @@ -1,352 +0,0 @@ -const assert = @import("std").debug.assert; - -const Value = union(enum) { - Int: u64, - Array: [9]u8, -}; - -const Agg = struct { - val1: Value, - val2: Value, -}; - -const v1 = Value{ .Int = 1234 }; -const v2 = Value{ .Array = []u8{3} ** 9 }; - -const err = (anyerror!Agg)(Agg{ - .val1 = v1, - .val2 = v2, -}); - -const array = []Value{ - v1, - v2, - v1, - v2, -}; - -test "unions embedded in aggregate types" { - switch (array[1]) { - Value.Array => |arr| assert(arr[4] == 3), - else => unreachable, - } - switch ((err catch unreachable).val1) { - Value.Int => |x| assert(x == 1234), - else => unreachable, - } -} - -const Foo = union { - float: f64, - int: i32, -}; - -test "basic unions" { - var foo = Foo{ .int = 1 }; - assert(foo.int == 1); - foo = Foo{ .float = 12.34 }; - assert(foo.float == 12.34); -} - -test "comptime union field access" { - comptime { - var foo = Foo{ .int = 0 }; - assert(foo.int == 0); - - foo = Foo{ .float = 42.42 }; - assert(foo.float == 42.42); - } -} - -test "init union with runtime value" { - var foo: Foo = undefined; - - setFloat(&foo, 12.34); - assert(foo.float == 12.34); - - setInt(&foo, 42); - assert(foo.int == 42); -} - -fn setFloat(foo: *Foo, x: f64) void { - foo.* = Foo{ .float = x }; -} - -fn setInt(foo: *Foo, x: i32) void { - foo.* = Foo{ .int = x }; -} - -const FooExtern = extern union { - float: f64, - int: i32, -}; - -test "basic extern unions" { - var foo = FooExtern{ .int = 1 }; - assert(foo.int == 1); - foo.float = 12.34; - assert(foo.float == 12.34); -} - -const Letter = enum { - A, - B, - C, -}; -const Payload = union(Letter) { - A: i32, - B: f64, - C: bool, -}; - -test "union with specified enum tag" { - doTest(); - comptime doTest(); -} - -fn doTest() void { - assert(bar(Payload{ .A = 1234 }) == -10); -} - -fn bar(value: Payload) i32 { - assert(Letter(value) == Letter.A); - return switch (value) { - Payload.A => |x| return x - 1244, - Payload.B => |x| if (x == 12.34) i32(20) else 21, - Payload.C => |x| if (x) i32(30) else 31, - }; -} - -const MultipleChoice = union(enum(u32)) { - A = 20, - B = 40, - C = 60, - D = 1000, -}; -test "simple union(enum(u32))" { - var x = MultipleChoice.C; - assert(x == MultipleChoice.C); - assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60); -} - -const MultipleChoice2 = union(enum(u32)) { - Unspecified1: i32, - A: f32 = 20, - Unspecified2: void, - B: bool = 40, - Unspecified3: i32, - C: i8 = 60, - Unspecified4: void, - D: void = 1000, - Unspecified5: i32, -}; - -test "union(enum(u32)) with specified and unspecified tag values" { - comptime assert(@TagType(@TagType(MultipleChoice2)) == u32); - testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); - comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); -} - -fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); - assert(1123 == switch (x) { - MultipleChoice2.A => 1, - MultipleChoice2.B => 2, - MultipleChoice2.C => |v| i32(1000) + v, - MultipleChoice2.D => 4, - MultipleChoice2.Unspecified1 => 5, - MultipleChoice2.Unspecified2 => 6, - MultipleChoice2.Unspecified3 => 7, - MultipleChoice2.Unspecified4 => 8, - MultipleChoice2.Unspecified5 => 9, - }); -} - -const ExternPtrOrInt = extern union { - ptr: *u8, - int: u64, -}; -test "extern union size" { - comptime assert(@sizeOf(ExternPtrOrInt) == 8); -} - -const PackedPtrOrInt = packed union { - ptr: *u8, - int: u64, -}; -test "extern union size" { - comptime assert(@sizeOf(PackedPtrOrInt) == 8); -} - -const ZeroBits = union { - OnlyField: void, -}; -test "union with only 1 field which is void should be zero bits" { - comptime assert(@sizeOf(ZeroBits) == 0); -} - -const TheTag = enum { - A, - B, - C, -}; -const TheUnion = union(TheTag) { - A: i32, - B: i32, - C: i32, -}; -test "union field access gives the enum values" { - assert(TheUnion.A == TheTag.A); - assert(TheUnion.B == TheTag.B); - assert(TheUnion.C == TheTag.C); -} - -test "cast union to tag type of union" { - testCastUnionToTagType(TheUnion{ .B = 1234 }); - comptime testCastUnionToTagType(TheUnion{ .B = 1234 }); -} - -fn testCastUnionToTagType(x: TheUnion) void { - assert(TheTag(x) == TheTag.B); -} - -test "cast tag type of union to union" { - var x: Value2 = Letter2.B; - assert(Letter2(x) == Letter2.B); -} -const Letter2 = enum { - A, - B, - C, -}; -const Value2 = union(Letter2) { - A: i32, - B, - C, -}; - -test "implicit cast union to its tag type" { - var x: Value2 = Letter2.B; - assert(x == Letter2.B); - giveMeLetterB(x); -} -fn giveMeLetterB(x: Letter2) void { - assert(x == Value2.B); -} - -pub const PackThis = union(enum) { - Invalid: bool, - StringLiteral: u2, -}; - -test "constant packed union" { - testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }}); -} - -fn testConstPackedUnion(expected_tokens: []const PackThis) void { - assert(expected_tokens[0].StringLiteral == 1); -} - -test "switch on union with only 1 field" { - var r: PartialInst = undefined; - r = PartialInst.Compiled; - switch (r) { - PartialInst.Compiled => { - var z: PartialInstWithPayload = undefined; - z = PartialInstWithPayload{ .Compiled = 1234 }; - switch (z) { - PartialInstWithPayload.Compiled => |x| { - assert(x == 1234); - return; - }, - } - }, - } - unreachable; -} - -const PartialInst = union(enum) { - Compiled, -}; - -const PartialInstWithPayload = union(enum) { - Compiled: i32, -}; - -test "access a member of tagged union with conflicting enum tag name" { - const Bar = union(enum) { - A: A, - B: B, - - const A = u8; - const B = void; - }; - - comptime assert(Bar.A == u8); -} - -test "tagged union initialization with runtime void" { - assert(testTaggedUnionInit({})); -} - -const TaggedUnionWithAVoid = union(enum) { - A, - B: i32, -}; - -fn testTaggedUnionInit(x: var) bool { - const y = TaggedUnionWithAVoid{ .A = x }; - return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A; -} - -pub const UnionEnumNoPayloads = union(enum) { - A, - B, -}; - -test "tagged union with no payloads" { - const a = UnionEnumNoPayloads{ .B = {} }; - switch (a) { - @TagType(UnionEnumNoPayloads).A => @panic("wrong"), - @TagType(UnionEnumNoPayloads).B => {}, - } -} - -test "union with only 1 field casted to its enum type" { - const Literal = union(enum) { - Number: f64, - Bool: bool, - }; - - const Expr = union(enum) { - Literal: Literal, - }; - - var e = Expr{ .Literal = Literal{ .Bool = true } }; - const Tag = @TagType(Expr); - comptime assert(@TagType(Tag) == comptime_int); - var t = Tag(e); - assert(t == Expr.Literal); -} - -test "union with only 1 field casted to its enum type which has enum value specified" { - const Literal = union(enum) { - Number: f64, - Bool: bool, - }; - - const Tag = enum { - Literal = 33, - }; - - const Expr = union(Tag) { - Literal: Literal, - }; - - var e = Expr{ .Literal = Literal{ .Bool = true } }; - comptime assert(@TagType(Tag) == comptime_int); - var t = Tag(e); - assert(t == Expr.Literal); - assert(@enumToInt(t) == 33); - comptime assert(@enumToInt(t) == 33); -} diff --git a/test/cases/var_args.zig b/test/cases/var_args.zig deleted file mode 100644 index 3eb6e30448..0000000000 --- a/test/cases/var_args.zig +++ /dev/null @@ -1,84 +0,0 @@ -const assert = @import("std").debug.assert; - -fn add(args: ...) i32 { - var sum = i32(0); - { - comptime var i: usize = 0; - inline while (i < args.len) : (i += 1) { - sum += args[i]; - } - } - return sum; -} - -test "add arbitrary args" { - assert(add(i32(1), i32(2), i32(3), i32(4)) == 10); - assert(add(i32(1234)) == 1234); - assert(add() == 0); -} - -fn readFirstVarArg(args: ...) void { - const value = args[0]; -} - -test "send void arg to var args" { - readFirstVarArg({}); -} - -test "pass args directly" { - assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); - assert(addSomeStuff(i32(1234)) == 1234); - assert(addSomeStuff() == 0); -} - -fn addSomeStuff(args: ...) i32 { - return add(args); -} - -test "runtime parameter before var args" { - assert(extraFn(10) == 0); - assert(extraFn(10, false) == 1); - assert(extraFn(10, false, true) == 2); - - // TODO issue #313 - //comptime { - // assert(extraFn(10) == 0); - // assert(extraFn(10, false) == 1); - // assert(extraFn(10, false, true) == 2); - //} -} - -fn extraFn(extra: u32, args: ...) usize { - if (args.len >= 1) { - assert(args[0] == false); - } - if (args.len >= 2) { - assert(args[1] == true); - } - return args.len; -} - -const foos = []fn (...) bool{ - foo1, - foo2, -}; - -fn foo1(args: ...) bool { - return true; -} -fn foo2(args: ...) bool { - return false; -} - -test "array of var args functions" { - assert(foos[0]()); - assert(!foos[1]()); -} - -test "pass zero length array to var args param" { - doNothingWithFirstArg(""); -} - -fn doNothingWithFirstArg(args: ...) void { - const a = args[0]; -} diff --git a/test/cases/void.zig b/test/cases/void.zig deleted file mode 100644 index 7121ac664b..0000000000 --- a/test/cases/void.zig +++ /dev/null @@ -1,30 +0,0 @@ -const assert = @import("std").debug.assert; - -const Foo = struct { - a: void, - b: i32, - c: void, -}; - -test "compare void with void compile time known" { - comptime { - const foo = Foo{ - .a = {}, - .b = 1, - .c = {}, - }; - assert(foo.a == {}); - } -} - -test "iterate over a void slice" { - var j: usize = 0; - for (times(10)) |_, i| { - assert(i == j); - j += 1; - } -} - -fn times(n: usize) []const void { - return ([*]void)(undefined)[0..n]; -} diff --git a/test/cases/while.zig b/test/cases/while.zig deleted file mode 100644 index f774e0ec6b..0000000000 --- a/test/cases/while.zig +++ /dev/null @@ -1,227 +0,0 @@ -const assert = @import("std").debug.assert; - -test "while loop" { - var i: i32 = 0; - while (i < 4) { - i += 1; - } - assert(i == 4); - assert(whileLoop1() == 1); -} -fn whileLoop1() i32 { - return whileLoop2(); -} -fn whileLoop2() i32 { - while (true) { - return 1; - } -} -test "static eval while" { - assert(static_eval_while_number == 1); -} -const static_eval_while_number = staticWhileLoop1(); -fn staticWhileLoop1() i32 { - return whileLoop2(); -} -fn staticWhileLoop2() i32 { - while (true) { - return 1; - } -} - -test "continue and break" { - runContinueAndBreakTest(); - assert(continue_and_break_counter == 8); -} -var continue_and_break_counter: i32 = 0; -fn runContinueAndBreakTest() void { - var i: i32 = 0; - while (true) { - continue_and_break_counter += 2; - i += 1; - if (i < 4) { - continue; - } - break; - } - assert(i == 4); -} - -test "return with implicit cast from while loop" { - returnWithImplicitCastFromWhileLoopTest() catch unreachable; -} -fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { - while (true) { - return; - } -} - -test "while with continue expression" { - var sum: i32 = 0; - { - var i: i32 = 0; - while (i < 10) : (i += 1) { - if (i == 5) continue; - sum += i; - } - } - assert(sum == 40); -} - -test "while with else" { - var sum: i32 = 0; - var i: i32 = 0; - var got_else: i32 = 0; - while (i < 10) : (i += 1) { - sum += 1; - } else { - got_else += 1; - } - assert(sum == 10); - assert(got_else == 1); -} - -test "while with optional as condition" { - numbers_left = 10; - var sum: i32 = 0; - while (getNumberOrNull()) |value| { - sum += value; - } - assert(sum == 45); -} - -test "while with optional as condition with else" { - numbers_left = 10; - var sum: i32 = 0; - var got_else: i32 = 0; - while (getNumberOrNull()) |value| { - sum += value; - assert(got_else == 0); - } else { - got_else += 1; - } - assert(sum == 45); - assert(got_else == 1); -} - -test "while with error union condition" { - numbers_left = 10; - var sum: i32 = 0; - var got_else: i32 = 0; - while (getNumberOrErr()) |value| { - sum += value; - } else |err| { - assert(err == error.OutOfNumbers); - got_else += 1; - } - assert(sum == 45); - assert(got_else == 1); -} - -var numbers_left: i32 = undefined; -fn getNumberOrErr() anyerror!i32 { - return if (numbers_left == 0) error.OutOfNumbers else x: { - numbers_left -= 1; - break :x numbers_left; - }; -} -fn getNumberOrNull() ?i32 { - return if (numbers_left == 0) null else x: { - numbers_left -= 1; - break :x numbers_left; - }; -} - -test "while on optional with else result follow else prong" { - const result = while (returnNull()) |value| { - break value; - } else - i32(2); - assert(result == 2); -} - -test "while on optional with else result follow break prong" { - const result = while (returnOptional(10)) |value| { - break value; - } else - i32(2); - assert(result == 10); -} - -test "while on error union with else result follow else prong" { - const result = while (returnError()) |value| { - break value; - } else |err| - i32(2); - assert(result == 2); -} - -test "while on error union with else result follow break prong" { - const result = while (returnSuccess(10)) |value| { - break value; - } else |err| - i32(2); - assert(result == 10); -} - -test "while on bool with else result follow else prong" { - const result = while (returnFalse()) { - break i32(10); - } else - i32(2); - assert(result == 2); -} - -test "while on bool with else result follow break prong" { - const result = while (returnTrue()) { - break i32(10); - } else - i32(2); - assert(result == 10); -} - -test "break from outer while loop" { - testBreakOuter(); - comptime testBreakOuter(); -} - -fn testBreakOuter() void { - outer: while (true) { - while (true) { - break :outer; - } - } -} - -test "continue outer while loop" { - testContinueOuter(); - comptime testContinueOuter(); -} - -fn testContinueOuter() void { - var i: usize = 0; - outer: while (i < 10) : (i += 1) { - while (true) { - continue :outer; - } - } -} - -fn returnNull() ?i32 { - return null; -} -fn returnOptional(x: i32) ?i32 { - return x; -} -fn returnError() anyerror!i32 { - return error.YouWantedAnError; -} -fn returnSuccess(x: i32) anyerror!i32 { - return x; -} -fn returnFalse() bool { - return false; -} -fn returnTrue() bool { - return true; -} diff --git a/test/cases/widening.zig b/test/cases/widening.zig deleted file mode 100644 index cf6ab4ca0f..0000000000 --- a/test/cases/widening.zig +++ /dev/null @@ -1,27 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const mem = std.mem; - -test "integer widening" { - var a: u8 = 250; - var b: u16 = a; - var c: u32 = b; - var d: u64 = c; - var e: u64 = d; - var f: u128 = e; - assert(f == a); -} - -test "implicit unsigned integer to signed integer" { - var a: u8 = 250; - var b: i16 = a; - assert(b == 250); -} - -test "float widening" { - var a: f16 = 12.34; - var b: f32 = a; - var c: f64 = b; - var d: f128 = c; - assert(d == a); -} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 0754f223e8..bc1ef660c3 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -3220,7 +3220,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ return 2; \\} , - ".tmp_source.zig:2:15: error: unable to infer expression type", + ".tmp_source.zig:2:15: error: values of type 'comptime_int' must be comptime known", ); cases.add( @@ -3566,7 +3566,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - ".tmp_source.zig:2:11: error: expected type, found 'i32'", + ".tmp_source.zig:2:11: error: expected type 'type', found 'i32'", ); cases.add( diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig new file mode 100644 index 0000000000..e545a4c418 --- /dev/null +++ b/test/stage1/behavior.zig @@ -0,0 +1,80 @@ +comptime { + _ = @import("behavior/align.zig"); + _ = @import("behavior/alignof.zig"); + _ = @import("behavior/array.zig"); + _ = @import("behavior/asm.zig"); + _ = @import("behavior/atomics.zig"); + _ = @import("behavior/bit_shifting.zig"); + _ = @import("behavior/bitcast.zig"); + _ = @import("behavior/bitreverse.zig"); + _ = @import("behavior/bool.zig"); + _ = @import("behavior/bswap.zig"); + _ = @import("behavior/bugs/1076.zig"); + _ = @import("behavior/bugs/1111.zig"); + _ = @import("behavior/bugs/1277.zig"); + _ = @import("behavior/bugs/1322.zig"); + _ = @import("behavior/bugs/1381.zig"); + _ = @import("behavior/bugs/1421.zig"); + _ = @import("behavior/bugs/1442.zig"); + _ = @import("behavior/bugs/1486.zig"); + _ = @import("behavior/bugs/394.zig"); + _ = @import("behavior/bugs/655.zig"); + _ = @import("behavior/bugs/656.zig"); + _ = @import("behavior/bugs/726.zig"); + _ = @import("behavior/bugs/828.zig"); + _ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/byval_arg_var.zig"); + _ = @import("behavior/cancel.zig"); + _ = @import("behavior/cast.zig"); + _ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/coroutine_await_struct.zig"); + _ = @import("behavior/coroutines.zig"); + _ = @import("behavior/defer.zig"); + _ = @import("behavior/enum.zig"); + _ = @import("behavior/enum_with_members.zig"); + _ = @import("behavior/error.zig"); + _ = @import("behavior/eval.zig"); + _ = @import("behavior/field_parent_ptr.zig"); + _ = @import("behavior/fn.zig"); + _ = @import("behavior/fn_in_struct_in_comptime.zig"); + _ = @import("behavior/for.zig"); + _ = @import("behavior/generics.zig"); + _ = @import("behavior/if.zig"); + _ = @import("behavior/import.zig"); + _ = @import("behavior/incomplete_struct_param_tld.zig"); + _ = @import("behavior/inttoptr.zig"); + _ = @import("behavior/ir_block_deps.zig"); + _ = @import("behavior/math.zig"); + _ = @import("behavior/merge_error_sets.zig"); + _ = @import("behavior/misc.zig"); + _ = @import("behavior/namespace_depends_on_compile_var/index.zig"); + _ = @import("behavior/new_stack_call.zig"); + _ = @import("behavior/null.zig"); + _ = @import("behavior/optional.zig"); + _ = @import("behavior/pointers.zig"); + _ = @import("behavior/popcount.zig"); + _ = @import("behavior/ptrcast.zig"); + _ = @import("behavior/pub_enum/index.zig"); + _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); + _ = @import("behavior/reflection.zig"); + _ = @import("behavior/sizeof_and_typeof.zig"); + _ = @import("behavior/slice.zig"); + _ = @import("behavior/struct.zig"); + _ = @import("behavior/struct_contains_null_ptr_itself.zig"); + _ = @import("behavior/struct_contains_slice_of_itself.zig"); + _ = @import("behavior/switch.zig"); + _ = @import("behavior/switch_prong_err_enum.zig"); + _ = @import("behavior/switch_prong_implicit_cast.zig"); + _ = @import("behavior/syntax.zig"); + _ = @import("behavior/this.zig"); + _ = @import("behavior/truncate.zig"); + _ = @import("behavior/try.zig"); + _ = @import("behavior/type_info.zig"); + _ = @import("behavior/undefined.zig"); + _ = @import("behavior/underscore.zig"); + _ = @import("behavior/union.zig"); + _ = @import("behavior/var_args.zig"); + _ = @import("behavior/void.zig"); + _ = @import("behavior/while.zig"); + _ = @import("behavior/widening.zig"); +} diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig new file mode 100644 index 0000000000..aa7a93ad84 --- /dev/null +++ b/test/stage1/behavior/align.zig @@ -0,0 +1,230 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const builtin = @import("builtin"); + +var foo: u8 align(4) = 100; + +test "global variable alignment" { + assertOrPanic(@typeOf(&foo).alignment == 4); + assertOrPanic(@typeOf(&foo) == *align(4) u8); + const slice = (*[1]u8)(&foo)[0..]; + assertOrPanic(@typeOf(slice) == []align(4) u8); +} + +fn derp() align(@sizeOf(usize) * 2) i32 { + return 1234; +} +fn noop1() align(1) void {} +fn noop4() align(4) void {} + +test "function alignment" { + assertOrPanic(derp() == 1234); + assertOrPanic(@typeOf(noop1) == fn () align(1) void); + assertOrPanic(@typeOf(noop4) == fn () align(4) void); + noop1(); + noop4(); +} + +var baz: packed struct { + a: u32, + b: u32, +} = undefined; + +test "packed struct alignment" { + assertOrPanic(@typeOf(&baz.b) == *align(1) u32); +} + +const blah: packed struct { + a: u3, + b: u3, + c: u2, +} = undefined; + +test "bit field alignment" { + assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3); +} + +test "default alignment allows unspecified in type syntax" { + assertOrPanic(*u32 == *align(@alignOf(u32)) u32); +} + +test "implicitly decreasing pointer alignment" { + const a: u32 align(4) = 3; + const b: u32 align(8) = 4; + assertOrPanic(addUnaligned(&a, &b) == 7); +} + +fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { + return a.* + b.*; +} + +test "implicitly decreasing slice alignment" { + const a: u32 align(4) = 3; + const b: u32 align(8) = 4; + assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); +} +fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { + return a[0] + b[0]; +} + +test "specifying alignment allows pointer cast" { + testBytesAlign(0x33); +} +fn testBytesAlign(b: u8) void { + var bytes align(4) = []u8{ + b, + b, + b, + b, + }; + const ptr = @ptrCast(*u32, &bytes[0]); + assertOrPanic(ptr.* == 0x33333333); +} + +test "specifying alignment allows slice cast" { + testBytesAlignSlice(0x33); +} +fn testBytesAlignSlice(b: u8) void { + var bytes align(4) = []u8{ + b, + b, + b, + b, + }; + const slice: []u32 = @bytesToSlice(u32, bytes[0..]); + assertOrPanic(slice[0] == 0x33333333); +} + +test "@alignCast pointers" { + var x: u32 align(4) = 1; + expectsOnly1(&x); + assertOrPanic(x == 2); +} +fn expectsOnly1(x: *align(1) u32) void { + expects4(@alignCast(4, x)); +} +fn expects4(x: *align(4) u32) void { + x.* += 1; +} + +test "@alignCast slices" { + var array align(4) = []u32{ + 1, + 1, + }; + const slice = array[0..]; + sliceExpectsOnly1(slice); + assertOrPanic(slice[0] == 2); +} +fn sliceExpectsOnly1(slice: []align(1) u32) void { + sliceExpects4(@alignCast(4, slice)); +} +fn sliceExpects4(slice: []align(4) u32) void { + slice[0] += 1; +} + +test "implicitly decreasing fn alignment" { + testImplicitlyDecreaseFnAlign(alignedSmall, 1234); + testImplicitlyDecreaseFnAlign(alignedBig, 5678); +} + +fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { + assertOrPanic(ptr() == answer); +} + +fn alignedSmall() align(8) i32 { + return 1234; +} +fn alignedBig() align(16) i32 { + return 5678; +} + +test "@alignCast functions" { + assertOrPanic(fnExpectsOnly1(simple4) == 0x19); +} +fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { + return fnExpects4(@alignCast(4, ptr)); +} +fn fnExpects4(ptr: fn () align(4) i32) i32 { + return ptr(); +} +fn simple4() align(4) i32 { + return 0x19; +} + +test "generic function with align param" { + assertOrPanic(whyWouldYouEverDoThis(1) == 0x1); + assertOrPanic(whyWouldYouEverDoThis(4) == 0x1); + assertOrPanic(whyWouldYouEverDoThis(8) == 0x1); +} + +fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { + return 0x1; +} + +test "@ptrCast preserves alignment of bigger source" { + var x: u32 align(16) = 1234; + const ptr = @ptrCast(*u8, &x); + assertOrPanic(@typeOf(ptr) == *align(16) u8); +} + +test "runtime known array index has best alignment possible" { + // take full advantage of over-alignment + var array align(4) = []u8{ 1, 2, 3, 4 }; + assertOrPanic(@typeOf(&array[0]) == *align(4) u8); + assertOrPanic(@typeOf(&array[1]) == *u8); + assertOrPanic(@typeOf(&array[2]) == *align(2) u8); + assertOrPanic(@typeOf(&array[3]) == *u8); + + // because align is too small but we still figure out to use 2 + var bigger align(2) = []u64{ 1, 2, 3, 4 }; + assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64); + assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64); + + // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 + var smaller align(2) = []u32{ 1, 2, 3, 4 }; + comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32); + comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32); + testIndex(smaller[0..].ptr, 0, *align(2) u32); + testIndex(smaller[0..].ptr, 1, *align(2) u32); + testIndex(smaller[0..].ptr, 2, *align(2) u32); + testIndex(smaller[0..].ptr, 3, *align(2) u32); + + // has to use ABI alignment because index known at runtime only + testIndex2(array[0..].ptr, 0, *u8); + testIndex2(array[0..].ptr, 1, *u8); + testIndex2(array[0..].ptr, 2, *u8); + testIndex2(array[0..].ptr, 3, *u8); +} +fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { + comptime assertOrPanic(@typeOf(&smaller[index]) == T); +} +fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { + comptime assertOrPanic(@typeOf(&ptr[index]) == T); +} + +test "alignstack" { + assertOrPanic(fnWithAlignedStack() == 1234); +} + +fn fnWithAlignedStack() i32 { + @setAlignStack(256); + return 1234; +} + +test "alignment of structs" { + assertOrPanic(@alignOf(struct { + a: i32, + b: *i32, + }) == @alignOf(usize)); +} + +test "alignment of extern() void" { + var runtime_nothing = nothing; + const casted1 = @ptrCast(*const u8, runtime_nothing); + const casted2 = @ptrCast(extern fn () void, casted1); + casted2(); +} + +extern fn nothing() void {} diff --git a/test/stage1/behavior/alignof.zig b/test/stage1/behavior/alignof.zig new file mode 100644 index 0000000000..98c805908b --- /dev/null +++ b/test/stage1/behavior/alignof.zig @@ -0,0 +1,18 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const builtin = @import("builtin"); +const maxInt = std.math.maxInt; + +const Foo = struct { + x: u32, + y: u32, + z: u32, +}; + +test "@alignOf(T) before referencing T" { + comptime assertOrPanic(@alignOf(Foo) != maxInt(usize)); + if (builtin.arch == builtin.Arch.x86_64) { + comptime assertOrPanic(@alignOf(Foo) == 4); + } +} + diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig new file mode 100644 index 0000000000..1183305209 --- /dev/null +++ b/test/stage1/behavior/array.zig @@ -0,0 +1,270 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +test "arrays" { + var array: [5]u32 = undefined; + + var i: u32 = 0; + while (i < 5) { + array[i] = i + 1; + i = array[i]; + } + + i = 0; + var accumulator = u32(0); + while (i < 5) { + accumulator += array[i]; + + i += 1; + } + + assertOrPanic(accumulator == 15); + assertOrPanic(getArrayLen(array) == 5); +} +fn getArrayLen(a: []const u32) usize { + return a.len; +} + +test "void arrays" { + var array: [4]void = undefined; + array[0] = void{}; + array[1] = array[2]; + assertOrPanic(@sizeOf(@typeOf(array)) == 0); + assertOrPanic(array.len == 4); +} + +test "array literal" { + const hex_mult = []u16{ + 4096, + 256, + 16, + 1, + }; + + assertOrPanic(hex_mult.len == 4); + assertOrPanic(hex_mult[1] == 256); +} + +test "array dot len const expr" { + assertOrPanic(comptime x: { + break :x some_array.len == 4; + }); +} + +const ArrayDotLenConstExpr = struct { + y: [some_array.len]u8, +}; +const some_array = []u8{ + 0, + 1, + 2, + 3, +}; + +test "nested arrays" { + const array_of_strings = [][]const u8{ + "hello", + "this", + "is", + "my", + "thing", + }; + for (array_of_strings) |s, i| { + if (i == 0) assertOrPanic(mem.eql(u8, s, "hello")); + if (i == 1) assertOrPanic(mem.eql(u8, s, "this")); + if (i == 2) assertOrPanic(mem.eql(u8, s, "is")); + if (i == 3) assertOrPanic(mem.eql(u8, s, "my")); + if (i == 4) assertOrPanic(mem.eql(u8, s, "thing")); + } +} + +var s_array: [8]Sub = undefined; +const Sub = struct { + b: u8, +}; +const Str = struct { + a: []Sub, +}; +test "set global var array via slice embedded in struct" { + var s = Str{ .a = s_array[0..] }; + + s.a[0].b = 1; + s.a[1].b = 2; + s.a[2].b = 3; + + assertOrPanic(s_array[0].b == 1); + assertOrPanic(s_array[1].b == 2); + assertOrPanic(s_array[2].b == 3); +} + +test "array literal with specified size" { + var array = [2]u8{ + 1, + 2, + }; + assertOrPanic(array[0] == 1); + assertOrPanic(array[1] == 2); +} + +test "array child property" { + var x: [5]i32 = undefined; + assertOrPanic(@typeOf(x).Child == i32); +} + +test "array len property" { + var x: [5]i32 = undefined; + assertOrPanic(@typeOf(x).len == 5); +} + +test "array len field" { + var arr = [4]u8{ 0, 0, 0, 0 }; + var ptr = &arr; + assertOrPanic(arr.len == 4); + comptime assertOrPanic(arr.len == 4); + assertOrPanic(ptr.len == 4); + comptime assertOrPanic(ptr.len == 4); +} + +test "single-item pointer to array indexing and slicing" { + testSingleItemPtrArrayIndexSlice(); + comptime testSingleItemPtrArrayIndexSlice(); +} + +fn testSingleItemPtrArrayIndexSlice() void { + var array = "aaaa"; + doSomeMangling(&array); + assertOrPanic(mem.eql(u8, "azya", array)); +} + +fn doSomeMangling(array: *[4]u8) void { + array[1] = 'z'; + array[2..3][0] = 'y'; +} + +test "implicit cast single-item pointer" { + testImplicitCastSingleItemPtr(); + comptime testImplicitCastSingleItemPtr(); +} + +fn testImplicitCastSingleItemPtr() void { + var byte: u8 = 100; + const slice = (*[1]u8)(&byte)[0..]; + slice[0] += 1; + assertOrPanic(byte == 101); +} + +fn testArrayByValAtComptime(b: [2]u8) u8 { + return b[0]; +} + +test "comptime evalutating function that takes array by value" { + const arr = []u8{ 0, 1 }; + _ = comptime testArrayByValAtComptime(arr); + _ = comptime testArrayByValAtComptime(arr); +} + +test "implicit comptime in array type size" { + var arr: [plusOne(10)]bool = undefined; + assertOrPanic(arr.len == 11); +} + +fn plusOne(x: u32) u32 { + return x + 1; +} + +test "array literal as argument to function" { + const S = struct { + fn entry(two: i32) void { + foo([]i32{ + 1, + 2, + 3, + }); + foo([]i32{ + 1, + two, + 3, + }); + foo2(true, []i32{ + 1, + 2, + 3, + }); + foo2(true, []i32{ + 1, + two, + 3, + }); + } + fn foo(x: []const i32) void { + assertOrPanic(x[0] == 1); + assertOrPanic(x[1] == 2); + assertOrPanic(x[2] == 3); + } + fn foo2(trash: bool, x: []const i32) void { + assertOrPanic(trash); + assertOrPanic(x[0] == 1); + assertOrPanic(x[1] == 2); + assertOrPanic(x[2] == 3); + } + }; + S.entry(2); + comptime S.entry(2); +} + +test "double nested array to const slice cast in array literal" { + const S = struct { + fn entry(two: i32) void { + const cases = [][]const []const i32{ + [][]const i32{[]i32{1}}, + [][]const i32{[]i32{ 2, 3 }}, + [][]const i32{ + []i32{4}, + []i32{ 5, 6, 7 }, + }, + }; + check(cases); + + const cases2 = [][]const i32{ + []i32{1}, + []i32{ two, 3 }, + }; + assertOrPanic(cases2.len == 2); + assertOrPanic(cases2[0].len == 1); + assertOrPanic(cases2[0][0] == 1); + assertOrPanic(cases2[1].len == 2); + assertOrPanic(cases2[1][0] == 2); + assertOrPanic(cases2[1][1] == 3); + + const cases3 = [][]const []const i32{ + [][]const i32{[]i32{1}}, + [][]const i32{[]i32{ two, 3 }}, + [][]const i32{ + []i32{4}, + []i32{ 5, 6, 7 }, + }, + }; + check(cases3); + } + + fn check(cases: []const []const []const i32) void { + assertOrPanic(cases.len == 3); + assertOrPanic(cases[0].len == 1); + assertOrPanic(cases[0][0].len == 1); + assertOrPanic(cases[0][0][0] == 1); + assertOrPanic(cases[1].len == 1); + assertOrPanic(cases[1][0].len == 2); + assertOrPanic(cases[1][0][0] == 2); + assertOrPanic(cases[1][0][1] == 3); + assertOrPanic(cases[2].len == 2); + assertOrPanic(cases[2][0].len == 1); + assertOrPanic(cases[2][0][0] == 4); + assertOrPanic(cases[2][1].len == 3); + assertOrPanic(cases[2][1][0] == 5); + assertOrPanic(cases[2][1][1] == 6); + assertOrPanic(cases[2][1][2] == 7); + } + }; + S.entry(2); + comptime S.entry(2); +} diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig new file mode 100644 index 0000000000..48701c5836 --- /dev/null +++ b/test/stage1/behavior/asm.zig @@ -0,0 +1,92 @@ +const config = @import("builtin"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +comptime { + if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { + asm volatile ( + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; + ); + } +} + +test "module level assembly" { + if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { + assertOrPanic(aoeu() == 1234); + } +} + +test "output constraint modifiers" { + // This is only testing compilation. + var a: u32 = 3; + asm volatile ("" + : [_] "=m,r" (a) + : + : "" + ); + asm volatile ("" + : [_] "=r,m" (a) + : + : "" + ); +} + +test "alternative constraints" { + // Make sure we allow commas as a separator for alternative constraints. + var a: u32 = 3; + asm volatile ("" + : [_] "=r,m" (a) + : [_] "r,m" (a) + : "" + ); +} + +test "sized integer/float in asm input" { + asm volatile ("" + : + : [_] "m" (usize(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i15(-3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (u3(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i3(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (u121(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (i121(3)) + : "" + ); + asm volatile ("" + : + : [_] "m" (f32(3.17)) + : "" + ); + asm volatile ("" + : + : [_] "m" (f64(3.17)) + : "" + ); +} + +extern fn aoeu() i32; + +export fn derp() i32 { + return 1234; +} diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig new file mode 100644 index 0000000000..fa3c5f29a6 --- /dev/null +++ b/test/stage1/behavior/atomics.zig @@ -0,0 +1,71 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const builtin = @import("builtin"); +const AtomicRmwOp = builtin.AtomicRmwOp; +const AtomicOrder = builtin.AtomicOrder; + +test "cmpxchg" { + var x: i32 = 1234; + if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { + assertOrPanic(x1 == 1234); + } else { + @panic("cmpxchg should have failed"); + } + + while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { + assertOrPanic(x1 == 1234); + } + assertOrPanic(x == 5678); + + assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + assertOrPanic(x == 42); +} + +test "fence" { + var x: i32 = 1234; + @fence(AtomicOrder.SeqCst); + x = 5678; +} + +test "atomicrmw and atomicload" { + var data: u8 = 200; + testAtomicRmw(&data); + assertOrPanic(data == 42); + testAtomicLoad(&data); +} + +fn testAtomicRmw(ptr: *u8) void { + const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); + assertOrPanic(prev_value == 200); + comptime { + var x: i32 = 1234; + const y: i32 = 12345; + assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); + assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); + } +} + +fn testAtomicLoad(ptr: *u8) void { + const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); + assertOrPanic(x == 42); +} + +test "cmpxchg with ptr" { + var data1: i32 = 1234; + var data2: i32 = 5678; + var data3: i32 = 9101; + var x: *i32 = &data1; + if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { + assertOrPanic(x1 == &data1); + } else { + @panic("cmpxchg should have failed"); + } + + while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { + assertOrPanic(x1 == &data1); + } + assertOrPanic(x == &data3); + + assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + assertOrPanic(x == &data2); +} diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig new file mode 100644 index 0000000000..3290688358 --- /dev/null +++ b/test/stage1/behavior/bit_shifting.zig @@ -0,0 +1,88 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { + assertOrPanic(Key == @IntType(false, Key.bit_count)); + assertOrPanic(Key.bit_count >= mask_bit_count); + const ShardKey = @IntType(false, mask_bit_count); + const shift_amount = Key.bit_count - ShardKey.bit_count; + return struct { + const Self = @This(); + shards: [1 << ShardKey.bit_count]?*Node, + + pub fn create() Self { + return Self{ .shards = []?*Node{null} ** (1 << ShardKey.bit_count) }; + } + + fn getShardKey(key: Key) ShardKey { + // https://github.com/ziglang/zig/issues/1544 + // this special case is needed because you can't u32 >> 32. + if (ShardKey == u0) return 0; + + // this can be u1 >> u0 + const shard_key = key >> shift_amount; + + // TODO: https://github.com/ziglang/zig/issues/1544 + // This cast could be implicit if we teach the compiler that + // u32 >> 30 -> u2 + return @intCast(ShardKey, shard_key); + } + + pub fn put(self: *Self, node: *Node) void { + const shard_key = Self.getShardKey(node.key); + node.next = self.shards[shard_key]; + self.shards[shard_key] = node; + } + + pub fn get(self: *Self, key: Key) ?*Node { + const shard_key = Self.getShardKey(key); + var maybe_node = self.shards[shard_key]; + while (maybe_node) |node| : (maybe_node = node.next) { + if (node.key == key) return node; + } + return null; + } + + pub const Node = struct { + key: Key, + value: V, + next: ?*Node, + + pub fn init(self: *Node, key: Key, value: V) void { + self.key = key; + self.value = value; + self.next = null; + } + }; + }; +} + +test "sharded table" { + // realistic 16-way sharding + testShardedTable(u32, 4, 8); + + testShardedTable(u5, 0, 32); // ShardKey == u0 + testShardedTable(u5, 2, 32); + testShardedTable(u5, 5, 32); + + testShardedTable(u1, 0, 2); + testShardedTable(u1, 1, 2); // this does u1 >> u0 + + testShardedTable(u0, 0, 1); +} +fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime node_count: comptime_int) void { + const Table = ShardedTable(Key, mask_bit_count, void); + + var table = Table.create(); + var node_buffer: [node_count]Table.Node = undefined; + for (node_buffer) |*node, i| { + const key = @intCast(Key, i); + assertOrPanic(table.get(key) == null); + node.init(key, {}); + table.put(node); + } + + for (node_buffer) |*node, i| { + assertOrPanic(table.get(@intCast(Key, i)) == node); + } +} diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig new file mode 100644 index 0000000000..19030255e4 --- /dev/null +++ b/test/stage1/behavior/bitcast.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const maxInt = std.math.maxInt; + +test "@bitCast i32 -> u32" { + testBitCast_i32_u32(); + comptime testBitCast_i32_u32(); +} + +fn testBitCast_i32_u32() void { + assertOrPanic(conv(-1) == maxInt(u32)); + assertOrPanic(conv2(maxInt(u32)) == -1); +} + +fn conv(x: i32) u32 { + return @bitCast(u32, x); +} +fn conv2(x: u32) i32 { + return @bitCast(i32, x); +} + +test "@bitCast extern enum to its integer type" { + const SOCK = extern enum { + A, + B, + + fn testBitCastExternEnum() void { + var SOCK_DGRAM = @This().B; + var sock_dgram = @bitCast(c_int, SOCK_DGRAM); + assertOrPanic(sock_dgram == 1); + } + }; + + SOCK.testBitCastExternEnum(); + comptime SOCK.testBitCastExternEnum(); +} diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig new file mode 100644 index 0000000000..97787ace84 --- /dev/null +++ b/test/stage1/behavior/bitreverse.zig @@ -0,0 +1,81 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const minInt = std.math.minInt; + +test "@bitreverse" { + comptime testBitReverse(); + testBitReverse(); +} + +fn testBitReverse() void { + // using comptime_ints, unsigned + assertOrPanic(@bitreverse(u0, 0) == 0); + assertOrPanic(@bitreverse(u5, 0x12) == 0x9); + assertOrPanic(@bitreverse(u8, 0x12) == 0x48); + assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48); + assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48); + assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using runtime uints, unsigned + var num0: u0 = 0; + assertOrPanic(@bitreverse(u0, num0) == 0); + var num5: u5 = 0x12; + assertOrPanic(@bitreverse(u5, num5) == 0x9); + var num8: u8 = 0x12; + assertOrPanic(@bitreverse(u8, num8) == 0x48); + var num16: u16 = 0x1234; + assertOrPanic(@bitreverse(u16, num16) == 0x2c48); + var num24: u24 = 0x123456; + assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48); + var num32: u32 = 0x12345678; + assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48); + var num40: u40 = 0x123456789a; + assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48); + var num48: u48 = 0x123456789abc; + assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48); + var num56: u56 = 0x123456789abcde; + assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + var num64: u64 = 0x123456789abcdef1; + assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + var num128: u128 = 0x123456789abcdef11121314151617181; + assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + + // using comptime_ints, signed, positive + assertOrPanic(@bitreverse(i0, 0) == 0); + assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); + assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); + assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); + assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); + assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); + assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); + assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); + assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); + assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); + + // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. + var neg5: i5 = minInt(i5) + 1; + assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + var neg8: i8 = -18; + assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + var neg16: i16 = -32694; + assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + var neg24: i24 = -6773785; + assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + var neg32: i32 = -16773785; + assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + var neg40: i40 = minInt(i40) + 12345; + assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + var neg48: i48 = minInt(i48) + 12345; + assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + var neg56: i56 = minInt(i56) + 12345; + assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + var neg64: i64 = minInt(i64) + 12345; + assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + var neg128: i128 = minInt(i128) + 12345; + assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); +} diff --git a/test/stage1/behavior/bool.zig b/test/stage1/behavior/bool.zig new file mode 100644 index 0000000000..2d7241526f --- /dev/null +++ b/test/stage1/behavior/bool.zig @@ -0,0 +1,35 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "bool literals" { + assertOrPanic(true); + assertOrPanic(!false); +} + +test "cast bool to int" { + const t = true; + const f = false; + assertOrPanic(@boolToInt(t) == u32(1)); + assertOrPanic(@boolToInt(f) == u32(0)); + nonConstCastBoolToInt(t, f); +} + +fn nonConstCastBoolToInt(t: bool, f: bool) void { + assertOrPanic(@boolToInt(t) == u32(1)); + assertOrPanic(@boolToInt(f) == u32(0)); +} + +test "bool cmp" { + assertOrPanic(testBoolCmp(true, false) == false); +} +fn testBoolCmp(a: bool, b: bool) bool { + return a == b; +} + +const global_f = false; +const global_t = true; +const not_global_f = !global_f; +const not_global_t = !global_t; +test "compile time bool not" { + assertOrPanic(not_global_f); + assertOrPanic(!not_global_t); +} diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig new file mode 100644 index 0000000000..8084538e03 --- /dev/null +++ b/test/stage1/behavior/bswap.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "@bswap" { + comptime testByteSwap(); + testByteSwap(); +} + +fn testByteSwap() void { + assertOrPanic(@bswap(u0, 0) == 0); + assertOrPanic(@bswap(u8, 0x12) == 0x12); + assertOrPanic(@bswap(u16, 0x1234) == 0x3412); + assertOrPanic(@bswap(u24, 0x123456) == 0x563412); + assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412); + assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412); + assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + + assertOrPanic(@bswap(i0, 0) == 0); + assertOrPanic(@bswap(i8, -50) == -50); + assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); +} diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig new file mode 100644 index 0000000000..69a7e70f7d --- /dev/null +++ b/test/stage1/behavior/bugs/1076.zig @@ -0,0 +1,16 @@ +const std = @import("std"); +const mem = std.mem; +const assertOrPanic = std.debug.assertOrPanic; + +test "comptime code should not modify constant data" { + testCastPtrOfArrayToSliceAndPtr(); + comptime testCastPtrOfArrayToSliceAndPtr(); +} + +fn testCastPtrOfArrayToSliceAndPtr() void { + var array = "aoeu"; + const x: [*]u8 = &array; + x[0] += 1; + assertOrPanic(mem.eql(u8, array[0..], "boeu")); +} + diff --git a/test/stage1/behavior/bugs/1111.zig b/test/stage1/behavior/bugs/1111.zig new file mode 100644 index 0000000000..f62107f9a3 --- /dev/null +++ b/test/stage1/behavior/bugs/1111.zig @@ -0,0 +1,12 @@ +const Foo = extern enum { + Bar = -1, +}; + +test "issue 1111 fixed" { + const v = Foo.Bar; + + switch (v) { + Foo.Bar => return, + else => return, + } +} diff --git a/test/stage1/behavior/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig new file mode 100644 index 0000000000..a83e7653e2 --- /dev/null +++ b/test/stage1/behavior/bugs/1277.zig @@ -0,0 +1,15 @@ +const std = @import("std"); + +const S = struct { + f: ?fn () i32, +}; + +const s = S{ .f = f }; + +fn f() i32 { + return 1234; +} + +test "don't emit an LLVM global for a const function when it's in an optional in a struct" { + std.debug.assertOrPanic(s.f.?() == 1234); +} diff --git a/test/stage1/behavior/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig new file mode 100644 index 0000000000..2e67f4473f --- /dev/null +++ b/test/stage1/behavior/bugs/1322.zig @@ -0,0 +1,19 @@ +const std = @import("std"); + +const B = union(enum) { + c: C, + None, +}; + +const A = struct { + b: B, +}; + +const C = struct {}; + +test "tagged union with all void fields but a meaningful tag" { + var a: A = A{ .b = B{ .c = C{} } }; + std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c); + a = A{ .b = B.None }; + std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None); +} diff --git a/test/stage1/behavior/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig new file mode 100644 index 0000000000..2d452da156 --- /dev/null +++ b/test/stage1/behavior/bugs/1381.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +const B = union(enum) { + D: u8, + E: u16, +}; + +const A = union(enum) { + B: B, + C: u8, +}; + +test "union that needs padding bytes inside an array" { + var as = []A{ + A{ .B = B{ .D = 1 } }, + A{ .B = B{ .D = 1 } }, + }; + + const a = as[0].B; + std.debug.assertOrPanic(a.D == 1); +} diff --git a/test/stage1/behavior/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig new file mode 100644 index 0000000000..fbc932781a --- /dev/null +++ b/test/stage1/behavior/bugs/1421.zig @@ -0,0 +1,14 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const assertOrPanic = std.debug.assertOrPanic; + +const S = struct { + fn method() builtin.TypeInfo { + return @typeInfo(S); + } +}; + +test "functions with return type required to be comptime are generic" { + const ti = S.method(); + assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct); +} diff --git a/test/stage1/behavior/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig new file mode 100644 index 0000000000..e9dfd5d2ce --- /dev/null +++ b/test/stage1/behavior/bugs/1442.zig @@ -0,0 +1,11 @@ +const std = @import("std"); + +const Union = union(enum) { + Text: []const u8, + Color: u32, +}; + +test "const error union field alignment" { + var union_or_err: anyerror!Union = Union{ .Color = 1234 }; + std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); +} diff --git a/test/stage1/behavior/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig new file mode 100644 index 0000000000..0483e3828c --- /dev/null +++ b/test/stage1/behavior/bugs/1486.zig @@ -0,0 +1,11 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const ptr = &global; +var global: u64 = 123; + +test "constant pointer to global variable causes runtime load" { + global = 1234; + assertOrPanic(&global == ptr); + assertOrPanic(ptr.* == 1234); +} + diff --git a/test/stage1/behavior/bugs/394.zig b/test/stage1/behavior/bugs/394.zig new file mode 100644 index 0000000000..766ad9e157 --- /dev/null +++ b/test/stage1/behavior/bugs/394.zig @@ -0,0 +1,18 @@ +const E = union(enum) { + A: [9]u8, + B: u64, +}; +const S = struct { + x: u8, + y: E, +}; + +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "bug 394 fixed" { + const x = S{ + .x = 3, + .y = E{ .B = 1 }, + }; + assertOrPanic(x.x == 3); +} diff --git a/test/stage1/behavior/bugs/655.zig b/test/stage1/behavior/bugs/655.zig new file mode 100644 index 0000000000..67ba6a231f --- /dev/null +++ b/test/stage1/behavior/bugs/655.zig @@ -0,0 +1,12 @@ +const std = @import("std"); +const other_file = @import("655_other_file.zig"); + +test "function with *const parameter with type dereferenced by namespace" { + const x: other_file.Integer = 1234; + comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer); + foo(&x); +} + +fn foo(x: *const other_file.Integer) void { + std.debug.assertOrPanic(x.* == 1234); +} diff --git a/test/stage1/behavior/bugs/655_other_file.zig b/test/stage1/behavior/bugs/655_other_file.zig new file mode 100644 index 0000000000..df1df44955 --- /dev/null +++ b/test/stage1/behavior/bugs/655_other_file.zig @@ -0,0 +1 @@ +pub const Integer = u32; diff --git a/test/stage1/behavior/bugs/656.zig b/test/stage1/behavior/bugs/656.zig new file mode 100644 index 0000000000..cb37fe67fe --- /dev/null +++ b/test/stage1/behavior/bugs/656.zig @@ -0,0 +1,31 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const PrefixOp = union(enum) { + Return, + AddrOf: Value, +}; + +const Value = struct { + align_expr: ?u32, +}; + +test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { + foo(false, true); +} + +fn foo(a: bool, b: bool) void { + var prefix_op = PrefixOp{ + .AddrOf = Value{ .align_expr = 1234 }, + }; + if (a) {} else { + switch (prefix_op) { + PrefixOp.AddrOf => |addr_of_info| { + if (b) {} + if (addr_of_info.align_expr) |align_expr| { + assertOrPanic(align_expr == 1234); + } + }, + PrefixOp.Return => {}, + } + } +} diff --git a/test/stage1/behavior/bugs/726.zig b/test/stage1/behavior/bugs/726.zig new file mode 100644 index 0000000000..ce20480c63 --- /dev/null +++ b/test/stage1/behavior/bugs/726.zig @@ -0,0 +1,16 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@ptrCast from const to nullable" { + const c: u8 = 4; + var x: ?*const u8 = @ptrCast(?*const u8, &c); + assertOrPanic(x.?.* == 4); +} + +test "@ptrCast from var in empty struct to nullable" { + const container = struct { + var c: u8 = 4; + }; + var x: ?*const u8 = @ptrCast(?*const u8, &container.c); + assertOrPanic(x.?.* == 4); +} + diff --git a/test/stage1/behavior/bugs/828.zig b/test/stage1/behavior/bugs/828.zig new file mode 100644 index 0000000000..50ae0fd279 --- /dev/null +++ b/test/stage1/behavior/bugs/828.zig @@ -0,0 +1,33 @@ +const CountBy = struct { + a: usize, + + const One = CountBy{ .a = 1 }; + + pub fn counter(self: *const CountBy) Counter { + return Counter{ .i = 0 }; + } +}; + +const Counter = struct { + i: usize, + + pub fn count(self: *Counter) bool { + self.i += 1; + return self.i <= 10; + } +}; + +fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { + comptime { + var cnt = cb.counter(); + if (cnt.i != 0) @compileError("Counter instance reused!"); + while (cnt.count()) {} + } +} + +test "comptime struct return should not return the same instance" { + //the first parameter must be passed by reference to trigger the bug + //a second parameter is required to trigger the bug + const ValA = constCount(&CountBy.One, 12); + const ValB = constCount(&CountBy.One, 15); +} diff --git a/test/stage1/behavior/bugs/920.zig b/test/stage1/behavior/bugs/920.zig new file mode 100644 index 0000000000..e29c5c4acf --- /dev/null +++ b/test/stage1/behavior/bugs/920.zig @@ -0,0 +1,65 @@ +const std = @import("std"); +const math = std.math; +const Random = std.rand.Random; + +const ZigTable = struct { + r: f64, + x: [257]f64, + f: [257]f64, + + pdf: fn (f64) f64, + is_symmetric: bool, + zero_case: fn (*Random, f64) f64, +}; + +fn ZigTableGen(comptime is_symmetric: bool, comptime r: f64, comptime v: f64, comptime f: fn (f64) f64, comptime f_inv: fn (f64) f64, comptime zero_case: fn (*Random, f64) f64) ZigTable { + var tables: ZigTable = undefined; + + tables.is_symmetric = is_symmetric; + tables.r = r; + tables.pdf = f; + tables.zero_case = zero_case; + + tables.x[0] = v / f(r); + tables.x[1] = r; + + for (tables.x[2..256]) |*entry, i| { + const last = tables.x[2 + i - 1]; + entry.* = f_inv(v / last + f(last)); + } + tables.x[256] = 0; + + for (tables.f[0..]) |*entry, i| { + entry.* = f(tables.x[i]); + } + + return tables; +} + +const norm_r = 3.6541528853610088; +const norm_v = 0.00492867323399; + +fn norm_f(x: f64) f64 { + return math.exp(-x * x / 2.0); +} +fn norm_f_inv(y: f64) f64 { + return math.sqrt(-2.0 * math.ln(y)); +} +fn norm_zero_case(random: *Random, u: f64) f64 { + return 0.0; +} + +const NormalDist = blk: { + @setEvalBranchQuota(30000); + break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); +}; + +test "bug 920 fixed" { + const NormalDist1 = blk: { + break :blk ZigTableGen(true, norm_r, norm_v, norm_f, norm_f_inv, norm_zero_case); + }; + + for (NormalDist1.f) |_, i| { + std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]); + } +} diff --git a/test/stage1/behavior/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig new file mode 100644 index 0000000000..14ee212ce0 --- /dev/null +++ b/test/stage1/behavior/byval_arg_var.zig @@ -0,0 +1,27 @@ +const std = @import("std"); + +var result: []const u8 = "wrong"; + +test "pass string literal byvalue to a generic var param" { + start(); + blowUpStack(10); + + std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal")); +} + +fn start() void { + foo("string literal"); +} + +fn foo(x: var) void { + bar(x); +} + +fn bar(x: var) void { + result = x; +} + +fn blowUpStack(x: u32) void { + if (x == 0) return; + blowUpStack(x - 1); +} diff --git a/test/stage1/behavior/cancel.zig b/test/stage1/behavior/cancel.zig new file mode 100644 index 0000000000..863da4bdb8 --- /dev/null +++ b/test/stage1/behavior/cancel.zig @@ -0,0 +1,92 @@ +const std = @import("std"); + +var defer_f1: bool = false; +var defer_f2: bool = false; +var defer_f3: bool = false; + +test "cancel forwards" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + const p = async<&da.allocator> f1() catch unreachable; + cancel p; + std.debug.assertOrPanic(defer_f1); + std.debug.assertOrPanic(defer_f2); + std.debug.assertOrPanic(defer_f3); +} + +async fn f1() void { + defer { + defer_f1 = true; + } + await (async f2() catch unreachable); +} + +async fn f2() void { + defer { + defer_f2 = true; + } + await (async f3() catch unreachable); +} + +async fn f3() void { + defer { + defer_f3 = true; + } + suspend; +} + +var defer_b1: bool = false; +var defer_b2: bool = false; +var defer_b3: bool = false; +var defer_b4: bool = false; + +test "cancel backwards" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + const p = async<&da.allocator> b1() catch unreachable; + cancel p; + std.debug.assertOrPanic(defer_b1); + std.debug.assertOrPanic(defer_b2); + std.debug.assertOrPanic(defer_b3); + std.debug.assertOrPanic(defer_b4); +} + +async fn b1() void { + defer { + defer_b1 = true; + } + await (async b2() catch unreachable); +} + +var b4_handle: promise = undefined; + +async fn b2() void { + const b3_handle = async b3() catch unreachable; + resume b4_handle; + cancel b4_handle; + defer { + defer_b2 = true; + } + const value = await b3_handle; + @panic("unreachable"); +} + +async fn b3() i32 { + defer { + defer_b3 = true; + } + await (async b4() catch unreachable); + return 1234; +} + +async fn b4() void { + defer { + defer_b4 = true; + } + suspend { + b4_handle = @handle(); + } + suspend; +} diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig new file mode 100644 index 0000000000..61ddcd8135 --- /dev/null +++ b/test/stage1/behavior/cast.zig @@ -0,0 +1,473 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const mem = std.mem; +const maxInt = std.math.maxInt; + +test "int to ptr cast" { + const x = usize(13); + const y = @intToPtr(*u8, x); + const z = @ptrToInt(y); + assertOrPanic(z == 13); +} + +test "integer literal to pointer cast" { + const vga_mem = @intToPtr(*u16, 0xB8000); + assertOrPanic(@ptrToInt(vga_mem) == 0xB8000); +} + +test "pointer reinterpret const float to int" { + const float: f64 = 5.99999999999994648725e-01; + const float_ptr = &float; + const int_ptr = @ptrCast(*const i32, float_ptr); + const int_val = int_ptr.*; + assertOrPanic(int_val == 858993411); +} + +test "implicitly cast indirect pointer to maybe-indirect pointer" { + const S = struct { + const Self = @This(); + x: u8, + fn constConst(p: *const *const Self) u8 { + return p.*.x; + } + fn maybeConstConst(p: ?*const *const Self) u8 { + return p.?.*.x; + } + fn constConstConst(p: *const *const *const Self) u8 { + return p.*.*.x; + } + fn maybeConstConstConst(p: ?*const *const *const Self) u8 { + return p.?.*.*.x; + } + }; + const s = S{ .x = 42 }; + const p = &s; + const q = &p; + const r = &q; + assertOrPanic(42 == S.constConst(q)); + assertOrPanic(42 == S.maybeConstConst(q)); + assertOrPanic(42 == S.constConstConst(r)); + assertOrPanic(42 == S.maybeConstConstConst(r)); +} + +test "explicit cast from integer to error type" { + testCastIntToErr(error.ItBroke); + comptime testCastIntToErr(error.ItBroke); +} +fn testCastIntToErr(err: anyerror) void { + const x = @errorToInt(err); + const y = @intToError(x); + assertOrPanic(error.ItBroke == y); +} + +test "peer resolve arrays of different size to const slice" { + assertOrPanic(mem.eql(u8, boolToStr(true), "true")); + assertOrPanic(mem.eql(u8, boolToStr(false), "false")); + comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true")); + comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false")); +} +fn boolToStr(b: bool) []const u8 { + return if (b) "true" else "false"; +} + +test "peer resolve array and const slice" { + testPeerResolveArrayConstSlice(true); + comptime testPeerResolveArrayConstSlice(true); +} +fn testPeerResolveArrayConstSlice(b: bool) void { + const value1 = if (b) "aoeu" else ([]const u8)("zz"); + const value2 = if (b) ([]const u8)("zz") else "aoeu"; + assertOrPanic(mem.eql(u8, value1, "aoeu")); + assertOrPanic(mem.eql(u8, value2, "zz")); +} + +test "implicitly cast from T to anyerror!?T" { + castToOptionalTypeError(1); + comptime castToOptionalTypeError(1); +} + +const A = struct { + a: i32, +}; +fn castToOptionalTypeError(z: i32) void { + const x = i32(1); + const y: anyerror!?i32 = x; + assertOrPanic((try y).? == 1); + + const f = z; + const g: anyerror!?i32 = f; + + const a = A{ .a = z }; + const b: anyerror!?A = a; + assertOrPanic((b catch unreachable).?.a == 1); +} + +test "implicitly cast from int to anyerror!?T" { + implicitIntLitToOptional(); + comptime implicitIntLitToOptional(); +} +fn implicitIntLitToOptional() void { + const f: ?i32 = 1; + const g: anyerror!?i32 = 1; +} + +test "return null from fn() anyerror!?&T" { + const a = returnNullFromOptionalTypeErrorRef(); + const b = returnNullLitFromOptionalTypeErrorRef(); + assertOrPanic((try a) == null and (try b) == null); +} +fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { + const a: ?*A = null; + return a; +} +fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { + return null; +} + +test "peer type resolution: ?T and T" { + assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); + assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + comptime { + assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); + assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + } +} +fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { + if (c) { + return if (b) null else usize(0); + } + + return usize(3); +} + +test "peer type resolution: [0]u8 and []const u8" { + assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + comptime { + assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + } +} +fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { + if (a) { + return []const u8{}; + } + + return slice[0..1]; +} + +test "implicitly cast from [N]T to ?[]const T" { + assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); + comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); +} + +fn castToOptionalSlice() ?[]const u8 { + return "hi"; +} + +test "implicitly cast from [0]T to anyerror![]T" { + testCastZeroArrayToErrSliceMut(); + comptime testCastZeroArrayToErrSliceMut(); +} + +fn testCastZeroArrayToErrSliceMut() void { + assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0); +} + +fn gimmeErrOrSlice() anyerror![]u8 { + return []u8{}; +} + +test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { + { + var data = "hi"; + const slice = data[0..]; + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } + comptime { + var data = "hi"; + const slice = data[0..]; + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } +} +fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { + if (a) { + return []u8{}; + } + + return slice[0..1]; +} + +test "resolve undefined with integer" { + testResolveUndefWithInt(true, 1234); + comptime testResolveUndefWithInt(true, 1234); +} +fn testResolveUndefWithInt(b: bool, x: i32) void { + const value = if (b) x else undefined; + if (b) { + assertOrPanic(value == x); + } +} + +test "implicit cast from &const [N]T to []const T" { + testCastConstArrayRefToConstSlice(); + comptime testCastConstArrayRefToConstSlice(); +} + +fn testCastConstArrayRefToConstSlice() void { + const blah = "aoeu"; + const const_array_ref = &blah; + assertOrPanic(@typeOf(const_array_ref) == *const [4]u8); + const slice: []const u8 = const_array_ref; + assertOrPanic(mem.eql(u8, slice, "aoeu")); +} + +test "peer type resolution: error and [N]T" { + // TODO: implicit error!T to error!U where T can implicitly cast to U + //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); +} + +//fn testPeerErrorAndArray(x: u8) error![]const u8 { +// return switch (x) { +// 0x00 => "OK", +// else => error.BadValue, +// }; +//} +fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { + return switch (x) { + 0x00 => "OK", + 0x01 => "OKK", + else => error.BadValue, + }; +} + +test "@floatToInt" { + testFloatToInts(); + comptime testFloatToInts(); +} + +fn testFloatToInts() void { + const x = i32(1e4); + assertOrPanic(x == 10000); + const y = @floatToInt(i32, f32(1e4)); + assertOrPanic(y == 10000); + expectFloatToInt(f16, 255.1, u8, 255); + expectFloatToInt(f16, 127.2, i8, 127); + expectFloatToInt(f16, -128.2, i8, -128); + expectFloatToInt(f32, 255.1, u8, 255); + expectFloatToInt(f32, 127.2, i8, 127); + expectFloatToInt(f32, -128.2, i8, -128); + expectFloatToInt(comptime_int, 1234, i16, 1234); +} + +fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { + assertOrPanic(@floatToInt(I, f) == i); +} + +test "cast u128 to f128 and back" { + comptime testCast128(); + testCast128(); +} + +fn testCast128() void { + assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); +} + +fn cast128Int(x: f128) u128 { + return @bitCast(u128, x); +} + +fn cast128Float(x: u128) f128 { + return @bitCast(f128, x); +} + +test "const slice widen cast" { + const bytes align(4) = []u8{ + 0x12, + 0x12, + 0x12, + 0x12, + }; + + const u32_value = @bytesToSlice(u32, bytes[0..])[0]; + assertOrPanic(u32_value == 0x12121212); + + assertOrPanic(@bitCast(u32, bytes) == 0x12121212); +} + +test "single-item pointer of array to slice and to unknown length pointer" { + testCastPtrOfArrayToSliceAndPtr(); + comptime testCastPtrOfArrayToSliceAndPtr(); +} + +fn testCastPtrOfArrayToSliceAndPtr() void { + var array = "aoeu"; + const x: [*]u8 = &array; + x[0] += 1; + assertOrPanic(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + assertOrPanic(mem.eql(u8, array[0..], "coeu")); +} + +test "cast *[1][*]const u8 to [*]const ?[*]const u8" { + const window_name = [1][*]const u8{c"window name"}; + const x: [*]const ?[*]const u8 = &window_name; + assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); +} + +test "@intCast comptime_int" { + const result = @intCast(i32, 1234); + assertOrPanic(@typeOf(result) == i32); + assertOrPanic(result == 1234); +} + +test "@floatCast comptime_int and comptime_float" { + { + const result = @floatCast(f16, 1234); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); + } + { + const result = @floatCast(f16, 1234.0); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); + } + { + const result = @floatCast(f32, 1234); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); + } + { + const result = @floatCast(f32, 1234.0); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); + } +} + +test "comptime_int @intToFloat" { + { + const result = @intToFloat(f16, 1234); + assertOrPanic(@typeOf(result) == f16); + assertOrPanic(result == 1234.0); + } + { + const result = @intToFloat(f32, 1234); + assertOrPanic(@typeOf(result) == f32); + assertOrPanic(result == 1234.0); + } +} + +test "@bytesToSlice keeps pointer alignment" { + var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; + const numbers = @bytesToSlice(u32, bytes[0..]); + comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); +} + +test "@intCast i32 to u7" { + var x: u128 = maxInt(u128); + var y: i32 = 120; + var z = x >> @intCast(u7, y); + assertOrPanic(z == 0xff); +} + +test "implicit cast undefined to optional" { + assertOrPanic(MakeType(void).getNull() == null); + assertOrPanic(MakeType(void).getNonNull() != null); +} + +fn MakeType(comptime T: type) type { + return struct { + fn getNull() ?T { + return null; + } + + fn getNonNull() ?T { + return T(undefined); + } + }; +} + +test "implicit cast from *[N]T to ?[*]T" { + var x: ?[*]u16 = null; + var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; + + x = &y; + assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); + x.?[0] = 8; + y[3] = 6; + assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); +} + +test "implicit cast from *T to ?*c_void" { + var a: u8 = 1; + incrementVoidPtrValue(&a); + std.debug.assertOrPanic(a == 2); +} + +fn incrementVoidPtrValue(value: ?*c_void) void { + @ptrCast(*u8, value.?).* += 1; +} + +test "implicit cast from [*]T to ?*c_void" { + var a = []u8{ 3, 2, 1 }; + incrementVoidPtrArray(a[0..].ptr, 3); + assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); +} + +fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { + var n: usize = 0; + while (n < len) : (n += 1) { + @ptrCast([*]u8, array.?)[n] += 1; + } +} + +test "*usize to *void" { + var i = usize(0); + var v = @ptrCast(*void, &i); + v.* = {}; +} + +test "compile time int to ptr of function" { + foobar(FUNCTION_CONSTANT); +} + +pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); +pub const PFN_void = extern fn (*c_void) void; + +fn foobar(func: PFN_void) void { + std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize)); +} + +test "implicit ptr to *c_void" { + var a: u32 = 1; + var ptr: *c_void = &a; + var b: *u32 = @ptrCast(*u32, ptr); + assertOrPanic(b.* == 1); + var ptr2: ?*c_void = &a; + var c: *u32 = @ptrCast(*u32, ptr2.?); + assertOrPanic(c.* == 1); +} + +test "@intCast to comptime_int" { + assertOrPanic(@intCast(comptime_int, 0) == 0); +} + +test "implicit cast comptime numbers to any type when the value fits" { + const a: u64 = 255; + var b: u8 = a; + assertOrPanic(b == 255); +} + +test "@intToEnum passed a comptime_int to an enum with one item" { + const E = enum { + A, + }; + const x = @intToEnum(E, 0); + assertOrPanic(x == E.A); +} diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig new file mode 100644 index 0000000000..5b9b70a558 --- /dev/null +++ b/test/stage1/behavior/const_slice_child.zig @@ -0,0 +1,45 @@ +const debug = @import("std").debug; +const assertOrPanic = debug.assertOrPanic; + +var argv: [*]const [*]const u8 = undefined; + +test "const slice child" { + const strs = ([][*]const u8){ + c"one", + c"two", + c"three", + }; + // TODO this should implicitly cast + argv = @ptrCast([*]const [*]const u8, &strs); + bar(strs.len); +} + +fn foo(args: [][]const u8) void { + assertOrPanic(args.len == 3); + assertOrPanic(streql(args[0], "one")); + assertOrPanic(streql(args[1], "two")); + assertOrPanic(streql(args[2], "three")); +} + +fn bar(argc: usize) void { + const args = debug.global_allocator.alloc([]const u8, argc) catch unreachable; + for (args) |_, i| { + const ptr = argv[i]; + args[i] = ptr[0..strlen(ptr)]; + } + foo(args); +} + +fn strlen(ptr: [*]const u8) usize { + var count: usize = 0; + while (ptr[count] != 0) : (count += 1) {} + return count; +} + +fn streql(a: []const u8, b: []const u8) bool { + if (a.len != b.len) return false; + for (a) |item, index| { + if (b[index] != item) return false; + } + return true; +} diff --git a/test/stage1/behavior/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig new file mode 100644 index 0000000000..6ca2a301ec --- /dev/null +++ b/test/stage1/behavior/coroutine_await_struct.zig @@ -0,0 +1,47 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const assertOrPanic = std.debug.assertOrPanic; + +const Foo = struct { + x: i32, +}; + +var await_a_promise: promise = undefined; +var await_final_result = Foo{ .x = 0 }; + +test "coroutine await struct" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + await_seq('a'); + const p = async<&da.allocator> await_amain() catch unreachable; + await_seq('f'); + resume await_a_promise; + await_seq('i'); + assertOrPanic(await_final_result.x == 1234); + assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); +} +async fn await_amain() void { + await_seq('b'); + const p = async await_another() catch unreachable; + await_seq('e'); + await_final_result = await p; + await_seq('h'); +} +async fn await_another() Foo { + await_seq('c'); + suspend { + await_seq('d'); + await_a_promise = @handle(); + } + await_seq('g'); + return Foo{ .x = 1234 }; +} + +var await_points = []u8{0} ** "abcdefghi".len; +var await_seq_index: usize = 0; + +fn await_seq(c: u8) void { + await_points[await_seq_index] = c; + await_seq_index += 1; +} diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig new file mode 100644 index 0000000000..a2327c5060 --- /dev/null +++ b/test/stage1/behavior/coroutines.zig @@ -0,0 +1,258 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const assertOrPanic = std.debug.assertOrPanic; + +var x: i32 = 1; + +test "create a coroutine and cancel it" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + const p = try async<&da.allocator> simpleAsyncFn(); + comptime assertOrPanic(@typeOf(p) == promise->void); + cancel p; + assertOrPanic(x == 2); +} +async fn simpleAsyncFn() void { + x += 1; + suspend; + x += 1; +} + +test "coroutine suspend, resume, cancel" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + seq('a'); + const p = try async<&da.allocator> testAsyncSeq(); + seq('c'); + resume p; + seq('f'); + cancel p; + seq('g'); + + assertOrPanic(std.mem.eql(u8, points, "abcdefg")); +} +async fn testAsyncSeq() void { + defer seq('e'); + + seq('b'); + suspend; + seq('d'); +} +var points = []u8{0} ** "abcdefg".len; +var index: usize = 0; + +fn seq(c: u8) void { + points[index] = c; + index += 1; +} + +test "coroutine suspend with block" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + const p = try async<&da.allocator> testSuspendBlock(); + std.debug.assertOrPanic(!result); + resume a_promise; + std.debug.assertOrPanic(result); + cancel p; +} + +var a_promise: promise = undefined; +var result = false; +async fn testSuspendBlock() void { + suspend { + comptime assertOrPanic(@typeOf(@handle()) == promise->void); + a_promise = @handle(); + } + + //Test to make sure that @handle() works as advertised (issue #1296) + //var our_handle: promise = @handle(); + assertOrPanic(a_promise == @handle()); + + result = true; +} + +var await_a_promise: promise = undefined; +var await_final_result: i32 = 0; + +test "coroutine await" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + await_seq('a'); + const p = async<&da.allocator> await_amain() catch unreachable; + await_seq('f'); + resume await_a_promise; + await_seq('i'); + assertOrPanic(await_final_result == 1234); + assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); +} +async fn await_amain() void { + await_seq('b'); + const p = async await_another() catch unreachable; + await_seq('e'); + await_final_result = await p; + await_seq('h'); +} +async fn await_another() i32 { + await_seq('c'); + suspend { + await_seq('d'); + await_a_promise = @handle(); + } + await_seq('g'); + return 1234; +} + +var await_points = []u8{0} ** "abcdefghi".len; +var await_seq_index: usize = 0; + +fn await_seq(c: u8) void { + await_points[await_seq_index] = c; + await_seq_index += 1; +} + +var early_final_result: i32 = 0; + +test "coroutine await early return" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + + early_seq('a'); + const p = async<&da.allocator> early_amain() catch @panic("out of memory"); + early_seq('f'); + assertOrPanic(early_final_result == 1234); + assertOrPanic(std.mem.eql(u8, early_points, "abcdef")); +} +async fn early_amain() void { + early_seq('b'); + const p = async early_another() catch @panic("out of memory"); + early_seq('d'); + early_final_result = await p; + early_seq('e'); +} +async fn early_another() i32 { + early_seq('c'); + return 1234; +} + +var early_points = []u8{0} ** "abcdef".len; +var early_seq_index: usize = 0; + +fn early_seq(c: u8) void { + early_points[early_seq_index] = c; + early_seq_index += 1; +} + +test "coro allocation failure" { + var failing_allocator = std.debug.FailingAllocator.init(std.debug.global_allocator, 0); + if (async<&failing_allocator.allocator> asyncFuncThatNeverGetsRun()) { + @panic("expected allocation failure"); + } else |err| switch (err) { + error.OutOfMemory => {}, + } +} +async fn asyncFuncThatNeverGetsRun() void { + @panic("coro frame allocation should fail"); +} + +test "async function with dot syntax" { + const S = struct { + var y: i32 = 1; + async fn foo() void { + y += 1; + suspend; + } + }; + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + const p = try async<&da.allocator> S.foo(); + cancel p; + assertOrPanic(S.y == 2); +} + +test "async fn pointer in a struct field" { + var data: i32 = 1; + const Foo = struct { + bar: async<*std.mem.Allocator> fn (*i32) void, + }; + var foo = Foo{ .bar = simpleAsyncFn2 }; + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; + assertOrPanic(data == 2); + cancel p; + assertOrPanic(data == 4); +} +async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { + defer y.* += 2; + y.* += 1; + suspend; +} + +test "async fn with inferred error set" { + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + const p = (async<&da.allocator> failing()) catch unreachable; + resume p; + cancel p; +} + +async fn failing() !void { + suspend; + return error.Fail; +} + +test "error return trace across suspend points - early return" { + const p = nonFailing(); + resume p; + var da = std.heap.DirectAllocator.init(); + defer da.deinit(); + const p2 = try async<&da.allocator> printTrace(p); + cancel p2; +} + +test "error return trace across suspend points - async return" { + const p = nonFailing(); + const p2 = try async printTrace(p); + resume p; + cancel p2; +} + +fn nonFailing() (promise->anyerror!void) { + return async suspendThenFail() catch unreachable; +} +async fn suspendThenFail() anyerror!void { + suspend; + return error.Fail; +} +async fn printTrace(p: promise->(anyerror!void)) void { + (await p) catch |e| { + std.debug.assertOrPanic(e == error.Fail); + if (@errorReturnTrace()) |trace| { + assertOrPanic(trace.index == 1); + } else switch (builtin.mode) { + builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), + builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, + } + }; +} + +test "break from suspend" { + var buf: [500]u8 = undefined; + var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator; + var my_result: i32 = 1; + const p = try async testBreakFromSuspend(&my_result); + cancel p; + std.debug.assertOrPanic(my_result == 2); +} +async fn testBreakFromSuspend(my_result: *i32) void { + suspend { + resume @handle(); + } + my_result.* += 1; + suspend; + my_result.* += 1; +} diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig new file mode 100644 index 0000000000..6c6c60311e --- /dev/null +++ b/test/stage1/behavior/defer.zig @@ -0,0 +1,78 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +var result: [3]u8 = undefined; +var index: usize = undefined; + +fn runSomeErrorDefers(x: bool) !bool { + index = 0; + defer { + result[index] = 'a'; + index += 1; + } + errdefer { + result[index] = 'b'; + index += 1; + } + defer { + result[index] = 'c'; + index += 1; + } + return if (x) x else error.FalseNotAllowed; +} + +test "mixing normal and error defers" { + assertOrPanic(runSomeErrorDefers(true) catch unreachable); + assertOrPanic(result[0] == 'c'); + assertOrPanic(result[1] == 'a'); + + const ok = runSomeErrorDefers(false) catch |err| x: { + assertOrPanic(err == error.FalseNotAllowed); + break :x true; + }; + assertOrPanic(ok); + assertOrPanic(result[0] == 'c'); + assertOrPanic(result[1] == 'b'); + assertOrPanic(result[2] == 'a'); +} + +test "break and continue inside loop inside defer expression" { + testBreakContInDefer(10); + comptime testBreakContInDefer(10); +} + +fn testBreakContInDefer(x: usize) void { + defer { + var i: usize = 0; + while (i < x) : (i += 1) { + if (i < 5) continue; + if (i == 5) break; + } + assertOrPanic(i == 5); + } +} + +test "defer and labeled break" { + var i = usize(0); + + blk: { + defer i += 1; + break :blk; + } + + assertOrPanic(i == 1); +} + +test "errdefer does not apply to fn inside fn" { + if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad); +} + +fn testNestedFnErrDefer() anyerror!void { + var a: i32 = 0; + errdefer a += 1; + const S = struct { + fn baz() anyerror { + return error.Bad; + } + }; + return S.baz(); +} diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig new file mode 100644 index 0000000000..9de138ef78 --- /dev/null +++ b/test/stage1/behavior/enum.zig @@ -0,0 +1,894 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +test "enum type" { + const foo1 = Foo{ .One = 13 }; + const foo2 = Foo{ + .Two = Point{ + .x = 1234, + .y = 5678, + }, + }; + const bar = Bar.B; + + assertOrPanic(bar == Bar.B); + assertOrPanic(@memberCount(Foo) == 3); + assertOrPanic(@memberCount(Bar) == 4); + assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + assertOrPanic(@sizeOf(Bar) == 1); +} + +test "enum as return value" { + switch (returnAnInt(13)) { + Foo.One => |value| assertOrPanic(value == 13), + else => unreachable, + } +} + +const Point = struct { + x: u64, + y: u64, +}; +const Foo = union(enum) { + One: i32, + Two: Point, + Three: void, +}; +const FooNoVoid = union(enum) { + One: i32, + Two: Point, +}; +const Bar = enum { + A, + B, + C, + D, +}; + +fn returnAnInt(x: i32) Foo { + return Foo{ .One = x }; +} + +test "constant enum with payload" { + var empty = AnEnumWithPayload{ .Empty = {} }; + var full = AnEnumWithPayload{ .Full = 13 }; + shouldBeEmpty(empty); + shouldBeNotEmpty(full); +} + +fn shouldBeEmpty(x: AnEnumWithPayload) void { + switch (x) { + AnEnumWithPayload.Empty => {}, + else => unreachable, + } +} + +fn shouldBeNotEmpty(x: AnEnumWithPayload) void { + switch (x) { + AnEnumWithPayload.Empty => unreachable, + else => {}, + } +} + +const AnEnumWithPayload = union(enum) { + Empty: void, + Full: i32, +}; + +const Number = enum { + Zero, + One, + Two, + Three, + Four, +}; + +test "enum to int" { + shouldEqual(Number.Zero, 0); + shouldEqual(Number.One, 1); + shouldEqual(Number.Two, 2); + shouldEqual(Number.Three, 3); + shouldEqual(Number.Four, 4); +} + +fn shouldEqual(n: Number, expected: u3) void { + assertOrPanic(@enumToInt(n) == expected); +} + +test "int to enum" { + testIntToEnumEval(3); +} +fn testIntToEnumEval(x: i32) void { + assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); +} +const IntToEnumNumber = enum { + Zero, + One, + Two, + Three, + Four, +}; + +test "@tagName" { + assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); +} + +fn testEnumTagNameBare(n: BareNumber) []const u8 { + return @tagName(n); +} + +const BareNumber = enum { + One, + Two, + Three, +}; + +test "enum alignment" { + comptime { + assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); + assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64)); + } +} + +const AlignTestEnum = union(enum) { + A: [9]u8, + B: u64, +}; + +const ValueCount1 = enum { + I0, +}; +const ValueCount2 = enum { + I0, + I1, +}; +const ValueCount256 = enum { + I0, + I1, + I2, + I3, + I4, + I5, + I6, + I7, + I8, + I9, + I10, + I11, + I12, + I13, + I14, + I15, + I16, + I17, + I18, + I19, + I20, + I21, + I22, + I23, + I24, + I25, + I26, + I27, + I28, + I29, + I30, + I31, + I32, + I33, + I34, + I35, + I36, + I37, + I38, + I39, + I40, + I41, + I42, + I43, + I44, + I45, + I46, + I47, + I48, + I49, + I50, + I51, + I52, + I53, + I54, + I55, + I56, + I57, + I58, + I59, + I60, + I61, + I62, + I63, + I64, + I65, + I66, + I67, + I68, + I69, + I70, + I71, + I72, + I73, + I74, + I75, + I76, + I77, + I78, + I79, + I80, + I81, + I82, + I83, + I84, + I85, + I86, + I87, + I88, + I89, + I90, + I91, + I92, + I93, + I94, + I95, + I96, + I97, + I98, + I99, + I100, + I101, + I102, + I103, + I104, + I105, + I106, + I107, + I108, + I109, + I110, + I111, + I112, + I113, + I114, + I115, + I116, + I117, + I118, + I119, + I120, + I121, + I122, + I123, + I124, + I125, + I126, + I127, + I128, + I129, + I130, + I131, + I132, + I133, + I134, + I135, + I136, + I137, + I138, + I139, + I140, + I141, + I142, + I143, + I144, + I145, + I146, + I147, + I148, + I149, + I150, + I151, + I152, + I153, + I154, + I155, + I156, + I157, + I158, + I159, + I160, + I161, + I162, + I163, + I164, + I165, + I166, + I167, + I168, + I169, + I170, + I171, + I172, + I173, + I174, + I175, + I176, + I177, + I178, + I179, + I180, + I181, + I182, + I183, + I184, + I185, + I186, + I187, + I188, + I189, + I190, + I191, + I192, + I193, + I194, + I195, + I196, + I197, + I198, + I199, + I200, + I201, + I202, + I203, + I204, + I205, + I206, + I207, + I208, + I209, + I210, + I211, + I212, + I213, + I214, + I215, + I216, + I217, + I218, + I219, + I220, + I221, + I222, + I223, + I224, + I225, + I226, + I227, + I228, + I229, + I230, + I231, + I232, + I233, + I234, + I235, + I236, + I237, + I238, + I239, + I240, + I241, + I242, + I243, + I244, + I245, + I246, + I247, + I248, + I249, + I250, + I251, + I252, + I253, + I254, + I255, +}; +const ValueCount257 = enum { + I0, + I1, + I2, + I3, + I4, + I5, + I6, + I7, + I8, + I9, + I10, + I11, + I12, + I13, + I14, + I15, + I16, + I17, + I18, + I19, + I20, + I21, + I22, + I23, + I24, + I25, + I26, + I27, + I28, + I29, + I30, + I31, + I32, + I33, + I34, + I35, + I36, + I37, + I38, + I39, + I40, + I41, + I42, + I43, + I44, + I45, + I46, + I47, + I48, + I49, + I50, + I51, + I52, + I53, + I54, + I55, + I56, + I57, + I58, + I59, + I60, + I61, + I62, + I63, + I64, + I65, + I66, + I67, + I68, + I69, + I70, + I71, + I72, + I73, + I74, + I75, + I76, + I77, + I78, + I79, + I80, + I81, + I82, + I83, + I84, + I85, + I86, + I87, + I88, + I89, + I90, + I91, + I92, + I93, + I94, + I95, + I96, + I97, + I98, + I99, + I100, + I101, + I102, + I103, + I104, + I105, + I106, + I107, + I108, + I109, + I110, + I111, + I112, + I113, + I114, + I115, + I116, + I117, + I118, + I119, + I120, + I121, + I122, + I123, + I124, + I125, + I126, + I127, + I128, + I129, + I130, + I131, + I132, + I133, + I134, + I135, + I136, + I137, + I138, + I139, + I140, + I141, + I142, + I143, + I144, + I145, + I146, + I147, + I148, + I149, + I150, + I151, + I152, + I153, + I154, + I155, + I156, + I157, + I158, + I159, + I160, + I161, + I162, + I163, + I164, + I165, + I166, + I167, + I168, + I169, + I170, + I171, + I172, + I173, + I174, + I175, + I176, + I177, + I178, + I179, + I180, + I181, + I182, + I183, + I184, + I185, + I186, + I187, + I188, + I189, + I190, + I191, + I192, + I193, + I194, + I195, + I196, + I197, + I198, + I199, + I200, + I201, + I202, + I203, + I204, + I205, + I206, + I207, + I208, + I209, + I210, + I211, + I212, + I213, + I214, + I215, + I216, + I217, + I218, + I219, + I220, + I221, + I222, + I223, + I224, + I225, + I226, + I227, + I228, + I229, + I230, + I231, + I232, + I233, + I234, + I235, + I236, + I237, + I238, + I239, + I240, + I241, + I242, + I243, + I244, + I245, + I246, + I247, + I248, + I249, + I250, + I251, + I252, + I253, + I254, + I255, + I256, +}; + +test "enum sizes" { + comptime { + assertOrPanic(@sizeOf(ValueCount1) == 0); + assertOrPanic(@sizeOf(ValueCount2) == 1); + assertOrPanic(@sizeOf(ValueCount256) == 1); + assertOrPanic(@sizeOf(ValueCount257) == 2); + } +} + +const Small2 = enum(u2) { + One, + Two, +}; +const Small = enum(u2) { + One, + Two, + Three, + Four, +}; + +test "set enum tag type" { + { + var x = Small.One; + x = Small.Two; + comptime assertOrPanic(@TagType(Small) == u2); + } + { + var x = Small2.One; + x = Small2.Two; + comptime assertOrPanic(@TagType(Small2) == u2); + } +} + +const A = enum(u3) { + One, + Two, + Three, + Four, + One2, + Two2, + Three2, + Four2, +}; + +const B = enum(u3) { + One3, + Two3, + Three3, + Four3, + One23, + Two23, + Three23, + Four23, +}; + +const C = enum(u2) { + One4, + Two4, + Three4, + Four4, +}; + +const BitFieldOfEnums = packed struct { + a: A, + b: B, + c: C, +}; + +const bit_field_1 = BitFieldOfEnums{ + .a = A.Two, + .b = B.Three3, + .c = C.Four4, +}; + +test "bit field access with enum fields" { + var data = bit_field_1; + assertOrPanic(getA(&data) == A.Two); + assertOrPanic(getB(&data) == B.Three3); + assertOrPanic(getC(&data) == C.Four4); + comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1); + + data.b = B.Four3; + assertOrPanic(data.b == B.Four3); + + data.a = A.Three; + assertOrPanic(data.a == A.Three); + assertOrPanic(data.b == B.Four3); +} + +fn getA(data: *const BitFieldOfEnums) A { + return data.a; +} + +fn getB(data: *const BitFieldOfEnums) B { + return data.b; +} + +fn getC(data: *const BitFieldOfEnums) C { + return data.c; +} + +test "casting enum to its tag type" { + testCastEnumToTagType(Small2.Two); + comptime testCastEnumToTagType(Small2.Two); +} + +fn testCastEnumToTagType(value: Small2) void { + assertOrPanic(@enumToInt(value) == 1); +} + +const MultipleChoice = enum(u32) { + A = 20, + B = 40, + C = 60, + D = 1000, +}; + +test "enum with specified tag values" { + testEnumWithSpecifiedTagValues(MultipleChoice.C); + comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); +} + +fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { + assertOrPanic(@enumToInt(x) == 60); + assertOrPanic(1234 == switch (x) { + MultipleChoice.A => 1, + MultipleChoice.B => 2, + MultipleChoice.C => u32(1234), + MultipleChoice.D => 4, + }); +} + +const MultipleChoice2 = enum(u32) { + Unspecified1, + A = 20, + Unspecified2, + B = 40, + Unspecified3, + C = 60, + Unspecified4, + D = 1000, + Unspecified5, +}; + +test "enum with specified and unspecified tag values" { + testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); + comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); +} + +fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { + assertOrPanic(@enumToInt(x) == 1000); + assertOrPanic(1234 == switch (x) { + MultipleChoice2.A => 1, + MultipleChoice2.B => 2, + MultipleChoice2.C => 3, + MultipleChoice2.D => u32(1234), + MultipleChoice2.Unspecified1 => 5, + MultipleChoice2.Unspecified2 => 6, + MultipleChoice2.Unspecified3 => 7, + MultipleChoice2.Unspecified4 => 8, + MultipleChoice2.Unspecified5 => 9, + }); +} + +test "cast integer literal to enum" { + assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); + assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); +} + +const EnumWithOneMember = enum { + Eof, +}; + +fn doALoopThing(id: EnumWithOneMember) void { + while (true) { + if (id == EnumWithOneMember.Eof) { + break; + } + @compileError("above if condition should be comptime"); + } +} + +test "comparison operator on enum with one member is comptime known" { + doALoopThing(EnumWithOneMember.Eof); +} + +const State = enum { + Start, +}; +test "switch on enum with one member is comptime known" { + var state = State.Start; + switch (state) { + State.Start => return, + } + @compileError("analysis should not reach here"); +} + +const EnumWithTagValues = enum(u4) { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = 1 << 3, +}; +test "enum with tag values don't require parens" { + assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100); +} + +test "enum with 1 field but explicit tag type should still have the tag type" { + const Enum = enum(u8) { + B = 2, + }; + comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8)); +} + +test "empty extern enum with members" { + const E = extern enum { + A, + B, + C, + }; + assertOrPanic(@sizeOf(E) == @sizeOf(c_int)); +} + +test "tag name with assigned enum values" { + const LocalFoo = enum { + A = 1, + B = 0, + }; + var b = LocalFoo.B; + assertOrPanic(mem.eql(u8, @tagName(b), "B")); +} diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig new file mode 100644 index 0000000000..49af1ceae7 --- /dev/null +++ b/test/stage1/behavior/enum_with_members.zig @@ -0,0 +1,27 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; +const fmt = @import("std").fmt; + +const ET = union(enum) { + SINT: i32, + UINT: u32, + + pub fn print(a: *const ET, buf: []u8) anyerror!usize { + return switch (a.*) { + ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), + ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, 0), + }; + } +}; + +test "enum with members" { + const a = ET{ .SINT = -42 }; + const b = ET{ .UINT = 42 }; + var buf: [20]u8 = undefined; + + assertOrPanic((a.print(buf[0..]) catch unreachable) == 3); + assertOrPanic(mem.eql(u8, buf[0..3], "-42")); + + assertOrPanic((b.print(buf[0..]) catch unreachable) == 2); + assertOrPanic(mem.eql(u8, buf[0..2], "42")); +} diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig new file mode 100644 index 0000000000..c7e38712bc --- /dev/null +++ b/test/stage1/behavior/error.zig @@ -0,0 +1,332 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const assertError = std.debug.assertError; +const mem = std.mem; +const builtin = @import("builtin"); + +pub fn foo() anyerror!i32 { + const x = try bar(); + return x + 1; +} + +pub fn bar() anyerror!i32 { + return 13; +} + +pub fn baz() anyerror!i32 { + const y = foo() catch 1234; + return y + 1; +} + +test "error wrapping" { + assertOrPanic((baz() catch unreachable) == 15); +} + +fn gimmeItBroke() []const u8 { + return @errorName(error.ItBroke); +} + +test "@errorName" { + assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError")); + assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); +} + +test "error values" { + const a = @errorToInt(error.err1); + const b = @errorToInt(error.err2); + assertOrPanic(a != b); +} + +test "redefinition of error values allowed" { + shouldBeNotEqual(error.AnError, error.SecondError); +} +fn shouldBeNotEqual(a: anyerror, b: anyerror) void { + if (a == b) unreachable; +} + +test "error binary operator" { + const a = errBinaryOperatorG(true) catch 3; + const b = errBinaryOperatorG(false) catch 3; + assertOrPanic(a == 3); + assertOrPanic(b == 10); +} +fn errBinaryOperatorG(x: bool) anyerror!isize { + return if (x) error.ItBroke else isize(10); +} + +test "unwrap simple value from error" { + const i = unwrapSimpleValueFromErrorDo() catch unreachable; + assertOrPanic(i == 13); +} +fn unwrapSimpleValueFromErrorDo() anyerror!isize { + return 13; +} + +test "error return in assignment" { + doErrReturnInAssignment() catch unreachable; +} + +fn doErrReturnInAssignment() anyerror!void { + var x: i32 = undefined; + x = try makeANonErr(); +} + +fn makeANonErr() anyerror!i32 { + return 1; +} + +test "error union type " { + testErrorUnionType(); + comptime testErrorUnionType(); +} + +fn testErrorUnionType() void { + const x: anyerror!i32 = 1234; + if (x) |value| assertOrPanic(value == 1234) else |_| unreachable; + assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); + assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); + assertOrPanic(@typeOf(x).ErrorSet == anyerror); +} + +test "error set type" { + testErrorSetType(); + comptime testErrorSetType(); +} + +const MyErrSet = error{ + OutOfMemory, + FileNotFound, +}; + +fn testErrorSetType() void { + assertOrPanic(@memberCount(MyErrSet) == 2); + + const a: MyErrSet!i32 = 5678; + const b: MyErrSet!i32 = MyErrSet.OutOfMemory; + + if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) { + error.OutOfMemory => unreachable, + error.FileNotFound => unreachable, + } +} + +test "explicit error set cast" { + testExplicitErrorSetCast(Set1.A); + comptime testExplicitErrorSetCast(Set1.A); +} + +const Set1 = error{ + A, + B, +}; +const Set2 = error{ + A, + C, +}; + +fn testExplicitErrorSetCast(set1: Set1) void { + var x = @errSetCast(Set2, set1); + var y = @errSetCast(Set1, x); + assertOrPanic(y == error.A); +} + +test "comptime test error for empty error set" { + testComptimeTestErrorEmptySet(1234); + comptime testComptimeTestErrorEmptySet(1234); +} + +const EmptyErrorSet = error{}; + +fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { + if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad"); +} + +test "syntax: optional operator in front of error union operator" { + comptime { + assertOrPanic(?(anyerror!i32) == ?(anyerror!i32)); + } +} + +test "comptime err to int of error set with only 1 possible value" { + testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); + comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A)); +} +fn testErrToIntWithOnePossibleValue( + x: error{A}, + comptime value: u32, +) void { + if (@errorToInt(x) != value) { + @compileError("bad"); + } +} + +test "error union peer type resolution" { + testErrorUnionPeerTypeResolution(1); +} + +fn testErrorUnionPeerTypeResolution(x: i32) void { + const y = switch (x) { + 1 => bar_1(), + 2 => baz_1(), + else => quux_1(), + }; + if (y) |_| { + @panic("expected error"); + } else |e| { + assertOrPanic(e == error.A); + } +} + +fn bar_1() anyerror { + return error.A; +} + +fn baz_1() !i32 { + return error.B; +} + +fn quux_1() !i32 { + return error.C; +} + +test "error: fn returning empty error set can be passed as fn returning any error" { + entry(); + comptime entry(); +} + +fn entry() void { + foo2(bar2); +} + +fn foo2(f: fn () anyerror!void) void { + const x = f(); +} + +fn bar2() (error{}!void) {} + +test "error: Zero sized error set returned with value payload crash" { + _ = foo3(0); + _ = comptime foo3(0); +} + +const Error = error{}; +fn foo3(b: usize) Error!usize { + return b; +} + +test "error: Infer error set from literals" { + _ = nullLiteral("n") catch |err| handleErrors(err); + _ = floatLiteral("n") catch |err| handleErrors(err); + _ = intLiteral("n") catch |err| handleErrors(err); + _ = comptime nullLiteral("n") catch |err| handleErrors(err); + _ = comptime floatLiteral("n") catch |err| handleErrors(err); + _ = comptime intLiteral("n") catch |err| handleErrors(err); +} + +fn handleErrors(err: var) noreturn { + switch (err) { + error.T => {}, + } + + unreachable; +} + +fn nullLiteral(str: []const u8) !?i64 { + if (str[0] == 'n') return null; + + return error.T; +} + +fn floatLiteral(str: []const u8) !?f64 { + if (str[0] == 'n') return 1.0; + + return error.T; +} + +fn intLiteral(str: []const u8) !?i64 { + if (str[0] == 'n') return 1; + + return error.T; +} + +test "nested error union function call in optional unwrap" { + const S = struct { + const Foo = struct { + a: i32, + }; + + fn errorable() !i32 { + var x: Foo = (try getFoo()) orelse return error.Other; + return x.a; + } + + fn errorable2() !i32 { + var x: Foo = (try getFoo2()) orelse return error.Other; + return x.a; + } + + fn errorable3() !i32 { + var x: Foo = (try getFoo3()) orelse return error.Other; + return x.a; + } + + fn getFoo() anyerror!?Foo { + return Foo{ .a = 1234 }; + } + + fn getFoo2() anyerror!?Foo { + return error.Failure; + } + + fn getFoo3() anyerror!?Foo { + return null; + } + }; + assertOrPanic((try S.errorable()) == 1234); + assertError(S.errorable2(), error.Failure); + assertError(S.errorable3(), error.Other); + comptime { + assertOrPanic((try S.errorable()) == 1234); + assertError(S.errorable2(), error.Failure); + assertError(S.errorable3(), error.Other); + } +} + +test "widen cast integer payload of error union function call" { + const S = struct { + fn errorable() !u64 { + var x = u64(try number()); + return x; + } + + fn number() anyerror!u32 { + return 1234; + } + }; + assertOrPanic((try S.errorable()) == 1234); +} + +test "return function call to error set from error union function" { + const S = struct { + fn errorable() anyerror!i32 { + return fail(); + } + + fn fail() anyerror { + return error.Failure; + } + }; + assertError(S.errorable(), error.Failure); + comptime assertError(S.errorable(), error.Failure); +} + +test "optional error set is the same size as error set" { + comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror)); + const S = struct { + fn returnsOptErrSet() ?anyerror { + return null; + } + }; + assertOrPanic(S.returnsOptErrSet() == null); + comptime assertOrPanic(S.returnsOptErrSet() == null); +} diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig new file mode 100644 index 0000000000..2d8494eb0b --- /dev/null +++ b/test/stage1/behavior/eval.zig @@ -0,0 +1,784 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const builtin = @import("builtin"); + +test "compile time recursion" { + assertOrPanic(some_data.len == 21); +} +var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; +fn fibonacci(x: i32) i32 { + if (x <= 1) return 1; + return fibonacci(x - 1) + fibonacci(x - 2); +} + +fn unwrapAndAddOne(blah: ?i32) i32 { + return blah.? + 1; +} +const should_be_1235 = unwrapAndAddOne(1234); +test "static add one" { + assertOrPanic(should_be_1235 == 1235); +} + +test "inlined loop" { + comptime var i = 0; + comptime var sum = 0; + inline while (i <= 5) : (i += 1) + sum += i; + assertOrPanic(sum == 15); +} + +fn gimme1or2(comptime a: bool) i32 { + const x: i32 = 1; + const y: i32 = 2; + comptime var z: i32 = if (a) x else y; + return z; +} +test "inline variable gets result of const if" { + assertOrPanic(gimme1or2(true) == 1); + assertOrPanic(gimme1or2(false) == 2); +} + +test "static function evaluation" { + assertOrPanic(statically_added_number == 3); +} +const statically_added_number = staticAdd(1, 2); +fn staticAdd(a: i32, b: i32) i32 { + return a + b; +} + +test "const expr eval on single expr blocks" { + assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); +} + +fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { + const literal = 3; + + const result = if (b) b: { + break :b literal; + } else b: { + break :b x; + }; + + return result; +} + +test "statically initialized list" { + assertOrPanic(static_point_list[0].x == 1); + assertOrPanic(static_point_list[0].y == 2); + assertOrPanic(static_point_list[1].x == 3); + assertOrPanic(static_point_list[1].y == 4); +} +const Point = struct { + x: i32, + y: i32, +}; +const static_point_list = []Point{ + makePoint(1, 2), + makePoint(3, 4), +}; +fn makePoint(x: i32, y: i32) Point { + return Point{ + .x = x, + .y = y, + }; +} + +test "static eval list init" { + assertOrPanic(static_vec3.data[2] == 1.0); + assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0); +} +const static_vec3 = vec3(0.0, 0.0, 1.0); +pub const Vec3 = struct { + data: [3]f32, +}; +pub fn vec3(x: f32, y: f32, z: f32) Vec3 { + return Vec3{ .data = []f32{ + x, + y, + z, + } }; +} + +test "constant expressions" { + var array: [array_size]u8 = undefined; + assertOrPanic(@sizeOf(@typeOf(array)) == 20); +} +const array_size: u8 = 20; + +test "constant struct with negation" { + assertOrPanic(vertices[0].x == -0.6); +} +const Vertex = struct { + x: f32, + y: f32, + r: f32, + g: f32, + b: f32, +}; +const vertices = []Vertex{ + Vertex{ + .x = -0.6, + .y = -0.4, + .r = 1.0, + .g = 0.0, + .b = 0.0, + }, + Vertex{ + .x = 0.6, + .y = -0.4, + .r = 0.0, + .g = 1.0, + .b = 0.0, + }, + Vertex{ + .x = 0.0, + .y = 0.6, + .r = 0.0, + .g = 0.0, + .b = 1.0, + }, +}; + +test "statically initialized struct" { + st_init_str_foo.x += 1; + assertOrPanic(st_init_str_foo.x == 14); +} +const StInitStrFoo = struct { + x: i32, + y: bool, +}; +var st_init_str_foo = StInitStrFoo{ + .x = 13, + .y = true, +}; + +test "statically initalized array literal" { + const y: [4]u8 = st_init_arr_lit_x; + assertOrPanic(y[3] == 4); +} +const st_init_arr_lit_x = []u8{ + 1, + 2, + 3, + 4, +}; + +test "const slice" { + comptime { + const a = "1234567890"; + assertOrPanic(a.len == 10); + const b = a[1..2]; + assertOrPanic(b.len == 1); + assertOrPanic(b[0] == '2'); + } +} + +test "try to trick eval with runtime if" { + assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10); +} + +fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { + comptime var i: usize = 0; + inline while (i < 10) : (i += 1) { + const result = if (b) false else true; + } + comptime { + return i; + } +} + +fn max(comptime T: type, a: T, b: T) T { + if (T == bool) { + return a or b; + } else if (a > b) { + return a; + } else { + return b; + } +} +fn letsTryToCompareBools(a: bool, b: bool) bool { + return max(bool, a, b); +} +test "inlined block and runtime block phi" { + assertOrPanic(letsTryToCompareBools(true, true)); + assertOrPanic(letsTryToCompareBools(true, false)); + assertOrPanic(letsTryToCompareBools(false, true)); + assertOrPanic(!letsTryToCompareBools(false, false)); + + comptime { + assertOrPanic(letsTryToCompareBools(true, true)); + assertOrPanic(letsTryToCompareBools(true, false)); + assertOrPanic(letsTryToCompareBools(false, true)); + assertOrPanic(!letsTryToCompareBools(false, false)); + } +} + +const CmdFn = struct { + name: []const u8, + func: fn (i32) i32, +}; + +const cmd_fns = []CmdFn{ + CmdFn{ + .name = "one", + .func = one, + }, + CmdFn{ + .name = "two", + .func = two, + }, + CmdFn{ + .name = "three", + .func = three, + }, +}; +fn one(value: i32) i32 { + return value + 1; +} +fn two(value: i32) i32 { + return value + 2; +} +fn three(value: i32) i32 { + return value + 3; +} + +fn performFn(comptime prefix_char: u8, start_value: i32) i32 { + var result: i32 = start_value; + comptime var i = 0; + inline while (i < cmd_fns.len) : (i += 1) { + if (cmd_fns[i].name[0] == prefix_char) { + result = cmd_fns[i].func(result); + } + } + return result; +} + +test "comptime iterate over fn ptr list" { + assertOrPanic(performFn('t', 1) == 6); + assertOrPanic(performFn('o', 0) == 1); + assertOrPanic(performFn('w', 99) == 99); +} + +test "eval @setRuntimeSafety at compile-time" { + const result = comptime fnWithSetRuntimeSafety(); + assertOrPanic(result == 1234); +} + +fn fnWithSetRuntimeSafety() i32 { + @setRuntimeSafety(true); + return 1234; +} + +test "eval @setFloatMode at compile-time" { + const result = comptime fnWithFloatMode(); + assertOrPanic(result == 1234.0); +} + +fn fnWithFloatMode() f32 { + @setFloatMode(builtin.FloatMode.Strict); + return 1234.0; +} + +const SimpleStruct = struct { + field: i32, + + fn method(self: *const SimpleStruct) i32 { + return self.field + 3; + } +}; + +var simple_struct = SimpleStruct{ .field = 1234 }; + +const bound_fn = simple_struct.method; + +test "call method on bound fn referring to var instance" { + assertOrPanic(bound_fn() == 1237); +} + +test "ptr to local array argument at comptime" { + comptime { + var bytes: [10]u8 = undefined; + modifySomeBytes(bytes[0..]); + assertOrPanic(bytes[0] == 'a'); + assertOrPanic(bytes[9] == 'b'); + } +} + +fn modifySomeBytes(bytes: []u8) void { + bytes[0] = 'a'; + bytes[9] = 'b'; +} + +test "comparisons 0 <= uint and 0 > uint should be comptime" { + testCompTimeUIntComparisons(1234); +} +fn testCompTimeUIntComparisons(x: u32) void { + if (!(0 <= x)) { + @compileError("this condition should be comptime known"); + } + if (0 > x) { + @compileError("this condition should be comptime known"); + } + if (!(x >= 0)) { + @compileError("this condition should be comptime known"); + } + if (x < 0) { + @compileError("this condition should be comptime known"); + } +} + +test "const ptr to variable data changes at runtime" { + assertOrPanic(foo_ref.name[0] == 'a'); + foo_ref.name = "b"; + assertOrPanic(foo_ref.name[0] == 'b'); +} + +const Foo = struct { + name: []const u8, +}; + +var foo_contents = Foo{ .name = "a" }; +const foo_ref = &foo_contents; + +test "create global array with for loop" { + assertOrPanic(global_array[5] == 5 * 5); + assertOrPanic(global_array[9] == 9 * 9); +} + +const global_array = x: { + var result: [10]usize = undefined; + for (result) |*item, index| { + item.* = index * index; + } + break :x result; +}; + +test "compile-time downcast when the bits fit" { + comptime { + const spartan_count: u16 = 255; + const byte = @intCast(u8, spartan_count); + assertOrPanic(byte == 255); + } +} + +const hi1 = "hi"; +const hi2 = hi1; +test "const global shares pointer with other same one" { + assertEqualPtrs(&hi1[0], &hi2[0]); + comptime assertOrPanic(&hi1[0] == &hi2[0]); +} +fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { + assertOrPanic(ptr1 == ptr2); +} + +test "@setEvalBranchQuota" { + comptime { + // 1001 for the loop and then 1 more for the assertOrPanic fn call + @setEvalBranchQuota(1002); + var i = 0; + var sum = 0; + while (i < 1001) : (i += 1) { + sum += i; + } + assertOrPanic(sum == 500500); + } +} + +// TODO test "float literal at compile time not lossy" { +// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0); +// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0); +// TODO } + +test "f32 at compile time is lossy" { + assertOrPanic(f32(1 << 24) + 1 == 1 << 24); +} + +test "f64 at compile time is lossy" { + assertOrPanic(f64(1 << 53) + 1 == 1 << 53); +} + +test "f128 at compile time is lossy" { + assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); +} + +comptime { + assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192); +} + +pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { + return struct { + pub const Node = struct {}; + }; +} + +test "string literal used as comptime slice is memoized" { + const a = "link"; + const b = "link"; + comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); + comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); +} + +test "comptime slice of undefined pointer of length 0" { + const slice1 = ([*]i32)(undefined)[0..0]; + assertOrPanic(slice1.len == 0); + const slice2 = ([*]i32)(undefined)[100..100]; + assertOrPanic(slice2.len == 0); +} + +fn copyWithPartialInline(s: []u32, b: []u8) void { + comptime var i: usize = 0; + inline while (i < 4) : (i += 1) { + s[i] = 0; + s[i] |= u32(b[i * 4 + 0]) << 24; + s[i] |= u32(b[i * 4 + 1]) << 16; + s[i] |= u32(b[i * 4 + 2]) << 8; + s[i] |= u32(b[i * 4 + 3]) << 0; + } +} + +test "binary math operator in partially inlined function" { + var s: [4]u32 = undefined; + var b: [16]u8 = undefined; + + for (b) |*r, i| + r.* = @intCast(u8, i + 1); + + copyWithPartialInline(s[0..], b[0..]); + assertOrPanic(s[0] == 0x1020304); + assertOrPanic(s[1] == 0x5060708); + assertOrPanic(s[2] == 0x90a0b0c); + assertOrPanic(s[3] == 0xd0e0f10); +} + +test "comptime function with the same args is memoized" { + comptime { + assertOrPanic(MakeType(i32) == MakeType(i32)); + assertOrPanic(MakeType(i32) != MakeType(f64)); + } +} + +fn MakeType(comptime T: type) type { + return struct { + field: T, + }; +} + +test "comptime function with mutable pointer is not memoized" { + comptime { + var x: i32 = 1; + const ptr = &x; + increment(ptr); + increment(ptr); + assertOrPanic(x == 3); + } +} + +fn increment(value: *i32) void { + value.* += 1; +} + +fn generateTable(comptime T: type) [1010]T { + var res: [1010]T = undefined; + var i: usize = 0; + while (i < 1010) : (i += 1) { + res[i] = @intCast(T, i); + } + return res; +} + +fn doesAlotT(comptime T: type, value: usize) T { + @setEvalBranchQuota(5000); + const table = comptime blk: { + break :blk generateTable(T); + }; + return table[value]; +} + +test "@setEvalBranchQuota at same scope as generic function call" { + assertOrPanic(doesAlotT(u32, 2) == 2); +} + +test "comptime slice of slice preserves comptime var" { + comptime { + var buff: [10]u8 = undefined; + buff[0..][0..][0] = 1; + assertOrPanic(buff[0..][0..][0] == 1); + } +} + +test "comptime slice of pointer preserves comptime var" { + comptime { + var buff: [10]u8 = undefined; + var a = buff[0..].ptr; + a[0..1][0] = 1; + assertOrPanic(buff[0..][0..][0] == 1); + } +} + +const SingleFieldStruct = struct { + x: i32, + + fn read_x(self: *const SingleFieldStruct) i32 { + return self.x; + } +}; +test "const ptr to comptime mutable data is not memoized" { + comptime { + var foo = SingleFieldStruct{ .x = 1 }; + assertOrPanic(foo.read_x() == 1); + foo.x = 2; + assertOrPanic(foo.read_x() == 2); + } +} + +test "array concat of slices gives slice" { + comptime { + var a: []const u8 = "aoeu"; + var b: []const u8 = "asdf"; + const c = a ++ b; + assertOrPanic(std.mem.eql(u8, c, "aoeuasdf")); + } +} + +test "comptime shlWithOverflow" { + const ct_shifted: u64 = comptime amt: { + var amt = u64(0); + _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); + break :amt amt; + }; + + const rt_shifted: u64 = amt: { + var amt = u64(0); + _ = @shlWithOverflow(u64, ~u64(0), 16, &amt); + break :amt amt; + }; + + assertOrPanic(ct_shifted == rt_shifted); +} + +test "runtime 128 bit integer division" { + var a: u128 = 152313999999999991610955792383; + var b: u128 = 10000000000000000000; + var c = a / b; + assertOrPanic(c == 15231399999); +} + +pub const Info = struct { + version: u8, +}; + +pub const diamond_info = Info{ .version = 0 }; + +test "comptime modification of const struct field" { + comptime { + var res = diamond_info; + res.version = 1; + assertOrPanic(diamond_info.version == 0); + assertOrPanic(res.version == 1); + } +} + +test "pointer to type" { + comptime { + var T: type = i32; + assertOrPanic(T == i32); + var ptr = &T; + assertOrPanic(@typeOf(ptr) == *type); + ptr.* = f32; + assertOrPanic(T == f32); + assertOrPanic(*T == *f32); + } +} + +test "slice of type" { + comptime { + var types_array = []type{ i32, f64, type }; + for (types_array) |T, i| { + switch (i) { + 0 => assertOrPanic(T == i32), + 1 => assertOrPanic(T == f64), + 2 => assertOrPanic(T == type), + else => unreachable, + } + } + for (types_array[0..]) |T, i| { + switch (i) { + 0 => assertOrPanic(T == i32), + 1 => assertOrPanic(T == f64), + 2 => assertOrPanic(T == type), + else => unreachable, + } + } + } +} + +const Wrapper = struct { + T: type, +}; + +fn wrap(comptime T: type) Wrapper { + return Wrapper{ .T = T }; +} + +test "function which returns struct with type field causes implicit comptime" { + const ty = wrap(i32).T; + assertOrPanic(ty == i32); +} + +test "call method with comptime pass-by-non-copying-value self parameter" { + const S = struct { + a: u8, + + fn b(comptime s: @This()) u8 { + return s.a; + } + }; + + const s = S{ .a = 2 }; + var b = s.b(); + assertOrPanic(b == 2); +} + +test "@tagName of @typeId" { + const str = @tagName(@typeId(u8)); + assertOrPanic(std.mem.eql(u8, str, "Int")); +} + +test "setting backward branch quota just before a generic fn call" { + @setEvalBranchQuota(1001); + loopNTimes(1001); +} + +fn loopNTimes(comptime n: usize) void { + comptime var i = 0; + inline while (i < n) : (i += 1) {} +} + +test "variable inside inline loop that has different types on different iterations" { + testVarInsideInlineLoop(true, u32(42)); +} + +fn testVarInsideInlineLoop(args: ...) void { + comptime var i = 0; + inline while (i < args.len) : (i += 1) { + const x = args[i]; + if (i == 0) assertOrPanic(x); + if (i == 1) assertOrPanic(x == 42); + } +} + +test "inline for with same type but different values" { + var res: usize = 0; + inline for ([]type{ [2]u8, [1]u8, [2]u8 }) |T| { + var a: T = undefined; + res += a.len; + } + assertOrPanic(res == 5); +} + +test "refer to the type of a generic function" { + const Func = fn (type) void; + const f: Func = doNothingWithType; + f(i32); +} + +fn doNothingWithType(comptime T: type) void {} + +test "zero extend from u0 to u1" { + var zero_u0: u0 = 0; + var zero_u1: u1 = zero_u0; + assertOrPanic(zero_u1 == 0); +} + +test "bit shift a u1" { + var x: u1 = 1; + var y = x << 0; + assertOrPanic(y == 1); +} + +test "@intCast to a u0" { + var x: u8 = 0; + var y: u0 = @intCast(u0, x); + assertOrPanic(y == 0); +} + +test "@bytesToslice on a packed struct" { + const F = packed struct { + a: u8, + }; + + var b = [1]u8{9}; + var f = @bytesToSlice(F, b); + assertOrPanic(f[0].a == 9); +} + +test "comptime pointer cast array and then slice" { + const array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; + + const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); + const sliceA: []const u8 = ptrA[0..2]; + + const ptrB: [*]const u8 = &array; + const sliceB: []const u8 = ptrB[0..2]; + + assertOrPanic(sliceA[1] == 2); + assertOrPanic(sliceB[1] == 2); +} + +test "slice bounds in comptime concatenation" { + const bs = comptime blk: { + const b = c"11"; + break :blk b[0..1]; + }; + const str = "" ++ bs; + assertOrPanic(str.len == 1); + assertOrPanic(std.mem.eql(u8, str, "1")); + + const str2 = bs ++ ""; + assertOrPanic(str2.len == 1); + assertOrPanic(std.mem.eql(u8, str2, "1")); +} + +test "comptime bitwise operators" { + comptime { + assertOrPanic(3 & 1 == 1); + assertOrPanic(3 & -1 == 3); + assertOrPanic(-3 & -1 == -3); + assertOrPanic(3 | -1 == -1); + assertOrPanic(-3 | -1 == -1); + assertOrPanic(3 ^ -1 == -4); + assertOrPanic(-3 ^ -1 == 2); + assertOrPanic(~i8(-1) == 0); + assertOrPanic(~i128(-1) == 0); + assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611); + assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); + assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff); + } +} + +test "*align(1) u16 is the same as *align(1:0:2) u16" { + comptime { + assertOrPanic(*align(1:0:2) u16 == *align(1) u16); + // TODO add parsing support for this syntax + //assertOrPanic(*align(:0:2) u16 == *u16); + } +} + +test "array concatenation forces comptime" { + var a = oneItem(3) ++ oneItem(4); + assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 })); +} + +test "array multiplication forces comptime" { + var a = oneItem(3) ** scalar(2); + assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 })); +} + +fn oneItem(x: i32) [1]i32 { + return []i32{x}; +} + +fn scalar(x: u32) u32 { + return x; +} diff --git a/test/stage1/behavior/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig new file mode 100644 index 0000000000..ed2487c020 --- /dev/null +++ b/test/stage1/behavior/field_parent_ptr.zig @@ -0,0 +1,41 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@fieldParentPtr non-first field" { + testParentFieldPtr(&foo.c); + comptime testParentFieldPtr(&foo.c); +} + +test "@fieldParentPtr first field" { + testParentFieldPtrFirst(&foo.a); + comptime testParentFieldPtrFirst(&foo.a); +} + +const Foo = struct { + a: bool, + b: f32, + c: i32, + d: i32, +}; + +const foo = Foo{ + .a = true, + .b = 0.123, + .c = 1234, + .d = -10, +}; + +fn testParentFieldPtr(c: *const i32) void { + assertOrPanic(c == &foo.c); + + const base = @fieldParentPtr(Foo, "c", c); + assertOrPanic(base == &foo); + assertOrPanic(&base.c == c); +} + +fn testParentFieldPtrFirst(a: *const bool) void { + assertOrPanic(a == &foo.a); + + const base = @fieldParentPtr(Foo, "a", a); + assertOrPanic(base == &foo); + assertOrPanic(&base.a == a); +} diff --git a/test/stage1/behavior/fn.zig b/test/stage1/behavior/fn.zig new file mode 100644 index 0000000000..3011bc41d0 --- /dev/null +++ b/test/stage1/behavior/fn.zig @@ -0,0 +1,208 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "params" { + assertOrPanic(testParamsAdd(22, 11) == 33); +} +fn testParamsAdd(a: i32, b: i32) i32 { + return a + b; +} + +test "local variables" { + testLocVars(2); +} +fn testLocVars(b: i32) void { + const a: i32 = 1; + if (a + b != 3) unreachable; +} + +test "void parameters" { + voidFun(1, void{}, 2, {}); +} +fn voidFun(a: i32, b: void, c: i32, d: void) void { + const v = b; + const vv: void = if (a == 1) v else {}; + assertOrPanic(a + c == 3); + return vv; +} + +test "mutable local variables" { + var zero: i32 = 0; + assertOrPanic(zero == 0); + + var i = i32(0); + while (i != 3) { + i += 1; + } + assertOrPanic(i == 3); +} + +test "separate block scopes" { + { + const no_conflict: i32 = 5; + assertOrPanic(no_conflict == 5); + } + + const c = x: { + const no_conflict = i32(10); + break :x no_conflict; + }; + assertOrPanic(c == 10); +} + +test "call function with empty string" { + acceptsString(""); +} + +fn acceptsString(foo: []u8) void {} + +fn @"weird function name"() i32 { + return 1234; +} +test "weird function name" { + assertOrPanic(@"weird function name"() == 1234); +} + +test "implicit cast function unreachable return" { + wantsFnWithVoid(fnWithUnreachable); +} + +fn wantsFnWithVoid(f: fn () void) void {} + +fn fnWithUnreachable() noreturn { + unreachable; +} + +test "function pointers" { + const fns = []@typeOf(fn1){ + fn1, + fn2, + fn3, + fn4, + }; + for (fns) |f, i| { + assertOrPanic(f() == @intCast(u32, i) + 5); + } +} +fn fn1() u32 { + return 5; +} +fn fn2() u32 { + return 6; +} +fn fn3() u32 { + return 7; +} +fn fn4() u32 { + return 8; +} + +test "inline function call" { + assertOrPanic(@inlineCall(add, 3, 9) == 12); +} + +fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "number literal as an argument" { + numberLiteralArg(3); + comptime numberLiteralArg(3); +} + +fn numberLiteralArg(a: var) void { + assertOrPanic(a == 3); +} + +test "assign inline fn to const variable" { + const a = inlineFn; + a(); +} + +inline fn inlineFn() void {} + +test "pass by non-copying value" { + assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); +} + +const Point = struct { + x: i32, + y: i32, +}; + +fn addPointCoords(pt: Point) i32 { + return pt.x + pt.y; +} + +test "pass by non-copying value through var arg" { + assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); +} + +fn addPointCoordsVar(pt: var) i32 { + comptime assertOrPanic(@typeOf(pt) == Point); + return pt.x + pt.y; +} + +test "pass by non-copying value as method" { + var pt = Point2{ .x = 1, .y = 2 }; + assertOrPanic(pt.addPointCoords() == 3); +} + +const Point2 = struct { + x: i32, + y: i32, + + fn addPointCoords(self: Point2) i32 { + return self.x + self.y; + } +}; + +test "pass by non-copying value as method, which is generic" { + var pt = Point3{ .x = 1, .y = 2 }; + assertOrPanic(pt.addPointCoords(i32) == 3); +} + +const Point3 = struct { + x: i32, + y: i32, + + fn addPointCoords(self: Point3, comptime T: type) i32 { + return self.x + self.y; + } +}; + +test "pass by non-copying value as method, at comptime" { + comptime { + var pt = Point2{ .x = 1, .y = 2 }; + assertOrPanic(pt.addPointCoords() == 3); + } +} + +fn outer(y: u32) fn (u32) u32 { + const Y = @typeOf(y); + const st = struct { + fn get(z: u32) u32 { + return z + @sizeOf(Y); + } + }; + return st.get; +} + +test "return inner function which references comptime variable of outer function" { + var func = outer(10); + assertOrPanic(func(3) == 7); +} + +test "extern struct with stdcallcc fn pointer" { + const S = extern struct { + ptr: stdcallcc fn () i32, + + stdcallcc fn foo() i32 { + return 1234; + } + }; + + var s: S = undefined; + s.ptr = S.foo; + assertOrPanic(s.ptr() == 1234); +} + diff --git a/test/stage1/behavior/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig new file mode 100644 index 0000000000..0af076d40a --- /dev/null +++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig @@ -0,0 +1,17 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +fn get_foo() fn (*u8) usize { + comptime { + return struct { + fn func(ptr: *u8) usize { + var u = @ptrToInt(ptr); + return u; + } + }.func; + } +} + +test "define a function in an anonymous struct in comptime" { + const foo = get_foo(); + assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345); +} diff --git a/test/stage1/behavior/for.zig b/test/stage1/behavior/for.zig new file mode 100644 index 0000000000..b6d1ef24c4 --- /dev/null +++ b/test/stage1/behavior/for.zig @@ -0,0 +1,106 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const mem = std.mem; + +test "continue in for loop" { + const array = []i32{ + 1, + 2, + 3, + 4, + 5, + }; + var sum: i32 = 0; + for (array) |x| { + sum += x; + if (x < 3) { + continue; + } + break; + } + if (sum != 6) unreachable; +} + +test "for loop with pointer elem var" { + const source = "abcdefg"; + var target: [source.len]u8 = undefined; + mem.copy(u8, target[0..], source); + mangleString(target[0..]); + assertOrPanic(mem.eql(u8, target, "bcdefgh")); +} +fn mangleString(s: []u8) void { + for (s) |*c| { + c.* += 1; + } +} + +test "basic for loop" { + const expected_result = []u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; + + var buffer: [expected_result.len]u8 = undefined; + var buf_index: usize = 0; + + const array = []u8{ 9, 8, 7, 6 }; + for (array) |item| { + buffer[buf_index] = item; + buf_index += 1; + } + for (array) |item, index| { + buffer[buf_index] = @intCast(u8, index); + buf_index += 1; + } + const array_ptr = &array; + for (array_ptr) |item| { + buffer[buf_index] = item; + buf_index += 1; + } + for (array_ptr) |item, index| { + buffer[buf_index] = @intCast(u8, index); + buf_index += 1; + } + const unknown_size: []const u8 = array; + for (unknown_size) |item| { + buffer[buf_index] = item; + buf_index += 1; + } + for (unknown_size) |item, index| { + buffer[buf_index] = @intCast(u8, index); + buf_index += 1; + } + + assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result)); +} + +test "break from outer for loop" { + testBreakOuter(); + comptime testBreakOuter(); +} + +fn testBreakOuter() void { + var array = "aoeu"; + var count: usize = 0; + outer: for (array) |_| { + for (array) |_| { + count += 1; + break :outer; + } + } + assertOrPanic(count == 1); +} + +test "continue outer for loop" { + testContinueOuter(); + comptime testContinueOuter(); +} + +fn testContinueOuter() void { + var array = "aoeu"; + var counter: usize = 0; + outer: for (array) |_| { + for (array) |_| { + counter += 1; + continue :outer; + } + } + assertOrPanic(counter == array.len); +} diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig new file mode 100644 index 0000000000..a0928634a7 --- /dev/null +++ b/test/stage1/behavior/generics.zig @@ -0,0 +1,151 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "simple generic fn" { + assertOrPanic(max(i32, 3, -1) == 3); + assertOrPanic(max(f32, 0.123, 0.456) == 0.456); + assertOrPanic(add(2, 3) == 5); +} + +fn max(comptime T: type, a: T, b: T) T { + return if (a > b) a else b; +} + +fn add(comptime a: i32, b: i32) i32 { + return (comptime a) + b; +} + +const the_max = max(u32, 1234, 5678); +test "compile time generic eval" { + assertOrPanic(the_max == 5678); +} + +fn gimmeTheBigOne(a: u32, b: u32) u32 { + return max(u32, a, b); +} + +fn shouldCallSameInstance(a: u32, b: u32) u32 { + return max(u32, a, b); +} + +fn sameButWithFloats(a: f64, b: f64) f64 { + return max(f64, a, b); +} + +test "fn with comptime args" { + assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678); + assertOrPanic(shouldCallSameInstance(34, 12) == 34); + assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49); +} + +test "var params" { + assertOrPanic(max_i32(12, 34) == 34); + assertOrPanic(max_f64(1.2, 3.4) == 3.4); +} + +comptime { + assertOrPanic(max_i32(12, 34) == 34); + assertOrPanic(max_f64(1.2, 3.4) == 3.4); +} + +fn max_var(a: var, b: var) @typeOf(a + b) { + return if (a > b) a else b; +} + +fn max_i32(a: i32, b: i32) i32 { + return max_var(a, b); +} + +fn max_f64(a: f64, b: f64) f64 { + return max_var(a, b); +} + +pub fn List(comptime T: type) type { + return SmallList(T, 8); +} + +pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type { + return struct { + items: []T, + length: usize, + prealloc_items: [STATIC_SIZE]T, + }; +} + +test "function with return type type" { + var list: List(i32) = undefined; + var list2: List(i32) = undefined; + list.length = 10; + list2.length = 10; + assertOrPanic(list.prealloc_items.len == 8); + assertOrPanic(list2.prealloc_items.len == 8); +} + +test "generic struct" { + var a1 = GenNode(i32){ + .value = 13, + .next = null, + }; + var b1 = GenNode(bool){ + .value = true, + .next = null, + }; + assertOrPanic(a1.value == 13); + assertOrPanic(a1.value == a1.getVal()); + assertOrPanic(b1.getVal()); +} +fn GenNode(comptime T: type) type { + return struct { + value: T, + next: ?*GenNode(T), + fn getVal(n: *const GenNode(T)) T { + return n.value; + } + }; +} + +test "const decls in struct" { + assertOrPanic(GenericDataThing(3).count_plus_one == 4); +} +fn GenericDataThing(comptime count: isize) type { + return struct { + const count_plus_one = count + 1; + }; +} + +test "use generic param in generic param" { + assertOrPanic(aGenericFn(i32, 3, 4) == 7); +} +fn aGenericFn(comptime T: type, comptime a: T, b: T) T { + return a + b; +} + +test "generic fn with implicit cast" { + assertOrPanic(getFirstByte(u8, []u8{13}) == 13); + assertOrPanic(getFirstByte(u16, []u16{ + 0, + 13, + }) == 0); +} +fn getByte(ptr: ?*const u8) u8 { + return ptr.?.*; +} +fn getFirstByte(comptime T: type, mem: []const T) u8 { + return getByte(@ptrCast(*const u8, &mem[0])); +} + +const foos = []fn (var) bool{ + foo1, + foo2, +}; + +fn foo1(arg: var) bool { + return arg; +} +fn foo2(arg: var) bool { + return !arg; +} + +test "array of generic fns" { + assertOrPanic(foos[0](true)); + assertOrPanic(!foos[1](true)); +} diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig new file mode 100644 index 0000000000..58d1b8fd73 --- /dev/null +++ b/test/stage1/behavior/if.zig @@ -0,0 +1,37 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "if statements" { + shouldBeEqual(1, 1); + firstEqlThird(2, 1, 2); +} +fn shouldBeEqual(a: i32, b: i32) void { + if (a != b) { + unreachable; + } else { + return; + } +} +fn firstEqlThird(a: i32, b: i32, c: i32) void { + if (a == b) { + unreachable; + } else if (b == c) { + unreachable; + } else if (a == c) { + return; + } else { + unreachable; + } +} + +test "else if expression" { + assertOrPanic(elseIfExpressionF(1) == 1); +} +fn elseIfExpressionF(c: u8) u8 { + if (c == 0) { + return 0; + } else if (c == 1) { + return 1; + } else { + return u8(2); + } +} diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig new file mode 100644 index 0000000000..736e4c219d --- /dev/null +++ b/test/stage1/behavior/import.zig @@ -0,0 +1,10 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const a_namespace = @import("import/a_namespace.zig"); + +test "call fn via namespace lookup" { + assertOrPanic(a_namespace.foo() == 1234); +} + +test "importing the same thing gives the same import" { + assertOrPanic(@import("std") == @import("std")); +} diff --git a/test/stage1/behavior/import/a_namespace.zig b/test/stage1/behavior/import/a_namespace.zig new file mode 100644 index 0000000000..042f1867a5 --- /dev/null +++ b/test/stage1/behavior/import/a_namespace.zig @@ -0,0 +1,3 @@ +pub fn foo() i32 { + return 1234; +} diff --git a/test/stage1/behavior/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig new file mode 100644 index 0000000000..d062311b2e --- /dev/null +++ b/test/stage1/behavior/incomplete_struct_param_tld.zig @@ -0,0 +1,30 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const A = struct { + b: B, +}; + +const B = struct { + c: C, +}; + +const C = struct { + x: i32, + + fn d(c: *const C) i32 { + return c.x; + } +}; + +fn foo(a: A) i32 { + return a.b.c.d(); +} + +test "incomplete struct param top level declaration" { + const a = A{ + .b = B{ + .c = C{ .x = 13 }, + }, + }; + assertOrPanic(foo(a) == 13); +} diff --git a/test/stage1/behavior/inttoptr.zig b/test/stage1/behavior/inttoptr.zig new file mode 100644 index 0000000000..bf657fc86a --- /dev/null +++ b/test/stage1/behavior/inttoptr.zig @@ -0,0 +1,26 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "casting random address to function pointer" { + randomAddressToFunction(); + comptime randomAddressToFunction(); +} + +fn randomAddressToFunction() void { + var addr: usize = 0xdeadbeef; + var ptr = @intToPtr(fn () void, addr); +} + +test "mutate through ptr initialized with constant intToPtr value" { + forceCompilerAnalyzeBranchHardCodedPtrDereference(false); +} + +fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { + const hardCodedP = @intToPtr(*volatile u8, 0xdeadbeef); + if (x) { + hardCodedP.* = hardCodedP.* | 10; + } else { + return; + } +} diff --git a/test/stage1/behavior/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig new file mode 100644 index 0000000000..bc61e11df7 --- /dev/null +++ b/test/stage1/behavior/ir_block_deps.zig @@ -0,0 +1,21 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +fn foo(id: u64) !i32 { + return switch (id) { + 1 => getErrInt(), + 2 => { + const size = try getErrInt(); + return try getErrInt(); + }, + else => error.ItBroke, + }; +} + +fn getErrInt() anyerror!i32 { + return 0; +} + +test "ir block deps" { + assertOrPanic((foo(1) catch unreachable) == 0); + assertOrPanic((foo(2) catch unreachable) == 0); +} diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig new file mode 100644 index 0000000000..9d6a5a4997 --- /dev/null +++ b/test/stage1/behavior/math.zig @@ -0,0 +1,500 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const maxInt = std.math.maxInt; +const minInt = std.math.minInt; + +test "division" { + testDivision(); + comptime testDivision(); +} +fn testDivision() void { + assertOrPanic(div(u32, 13, 3) == 4); + assertOrPanic(div(f16, 1.0, 2.0) == 0.5); + assertOrPanic(div(f32, 1.0, 2.0) == 0.5); + + assertOrPanic(divExact(u32, 55, 11) == 5); + assertOrPanic(divExact(i32, -55, 11) == -5); + assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0); + assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0); + assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0); + assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0); + + assertOrPanic(divFloor(i32, 5, 3) == 1); + assertOrPanic(divFloor(i32, -5, 3) == -2); + assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0); + assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0); + assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0); + assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0); + assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000); + assertOrPanic(divFloor(i32, 0, -0x80000000) == 0); + assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2); + assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000); + + assertOrPanic(divTrunc(i32, 5, 3) == 1); + assertOrPanic(divTrunc(i32, -5, 3) == -1); + assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0); + assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0); + assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0); + assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0); + + comptime { + assertOrPanic( + 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, + ); + assertOrPanic( + @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, + ); + assertOrPanic( + 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, + ); + assertOrPanic( + @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, + ); + assertOrPanic( + @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, + ); + assertOrPanic( + @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, + ); + assertOrPanic( + 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, + ); + } +} +fn div(comptime T: type, a: T, b: T) T { + return a / b; +} +fn divExact(comptime T: type, a: T, b: T) T { + return @divExact(a, b); +} +fn divFloor(comptime T: type, a: T, b: T) T { + return @divFloor(a, b); +} +fn divTrunc(comptime T: type, a: T, b: T) T { + return @divTrunc(a, b); +} + +test "@addWithOverflow" { + var result: u8 = undefined; + assertOrPanic(@addWithOverflow(u8, 250, 100, &result)); + assertOrPanic(!@addWithOverflow(u8, 100, 150, &result)); + assertOrPanic(result == 250); +} + +// TODO test mulWithOverflow +// TODO test subWithOverflow + +test "@shlWithOverflow" { + var result: u16 = undefined; + assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); + assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); + assertOrPanic(result == 0b1011111111111100); +} + +test "@clz" { + testClz(); + comptime testClz(); +} + +fn testClz() void { + assertOrPanic(clz(u8(0b00001010)) == 4); + assertOrPanic(clz(u8(0b10001010)) == 0); + assertOrPanic(clz(u8(0b00000000)) == 8); + assertOrPanic(clz(u128(0xffffffffffffffff)) == 64); + assertOrPanic(clz(u128(0x10000000000000000)) == 63); +} + +fn clz(x: var) usize { + return @clz(x); +} + +test "@ctz" { + testCtz(); + comptime testCtz(); +} + +fn testCtz() void { + assertOrPanic(ctz(u8(0b10100000)) == 5); + assertOrPanic(ctz(u8(0b10001010)) == 1); + assertOrPanic(ctz(u8(0b00000000)) == 8); +} + +fn ctz(x: var) usize { + return @ctz(x); +} + +test "assignment operators" { + var i: u32 = 0; + i += 5; + assertOrPanic(i == 5); + i -= 2; + assertOrPanic(i == 3); + i *= 20; + assertOrPanic(i == 60); + i /= 3; + assertOrPanic(i == 20); + i %= 11; + assertOrPanic(i == 9); + i <<= 1; + assertOrPanic(i == 18); + i >>= 2; + assertOrPanic(i == 4); + i = 6; + i &= 5; + assertOrPanic(i == 4); + i ^= 6; + assertOrPanic(i == 2); + i = 6; + i |= 3; + assertOrPanic(i == 7); +} + +test "three expr in a row" { + testThreeExprInARow(false, true); + comptime testThreeExprInARow(false, true); +} +fn testThreeExprInARow(f: bool, t: bool) void { + assertFalse(f or f or f); + assertFalse(t and t and f); + assertFalse(1 | 2 | 4 != 7); + assertFalse(3 ^ 6 ^ 8 != 13); + assertFalse(7 & 14 & 28 != 4); + assertFalse(9 << 1 << 2 != 9 << 3); + assertFalse(90 >> 1 >> 2 != 90 >> 3); + assertFalse(100 - 1 + 1000 != 1099); + assertFalse(5 * 4 / 2 % 3 != 1); + assertFalse(i32(i32(5)) != 5); + assertFalse(!!false); + assertFalse(i32(7) != --(i32(7))); +} +fn assertFalse(b: bool) void { + assertOrPanic(!b); +} + +test "const number literal" { + const one = 1; + const eleven = ten + one; + + assertOrPanic(eleven == 11); +} +const ten = 10; + +test "unsigned wrapping" { + testUnsignedWrappingEval(maxInt(u32)); + comptime testUnsignedWrappingEval(maxInt(u32)); +} +fn testUnsignedWrappingEval(x: u32) void { + const zero = x +% 1; + assertOrPanic(zero == 0); + const orig = zero -% 1; + assertOrPanic(orig == maxInt(u32)); +} + +test "signed wrapping" { + testSignedWrappingEval(maxInt(i32)); + comptime testSignedWrappingEval(maxInt(i32)); +} +fn testSignedWrappingEval(x: i32) void { + const min_val = x +% 1; + assertOrPanic(min_val == minInt(i32)); + const max_val = min_val -% 1; + assertOrPanic(max_val == maxInt(i32)); +} + +test "negation wrapping" { + testNegationWrappingEval(minInt(i16)); + comptime testNegationWrappingEval(minInt(i16)); +} +fn testNegationWrappingEval(x: i16) void { + assertOrPanic(x == -32768); + const neg = -%x; + assertOrPanic(neg == -32768); +} + +test "unsigned 64-bit division" { + test_u64_div(); + comptime test_u64_div(); +} +fn test_u64_div() void { + const result = divWithResult(1152921504606846976, 34359738365); + assertOrPanic(result.quotient == 33554432); + assertOrPanic(result.remainder == 100663296); +} +fn divWithResult(a: u64, b: u64) DivResult { + return DivResult{ + .quotient = a / b, + .remainder = a % b, + }; +} +const DivResult = struct { + quotient: u64, + remainder: u64, +}; + +test "binary not" { + assertOrPanic(comptime x: { + break :x ~u16(0b1010101010101010) == 0b0101010101010101; + }); + assertOrPanic(comptime x: { + break :x ~u64(2147483647) == 18446744071562067968; + }); + testBinaryNot(0b1010101010101010); +} + +fn testBinaryNot(x: u16) void { + assertOrPanic(~x == 0b0101010101010101); +} + +test "small int addition" { + var x: @IntType(false, 2) = 0; + assertOrPanic(x == 0); + + x += 1; + assertOrPanic(x == 1); + + x += 1; + assertOrPanic(x == 2); + + x += 1; + assertOrPanic(x == 3); + + var result: @typeOf(x) = 3; + assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result)); + + assertOrPanic(result == 0); +} + +test "float equality" { + const x: f64 = 0.012; + const y: f64 = x + 1.0; + + testFloatEqualityImpl(x, y); + comptime testFloatEqualityImpl(x, y); +} + +fn testFloatEqualityImpl(x: f64, y: f64) void { + const y2 = x + 1.0; + assertOrPanic(y == y2); +} + +test "allow signed integer division/remainder when values are comptime known and positive or exact" { + assertOrPanic(5 / 3 == 1); + assertOrPanic(-5 / -3 == 1); + assertOrPanic(-6 / 3 == -2); + + assertOrPanic(5 % 3 == 2); + assertOrPanic(-6 % 3 == 0); +} + +test "hex float literal parsing" { + comptime assertOrPanic(0x1.0 == 1.0); +} + +test "quad hex float literal parsing in range" { + const a = 0x1.af23456789bbaaab347645365cdep+5; + const b = 0x1.dedafcff354b6ae9758763545432p-9; + const c = 0x1.2f34dd5f437e849b4baab754cdefp+4534; + const d = 0x1.edcbff8ad76ab5bf46463233214fp-435; +} + +test "quad hex float literal parsing accurate" { + const a: f128 = 0x1.1111222233334444555566667777p+0; + + // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. + const expected: u128 = 0x3fff1111222233334444555566667777; + assertOrPanic(@bitCast(u128, a) == expected); +} + +test "hex float literal within range" { + const a = 0x1.0p16383; + const b = 0x0.1p16387; + const c = 0x1.0p-16382; +} + +test "truncating shift left" { + testShlTrunc(maxInt(u16)); + comptime testShlTrunc(maxInt(u16)); +} +fn testShlTrunc(x: u16) void { + const shifted = x << 1; + assertOrPanic(shifted == 65534); +} + +test "truncating shift right" { + testShrTrunc(maxInt(u16)); + comptime testShrTrunc(maxInt(u16)); +} +fn testShrTrunc(x: u16) void { + const shifted = x >> 1; + assertOrPanic(shifted == 32767); +} + +test "exact shift left" { + testShlExact(0b00110101); + comptime testShlExact(0b00110101); +} +fn testShlExact(x: u8) void { + const shifted = @shlExact(x, 2); + assertOrPanic(shifted == 0b11010100); +} + +test "exact shift right" { + testShrExact(0b10110100); + comptime testShrExact(0b10110100); +} +fn testShrExact(x: u8) void { + const shifted = @shrExact(x, 2); + assertOrPanic(shifted == 0b00101101); +} + +test "comptime_int addition" { + comptime { + assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); + assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); + } +} + +test "comptime_int multiplication" { + comptime { + assertOrPanic( + 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, + ); + assertOrPanic( + 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, + ); + } +} + +test "comptime_int shifting" { + comptime { + assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000); + } +} + +test "comptime_int multi-limb shift and mask" { + comptime { + var a = 0xefffffffa0000001eeeeeeefaaaaaaab; + + assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab); + a >>= 32; + assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef); + a >>= 32; + assertOrPanic(u32(a & 0xffffffff) == 0xa0000001); + a >>= 32; + assertOrPanic(u32(a & 0xffffffff) == 0xefffffff); + a >>= 32; + + assertOrPanic(a == 0); + } +} + +test "comptime_int multi-limb partial shift right" { + comptime { + var a = 0x1ffffffffeeeeeeee; + a >>= 16; + assertOrPanic(a == 0x1ffffffffeeee); + } +} + +test "xor" { + test_xor(); + comptime test_xor(); +} + +fn test_xor() void { + assertOrPanic(0xFF ^ 0x00 == 0xFF); + assertOrPanic(0xF0 ^ 0x0F == 0xFF); + assertOrPanic(0xFF ^ 0xF0 == 0x0F); + assertOrPanic(0xFF ^ 0x0F == 0xF0); + assertOrPanic(0xFF ^ 0xFF == 0x00); +} + +test "comptime_int xor" { + comptime { + assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); + assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); + assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); + assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); + assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); + } +} + +test "f128" { + test_f128(); + comptime test_f128(); +} + +fn make_f128(x: f128) f128 { + return x; +} + +fn test_f128() void { + assertOrPanic(@sizeOf(f128) == 16); + assertOrPanic(make_f128(1.0) == 1.0); + assertOrPanic(make_f128(1.0) != 1.1); + assertOrPanic(make_f128(1.0) > 0.9); + assertOrPanic(make_f128(1.0) >= 0.9); + assertOrPanic(make_f128(1.0) >= 1.0); + should_not_be_zero(1.0); +} + +fn should_not_be_zero(x: f128) void { + assertOrPanic(x != 0.0); +} + +test "comptime float rem int" { + comptime { + var x = f32(1) % 2; + assertOrPanic(x == 1.0); + } +} + +test "remainder division" { + comptime remdiv(f16); + comptime remdiv(f32); + comptime remdiv(f64); + comptime remdiv(f128); + remdiv(f16); + remdiv(f64); + remdiv(f128); +} + +fn remdiv(comptime T: type) void { + assertOrPanic(T(1) == T(1) % T(2)); + assertOrPanic(T(1) == T(7) % T(3)); +} + +test "@sqrt" { + testSqrt(f64, 12.0); + comptime testSqrt(f64, 12.0); + testSqrt(f32, 13.0); + comptime testSqrt(f32, 13.0); + testSqrt(f16, 13.0); + comptime testSqrt(f16, 13.0); + + const x = 14.0; + const y = x * x; + const z = @sqrt(@typeOf(y), y); + comptime assertOrPanic(z == x); +} + +fn testSqrt(comptime T: type, x: T) void { + assertOrPanic(@sqrt(T, x * x) == x); +} + +test "comptime_int param and return" { + const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); + assertOrPanic(a == 137114567242441932203689521744947848950); + + const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); + assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380); +} + +fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { + return a + b; +} diff --git a/test/stage1/behavior/merge_error_sets.zig b/test/stage1/behavior/merge_error_sets.zig new file mode 100644 index 0000000000..147b580232 --- /dev/null +++ b/test/stage1/behavior/merge_error_sets.zig @@ -0,0 +1,21 @@ +const A = error{ + FileNotFound, + NotDir, +}; +const B = error{OutOfMemory}; + +const C = A || B; + +fn foo() C!void { + return error.NotDir; +} + +test "merge error sets" { + if (foo()) { + @panic("unexpected"); + } else |err| switch (err) { + error.OutOfMemory => @panic("unexpected"), + error.FileNotFound => @panic("unexpected"), + error.NotDir => {}, + } +} diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig new file mode 100644 index 0000000000..8d2555dddd --- /dev/null +++ b/test/stage1/behavior/misc.zig @@ -0,0 +1,687 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const mem = std.mem; +const cstr = std.cstr; +const builtin = @import("builtin"); +const maxInt = std.math.maxInt; + +// normal comment + +/// this is a documentation comment +/// doc comment line 2 +fn emptyFunctionWithComments() void {} + +test "empty function with comments" { + emptyFunctionWithComments(); +} + +comptime { + @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); +} + +extern fn disabledExternFn() void {} + +test "call disabled extern fn" { + disabledExternFn(); +} + +test "@IntType builtin" { + assertOrPanic(@IntType(true, 8) == i8); + assertOrPanic(@IntType(true, 16) == i16); + assertOrPanic(@IntType(true, 32) == i32); + assertOrPanic(@IntType(true, 64) == i64); + + assertOrPanic(@IntType(false, 8) == u8); + assertOrPanic(@IntType(false, 16) == u16); + assertOrPanic(@IntType(false, 32) == u32); + assertOrPanic(@IntType(false, 64) == u64); + + assertOrPanic(i8.bit_count == 8); + assertOrPanic(i16.bit_count == 16); + assertOrPanic(i32.bit_count == 32); + assertOrPanic(i64.bit_count == 64); + + assertOrPanic(i8.is_signed); + assertOrPanic(i16.is_signed); + assertOrPanic(i32.is_signed); + assertOrPanic(i64.is_signed); + assertOrPanic(isize.is_signed); + + assertOrPanic(!u8.is_signed); + assertOrPanic(!u16.is_signed); + assertOrPanic(!u32.is_signed); + assertOrPanic(!u64.is_signed); + assertOrPanic(!usize.is_signed); +} + +test "floating point primitive bit counts" { + assertOrPanic(f16.bit_count == 16); + assertOrPanic(f32.bit_count == 32); + assertOrPanic(f64.bit_count == 64); +} + +test "short circuit" { + testShortCircuit(false, true); + comptime testShortCircuit(false, true); +} + +fn testShortCircuit(f: bool, t: bool) void { + var hit_1 = f; + var hit_2 = f; + var hit_3 = f; + var hit_4 = f; + + if (t or x: { + assertOrPanic(f); + break :x f; + }) { + hit_1 = t; + } + if (f or x: { + hit_2 = t; + break :x f; + }) { + assertOrPanic(f); + } + + if (t and x: { + hit_3 = t; + break :x f; + }) { + assertOrPanic(f); + } + if (f and x: { + assertOrPanic(f); + break :x f; + }) { + assertOrPanic(f); + } else { + hit_4 = t; + } + assertOrPanic(hit_1); + assertOrPanic(hit_2); + assertOrPanic(hit_3); + assertOrPanic(hit_4); +} + +test "truncate" { + assertOrPanic(testTruncate(0x10fd) == 0xfd); +} +fn testTruncate(x: u32) u8 { + return @truncate(u8, x); +} + +fn first4KeysOfHomeRow() []const u8 { + return "aoeu"; +} + +test "return string from function" { + assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); +} + +const g1: i32 = 1233 + 1; +var g2: i32 = 0; + +test "global variables" { + assertOrPanic(g2 == 0); + g2 = g1; + assertOrPanic(g2 == 1234); +} + +test "memcpy and memset intrinsics" { + var foo: [20]u8 = undefined; + var bar: [20]u8 = undefined; + + @memset(foo[0..].ptr, 'A', foo.len); + @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); + + if (bar[11] != 'A') unreachable; +} + +test "builtin static eval" { + const x: i32 = comptime x: { + break :x 1 + 2 + 3; + }; + assertOrPanic(x == comptime 6); +} + +test "slicing" { + var array: [20]i32 = undefined; + + array[5] = 1234; + + var slice = array[5..10]; + + if (slice.len != 5) unreachable; + + const ptr = &slice[0]; + if (ptr.* != 1234) unreachable; + + var slice_rest = array[10..]; + if (slice_rest.len != 10) unreachable; +} + +test "constant equal function pointers" { + const alias = emptyFn; + assertOrPanic(comptime x: { + break :x emptyFn == alias; + }); +} + +fn emptyFn() void {} + +test "hex escape" { + assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); +} + +test "string concatenation" { + assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); +} + +test "array mult operator" { + assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab")); +} + +test "string escapes" { + assertOrPanic(mem.eql(u8, "\"", "\x22")); + assertOrPanic(mem.eql(u8, "\'", "\x27")); + assertOrPanic(mem.eql(u8, "\n", "\x0a")); + assertOrPanic(mem.eql(u8, "\r", "\x0d")); + assertOrPanic(mem.eql(u8, "\t", "\x09")); + assertOrPanic(mem.eql(u8, "\\", "\x5c")); + assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); +} + +test "multiline string" { + const s1 = + \\one + \\two) + \\three + ; + const s2 = "one\ntwo)\nthree"; + assertOrPanic(mem.eql(u8, s1, s2)); +} + +test "multiline C string" { + const s1 = + c\\one + c\\two) + c\\three + ; + const s2 = c"one\ntwo)\nthree"; + assertOrPanic(cstr.cmp(s1, s2) == 0); +} + +test "type equality" { + assertOrPanic(*const u8 != *u8); +} + +const global_a: i32 = 1234; +const global_b: *const i32 = &global_a; +const global_c: *const f32 = @ptrCast(*const f32, global_b); +test "compile time global reinterpret" { + const d = @ptrCast(*const i32, global_c); + assertOrPanic(d.* == 1234); +} + +test "explicit cast maybe pointers" { + const a: ?*i32 = undefined; + const b: ?*f32 = @ptrCast(?*f32, a); +} + +test "generic malloc free" { + const a = memAlloc(u8, 10) catch unreachable; + memFree(u8, a); +} +var some_mem: [100]u8 = undefined; +fn memAlloc(comptime T: type, n: usize) anyerror![]T { + return @ptrCast([*]T, &some_mem[0])[0..n]; +} +fn memFree(comptime T: type, memory: []T) void {} + +test "cast undefined" { + const array: [100]u8 = undefined; + const slice = ([]const u8)(array); + testCastUndefined(slice); +} +fn testCastUndefined(x: []const u8) void {} + +test "cast small unsigned to larger signed" { + assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200)); + assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); +} +fn castSmallUnsignedToLargerSigned1(x: u8) i16 { + return x; +} +fn castSmallUnsignedToLargerSigned2(x: u16) i64 { + return x; +} + +test "implicit cast after unreachable" { + assertOrPanic(outer() == 1234); +} +fn inner() i32 { + return 1234; +} +fn outer() i64 { + return inner(); +} + +test "pointer dereferencing" { + var x = i32(3); + const y = &x; + + y.* += 1; + + assertOrPanic(x == 4); + assertOrPanic(y.* == 4); +} + +test "call result of if else expression" { + assertOrPanic(mem.eql(u8, f2(true), "a")); + assertOrPanic(mem.eql(u8, f2(false), "b")); +} +fn f2(x: bool) []const u8 { + return (if (x) fA else fB)(); +} +fn fA() []const u8 { + return "a"; +} +fn fB() []const u8 { + return "b"; +} + +test "const expression eval handling of variables" { + var x = true; + while (x) { + x = false; + } +} + +test "constant enum initialization with differing sizes" { + test3_1(test3_foo); + test3_2(test3_bar); +} +const Test3Foo = union(enum) { + One: void, + Two: f32, + Three: Test3Point, +}; +const Test3Point = struct { + x: i32, + y: i32, +}; +const test3_foo = Test3Foo{ + .Three = Test3Point{ + .x = 3, + .y = 4, + }, +}; +const test3_bar = Test3Foo{ .Two = 13 }; +fn test3_1(f: Test3Foo) void { + switch (f) { + Test3Foo.Three => |pt| { + assertOrPanic(pt.x == 3); + assertOrPanic(pt.y == 4); + }, + else => unreachable, + } +} +fn test3_2(f: Test3Foo) void { + switch (f) { + Test3Foo.Two => |x| { + assertOrPanic(x == 13); + }, + else => unreachable, + } +} + +test "character literals" { + assertOrPanic('\'' == single_quote); +} +const single_quote = '\''; + +test "take address of parameter" { + testTakeAddressOfParameter(12.34); +} +fn testTakeAddressOfParameter(f: f32) void { + const f_ptr = &f; + assertOrPanic(f_ptr.* == 12.34); +} + +test "pointer comparison" { + const a = ([]const u8)("a"); + const b = &a; + assertOrPanic(ptrEql(b, b)); +} +fn ptrEql(a: *const []const u8, b: *const []const u8) bool { + return a == b; +} + +test "C string concatenation" { + const a = c"OK" ++ c" IT " ++ c"WORKED"; + const b = c"OK IT WORKED"; + + const len = cstr.len(b); + const len_with_null = len + 1; + { + var i: u32 = 0; + while (i < len_with_null) : (i += 1) { + assertOrPanic(a[i] == b[i]); + } + } + assertOrPanic(a[len] == 0); + assertOrPanic(b[len] == 0); +} + +test "cast slice to u8 slice" { + assertOrPanic(@sizeOf(i32) == 4); + var big_thing_array = []i32{ 1, 2, 3, 4 }; + const big_thing_slice: []i32 = big_thing_array[0..]; + const bytes = @sliceToBytes(big_thing_slice); + assertOrPanic(bytes.len == 4 * 4); + bytes[4] = 0; + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + assertOrPanic(big_thing_slice[1] == 0); + const big_thing_again = @bytesToSlice(i32, bytes); + assertOrPanic(big_thing_again[2] == 3); + big_thing_again[2] = -1; + assertOrPanic(bytes[8] == maxInt(u8)); + assertOrPanic(bytes[9] == maxInt(u8)); + assertOrPanic(bytes[10] == maxInt(u8)); + assertOrPanic(bytes[11] == maxInt(u8)); +} + +test "pointer to void return type" { + testPointerToVoidReturnType() catch unreachable; +} +fn testPointerToVoidReturnType() anyerror!void { + const a = testPointerToVoidReturnType2(); + return a.*; +} +const test_pointer_to_void_return_type_x = void{}; +fn testPointerToVoidReturnType2() *const void { + return &test_pointer_to_void_return_type_x; +} + +test "non const ptr to aliased type" { + const int = i32; + assertOrPanic(?*int == ?*i32); +} + +test "array 2D const double ptr" { + const rect_2d_vertexes = [][1]f32{ + []f32{1.0}, + []f32{2.0}, + }; + testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]); +} + +fn testArray2DConstDoublePtr(ptr: *const f32) void { + const ptr2 = @ptrCast([*]const f32, ptr); + assertOrPanic(ptr2[0] == 1.0); + assertOrPanic(ptr2[1] == 2.0); +} + +const Tid = builtin.TypeId; +const AStruct = struct { + x: i32, +}; +const AnEnum = enum { + One, + Two, +}; +const AUnionEnum = union(enum) { + One: i32, + Two: void, +}; +const AUnion = union { + One: void, + Two: void, +}; + +test "@typeId" { + comptime { + assertOrPanic(@typeId(type) == Tid.Type); + assertOrPanic(@typeId(void) == Tid.Void); + assertOrPanic(@typeId(bool) == Tid.Bool); + assertOrPanic(@typeId(noreturn) == Tid.NoReturn); + assertOrPanic(@typeId(i8) == Tid.Int); + assertOrPanic(@typeId(u8) == Tid.Int); + assertOrPanic(@typeId(i64) == Tid.Int); + assertOrPanic(@typeId(u64) == Tid.Int); + assertOrPanic(@typeId(f32) == Tid.Float); + assertOrPanic(@typeId(f64) == Tid.Float); + assertOrPanic(@typeId(*f32) == Tid.Pointer); + assertOrPanic(@typeId([2]u8) == Tid.Array); + assertOrPanic(@typeId(AStruct) == Tid.Struct); + assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt); + assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); + assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined); + assertOrPanic(@typeId(@typeOf(null)) == Tid.Null); + assertOrPanic(@typeId(?i32) == Tid.Optional); + assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion); + assertOrPanic(@typeId(anyerror) == Tid.ErrorSet); + assertOrPanic(@typeId(AnEnum) == Tid.Enum); + assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); + assertOrPanic(@typeId(AUnionEnum) == Tid.Union); + assertOrPanic(@typeId(AUnion) == Tid.Union); + assertOrPanic(@typeId(fn () void) == Tid.Fn); + assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace); + // TODO bound fn + // TODO arg tuple + // TODO opaque + } +} + +test "@typeName" { + const Struct = struct {}; + const Union = union { + unused: u8, + }; + const Enum = enum { + Unused, + }; + comptime { + assertOrPanic(mem.eql(u8, @typeName(i64), "i64")); + assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize")); + // https://github.com/ziglang/zig/issues/675 + assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); + assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct")); + assertOrPanic(mem.eql(u8, @typeName(Union), "Union")); + assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum")); + } +} + +fn TypeFromFn(comptime T: type) type { + return struct {}; +} + +test "double implicit cast in same expression" { + var x = i32(u16(nine())); + assertOrPanic(x == 9); +} +fn nine() u8 { + return 9; +} + +test "global variable initialized to global variable array element" { + assertOrPanic(global_ptr == &gdt[0]); +} +const GDTEntry = struct { + field: i32, +}; +var gdt = []GDTEntry{ + GDTEntry{ .field = 1 }, + GDTEntry{ .field = 2 }, +}; +var global_ptr = &gdt[0]; + +// can't really run this test but we can make sure it has no compile error +// and generates code +const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000]; +export fn writeToVRam() void { + vram[0] = 'X'; +} + +const OpaqueA = @OpaqueType(); +const OpaqueB = @OpaqueType(); +test "@OpaqueType" { + assertOrPanic(*OpaqueA != *OpaqueB); + assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); + assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); +} + +test "variable is allowed to be a pointer to an opaque type" { + var x: i32 = 1234; + _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); +} +fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { + var a = ptr; + return a; +} + +test "comptime if inside runtime while which unconditionally breaks" { + testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); + comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true); +} +fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void { + while (cond) { + if (false) {} + break; + } +} + +test "implicit comptime while" { + while (false) { + @compileError("bad"); + } +} + +fn fnThatClosesOverLocalConst() type { + const c = 1; + return struct { + fn g() i32 { + return c; + } + }; +} + +test "function closes over local const" { + const x = fnThatClosesOverLocalConst().g(); + assertOrPanic(x == 1); +} + +test "cold function" { + thisIsAColdFn(); + comptime thisIsAColdFn(); +} + +fn thisIsAColdFn() void { + @setCold(true); +} + +const PackedStruct = packed struct { + a: u8, + b: u8, +}; +const PackedUnion = packed union { + a: u8, + b: u32, +}; +const PackedEnum = packed enum { + A, + B, +}; + +test "packed struct, enum, union parameters in extern function" { + testPackedStuff(&(PackedStruct{ + .a = 1, + .b = 2, + }), &(PackedUnion{ .a = 1 }), PackedEnum.A); +} + +export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: PackedEnum) void {} + +test "slicing zero length array" { + const s1 = ""[0..]; + const s2 = ([]u32{})[0..]; + assertOrPanic(s1.len == 0); + assertOrPanic(s2.len == 0); + assertOrPanic(mem.eql(u8, s1, "")); + assertOrPanic(mem.eql(u32, s2, []u32{})); +} + +const addr1 = @ptrCast(*const u8, emptyFn); +test "comptime cast fn to ptr" { + const addr2 = @ptrCast(*const u8, emptyFn); + comptime assertOrPanic(addr1 == addr2); +} + +test "equality compare fn ptrs" { + var a = emptyFn; + assertOrPanic(a == a); +} + +test "self reference through fn ptr field" { + const S = struct { + const A = struct { + f: fn (A) u8, + }; + + fn foo(a: A) u8 { + return 12; + } + }; + var a: S.A = undefined; + a.f = S.foo; + assertOrPanic(a.f(a) == 12); +} + +test "volatile load and store" { + var number: i32 = 1234; + const ptr = (*volatile i32)(&number); + ptr.* += 1; + assertOrPanic(ptr.* == 1235); +} + +test "slice string literal has type []const u8" { + comptime { + assertOrPanic(@typeOf("aoeu"[0..]) == []const u8); + const array = []i32{ 1, 2, 3, 4 }; + assertOrPanic(@typeOf(array[0..]) == []const i32); + } +} + +test "pointer child field" { + assertOrPanic((*u32).Child == u32); +} + +test "struct inside function" { + testStructInFn(); + comptime testStructInFn(); +} + +fn testStructInFn() void { + const BlockKind = u32; + + const Block = struct { + kind: BlockKind, + }; + + var block = Block{ .kind = 1234 }; + + block.kind += 1; + + assertOrPanic(block.kind == 1235); +} + +test "fn call returning scalar optional in equality expression" { + assertOrPanic(getNull() == null); +} + +fn getNull() ?*i32 { + return null; +} diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/a.zig b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig new file mode 100644 index 0000000000..5ce0e94f8b --- /dev/null +++ b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig @@ -0,0 +1 @@ +pub const a_bool = true; diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/b.zig b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig new file mode 100644 index 0000000000..a12a54b589 --- /dev/null +++ b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig @@ -0,0 +1 @@ +pub const a_bool = false; diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig new file mode 100644 index 0000000000..fe3e0cc020 --- /dev/null +++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig @@ -0,0 +1,14 @@ +const builtin = @import("builtin"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "namespace depends on compile var" { + if (some_namespace.a_bool) { + assertOrPanic(some_namespace.a_bool); + } else { + assertOrPanic(!some_namespace.a_bool); + } +} +const some_namespace = switch (builtin.os) { + builtin.Os.linux => @import("a.zig"), + else => @import("b.zig"), +}; diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig new file mode 100644 index 0000000000..b9ae2d27cd --- /dev/null +++ b/test/stage1/behavior/new_stack_call.zig @@ -0,0 +1,26 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +var new_stack_bytes: [1024]u8 = undefined; + +test "calling a function with a new stack" { + const arg = 1234; + + const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); + const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); + _ = targetFunction(arg); + + assertOrPanic(arg == 1234); + assertOrPanic(a < b); +} + +fn targetFunction(x: i32) usize { + assertOrPanic(x == 1234); + + var local_variable: i32 = 42; + const ptr = &local_variable; + ptr.* += 1; + + assertOrPanic(local_variable == 43); + return @ptrToInt(ptr); +} diff --git a/test/stage1/behavior/null.zig b/test/stage1/behavior/null.zig new file mode 100644 index 0000000000..e2f86a05ba --- /dev/null +++ b/test/stage1/behavior/null.zig @@ -0,0 +1,162 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "optional type" { + const x: ?bool = true; + + if (x) |y| { + if (y) { + // OK + } else { + unreachable; + } + } else { + unreachable; + } + + const next_x: ?i32 = null; + + const z = next_x orelse 1234; + + assertOrPanic(z == 1234); + + const final_x: ?i32 = 13; + + const num = final_x orelse unreachable; + + assertOrPanic(num == 13); +} + +test "test maybe object and get a pointer to the inner value" { + var maybe_bool: ?bool = true; + + if (maybe_bool) |*b| { + b.* = false; + } + + assertOrPanic(maybe_bool.? == false); +} + +test "rhs maybe unwrap return" { + const x: ?bool = true; + const y = x orelse return; +} + +test "maybe return" { + maybeReturnImpl(); + comptime maybeReturnImpl(); +} + +fn maybeReturnImpl() void { + assertOrPanic(foo(1235).?); + if (foo(null) != null) unreachable; + assertOrPanic(!foo(1234).?); +} + +fn foo(x: ?i32) ?bool { + const value = x orelse return null; + return value > 1234; +} + +test "if var maybe pointer" { + assertOrPanic(shouldBeAPlus1(Particle{ + .a = 14, + .b = 1, + .c = 1, + .d = 1, + }) == 15); +} +fn shouldBeAPlus1(p: Particle) u64 { + var maybe_particle: ?Particle = p; + if (maybe_particle) |*particle| { + particle.a += 1; + } + if (maybe_particle) |particle| { + return particle.a; + } + return 0; +} +const Particle = struct { + a: u64, + b: u64, + c: u64, + d: u64, +}; + +test "null literal outside function" { + const is_null = here_is_a_null_literal.context == null; + assertOrPanic(is_null); + + const is_non_null = here_is_a_null_literal.context != null; + assertOrPanic(!is_non_null); +} +const SillyStruct = struct { + context: ?i32, +}; +const here_is_a_null_literal = SillyStruct{ .context = null }; + +test "test null runtime" { + testTestNullRuntime(null); +} +fn testTestNullRuntime(x: ?i32) void { + assertOrPanic(x == null); + assertOrPanic(!(x != null)); +} + +test "optional void" { + optionalVoidImpl(); + comptime optionalVoidImpl(); +} + +fn optionalVoidImpl() void { + assertOrPanic(bar(null) == null); + assertOrPanic(bar({}) != null); +} + +fn bar(x: ?void) ?void { + if (x) |_| { + return {}; + } else { + return null; + } +} + +const StructWithOptional = struct { + field: ?i32, +}; + +var struct_with_optional: StructWithOptional = undefined; + +test "unwrap optional which is field of global var" { + struct_with_optional.field = null; + if (struct_with_optional.field) |payload| { + unreachable; + } + struct_with_optional.field = 1234; + if (struct_with_optional.field) |payload| { + assertOrPanic(payload == 1234); + } else { + unreachable; + } +} + +test "null with default unwrap" { + const x: i32 = null orelse 1; + assertOrPanic(x == 1); +} + +test "optional types" { + comptime { + const opt_type_struct = StructWithOptionalType{ .t = u8 }; + assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8); + } +} + +const StructWithOptionalType = struct { + t: ?type, +}; + +test "optional pointer to 0 bit type null value at runtime" { + const EmptyStruct = struct {}; + var x: ?*EmptyStruct = null; + assertOrPanic(x == null); +} diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig new file mode 100644 index 0000000000..14692cb1ea --- /dev/null +++ b/test/stage1/behavior/optional.zig @@ -0,0 +1,81 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +pub const EmptyStruct = struct {}; + +test "optional pointer to size zero struct" { + var e = EmptyStruct{}; + var o: ?*EmptyStruct = &e; + assertOrPanic(o != null); +} + +test "equality compare nullable pointers" { + testNullPtrsEql(); + comptime testNullPtrsEql(); +} + +fn testNullPtrsEql() void { + var number: i32 = 1234; + + var x: ?*i32 = null; + var y: ?*i32 = null; + assertOrPanic(x == y); + y = &number; + assertOrPanic(x != y); + assertOrPanic(x != &number); + assertOrPanic(&number != x); + x = &number; + assertOrPanic(x == y); + assertOrPanic(x == &number); + assertOrPanic(&number == x); +} + +test "address of unwrap optional" { + const S = struct { + const Foo = struct { + a: i32, + }; + + var global: ?Foo = null; + + pub fn getFoo() anyerror!*Foo { + return &global.?; + } + }; + S.global = S.Foo{ .a = 1234 }; + const foo = S.getFoo() catch unreachable; + assertOrPanic(foo.a == 1234); +} + +test "passing an optional integer as a parameter" { + const S = struct { + fn entry() bool { + var x: i32 = 1234; + return foo(x); + } + + fn foo(x: ?i32) bool { + return x.? == 1234; + } + }; + assertOrPanic(S.entry()); + comptime assertOrPanic(S.entry()); +} + +test "unwrap function call with optional pointer return value" { + const S = struct { + fn entry() void { + assertOrPanic(foo().?.* == 1234); + assertOrPanic(bar() == null); + } + const global: i32 = 1234; + fn foo() ?*const i32 { + return &global; + } + fn bar() ?*i32 { + return null; + } + }; + S.entry(); + // TODO https://github.com/ziglang/zig/issues/1901 + //comptime S.entry(); +} diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig new file mode 100644 index 0000000000..1142d89ab5 --- /dev/null +++ b/test/stage1/behavior/pointers.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "dereference pointer" { + comptime testDerefPtr(); + testDerefPtr(); +} + +fn testDerefPtr() void { + var x: i32 = 1234; + var y = &x; + y.* += 1; + assertOrPanic(x == 1235); +} + +test "pointer arithmetic" { + var ptr = c"abcd"; + + assertOrPanic(ptr[0] == 'a'); + ptr += 1; + assertOrPanic(ptr[0] == 'b'); + ptr += 1; + assertOrPanic(ptr[0] == 'c'); + ptr += 1; + assertOrPanic(ptr[0] == 'd'); + ptr += 1; + assertOrPanic(ptr[0] == 0); + ptr -= 1; + assertOrPanic(ptr[0] == 'd'); + ptr -= 1; + assertOrPanic(ptr[0] == 'c'); + ptr -= 1; + assertOrPanic(ptr[0] == 'b'); + ptr -= 1; + assertOrPanic(ptr[0] == 'a'); +} + +test "double pointer parsing" { + comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32); +} + +fn PtrOf(comptime T: type) type { + return *T; +} diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig new file mode 100644 index 0000000000..f7f8bb523b --- /dev/null +++ b/test/stage1/behavior/popcount.zig @@ -0,0 +1,25 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@popCount" { + comptime testPopCount(); + testPopCount(); +} + +fn testPopCount() void { + { + var x: u32 = 0xaa; + assertOrPanic(@popCount(x) == 4); + } + { + var x: u32 = 0xaaaaaaaa; + assertOrPanic(@popCount(x) == 16); + } + { + var x: i16 = -1; + assertOrPanic(@popCount(x) == 16); + } + comptime { + assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); + } +} + diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig new file mode 100644 index 0000000000..54c3dda849 --- /dev/null +++ b/test/stage1/behavior/ptrcast.zig @@ -0,0 +1,52 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "reinterpret bytes as integer with nonzero offset" { + testReinterpretBytesAsInteger(); + comptime testReinterpretBytesAsInteger(); +} + +fn testReinterpretBytesAsInteger() void { + const bytes = "\x12\x34\x56\x78\xab"; + const expected = switch (builtin.endian) { + builtin.Endian.Little => 0xab785634, + builtin.Endian.Big => 0x345678ab, + }; + assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); +} + +test "reinterpret bytes of an array into an extern struct" { + testReinterpretBytesAsExternStruct(); + comptime testReinterpretBytesAsExternStruct(); +} + +fn testReinterpretBytesAsExternStruct() void { + var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 }; + + const S = extern struct { + a: u8, + b: u16, + c: u8, + }; + + var ptr = @ptrCast(*const S, &bytes); + var val = ptr.c; + assertOrPanic(val == 5); +} + +test "reinterpret struct field at comptime" { + const numLittle = comptime Bytes.init(0x12345678); + assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); +} + +const Bytes = struct { + bytes: [4]u8, + + pub fn init(v: u32) Bytes { + var res: Bytes = undefined; + @ptrCast(*align(1) u32, &res.bytes).* = v; + + return res; + } +}; diff --git a/test/stage1/behavior/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig new file mode 100644 index 0000000000..181113f6bf --- /dev/null +++ b/test/stage1/behavior/pub_enum/index.zig @@ -0,0 +1,13 @@ +const other = @import("other.zig"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "pub enum" { + pubEnumTest(other.APubEnum.Two); +} +fn pubEnumTest(foo: other.APubEnum) void { + assertOrPanic(foo == other.APubEnum.Two); +} + +test "cast with imported symbol" { + assertOrPanic(other.size_t(42) == 42); +} diff --git a/test/stage1/behavior/pub_enum/other.zig b/test/stage1/behavior/pub_enum/other.zig new file mode 100644 index 0000000000..c663950383 --- /dev/null +++ b/test/stage1/behavior/pub_enum/other.zig @@ -0,0 +1,6 @@ +pub const APubEnum = enum { + One, + Two, + Three, +}; +pub const size_t = u64; diff --git a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig new file mode 100644 index 0000000000..acbe6b2459 --- /dev/null +++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -0,0 +1,37 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +var ok: bool = false; +test "reference a variable in an if after an if in the 2nd switch prong" { + foo(true, Num.Two, false, "aoeu"); + assertOrPanic(!ok); + foo(false, Num.One, false, "aoeu"); + assertOrPanic(!ok); + foo(true, Num.One, false, "aoeu"); + assertOrPanic(ok); +} + +const Num = enum { + One, + Two, +}; + +fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { + switch (k) { + Num.Two => {}, + Num.One => { + if (c) { + const output_path = b; + + if (c2) {} + + a(output_path); + } + }, + } +} + +fn a(x: []const u8) void { + assertOrPanic(mem.eql(u8, x, "aoeu")); + ok = true; +} diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig new file mode 100644 index 0000000000..f4c142e0f7 --- /dev/null +++ b/test/stage1/behavior/reflection.zig @@ -0,0 +1,96 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; +const reflection = @This(); + +test "reflection: array, pointer, optional, error union type child" { + comptime { + assertOrPanic(([10]u8).Child == u8); + assertOrPanic((*u8).Child == u8); + assertOrPanic((anyerror!u8).Payload == u8); + assertOrPanic((?u8).Child == u8); + } +} + +test "reflection: function return type, var args, and param types" { + comptime { + assertOrPanic(@typeOf(dummy).ReturnType == i32); + assertOrPanic(!@typeOf(dummy).is_var_args); + assertOrPanic(@typeOf(dummy_varargs).is_var_args); + assertOrPanic(@typeOf(dummy).arg_count == 3); + assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool); + assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32); + assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32); + } +} + +fn dummy(a: bool, b: i32, c: f32) i32 { + return 1234; +} +fn dummy_varargs(args: ...) void {} + +test "reflection: struct member types and names" { + comptime { + assertOrPanic(@memberCount(Foo) == 3); + + assertOrPanic(@memberType(Foo, 0) == i32); + assertOrPanic(@memberType(Foo, 1) == bool); + assertOrPanic(@memberType(Foo, 2) == void); + + assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one")); + assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two")); + assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three")); + } +} + +test "reflection: enum member types and names" { + comptime { + assertOrPanic(@memberCount(Bar) == 4); + + assertOrPanic(@memberType(Bar, 0) == void); + assertOrPanic(@memberType(Bar, 1) == i32); + assertOrPanic(@memberType(Bar, 2) == bool); + assertOrPanic(@memberType(Bar, 3) == f64); + + assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three")); + assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four")); + } +} + +test "reflection: @field" { + var f = Foo{ + .one = 42, + .two = true, + .three = void{}, + }; + + assertOrPanic(f.one == f.one); + assertOrPanic(@field(f, "o" ++ "ne") == f.one); + assertOrPanic(@field(f, "t" ++ "wo") == f.two); + assertOrPanic(@field(f, "th" ++ "ree") == f.three); + assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant); + assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One); + assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two); + assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three); + assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four); + assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); + @field(f, "o" ++ "ne") = 4; + assertOrPanic(f.one == 4); +} + +const Foo = struct { + const constant = 52; + + one: i32, + two: bool, + three: void, +}; + +const Bar = union(enum) { + One: void, + Two: i32, + Three: bool, + Four: f64, +}; + diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig new file mode 100644 index 0000000000..ddaea4c242 --- /dev/null +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -0,0 +1,69 @@ +const builtin = @import("builtin"); +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "@sizeOf and @typeOf" { + const y: @typeOf(x) = 120; + assertOrPanic(@sizeOf(@typeOf(y)) == 2); +} +const x: u16 = 13; +const z: @typeOf(x) = 19; + +const A = struct { + a: u8, + b: u32, + c: u8, + d: u3, + e: u5, + f: u16, + g: u16, +}; + +const P = packed struct { + a: u8, + b: u32, + c: u8, + d: u3, + e: u5, + f: u16, + g: u16, +}; + +test "@byteOffsetOf" { + // Packed structs have fixed memory layout + assertOrPanic(@byteOffsetOf(P, "a") == 0); + assertOrPanic(@byteOffsetOf(P, "b") == 1); + assertOrPanic(@byteOffsetOf(P, "c") == 5); + assertOrPanic(@byteOffsetOf(P, "d") == 6); + assertOrPanic(@byteOffsetOf(P, "e") == 6); + assertOrPanic(@byteOffsetOf(P, "f") == 7); + assertOrPanic(@byteOffsetOf(P, "g") == 9); + + // Normal struct fields can be moved/padded + var a: A = undefined; + assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); + assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); + assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); + assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); + assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); + assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); + assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); +} + +test "@bitOffsetOf" { + // Packed structs have fixed memory layout + assertOrPanic(@bitOffsetOf(P, "a") == 0); + assertOrPanic(@bitOffsetOf(P, "b") == 8); + assertOrPanic(@bitOffsetOf(P, "c") == 40); + assertOrPanic(@bitOffsetOf(P, "d") == 48); + assertOrPanic(@bitOffsetOf(P, "e") == 51); + assertOrPanic(@bitOffsetOf(P, "f") == 56); + assertOrPanic(@bitOffsetOf(P, "g") == 72); + + assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); + assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); + assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); + assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); + assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); + assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); + assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); +} diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig new file mode 100644 index 0000000000..cc29e43485 --- /dev/null +++ b/test/stage1/behavior/slice.zig @@ -0,0 +1,40 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +const x = @intToPtr([*]i32, 0x1000)[0..0x500]; +const y = x[0x100..]; +test "compile time slice of pointer to hard coded address" { + assertOrPanic(@ptrToInt(x.ptr) == 0x1000); + assertOrPanic(x.len == 0x500); + + assertOrPanic(@ptrToInt(y.ptr) == 0x1100); + assertOrPanic(y.len == 0x400); +} + +test "slice child property" { + var array: [5]i32 = undefined; + var slice = array[0..]; + assertOrPanic(@typeOf(slice).Child == i32); +} + +test "runtime safety lets us slice from len..len" { + var an_array = []u8{ + 1, + 2, + 3, + }; + assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); +} + +fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { + return a_slice[start..end]; +} + +test "implicitly cast array of size 0 to slice" { + var msg = []u8{}; + assertLenIsZero(msg); +} + +fn assertLenIsZero(msg: []const u8) void { + assertOrPanic(msg.len == 0); +} diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig new file mode 100644 index 0000000000..92ae2baa15 --- /dev/null +++ b/test/stage1/behavior/struct.zig @@ -0,0 +1,470 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const builtin = @import("builtin"); +const maxInt = std.math.maxInt; + +const StructWithNoFields = struct { + fn add(a: i32, b: i32) i32 { + return a + b; + } +}; +const empty_global_instance = StructWithNoFields{}; + +test "call struct static method" { + const result = StructWithNoFields.add(3, 4); + assertOrPanic(result == 7); +} + +test "return empty struct instance" { + _ = returnEmptyStructInstance(); +} +fn returnEmptyStructInstance() StructWithNoFields { + return empty_global_instance; +} + +const should_be_11 = StructWithNoFields.add(5, 6); + +test "invoke static method in global scope" { + assertOrPanic(should_be_11 == 11); +} + +test "void struct fields" { + const foo = VoidStructFieldsFoo{ + .a = void{}, + .b = 1, + .c = void{}, + }; + assertOrPanic(foo.b == 1); + assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4); +} +const VoidStructFieldsFoo = struct { + a: void, + b: i32, + c: void, +}; + +test "structs" { + var foo: StructFoo = undefined; + @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); + foo.a += 1; + foo.b = foo.a == 1; + testFoo(foo); + testMutation(&foo); + assertOrPanic(foo.c == 100); +} +const StructFoo = struct { + a: i32, + b: bool, + c: f32, +}; +fn testFoo(foo: StructFoo) void { + assertOrPanic(foo.b); +} +fn testMutation(foo: *StructFoo) void { + foo.c = 100; +} + +const Node = struct { + val: Val, + next: *Node, +}; + +const Val = struct { + x: i32, +}; + +test "struct point to self" { + var root: Node = undefined; + root.val.x = 1; + + var node: Node = undefined; + node.next = &root; + node.val.x = 2; + + root.next = &node; + + assertOrPanic(node.next.next.next.val.x == 1); +} + +test "struct byval assign" { + var foo1: StructFoo = undefined; + var foo2: StructFoo = undefined; + + foo1.a = 1234; + foo2.a = 0; + assertOrPanic(foo2.a == 0); + foo2 = foo1; + assertOrPanic(foo2.a == 1234); +} + +fn structInitializer() void { + const val = Val{ .x = 42 }; + assertOrPanic(val.x == 42); +} + +test "fn call of struct field" { + assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13); +} + +const Foo = struct { + ptr: fn () i32, +}; + +fn aFunc() i32 { + return 13; +} + +fn callStructField(foo: Foo) i32 { + return foo.ptr(); +} + +test "store member function in variable" { + const instance = MemberFnTestFoo{ .x = 1234 }; + const memberFn = MemberFnTestFoo.member; + const result = memberFn(instance); + assertOrPanic(result == 1234); +} +const MemberFnTestFoo = struct { + x: i32, + fn member(foo: MemberFnTestFoo) i32 { + return foo.x; + } +}; + +test "call member function directly" { + const instance = MemberFnTestFoo{ .x = 1234 }; + const result = MemberFnTestFoo.member(instance); + assertOrPanic(result == 1234); +} + +test "member functions" { + const r = MemberFnRand{ .seed = 1234 }; + assertOrPanic(r.getSeed() == 1234); +} +const MemberFnRand = struct { + seed: u32, + pub fn getSeed(r: *const MemberFnRand) u32 { + return r.seed; + } +}; + +test "return struct byval from function" { + const bar = makeBar(1234, 5678); + assertOrPanic(bar.y == 5678); +} +const Bar = struct { + x: i32, + y: i32, +}; +fn makeBar(x: i32, y: i32) Bar { + return Bar{ + .x = x, + .y = y, + }; +} + +test "empty struct method call" { + const es = EmptyStruct{}; + assertOrPanic(es.method() == 1234); +} +const EmptyStruct = struct { + fn method(es: *const EmptyStruct) i32 { + return 1234; + } +}; + +test "return empty struct from fn" { + _ = testReturnEmptyStructFromFn(); +} +const EmptyStruct2 = struct {}; +fn testReturnEmptyStructFromFn() EmptyStruct2 { + return EmptyStruct2{}; +} + +test "pass slice of empty struct to fn" { + assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); +} +fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { + return slice.len; +} + +const APackedStruct = packed struct { + x: u8, + y: u8, +}; + +test "packed struct" { + var foo = APackedStruct{ + .x = 1, + .y = 2, + }; + foo.y += 1; + const four = foo.x + foo.y; + assertOrPanic(four == 4); +} + +const BitField1 = packed struct { + a: u3, + b: u3, + c: u2, +}; + +const bit_field_1 = BitField1{ + .a = 1, + .b = 2, + .c = 3, +}; + +test "bit field access" { + var data = bit_field_1; + assertOrPanic(getA(&data) == 1); + assertOrPanic(getB(&data) == 2); + assertOrPanic(getC(&data) == 3); + comptime assertOrPanic(@sizeOf(BitField1) == 1); + + data.b += 1; + assertOrPanic(data.b == 3); + + data.a += 1; + assertOrPanic(data.a == 2); + assertOrPanic(data.b == 3); +} + +fn getA(data: *const BitField1) u3 { + return data.a; +} + +fn getB(data: *const BitField1) u3 { + return data.b; +} + +fn getC(data: *const BitField1) u2 { + return data.c; +} + +const Foo24Bits = packed struct { + field: u24, +}; +const Foo96Bits = packed struct { + a: u24, + b: u24, + c: u24, + d: u24, +}; + +test "packed struct 24bits" { + comptime { + assertOrPanic(@sizeOf(Foo24Bits) == 3); + assertOrPanic(@sizeOf(Foo96Bits) == 12); + } + + var value = Foo96Bits{ + .a = 0, + .b = 0, + .c = 0, + .d = 0, + }; + value.a += 1; + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 0); + assertOrPanic(value.c == 0); + assertOrPanic(value.d == 0); + + value.b += 1; + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 0); + assertOrPanic(value.d == 0); + + value.c += 1; + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 1); + assertOrPanic(value.d == 0); + + value.d += 1; + assertOrPanic(value.a == 1); + assertOrPanic(value.b == 1); + assertOrPanic(value.c == 1); + assertOrPanic(value.d == 1); +} + +const FooArray24Bits = packed struct { + a: u16, + b: [2]Foo24Bits, + c: u16, +}; + +test "packed array 24bits" { + comptime { + assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3); + assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); + } + + var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); + bytes[bytes.len - 1] = 0xaa; + const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; + assertOrPanic(ptr.a == 0); + assertOrPanic(ptr.b[0].field == 0); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); + + ptr.a = maxInt(u16); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == 0); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); + + ptr.b[0].field = maxInt(u24); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == 0); + assertOrPanic(ptr.c == 0); + + ptr.b[1].field = maxInt(u24); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == maxInt(u24)); + assertOrPanic(ptr.c == 0); + + ptr.c = maxInt(u16); + assertOrPanic(ptr.a == maxInt(u16)); + assertOrPanic(ptr.b[0].field == maxInt(u24)); + assertOrPanic(ptr.b[1].field == maxInt(u24)); + assertOrPanic(ptr.c == maxInt(u16)); + + assertOrPanic(bytes[bytes.len - 1] == 0xaa); +} + +const FooStructAligned = packed struct { + a: u8, + b: u8, +}; + +const FooArrayOfAligned = packed struct { + a: [2]FooStructAligned, +}; + +test "aligned array of packed struct" { + comptime { + assertOrPanic(@sizeOf(FooStructAligned) == 2); + assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2); + } + + var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); + const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; + + assertOrPanic(ptr.a[0].a == 0xbb); + assertOrPanic(ptr.a[0].b == 0xbb); + assertOrPanic(ptr.a[1].a == 0xbb); + assertOrPanic(ptr.a[1].b == 0xbb); +} + +test "runtime struct initialization of bitfield" { + const s1 = Nibbles{ + .x = x1, + .y = x1, + }; + const s2 = Nibbles{ + .x = @intCast(u4, x2), + .y = @intCast(u4, x2), + }; + + assertOrPanic(s1.x == x1); + assertOrPanic(s1.y == x1); + assertOrPanic(s2.x == @intCast(u4, x2)); + assertOrPanic(s2.y == @intCast(u4, x2)); +} + +var x1 = u4(1); +var x2 = u8(2); + +const Nibbles = packed struct { + x: u4, + y: u4, +}; + +const Bitfields = packed struct { + f1: u16, + f2: u16, + f3: u8, + f4: u8, + f5: u4, + f6: u4, + f7: u8, +}; + +test "native bit field understands endianness" { + var all: u64 = 0x7765443322221111; + var bytes: [8]u8 = undefined; + @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); + var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; + + assertOrPanic(bitfields.f1 == 0x1111); + assertOrPanic(bitfields.f2 == 0x2222); + assertOrPanic(bitfields.f3 == 0x33); + assertOrPanic(bitfields.f4 == 0x44); + assertOrPanic(bitfields.f5 == 0x5); + assertOrPanic(bitfields.f6 == 0x6); + assertOrPanic(bitfields.f7 == 0x77); +} + +test "align 1 field before self referential align 8 field as slice return type" { + const result = alloc(Expr); + assertOrPanic(result.len == 0); +} + +const Expr = union(enum) { + Literal: u8, + Question: *Expr, +}; + +fn alloc(comptime T: type) []T { + return []T{}; +} + +test "call method with mutable reference to struct with no fields" { + const S = struct { + fn doC(s: *const @This()) bool { + return true; + } + fn do(s: *@This()) bool { + return true; + } + }; + + var s = S{}; + assertOrPanic(S.doC(&s)); + assertOrPanic(s.doC()); + assertOrPanic(S.do(&s)); + assertOrPanic(s.do()); +} + +test "implicit cast packed struct field to const ptr" { + const LevelUpMove = packed struct { + move_id: u9, + level: u7, + + fn toInt(value: u7) u7 { + return value; + } + }; + + var lup: LevelUpMove = undefined; + lup.level = 12; + const res = LevelUpMove.toInt(lup.level); + assertOrPanic(res == 12); +} + +test "pointer to packed struct member in a stack variable" { + const S = packed struct { + a: u2, + b: u2, + }; + + var s = S{ .a = 2, .b = 0 }; + var b_ptr = &s.b; + assertOrPanic(s.b == 0); + b_ptr.* = 2; + assertOrPanic(s.b == 2); +} diff --git a/test/stage1/behavior/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig new file mode 100644 index 0000000000..4cc479f31c --- /dev/null +++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig @@ -0,0 +1,21 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "struct contains null pointer which contains original struct" { + var x: ?*NodeLineComment = null; + assertOrPanic(x == null); +} + +pub const Node = struct { + id: Id, + comment: ?*NodeLineComment, + + pub const Id = enum { + Root, + LineComment, + }; +}; + +pub const NodeLineComment = struct { + base: Node, +}; diff --git a/test/stage1/behavior/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig new file mode 100644 index 0000000000..15780a7c44 --- /dev/null +++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig @@ -0,0 +1,85 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const Node = struct { + payload: i32, + children: []Node, +}; + +const NodeAligned = struct { + payload: i32, + children: []align(@alignOf(NodeAligned)) NodeAligned, +}; + +test "struct contains slice of itself" { + var other_nodes = []Node{ + Node{ + .payload = 31, + .children = []Node{}, + }, + Node{ + .payload = 32, + .children = []Node{}, + }, + }; + var nodes = []Node{ + Node{ + .payload = 1, + .children = []Node{}, + }, + Node{ + .payload = 2, + .children = []Node{}, + }, + Node{ + .payload = 3, + .children = other_nodes[0..], + }, + }; + const root = Node{ + .payload = 1234, + .children = nodes[0..], + }; + assertOrPanic(root.payload == 1234); + assertOrPanic(root.children[0].payload == 1); + assertOrPanic(root.children[1].payload == 2); + assertOrPanic(root.children[2].payload == 3); + assertOrPanic(root.children[2].children[0].payload == 31); + assertOrPanic(root.children[2].children[1].payload == 32); +} + +test "struct contains aligned slice of itself" { + var other_nodes = []NodeAligned{ + NodeAligned{ + .payload = 31, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 32, + .children = []NodeAligned{}, + }, + }; + var nodes = []NodeAligned{ + NodeAligned{ + .payload = 1, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 2, + .children = []NodeAligned{}, + }, + NodeAligned{ + .payload = 3, + .children = other_nodes[0..], + }, + }; + const root = NodeAligned{ + .payload = 1234, + .children = nodes[0..], + }; + assertOrPanic(root.payload == 1234); + assertOrPanic(root.children[0].payload == 1); + assertOrPanic(root.children[1].payload == 2); + assertOrPanic(root.children[2].payload == 3); + assertOrPanic(root.children[2].children[0].payload == 31); + assertOrPanic(root.children[2].children[1].payload == 32); +} diff --git a/test/stage1/behavior/switch.zig b/test/stage1/behavior/switch.zig new file mode 100644 index 0000000000..4ac971397e --- /dev/null +++ b/test/stage1/behavior/switch.zig @@ -0,0 +1,271 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "switch with numbers" { + testSwitchWithNumbers(13); +} + +fn testSwitchWithNumbers(x: u32) void { + const result = switch (x) { + 1, 2, 3, 4...8 => false, + 13 => true, + else => false, + }; + assertOrPanic(result); +} + +test "switch with all ranges" { + assertOrPanic(testSwitchWithAllRanges(50, 3) == 1); + assertOrPanic(testSwitchWithAllRanges(101, 0) == 2); + assertOrPanic(testSwitchWithAllRanges(300, 5) == 3); + assertOrPanic(testSwitchWithAllRanges(301, 6) == 6); +} + +fn testSwitchWithAllRanges(x: u32, y: u32) u32 { + return switch (x) { + 0...100 => 1, + 101...200 => 2, + 201...300 => 3, + else => y, + }; +} + +test "implicit comptime switch" { + const x = 3 + 4; + const result = switch (x) { + 3 => 10, + 4 => 11, + 5, 6 => 12, + 7, 8 => 13, + else => 14, + }; + + comptime { + assertOrPanic(result + 1 == 14); + } +} + +test "switch on enum" { + const fruit = Fruit.Orange; + nonConstSwitchOnEnum(fruit); +} +const Fruit = enum { + Apple, + Orange, + Banana, +}; +fn nonConstSwitchOnEnum(fruit: Fruit) void { + switch (fruit) { + Fruit.Apple => unreachable, + Fruit.Orange => {}, + Fruit.Banana => unreachable, + } +} + +test "switch statement" { + nonConstSwitch(SwitchStatmentFoo.C); +} +fn nonConstSwitch(foo: SwitchStatmentFoo) void { + const val = switch (foo) { + SwitchStatmentFoo.A => i32(1), + SwitchStatmentFoo.B => 2, + SwitchStatmentFoo.C => 3, + SwitchStatmentFoo.D => 4, + }; + assertOrPanic(val == 3); +} +const SwitchStatmentFoo = enum { + A, + B, + C, + D, +}; + +test "switch prong with variable" { + switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); + switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); + switchProngWithVarFn(SwitchProngWithVarEnum{ .Meh = {} }); +} +const SwitchProngWithVarEnum = union(enum) { + One: i32, + Two: f32, + Meh: void, +}; +fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { + switch (a) { + SwitchProngWithVarEnum.One => |x| { + assertOrPanic(x == 13); + }, + SwitchProngWithVarEnum.Two => |x| { + assertOrPanic(x == 13.0); + }, + SwitchProngWithVarEnum.Meh => |x| { + const v: void = x; + }, + } +} + +test "switch on enum using pointer capture" { + testSwitchEnumPtrCapture(); + comptime testSwitchEnumPtrCapture(); +} + +fn testSwitchEnumPtrCapture() void { + var value = SwitchProngWithVarEnum{ .One = 1234 }; + switch (value) { + SwitchProngWithVarEnum.One => |*x| x.* += 1, + else => unreachable, + } + switch (value) { + SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235), + else => unreachable, + } +} + +test "switch with multiple expressions" { + const x = switch (returnsFive()) { + 1, 2, 3 => 1, + 4, 5, 6 => 2, + else => i32(3), + }; + assertOrPanic(x == 2); +} +fn returnsFive() i32 { + return 5; +} + +const Number = union(enum) { + One: u64, + Two: u8, + Three: f32, +}; + +const number = Number{ .Three = 1.23 }; + +fn returnsFalse() bool { + switch (number) { + Number.One => |x| return x > 1234, + Number.Two => |x| return x == 'a', + Number.Three => |x| return x > 12.34, + } +} +test "switch on const enum with var" { + assertOrPanic(!returnsFalse()); +} + +test "switch on type" { + assertOrPanic(trueIfBoolFalseOtherwise(bool)); + assertOrPanic(!trueIfBoolFalseOtherwise(i32)); +} + +fn trueIfBoolFalseOtherwise(comptime T: type) bool { + return switch (T) { + bool => true, + else => false, + }; +} + +test "switch handles all cases of number" { + testSwitchHandleAllCases(); + comptime testSwitchHandleAllCases(); +} + +fn testSwitchHandleAllCases() void { + assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3); + assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2); + assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1); + assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0); + + assertOrPanic(testSwitchHandleAllCasesRange(100) == 0); + assertOrPanic(testSwitchHandleAllCasesRange(200) == 1); + assertOrPanic(testSwitchHandleAllCasesRange(201) == 2); + assertOrPanic(testSwitchHandleAllCasesRange(202) == 4); + assertOrPanic(testSwitchHandleAllCasesRange(230) == 3); +} + +fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { + return switch (x) { + 0 => u2(3), + 1 => 2, + 2 => 1, + 3 => 0, + }; +} + +fn testSwitchHandleAllCasesRange(x: u8) u8 { + return switch (x) { + 0...100 => u8(0), + 101...200 => 1, + 201, 203 => 2, + 202 => 4, + 204...255 => 3, + }; +} + +test "switch all prongs unreachable" { + testAllProngsUnreachable(); + comptime testAllProngsUnreachable(); +} + +fn testAllProngsUnreachable() void { + assertOrPanic(switchWithUnreachable(1) == 2); + assertOrPanic(switchWithUnreachable(2) == 10); +} + +fn switchWithUnreachable(x: i32) i32 { + while (true) { + switch (x) { + 1 => return 2, + 2 => break, + else => continue, + } + } + return 10; +} + +fn return_a_number() anyerror!i32 { + return 1; +} + +test "capture value of switch with all unreachable prongs" { + const x = return_a_number() catch |err| switch (err) { + else => unreachable, + }; + assertOrPanic(x == 1); +} + +test "switching on booleans" { + testSwitchOnBools(); + comptime testSwitchOnBools(); +} + +fn testSwitchOnBools() void { + assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false); + assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true); + + assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false); + assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true); + + assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false); + assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true); +} + +fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { + return switch (x) { + true => false, + false => true, + }; +} + +fn testSwitchOnBoolsTrueWithElse(x: bool) bool { + return switch (x) { + true => false, + else => true, + }; +} + +fn testSwitchOnBoolsFalseWithElse(x: bool) bool { + return switch (x) { + false => true, + else => false, + }; +} diff --git a/test/stage1/behavior/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig new file mode 100644 index 0000000000..6ac1919f0d --- /dev/null +++ b/test/stage1/behavior/switch_prong_err_enum.zig @@ -0,0 +1,30 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +var read_count: u64 = 0; + +fn readOnce() anyerror!u64 { + read_count += 1; + return read_count; +} + +const FormValue = union(enum) { + Address: u64, + Other: bool, +}; + +fn doThing(form_id: u64) anyerror!FormValue { + return switch (form_id) { + 17 => FormValue{ .Address = try readOnce() }, + else => error.InvalidDebugInfo, + }; +} + +test "switch prong returns error enum" { + switch (doThing(17) catch unreachable) { + FormValue.Address => |payload| { + assertOrPanic(payload == 1); + }, + else => unreachable, + } + assertOrPanic(read_count == 1); +} diff --git a/test/stage1/behavior/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig new file mode 100644 index 0000000000..4ca031e2e1 --- /dev/null +++ b/test/stage1/behavior/switch_prong_implicit_cast.zig @@ -0,0 +1,22 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const FormValue = union(enum) { + One: void, + Two: bool, +}; + +fn foo(id: u64) !FormValue { + return switch (id) { + 2 => FormValue{ .Two = true }, + 1 => FormValue{ .One = {} }, + else => return error.Whatever, + }; +} + +test "switch prong implicit cast" { + const result = switch (foo(2) catch unreachable) { + FormValue.One => false, + FormValue.Two => |x| x, + }; + assertOrPanic(result); +} diff --git a/test/stage1/behavior/syntax.zig b/test/stage1/behavior/syntax.zig new file mode 100644 index 0000000000..451e396142 --- /dev/null +++ b/test/stage1/behavior/syntax.zig @@ -0,0 +1,60 @@ +// Test trailing comma syntax +// zig fmt: off + +const struct_trailing_comma = struct { x: i32, y: i32, }; +const struct_no_comma = struct { x: i32, y: i32 }; +const struct_fn_no_comma = struct { fn m() void {} y: i32 }; + +const enum_no_comma = enum { A, B }; + +fn container_init() void { + const S = struct { x: i32, y: i32 }; + _ = S { .x = 1, .y = 2 }; + _ = S { .x = 1, .y = 2, }; +} + +fn type_expr_return1() if (true) A {} +fn type_expr_return2() for (true) |_| A {} +fn type_expr_return3() while (true) A {} +fn type_expr_return4() comptime A {} + +fn switch_cases(x: i32) void { + switch (x) { + 1,2,3 => {}, + 4,5, => {}, + 6...8, => {}, + else => {}, + } +} + +fn switch_prongs(x: i32) void { + switch (x) { + 0 => {}, + else => {}, + } + switch (x) { + 0 => {}, + else => {} + } +} + +const fn_no_comma = fn(i32, i32)void; +const fn_trailing_comma = fn(i32, i32,)void; + +fn fn_calls() void { + fn add(x: i32, y: i32,) i32 { x + y }; + _ = add(1, 2); + _ = add(1, 2,); +} + +fn asm_lists() void { + if (false) { // Build AST but don't analyze + asm ("not real assembly" + :[a] "x" (x),); + asm ("not real assembly" + :[a] "x" (->i32),:[a] "x" (1),); + asm ("still not real assembly" + :::"a","b",); + } +} + diff --git a/test/stage1/behavior/this.zig b/test/stage1/behavior/this.zig new file mode 100644 index 0000000000..0e3a7a03ae --- /dev/null +++ b/test/stage1/behavior/this.zig @@ -0,0 +1,35 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const module = @This(); + +fn Point(comptime T: type) type { + return struct { + const Self = @This(); + x: T, + y: T, + + fn addOne(self: *Self) void { + self.x += 1; + self.y += 1; + } + }; +} + +fn add(x: i32, y: i32) i32 { + return x + y; +} + +test "this refer to module call private fn" { + assertOrPanic(module.add(1, 2) == 3); +} + +test "this refer to container" { + var pt = Point(i32){ + .x = 12, + .y = 34, + }; + pt.addOne(); + assertOrPanic(pt.x == 13); + assertOrPanic(pt.y == 35); +} + diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig new file mode 100644 index 0000000000..b7904bc7fb --- /dev/null +++ b/test/stage1/behavior/truncate.zig @@ -0,0 +1,8 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "truncate u0 to larger integer allowed and has comptime known result" { + var x: u0 = 0; + const y = @truncate(u8, x); + comptime assertOrPanic(y == 0); +} diff --git a/test/stage1/behavior/try.zig b/test/stage1/behavior/try.zig new file mode 100644 index 0000000000..ed48875eb4 --- /dev/null +++ b/test/stage1/behavior/try.zig @@ -0,0 +1,43 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "try on error union" { + tryOnErrorUnionImpl(); + comptime tryOnErrorUnionImpl(); +} + +fn tryOnErrorUnionImpl() void { + const x = if (returnsTen()) |val| val + 1 else |err| switch (err) { + error.ItBroke, error.NoMem => 1, + error.CrappedOut => i32(2), + else => unreachable, + }; + assertOrPanic(x == 11); +} + +fn returnsTen() anyerror!i32 { + return 10; +} + +test "try without vars" { + const result1 = if (failIfTrue(true)) 1 else |_| i32(2); + assertOrPanic(result1 == 2); + + const result2 = if (failIfTrue(false)) 1 else |_| i32(2); + assertOrPanic(result2 == 1); +} + +fn failIfTrue(ok: bool) anyerror!void { + if (ok) { + return error.ItBroke; + } else { + return; + } +} + +test "try then not executed with assignment" { + if (failIfTrue(true)) { + unreachable; + } else |err| { + assertOrPanic(err == error.ItBroke); + } +} diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig new file mode 100644 index 0000000000..5ad80e06e1 --- /dev/null +++ b/test/stage1/behavior/type_info.zig @@ -0,0 +1,264 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; +const TypeInfo = @import("builtin").TypeInfo; +const TypeId = @import("builtin").TypeId; + +test "type info: tag type, void info" { + testBasic(); + comptime testBasic(); +} + +fn testBasic() void { + assertOrPanic(@TagType(TypeInfo) == TypeId); + const void_info = @typeInfo(void); + assertOrPanic(TypeId(void_info) == TypeId.Void); + assertOrPanic(void_info.Void == {}); +} + +test "type info: integer, floating point type info" { + testIntFloat(); + comptime testIntFloat(); +} + +fn testIntFloat() void { + const u8_info = @typeInfo(u8); + assertOrPanic(TypeId(u8_info) == TypeId.Int); + assertOrPanic(!u8_info.Int.is_signed); + assertOrPanic(u8_info.Int.bits == 8); + + const f64_info = @typeInfo(f64); + assertOrPanic(TypeId(f64_info) == TypeId.Float); + assertOrPanic(f64_info.Float.bits == 64); +} + +test "type info: pointer type info" { + testPointer(); + comptime testPointer(); +} + +fn testPointer() void { + const u32_ptr_info = @typeInfo(*u32); + assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); + assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); + assertOrPanic(u32_ptr_info.Pointer.is_const == false); + assertOrPanic(u32_ptr_info.Pointer.is_volatile == false); + assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32)); + assertOrPanic(u32_ptr_info.Pointer.child == u32); +} + +test "type info: unknown length pointer type info" { + testUnknownLenPtr(); + comptime testUnknownLenPtr(); +} + +fn testUnknownLenPtr() void { + const u32_ptr_info = @typeInfo([*]const volatile f64); + assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); + assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); + assertOrPanic(u32_ptr_info.Pointer.is_const == true); + assertOrPanic(u32_ptr_info.Pointer.is_volatile == true); + assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64)); + assertOrPanic(u32_ptr_info.Pointer.child == f64); +} + +test "type info: slice type info" { + testSlice(); + comptime testSlice(); +} + +fn testSlice() void { + const u32_slice_info = @typeInfo([]u32); + assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer); + assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); + assertOrPanic(u32_slice_info.Pointer.is_const == false); + assertOrPanic(u32_slice_info.Pointer.is_volatile == false); + assertOrPanic(u32_slice_info.Pointer.alignment == 4); + assertOrPanic(u32_slice_info.Pointer.child == u32); +} + +test "type info: array type info" { + testArray(); + comptime testArray(); +} + +fn testArray() void { + const arr_info = @typeInfo([42]bool); + assertOrPanic(TypeId(arr_info) == TypeId.Array); + assertOrPanic(arr_info.Array.len == 42); + assertOrPanic(arr_info.Array.child == bool); +} + +test "type info: optional type info" { + testOptional(); + comptime testOptional(); +} + +fn testOptional() void { + const null_info = @typeInfo(?void); + assertOrPanic(TypeId(null_info) == TypeId.Optional); + assertOrPanic(null_info.Optional.child == void); +} + +test "type info: promise info" { + testPromise(); + comptime testPromise(); +} + +fn testPromise() void { + const null_promise_info = @typeInfo(promise); + assertOrPanic(TypeId(null_promise_info) == TypeId.Promise); + assertOrPanic(null_promise_info.Promise.child == null); + + const promise_info = @typeInfo(promise->usize); + assertOrPanic(TypeId(promise_info) == TypeId.Promise); + assertOrPanic(promise_info.Promise.child.? == usize); +} + +test "type info: error set, error union info" { + testErrorSet(); + comptime testErrorSet(); +} + +fn testErrorSet() void { + const TestErrorSet = error{ + First, + Second, + Third, + }; + + const error_set_info = @typeInfo(TestErrorSet); + assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet); + assertOrPanic(error_set_info.ErrorSet.errors.len == 3); + assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); + assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); + + const error_union_info = @typeInfo(TestErrorSet!usize); + assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion); + assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet); + assertOrPanic(error_union_info.ErrorUnion.payload == usize); +} + +test "type info: enum info" { + testEnum(); + comptime testEnum(); +} + +fn testEnum() void { + const Os = enum { + Windows, + Macos, + Linux, + FreeBSD, + }; + + const os_info = @typeInfo(Os); + assertOrPanic(TypeId(os_info) == TypeId.Enum); + assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(os_info.Enum.fields.len == 4); + assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); + assertOrPanic(os_info.Enum.fields[3].value == 3); + assertOrPanic(os_info.Enum.tag_type == u2); + assertOrPanic(os_info.Enum.defs.len == 0); +} + +test "type info: union info" { + testUnion(); + comptime testUnion(); +} + +fn testUnion() void { + const typeinfo_info = @typeInfo(TypeInfo); + assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); + assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); + assertOrPanic(typeinfo_info.Union.fields.len == 24); + assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); + assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); + assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); + assertOrPanic(typeinfo_info.Union.defs.len == 20); + + const TestNoTagUnion = union { + Foo: void, + Bar: u32, + }; + + const notag_union_info = @typeInfo(TestNoTagUnion); + assertOrPanic(TypeId(notag_union_info) == TypeId.Union); + assertOrPanic(notag_union_info.Union.tag_type == null); + assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + assertOrPanic(notag_union_info.Union.fields.len == 2); + assertOrPanic(notag_union_info.Union.fields[0].enum_field == null); + assertOrPanic(notag_union_info.Union.fields[1].field_type == u32); + + const TestExternUnion = extern union { + foo: *c_void, + }; + + const extern_union_info = @typeInfo(TestExternUnion); + assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + assertOrPanic(extern_union_info.Union.tag_type == null); + assertOrPanic(extern_union_info.Union.fields[0].enum_field == null); + assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void); +} + +test "type info: struct info" { + testStruct(); + comptime testStruct(); +} + +fn testStruct() void { + const struct_info = @typeInfo(TestStruct); + assertOrPanic(TypeId(struct_info) == TypeId.Struct); + assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + assertOrPanic(struct_info.Struct.fields.len == 3); + assertOrPanic(struct_info.Struct.fields[1].offset == null); + assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct); + assertOrPanic(struct_info.Struct.defs.len == 2); + assertOrPanic(struct_info.Struct.defs[0].is_pub); + assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void); + assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); +} + +const TestStruct = packed struct { + const Self = @This(); + + fieldA: usize, + fieldB: void, + fieldC: *Self, + + pub fn foo(self: *const Self) void {} +}; + +test "type info: function type info" { + testFunction(); + comptime testFunction(); +} + +fn testFunction() void { + const fn_info = @typeInfo(@typeOf(foo)); + assertOrPanic(TypeId(fn_info) == TypeId.Fn); + assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); + assertOrPanic(fn_info.Fn.is_generic); + assertOrPanic(fn_info.Fn.args.len == 2); + assertOrPanic(fn_info.Fn.is_var_args); + assertOrPanic(fn_info.Fn.return_type == null); + assertOrPanic(fn_info.Fn.async_allocator_type == null); + + const test_instance: TestStruct = undefined; + const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); + assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn); + assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); +} + +fn foo(comptime a: usize, b: bool, args: ...) usize { + return 0; +} + +test "typeInfo with comptime parameter in struct fn def" { + const S = struct { + pub fn func(comptime x: f32) void {} + }; + comptime var info = @typeInfo(S); +} diff --git a/test/stage1/behavior/undefined.zig b/test/stage1/behavior/undefined.zig new file mode 100644 index 0000000000..333e217d49 --- /dev/null +++ b/test/stage1/behavior/undefined.zig @@ -0,0 +1,69 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; +const mem = @import("std").mem; + +fn initStaticArray() [10]i32 { + var array: [10]i32 = undefined; + array[0] = 1; + array[4] = 2; + array[7] = 3; + array[9] = 4; + return array; +} +const static_array = initStaticArray(); +test "init static array to undefined" { + assertOrPanic(static_array[0] == 1); + assertOrPanic(static_array[4] == 2); + assertOrPanic(static_array[7] == 3); + assertOrPanic(static_array[9] == 4); + + comptime { + assertOrPanic(static_array[0] == 1); + assertOrPanic(static_array[4] == 2); + assertOrPanic(static_array[7] == 3); + assertOrPanic(static_array[9] == 4); + } +} + +const Foo = struct { + x: i32, + + fn setFooXMethod(foo: *Foo) void { + foo.x = 3; + } +}; + +fn setFooX(foo: *Foo) void { + foo.x = 2; +} + +test "assign undefined to struct" { + comptime { + var foo: Foo = undefined; + setFooX(&foo); + assertOrPanic(foo.x == 2); + } + { + var foo: Foo = undefined; + setFooX(&foo); + assertOrPanic(foo.x == 2); + } +} + +test "assign undefined to struct with method" { + comptime { + var foo: Foo = undefined; + foo.setFooXMethod(); + assertOrPanic(foo.x == 3); + } + { + var foo: Foo = undefined; + foo.setFooXMethod(); + assertOrPanic(foo.x == 3); + } +} + +test "type name of undefined" { + const x = undefined; + assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); +} + diff --git a/test/stage1/behavior/underscore.zig b/test/stage1/behavior/underscore.zig new file mode 100644 index 0000000000..7443319336 --- /dev/null +++ b/test/stage1/behavior/underscore.zig @@ -0,0 +1,28 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "ignore lval with underscore" { + _ = false; +} + +test "ignore lval with underscore (for loop)" { + for ([]void{}) |_, i| { + for ([]void{}) |_, j| { + break; + } + break; + } +} + +test "ignore lval with underscore (while loop)" { + while (optionalReturnError()) |_| { + while (optionalReturnError()) |_| { + break; + } else |_| {} + break; + } else |_| {} +} + +fn optionalReturnError() !?u32 { + return error.optionalReturnError; +} diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig new file mode 100644 index 0000000000..c8e8feb11e --- /dev/null +++ b/test/stage1/behavior/union.zig @@ -0,0 +1,352 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const Value = union(enum) { + Int: u64, + Array: [9]u8, +}; + +const Agg = struct { + val1: Value, + val2: Value, +}; + +const v1 = Value{ .Int = 1234 }; +const v2 = Value{ .Array = []u8{3} ** 9 }; + +const err = (anyerror!Agg)(Agg{ + .val1 = v1, + .val2 = v2, +}); + +const array = []Value{ + v1, + v2, + v1, + v2, +}; + +test "unions embedded in aggregate types" { + switch (array[1]) { + Value.Array => |arr| assertOrPanic(arr[4] == 3), + else => unreachable, + } + switch ((err catch unreachable).val1) { + Value.Int => |x| assertOrPanic(x == 1234), + else => unreachable, + } +} + +const Foo = union { + float: f64, + int: i32, +}; + +test "basic unions" { + var foo = Foo{ .int = 1 }; + assertOrPanic(foo.int == 1); + foo = Foo{ .float = 12.34 }; + assertOrPanic(foo.float == 12.34); +} + +test "comptime union field access" { + comptime { + var foo = Foo{ .int = 0 }; + assertOrPanic(foo.int == 0); + + foo = Foo{ .float = 42.42 }; + assertOrPanic(foo.float == 42.42); + } +} + +test "init union with runtime value" { + var foo: Foo = undefined; + + setFloat(&foo, 12.34); + assertOrPanic(foo.float == 12.34); + + setInt(&foo, 42); + assertOrPanic(foo.int == 42); +} + +fn setFloat(foo: *Foo, x: f64) void { + foo.* = Foo{ .float = x }; +} + +fn setInt(foo: *Foo, x: i32) void { + foo.* = Foo{ .int = x }; +} + +const FooExtern = extern union { + float: f64, + int: i32, +}; + +test "basic extern unions" { + var foo = FooExtern{ .int = 1 }; + assertOrPanic(foo.int == 1); + foo.float = 12.34; + assertOrPanic(foo.float == 12.34); +} + +const Letter = enum { + A, + B, + C, +}; +const Payload = union(Letter) { + A: i32, + B: f64, + C: bool, +}; + +test "union with specified enum tag" { + doTest(); + comptime doTest(); +} + +fn doTest() void { + assertOrPanic(bar(Payload{ .A = 1234 }) == -10); +} + +fn bar(value: Payload) i32 { + assertOrPanic(Letter(value) == Letter.A); + return switch (value) { + Payload.A => |x| return x - 1244, + Payload.B => |x| if (x == 12.34) i32(20) else 21, + Payload.C => |x| if (x) i32(30) else 31, + }; +} + +const MultipleChoice = union(enum(u32)) { + A = 20, + B = 40, + C = 60, + D = 1000, +}; +test "simple union(enum(u32))" { + var x = MultipleChoice.C; + assertOrPanic(x == MultipleChoice.C); + assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60); +} + +const MultipleChoice2 = union(enum(u32)) { + Unspecified1: i32, + A: f32 = 20, + Unspecified2: void, + B: bool = 40, + Unspecified3: i32, + C: i8 = 60, + Unspecified4: void, + D: void = 1000, + Unspecified5: i32, +}; + +test "union(enum(u32)) with specified and unspecified tag values" { + comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32); + testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); + comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); +} + +fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { + assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); + assertOrPanic(1123 == switch (x) { + MultipleChoice2.A => 1, + MultipleChoice2.B => 2, + MultipleChoice2.C => |v| i32(1000) + v, + MultipleChoice2.D => 4, + MultipleChoice2.Unspecified1 => 5, + MultipleChoice2.Unspecified2 => 6, + MultipleChoice2.Unspecified3 => 7, + MultipleChoice2.Unspecified4 => 8, + MultipleChoice2.Unspecified5 => 9, + }); +} + +const ExternPtrOrInt = extern union { + ptr: *u8, + int: u64, +}; +test "extern union size" { + comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8); +} + +const PackedPtrOrInt = packed union { + ptr: *u8, + int: u64, +}; +test "extern union size" { + comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8); +} + +const ZeroBits = union { + OnlyField: void, +}; +test "union with only 1 field which is void should be zero bits" { + comptime assertOrPanic(@sizeOf(ZeroBits) == 0); +} + +const TheTag = enum { + A, + B, + C, +}; +const TheUnion = union(TheTag) { + A: i32, + B: i32, + C: i32, +}; +test "union field access gives the enum values" { + assertOrPanic(TheUnion.A == TheTag.A); + assertOrPanic(TheUnion.B == TheTag.B); + assertOrPanic(TheUnion.C == TheTag.C); +} + +test "cast union to tag type of union" { + testCastUnionToTagType(TheUnion{ .B = 1234 }); + comptime testCastUnionToTagType(TheUnion{ .B = 1234 }); +} + +fn testCastUnionToTagType(x: TheUnion) void { + assertOrPanic(TheTag(x) == TheTag.B); +} + +test "cast tag type of union to union" { + var x: Value2 = Letter2.B; + assertOrPanic(Letter2(x) == Letter2.B); +} +const Letter2 = enum { + A, + B, + C, +}; +const Value2 = union(Letter2) { + A: i32, + B, + C, +}; + +test "implicit cast union to its tag type" { + var x: Value2 = Letter2.B; + assertOrPanic(x == Letter2.B); + giveMeLetterB(x); +} +fn giveMeLetterB(x: Letter2) void { + assertOrPanic(x == Value2.B); +} + +pub const PackThis = union(enum) { + Invalid: bool, + StringLiteral: u2, +}; + +test "constant packed union" { + testConstPackedUnion([]PackThis{PackThis{ .StringLiteral = 1 }}); +} + +fn testConstPackedUnion(expected_tokens: []const PackThis) void { + assertOrPanic(expected_tokens[0].StringLiteral == 1); +} + +test "switch on union with only 1 field" { + var r: PartialInst = undefined; + r = PartialInst.Compiled; + switch (r) { + PartialInst.Compiled => { + var z: PartialInstWithPayload = undefined; + z = PartialInstWithPayload{ .Compiled = 1234 }; + switch (z) { + PartialInstWithPayload.Compiled => |x| { + assertOrPanic(x == 1234); + return; + }, + } + }, + } + unreachable; +} + +const PartialInst = union(enum) { + Compiled, +}; + +const PartialInstWithPayload = union(enum) { + Compiled: i32, +}; + +test "access a member of tagged union with conflicting enum tag name" { + const Bar = union(enum) { + A: A, + B: B, + + const A = u8; + const B = void; + }; + + comptime assertOrPanic(Bar.A == u8); +} + +test "tagged union initialization with runtime void" { + assertOrPanic(testTaggedUnionInit({})); +} + +const TaggedUnionWithAVoid = union(enum) { + A, + B: i32, +}; + +fn testTaggedUnionInit(x: var) bool { + const y = TaggedUnionWithAVoid{ .A = x }; + return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A; +} + +pub const UnionEnumNoPayloads = union(enum) { + A, + B, +}; + +test "tagged union with no payloads" { + const a = UnionEnumNoPayloads{ .B = {} }; + switch (a) { + @TagType(UnionEnumNoPayloads).A => @panic("wrong"), + @TagType(UnionEnumNoPayloads).B => {}, + } +} + +test "union with only 1 field casted to its enum type" { + const Literal = union(enum) { + Number: f64, + Bool: bool, + }; + + const Expr = union(enum) { + Literal: Literal, + }; + + var e = Expr{ .Literal = Literal{ .Bool = true } }; + const Tag = @TagType(Expr); + comptime assertOrPanic(@TagType(Tag) == comptime_int); + var t = Tag(e); + assertOrPanic(t == Expr.Literal); +} + +test "union with only 1 field casted to its enum type which has enum value specified" { + const Literal = union(enum) { + Number: f64, + Bool: bool, + }; + + const Tag = enum { + Literal = 33, + }; + + const Expr = union(Tag) { + Literal: Literal, + }; + + var e = Expr{ .Literal = Literal{ .Bool = true } }; + comptime assertOrPanic(@TagType(Tag) == comptime_int); + var t = Tag(e); + assertOrPanic(t == Expr.Literal); + assertOrPanic(@enumToInt(t) == 33); + comptime assertOrPanic(@enumToInt(t) == 33); +} diff --git a/test/stage1/behavior/var_args.zig b/test/stage1/behavior/var_args.zig new file mode 100644 index 0000000000..1f782a3bb3 --- /dev/null +++ b/test/stage1/behavior/var_args.zig @@ -0,0 +1,84 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +fn add(args: ...) i32 { + var sum = i32(0); + { + comptime var i: usize = 0; + inline while (i < args.len) : (i += 1) { + sum += args[i]; + } + } + return sum; +} + +test "add arbitrary args" { + assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10); + assertOrPanic(add(i32(1234)) == 1234); + assertOrPanic(add() == 0); +} + +fn readFirstVarArg(args: ...) void { + const value = args[0]; +} + +test "send void arg to var args" { + readFirstVarArg({}); +} + +test "pass args directly" { + assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); + assertOrPanic(addSomeStuff(i32(1234)) == 1234); + assertOrPanic(addSomeStuff() == 0); +} + +fn addSomeStuff(args: ...) i32 { + return add(args); +} + +test "runtime parameter before var args" { + assertOrPanic(extraFn(10) == 0); + assertOrPanic(extraFn(10, false) == 1); + assertOrPanic(extraFn(10, false, true) == 2); + + // TODO issue #313 + //comptime { + // assertOrPanic(extraFn(10) == 0); + // assertOrPanic(extraFn(10, false) == 1); + // assertOrPanic(extraFn(10, false, true) == 2); + //} +} + +fn extraFn(extra: u32, args: ...) usize { + if (args.len >= 1) { + assertOrPanic(args[0] == false); + } + if (args.len >= 2) { + assertOrPanic(args[1] == true); + } + return args.len; +} + +const foos = []fn (...) bool{ + foo1, + foo2, +}; + +fn foo1(args: ...) bool { + return true; +} +fn foo2(args: ...) bool { + return false; +} + +test "array of var args functions" { + assertOrPanic(foos[0]()); + assertOrPanic(!foos[1]()); +} + +test "pass zero length array to var args param" { + doNothingWithFirstArg(""); +} + +fn doNothingWithFirstArg(args: ...) void { + const a = args[0]; +} diff --git a/test/stage1/behavior/void.zig b/test/stage1/behavior/void.zig new file mode 100644 index 0000000000..431d3f4eb1 --- /dev/null +++ b/test/stage1/behavior/void.zig @@ -0,0 +1,35 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +const Foo = struct { + a: void, + b: i32, + c: void, +}; + +test "compare void with void compile time known" { + comptime { + const foo = Foo{ + .a = {}, + .b = 1, + .c = {}, + }; + assertOrPanic(foo.a == {}); + } +} + +test "iterate over a void slice" { + var j: usize = 0; + for (times(10)) |_, i| { + assertOrPanic(i == j); + j += 1; + } +} + +fn times(n: usize) []const void { + return ([*]void)(undefined)[0..n]; +} + +test "void optional" { + var x: ?void = {}; + assertOrPanic(x != null); +} diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig new file mode 100644 index 0000000000..579b4e4db8 --- /dev/null +++ b/test/stage1/behavior/while.zig @@ -0,0 +1,228 @@ +const assertOrPanic = @import("std").debug.assertOrPanic; + +test "while loop" { + var i: i32 = 0; + while (i < 4) { + i += 1; + } + assertOrPanic(i == 4); + assertOrPanic(whileLoop1() == 1); +} +fn whileLoop1() i32 { + return whileLoop2(); +} +fn whileLoop2() i32 { + while (true) { + return 1; + } +} + +test "static eval while" { + assertOrPanic(static_eval_while_number == 1); +} +const static_eval_while_number = staticWhileLoop1(); +fn staticWhileLoop1() i32 { + return whileLoop2(); +} +fn staticWhileLoop2() i32 { + while (true) { + return 1; + } +} + +test "continue and break" { + runContinueAndBreakTest(); + assertOrPanic(continue_and_break_counter == 8); +} +var continue_and_break_counter: i32 = 0; +fn runContinueAndBreakTest() void { + var i: i32 = 0; + while (true) { + continue_and_break_counter += 2; + i += 1; + if (i < 4) { + continue; + } + break; + } + assertOrPanic(i == 4); +} + +test "return with implicit cast from while loop" { + returnWithImplicitCastFromWhileLoopTest() catch unreachable; +} +fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { + while (true) { + return; + } +} + +test "while with continue expression" { + var sum: i32 = 0; + { + var i: i32 = 0; + while (i < 10) : (i += 1) { + if (i == 5) continue; + sum += i; + } + } + assertOrPanic(sum == 40); +} + +test "while with else" { + var sum: i32 = 0; + var i: i32 = 0; + var got_else: i32 = 0; + while (i < 10) : (i += 1) { + sum += 1; + } else { + got_else += 1; + } + assertOrPanic(sum == 10); + assertOrPanic(got_else == 1); +} + +test "while with optional as condition" { + numbers_left = 10; + var sum: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + } + assertOrPanic(sum == 45); +} + +test "while with optional as condition with else" { + numbers_left = 10; + var sum: i32 = 0; + var got_else: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + assertOrPanic(got_else == 0); + } else { + got_else += 1; + } + assertOrPanic(sum == 45); + assertOrPanic(got_else == 1); +} + +test "while with error union condition" { + numbers_left = 10; + var sum: i32 = 0; + var got_else: i32 = 0; + while (getNumberOrErr()) |value| { + sum += value; + } else |err| { + assertOrPanic(err == error.OutOfNumbers); + got_else += 1; + } + assertOrPanic(sum == 45); + assertOrPanic(got_else == 1); +} + +var numbers_left: i32 = undefined; +fn getNumberOrErr() anyerror!i32 { + return if (numbers_left == 0) error.OutOfNumbers else x: { + numbers_left -= 1; + break :x numbers_left; + }; +} +fn getNumberOrNull() ?i32 { + return if (numbers_left == 0) null else x: { + numbers_left -= 1; + break :x numbers_left; + }; +} + +test "while on optional with else result follow else prong" { + const result = while (returnNull()) |value| { + break value; + } else + i32(2); + assertOrPanic(result == 2); +} + +test "while on optional with else result follow break prong" { + const result = while (returnOptional(10)) |value| { + break value; + } else + i32(2); + assertOrPanic(result == 10); +} + +test "while on error union with else result follow else prong" { + const result = while (returnError()) |value| { + break value; + } else |err| + i32(2); + assertOrPanic(result == 2); +} + +test "while on error union with else result follow break prong" { + const result = while (returnSuccess(10)) |value| { + break value; + } else |err| + i32(2); + assertOrPanic(result == 10); +} + +test "while on bool with else result follow else prong" { + const result = while (returnFalse()) { + break i32(10); + } else + i32(2); + assertOrPanic(result == 2); +} + +test "while on bool with else result follow break prong" { + const result = while (returnTrue()) { + break i32(10); + } else + i32(2); + assertOrPanic(result == 10); +} + +test "break from outer while loop" { + testBreakOuter(); + comptime testBreakOuter(); +} + +fn testBreakOuter() void { + outer: while (true) { + while (true) { + break :outer; + } + } +} + +test "continue outer while loop" { + testContinueOuter(); + comptime testContinueOuter(); +} + +fn testContinueOuter() void { + var i: usize = 0; + outer: while (i < 10) : (i += 1) { + while (true) { + continue :outer; + } + } +} + +fn returnNull() ?i32 { + return null; +} +fn returnOptional(x: i32) ?i32 { + return x; +} +fn returnError() anyerror!i32 { + return error.YouWantedAnError; +} +fn returnSuccess(x: i32) anyerror!i32 { + return x; +} +fn returnFalse() bool { + return false; +} +fn returnTrue() bool { + return true; +} diff --git a/test/stage1/behavior/widening.zig b/test/stage1/behavior/widening.zig new file mode 100644 index 0000000000..7577868aff --- /dev/null +++ b/test/stage1/behavior/widening.zig @@ -0,0 +1,28 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; +const mem = std.mem; + +test "integer widening" { + var a: u8 = 250; + var b: u16 = a; + var c: u32 = b; + var d: u64 = c; + var e: u64 = d; + var f: u128 = e; + assertOrPanic(f == a); +} + +test "implicit unsigned integer to signed integer" { + var a: u8 = 250; + var b: i16 = a; + assertOrPanic(b == 250); +} + +test "float widening" { + var a: f16 = 12.34; + var b: f32 = a; + var c: f64 = b; + var d: f128 = c; + assertOrPanic(d == a); +} + -- cgit v1.2.3 From 545064c1d9137a603e3e28aa066ce9e65a1ed4b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 30 Jan 2019 23:36:52 -0500 Subject: introduce vector type for SIMD See #903 * create with `@Vector(len, ElemType)` * only wrapping addition is implemented This feature is far from complete; this is only the beginning. --- doc/langref.html.in | 34 ++++++ src-self-hosted/type.zig | 16 +++ src/all_types.hpp | 26 +++++ src/analyze.cpp | 91 ++++++++++++++-- src/analyze.hpp | 1 + src/codegen.cpp | 47 +++++++- src/ir.cpp | 213 +++++++++++++++++++++++++++++-------- src/ir_print.cpp | 11 ++ src/zig_llvm.cpp | 13 +++ src/zig_llvm.h | 3 + std/hash_map.zig | 2 + test/stage1/behavior/type_info.zig | 16 ++- 12 files changed, 419 insertions(+), 54 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index 909c0f5817..e192dbbf76 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -1531,6 +1531,29 @@ test "array initialization with function calls" { {#code_end#} {#see_also|for|Slices#} {#header_close#} + + {#header_open|Vectors#} +

+ A vector is a group of {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on + in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin + function {#link|@Vector#}. +

+

+ TODO talk about C ABI interop +

+ {#header_open|SIMD#} +

+ TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the + docs with: + * What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector? + * How to convert to/from vectors/arrays + * How to access individual elements from vectors, how to loop over the elements + * "shuffle" + * Advice on writing high perf software, how to abstract the best way +

+ {#header_close#} + {#header_close#} + {#header_open|Pointers#}

Zig has two kinds of pointers: @@ -6607,6 +6630,17 @@ pub const TypeInfo = union(TypeId) { expression passed as an argument. The expression is evaluated.

+ {#header_close#} + + {#header_open|@Vector#} +
{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}
+

+ This function returns a vector type for {#link|SIMD#}. +

+

+ {#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a + {#link|pointer|Pointers#}. +

{#header_close#} {#header_close#} diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index aa00bb876d..fa31343902 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -44,6 +44,7 @@ pub const Type = struct { Id.ArgTuple => @fieldParentPtr(ArgTuple, "base", base).destroy(comp), Id.Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp), Id.Promise => @fieldParentPtr(Promise, "base", base).destroy(comp), + Id.Vector => @fieldParentPtr(Vector, "base", base).destroy(comp), } } @@ -77,6 +78,7 @@ pub const Type = struct { Id.ArgTuple => unreachable, Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context), Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context), + Id.Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context), } } @@ -103,6 +105,7 @@ pub const Type = struct { Id.Enum, Id.Fn, Id.Promise, + Id.Vector, => return false, Id.Struct => @panic("TODO"), @@ -135,6 +138,7 @@ pub const Type = struct { Id.Float, Id.Fn, Id.Promise, + Id.Vector, => return true, Id.Pointer => { @@ -902,6 +906,18 @@ pub const Type = struct { } }; + pub const Vector = struct { + base: Type, + + pub fn destroy(self: *Vector, comp: *Compilation) void { + comp.gpa().destroy(self); + } + + pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + @panic("TODO"); + } + }; + pub const ComptimeFloat = struct { base: Type, diff --git a/src/all_types.hpp b/src/all_types.hpp index 4b134361a3..f6fe72891d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -252,6 +252,10 @@ struct ConstArgTuple { size_t end_index; }; +struct ConstVector { + ConstExprValue *elements; +}; + enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, @@ -318,6 +322,7 @@ struct ConstExprValue { ConstPtrValue x_ptr; ImportTableEntry *x_import; ConstArgTuple x_arg_tuple; + ConstVector x_vector; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -1210,6 +1215,12 @@ struct ZigTypePromise { ZigType *result_type; }; +struct ZigTypeVector { + // The type must be a pointer, integer, or float + ZigType *elem_type; + uint32_t len; +}; + enum ZigTypeId { ZigTypeIdInvalid, ZigTypeIdMetaType, @@ -1236,6 +1247,7 @@ enum ZigTypeId { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdPromise, + ZigTypeIdVector, }; struct ZigType { @@ -1262,6 +1274,7 @@ struct ZigType { ZigTypeFn fn; ZigTypeBoundFn bound_fn; ZigTypePromise promise; + ZigTypeVector vector; } data; // use these fields to make sure we don't duplicate type table entries for the same type @@ -1415,6 +1428,7 @@ enum BuiltinFnId { BuiltinFnIdEnumToInt, BuiltinFnIdIntToEnum, BuiltinFnIdIntType, + BuiltinFnIdVectorType, BuiltinFnIdSetCold, BuiltinFnIdSetRuntimeSafety, BuiltinFnIdSetFloatMode, @@ -1505,6 +1519,10 @@ struct TypeId { ZigType *err_set_type; ZigType *payload_type; } error_union; + struct { + ZigType *elem_type; + uint32_t len; + } vector; } data; }; @@ -2139,6 +2157,7 @@ enum IrInstructionId { IrInstructionIdFloatToInt, IrInstructionIdBoolToInt, IrInstructionIdIntType, + IrInstructionIdVectorType, IrInstructionIdBoolNot, IrInstructionIdMemset, IrInstructionIdMemcpy, @@ -2807,6 +2826,13 @@ struct IrInstructionIntType { IrInstruction *bit_count; }; +struct IrInstructionVectorType { + IrInstruction base; + + IrInstruction *len; + IrInstruction *elem_type; +}; + struct IrInstructionBoolNot { IrInstruction base; diff --git a/src/analyze.cpp b/src/analyze.cpp index 194888068c..99378eb7a8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -250,6 +250,7 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return nullptr; } zig_unreachable(); @@ -311,6 +312,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return true; } zig_unreachable(); @@ -1055,11 +1057,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { } if (g->zig_target.arch.arch == ZigLLVM_x86_64) { X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); - if (abi_class == X64CABIClass_MEMORY) { - return true; - } - zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", - buf_ptr(&fn_type_id->return_type->name)); + return abi_class == X64CABIClass_MEMORY; } else if (target_is_arm(&g->zig_target)) { return type_size(g, fn_type_id->return_type) > 16; } @@ -1424,6 +1422,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdFn: + case ZigTypeIdVector: return true; case ZigTypeIdStruct: return type_entry->data.structure.layout == ContainerLayoutPacked; @@ -1472,6 +1471,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { default: return false; } + case ZigTypeIdVector: + return type_allowed_in_extern(g, type_entry->data.vector.elem_type); case ZigTypeIdFloat: return true; case ZigTypeIdArray: @@ -1625,6 +1626,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, type_entry)) { case ReqCompTimeNo: break; @@ -1720,6 +1722,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, fn_type_id.return_type)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; @@ -3577,6 +3580,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry case ZigTypeIdFn: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: return type_entry; } zig_unreachable(); @@ -3943,6 +3947,7 @@ static bool is_container(ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; } zig_unreachable(); @@ -4002,6 +4007,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: zig_unreachable(); } } @@ -4451,6 +4457,34 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return new_entry; } +ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { + TypeId type_id = {}; + type_id.id = ZigTypeIdVector; + type_id.data.vector.len = len; + type_id.data.vector.elem_type = elem_type; + + { + auto entry = g->type_table.maybe_get(type_id); + if (entry) + return entry->value; + } + + ZigType *entry = new_type_table_entry(ZigTypeIdVector); + entry->zero_bits = (len == 0) || !type_has_bits(elem_type); + entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len); + entry->data.vector.len = len; + entry->data.vector.elem_type = elem_type; + + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); + + entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, len, + LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type); + + g->type_table.put(type_id, entry); + return entry; +} + ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { return &g->builtin_types.entry_c_int[c_int_type]; } @@ -4482,6 +4516,7 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdFn: case ZigTypeIdEnum: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; case ZigTypeIdArray: case ZigTypeIdStruct: @@ -4914,6 +4949,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return hash_const_val_error_set(const_val); case ZigTypeIdNamespace: return hash_ptr(const_val->data.x_import); + case ZigTypeIdVector: + // TODO better hashing algorithm + return 3647867726; case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -4966,6 +5004,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdBool: case ZigTypeIdUnreachable: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -5049,6 +5088,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdPointer: + case ZigTypeIdVector: return true; case ZigTypeIdArray: @@ -5201,6 +5241,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdInt: + case ZigTypeIdVector: return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; case ZigTypeIdPointer: return type_has_one_possible_value(g, type_entry->data.pointer.child_type); @@ -5251,6 +5292,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdBool: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdVoid: case ZigTypeIdUnreachable: @@ -5777,7 +5819,7 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; i += 1) { if (!const_values_equal(g, &a_elems[i], &b_elems[i])) return false; } @@ -5811,6 +5853,20 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdArgTuple: return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index && a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index; + case ZigTypeIdVector: { + assert(a->type->data.vector.len == b->type->data.vector.len); + + size_t len = a->type->data.vector.len; + ConstExprValue *a_elems = a->data.x_vector.elements; + ConstExprValue *b_elems = b->data.x_vector.elements; + + for (size_t i = 0; i < len; i += 1) { + if (!const_values_equal(g, &a_elems[i], &b_elems[i])) + return false; + } + + return true; + } case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -6042,6 +6098,18 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } } zig_unreachable(); + case ZigTypeIdVector: { + buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); + uint64_t len = type_entry->data.vector.len; + for (uint32_t i = 0; i < len; i += 1) { + if (i != 0) + buf_appendf(buf, ","); + ConstExprValue *child_value = &const_val->data.x_vector.elements[i]; + render_const_value(g, buf, child_value); + } + buf_appendf(buf, "}"); + return; + } case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -6200,6 +6268,8 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdInt: return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); + case ZigTypeIdVector: + return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681); } zig_unreachable(); } @@ -6248,6 +6318,9 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdInt: return a.data.integer.is_signed == b.data.integer.is_signed && a.data.integer.bit_count == b.data.integer.bit_count; + case ZigTypeIdVector: + return a.data.vector.elem_type == b.data.vector.elem_type && + a.data.vector.len == b.data.vector.len; } zig_unreachable(); } @@ -6382,6 +6455,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdPromise, + ZigTypeIdVector, }; ZigTypeId type_id_at_index(size_t index) { @@ -6447,6 +6521,8 @@ size_t type_id_index(ZigType *entry) { return 22; case ZigTypeIdPromise: return 23; + case ZigTypeIdVector: + return 24; } zig_unreachable(); } @@ -6503,6 +6579,8 @@ const char *type_id_name(ZigTypeId id) { return "Opaque"; case ZigTypeIdPromise: return "Promise"; + case ZigTypeIdVector: + return "Vector"; } zig_unreachable(); } @@ -6658,6 +6736,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { case ZigTypeIdBool: return X64CABIClass_INTEGER; case ZigTypeIdFloat: + case ZigTypeIdVector: return X64CABIClass_SSE; case ZigTypeIdStruct: { // "If the size of an object is larger than four eightbytes, or it contains unaligned diff --git a/src/analyze.hpp b/src/analyze.hpp index 1bac15ebcc..da5265a594 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -20,6 +20,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint64_t type_size(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); +ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); diff --git a/src/codegen.cpp b/src/codegen.cpp index 2f360735dd..e2576f5335 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1980,7 +1980,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ break; } - if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || + if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || ty->id == ZigTypeIdVector || ty->id == ZigTypeIdInt // TODO investigate if we need to change this ) { switch (fn_walk->id) { @@ -2660,6 +2660,27 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, } else { return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); } + } else if (type_entry->id == ZigTypeIdVector) { + ZigType *elem_type = type_entry->data.vector.elem_type; + if (elem_type->id == ZigTypeIdFloat) { + ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); + return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); + } else if (elem_type->id == ZigTypeIdPointer) { + zig_panic("TODO codegen for pointers in vectors"); + } else if (elem_type->id == ZigTypeIdInt) { + bool is_wrapping = (op_id == IrBinOpAddWrap); + if (is_wrapping) { + return LLVMBuildAdd(g->builder, op1_value, op2_value, ""); + } else if (want_runtime_safety) { + zig_panic("TODO runtime safety for vector integer addition"); + } else if (elem_type->data.integral.is_signed) { + return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, ""); + } else { + return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, ""); + } + } else { + zig_unreachable(); + } } else { zig_unreachable(); } @@ -5211,6 +5232,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCUndef: case IrInstructionIdEmbedFile: case IrInstructionIdIntType: + case IrInstructionIdVectorType: case IrInstructionIdMemberCount: case IrInstructionIdMemberType: case IrInstructionIdMemberName: @@ -5620,6 +5642,8 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con } case ZigTypeIdArray: zig_panic("TODO bit pack an array"); + case ZigTypeIdVector: + zig_panic("TODO bit pack a vector"); case ZigTypeIdUnion: zig_panic("TODO bit pack a union"); case ZigTypeIdStruct: @@ -5992,6 +6016,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c } } } + case ZigTypeIdVector: { + uint32_t len = type_entry->data.vector.len; + LLVMValueRef *values = allocate(len); + for (uint32_t i = 0; i < len; i += 1) { + values[i] = gen_const_val(g, &const_val->data.x_vector.elements[i], ""); + } + return LLVMConstVector(values, len); + } case ZigTypeIdUnion: { LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; @@ -6927,6 +6959,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int + create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); @@ -7152,6 +7185,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " ArgTuple: void,\n" " Opaque: void,\n" " Promise: Promise,\n" + " Vector: Vector,\n" "\n\n" " pub const Int = struct {\n" " is_signed: bool,\n" @@ -7270,6 +7304,11 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " child: ?type,\n" " };\n" "\n" + " pub const Vector = struct {\n" + " len: u32,\n" + " child: type,\n" + " };\n" + "\n" " pub const Definition = struct {\n" " name: []const u8,\n" " is_pub: bool,\n" @@ -7841,6 +7880,9 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e case ZigTypeIdArray: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); return; + case ZigTypeIdVector: + prepend_c_type_to_decl_list(g, gen_h, type_entry->data.vector.elem_type); + return; case ZigTypeIdOptional: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); return; @@ -7972,6 +8014,8 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu buf_appendf(out_buf, "%s", buf_ptr(child_buf)); return; } + case ZigTypeIdVector: + zig_panic("TODO implement get_c_type for vector types"); case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: case ZigTypeIdFn: @@ -8137,6 +8181,7 @@ static void gen_h_file(CodeGen *g) { case ZigTypeIdOptional: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: zig_unreachable(); case ZigTypeIdEnum: if (type_entry->data.enumeration.layout == ContainerLayoutExtern) { diff --git a/src/ir.cpp b/src/ir.cpp index 06eb4a47f1..d5152f3c85 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -587,6 +587,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntType *) { return IrInstructionIdIntType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { + return IrInstructionIdVectorType; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { return IrInstructionIdBoolNot; } @@ -1953,6 +1957,19 @@ static IrInstruction *ir_build_int_type(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } +static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *len, + IrInstruction *elem_type) +{ + IrInstructionVectorType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->len = len; + instruction->elem_type = elem_type; + + ir_ref_instruction(len, irb->current_basic_block); + ir_ref_instruction(elem_type, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { IrInstructionBoolNot *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; @@ -4230,6 +4247,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, int_type, lval); } + case BuiltinFnIdVectorType: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, vector_type, lval); + } case BuiltinFnIdMemcpy: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -11617,6 +11649,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdComptimeInt: case ZigTypeIdInt: case ZigTypeIdFloat: + case ZigTypeIdVector: operator_allowed = true; break; @@ -12032,6 +12065,48 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b return result; } +static bool ok_float_op(IrBinOp op) { + switch (op) { + case IrBinOpInvalid: + zig_unreachable(); + case IrBinOpAdd: + case IrBinOpSub: + case IrBinOpMult: + case IrBinOpDivUnspecified: + case IrBinOpDivTrunc: + case IrBinOpDivFloor: + case IrBinOpDivExact: + case IrBinOpRemRem: + case IrBinOpRemMod: + return true; + + case IrBinOpBoolOr: + case IrBinOpBoolAnd: + case IrBinOpCmpEq: + case IrBinOpCmpNotEq: + case IrBinOpCmpLessThan: + case IrBinOpCmpGreaterThan: + case IrBinOpCmpLessOrEq: + case IrBinOpCmpGreaterOrEq: + case IrBinOpBinOr: + case IrBinOpBinXor: + case IrBinOpBinAnd: + case IrBinOpBitShiftLeftLossy: + case IrBinOpBitShiftLeftExact: + case IrBinOpBitShiftRightLossy: + case IrBinOpBitShiftRightExact: + case IrBinOpAddWrap: + case IrBinOpSubWrap: + case IrBinOpMultWrap: + case IrBinOpRemUnspecified: + case IrBinOpArrayCat: + case IrBinOpArrayMult: + case IrBinOpMergeErrorSets: + return false; + } + zig_unreachable(); +} + static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) @@ -12169,21 +12244,20 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp op_id = IrBinOpRemRem; } + bool ok = false; if (is_int) { - // int - } else if (is_float && - (op_id == IrBinOpAdd || - op_id == IrBinOpSub || - op_id == IrBinOpMult || - op_id == IrBinOpDivUnspecified || - op_id == IrBinOpDivTrunc || - op_id == IrBinOpDivFloor || - op_id == IrBinOpDivExact || - op_id == IrBinOpRemRem || - op_id == IrBinOpRemMod)) - { - // float - } else { + ok = true; + } else if (is_float && ok_float_op(op_id)) { + ok = true; + } else if (resolved_type->id == ZigTypeIdVector) { + ZigType *elem_type = resolved_type->data.vector.elem_type; + if (elem_type->id == ZigTypeIdInt || elem_type->id == ZigTypeIdComptimeInt) { + ok = true; + } else if ((elem_type->id == ZigTypeIdFloat || elem_type->id == ZigTypeIdComptimeFloat) && ok_float_op(op_id)) { + ok = true; + } + } + if (!ok) { AstNode *source_node = instruction->base.source_node; ir_add_error_node(ira, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'", @@ -12817,6 +12891,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdBool: + case ZigTypeIdVector: break; case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -12851,6 +12926,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: + case ZigTypeIdVector: zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); case ZigTypeIdNamespace: case ZigTypeIdBoundFn: @@ -14009,6 +14085,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ case ZigTypeIdVoid: case ZigTypeIdBool: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdPointer: case ZigTypeIdArray: @@ -15383,37 +15460,7 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio ZigType *type_entry = expr_value->value.type; if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - switch (type_entry->id) { - case ZigTypeIdInvalid: - zig_unreachable(); // handled above - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdNamespace: - case ZigTypeIdBoundFn: - case ZigTypeIdMetaType: - case ZigTypeIdVoid: - case ZigTypeIdBool: - case ZigTypeIdUnreachable: - case ZigTypeIdInt: - case ZigTypeIdFloat: - case ZigTypeIdPointer: - case ZigTypeIdArray: - case ZigTypeIdStruct: - case ZigTypeIdOptional: - case ZigTypeIdErrorUnion: - case ZigTypeIdErrorSet: - case ZigTypeIdEnum: - case ZigTypeIdUnion: - case ZigTypeIdFn: - case ZigTypeIdArgTuple: - case ZigTypeIdOpaque: - case ZigTypeIdPromise: - return ir_const_type(ira, &typeof_instruction->base, type_entry); - } - - zig_unreachable(); + return ir_const_type(ira, &typeof_instruction->base, type_entry); } static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, @@ -15652,6 +15699,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -15772,6 +15820,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdNamespace: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { if ((err = ensure_complete_type(ira->codegen, child_type))) return ira->codegen->invalid_instruction; @@ -15838,6 +15887,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: { uint64_t size_in_bytes = type_size(ira->codegen, type_entry); return ir_const_unsigned(ira, &size_of_instruction->base, size_in_bytes); @@ -16307,6 +16357,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdOpaque: + case ZigTypeIdVector: ir_add_error(ira, &switch_target_instruction->base, buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); return ira->codegen->invalid_instruction; @@ -17496,6 +17547,27 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE break; } + case ZigTypeIdVector: { + result = create_const_vals(1); + result->special = ConstValSpecialStatic; + result->type = ir_type_info_get_type(ira, "Vector", nullptr); + + ConstExprValue *fields = create_const_vals(2); + result->data.x_struct.fields = fields; + + // len: usize + ensure_field_index(result->type, "len", 0); + fields[0].special = ConstValSpecialStatic; + fields[0].type = ira->codegen->builtin_types.entry_u32; + bigint_init_unsigned(&fields[0].data.x_bigint, type_entry->data.vector.len); + // child: type + ensure_field_index(result->type, "child", 1); + fields[1].special = ConstValSpecialStatic; + fields[1].type = ira->codegen->builtin_types.entry_type; + fields[1].data.x_type = type_entry->data.vector.elem_type; + + break; + } case ZigTypeIdOptional: { result = create_const_vals(1); @@ -18671,6 +18743,30 @@ static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruct return ir_const_type(ira, &instruction->base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count)); } +static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstructionVectorType *instruction) { + uint64_t len; + if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) + return ira->codegen->invalid_instruction; + + ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); + if (type_is_invalid(elem_type)) + return ira->codegen->invalid_instruction; + + if (elem_type->id != ZigTypeIdInt && + elem_type->id != ZigTypeIdFloat && + get_codegen_ptr_type(elem_type) == nullptr) + { + ir_add_error(ira, instruction->elem_type, + buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", + buf_ptr(&elem_type->name))); + return ira->codegen->invalid_instruction; + } + + ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); + + return ir_const_type(ira, &instruction->base, vector_type); +} + static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { IrInstruction *value = instruction->value->child; if (type_is_invalid(value->value.type)) @@ -19474,6 +19570,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct case ZigTypeIdEnum: case ZigTypeIdUnion: case ZigTypeIdFn: + case ZigTypeIdVector: { uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); return ir_const_unsigned(ira, &instruction->base, align_in_bytes); @@ -20311,6 +20408,15 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue } } return; + case ZigTypeIdVector: { + size_t buf_i = 0; + for (uint32_t elem_i = 0; elem_i < val->type->data.vector.len; elem_i += 1) { + ConstExprValue *elem = &val->data.x_vector.elements[elem_i]; + buf_write_value_bytes(codegen, &buf[buf_i], elem); + buf_i += type_size(codegen, elem->type); + } + return; + } case ZigTypeIdStruct: zig_panic("TODO buf_write_value_bytes struct type"); case ZigTypeIdOptional: @@ -20387,6 +20493,20 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou } zig_unreachable(); } + case ZigTypeIdVector: { + uint64_t elem_size = type_size(codegen, val->type->data.vector.elem_type); + uint32_t len = val->type->data.vector.len; + + val->data.x_vector.elements = create_const_vals(len); + for (uint32_t i = 0; i < len; i += 1) { + ConstExprValue *elem = &val->data.x_vector.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = val->type->data.vector.elem_type; + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) + return err; + } + return ErrorNone; + } case ZigTypeIdEnum: switch (val->type->data.enumeration.layout) { case ContainerLayoutAuto: @@ -21633,6 +21753,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_bool_to_int(ira, (IrInstructionBoolToInt *)instruction); case IrInstructionIdIntType: return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); + case IrInstructionIdVectorType: + return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); case IrInstructionIdBoolNot: return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); case IrInstructionIdMemset: @@ -21943,6 +22065,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEmbedFile: case IrInstructionIdTruncate: case IrInstructionIdIntType: + case IrInstructionIdVectorType: case IrInstructionIdBoolNot: case IrInstructionIdSlice: case IrInstructionIdMemberCount: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a3ec8e9d35..a1fd450b65 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -719,6 +719,14 @@ static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { fprintf(irp->f, ")"); } +static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruction) { + fprintf(irp->f, "@Vector("); + ir_print_other_instruction(irp, instruction->len); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->elem_type); + fprintf(irp->f, ")"); +} + static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { fprintf(irp->f, "! "); ir_print_other_instruction(irp, instruction->value); @@ -1577,6 +1585,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdIntType: ir_print_int_type(irp, (IrInstructionIntType *)instruction); break; + case IrInstructionIdVectorType: + ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); + break; case IrInstructionIdBoolNot: ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); break; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index 3c01a0954d..65f6b5abb7 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -263,6 +263,19 @@ ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const ch return reinterpret_cast(di_type); } +struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, + uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty) +{ + SmallVector subrange; + subrange.push_back(reinterpret_cast(dibuilder)->getOrCreateSubrange(0, Size)); + DIType *di_type = reinterpret_cast(dibuilder)->createVectorType( + Size, + AlignInBits, + reinterpret_cast(Ty), + reinterpret_cast(dibuilder)->getOrCreateArray(subrange)); + return reinterpret_cast(di_type); +} + ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, uint64_t size_in_bits, uint64_t align_in_bits, ZigLLVMDIType *elem_type, int elem_count) { diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 551a4a7448..26dca1198b 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -191,6 +191,9 @@ ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIB unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram); +ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMDIBuilderCreateVectorType(struct ZigLLVMDIBuilder *dibuilder, + uint64_t Size, uint32_t AlignInBits, struct ZigLLVMDIType *Ty); + ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder); diff --git a/std/hash_map.zig b/std/hash_map.zig index 99237047e0..a63a549814 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -508,6 +508,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type builtin.TypeId.Optional => @compileError("TODO auto hash for optionals"), builtin.TypeId.Array => @compileError("TODO auto hash for arrays"), + builtin.TypeId.Vector => @compileError("TODO auto hash for vectors"), builtin.TypeId.Struct => @compileError("TODO auto hash for structs"), builtin.TypeId.Union => @compileError("TODO auto hash for unions"), builtin.TypeId.ErrorUnion => @compileError("TODO auto hash for unions"), @@ -555,5 +556,6 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Struct => @compileError("TODO auto eql for structs"), builtin.TypeId.Union => @compileError("TODO auto eql for unions"), builtin.TypeId.ErrorUnion => @compileError("TODO auto eql for unions"), + builtin.TypeId.Vector => @compileError("TODO auto eql for vectors"), } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 5ad80e06e1..f3bb17b282 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -171,11 +171,11 @@ fn testUnion() void { assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); - assertOrPanic(typeinfo_info.Union.fields.len == 24); + assertOrPanic(typeinfo_info.Union.fields.len == 25); assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assertOrPanic(typeinfo_info.Union.defs.len == 20); + assertOrPanic(typeinfo_info.Union.defs.len == 21); const TestNoTagUnion = union { Foo: void, @@ -262,3 +262,15 @@ test "typeInfo with comptime parameter in struct fn def" { }; comptime var info = @typeInfo(S); } + +test "type info: vectors" { + testVector(); + comptime testVector(); +} + +fn testVector() void { + const vec_info = @typeInfo(@Vector(4, i32)); + assertOrPanic(TypeId(vec_info) == TypeId.Vector); + assertOrPanic(vec_info.Vector.len == 4); + assertOrPanic(vec_info.Vector.child == i32); +} -- cgit v1.2.3 From ae1ebe09b7c1258bfa8de37244fd9b510b1447a4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 1 Feb 2019 14:06:51 -0500 Subject: add compile errror for @bitCast when bit counts mismatch fixes invalid LLVM IR from previous commit --- src/ir.cpp | 14 ++++++++++++-- std/io.zig | 46 +++++++++++++++++++++++++--------------------- test/compile_errors.zig | 9 +++++++++ 3 files changed, 46 insertions(+), 23 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index d5152f3c85..dc700c4178 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20580,10 +20580,10 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, dest_type))) + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - if ((err = ensure_complete_type(ira->codegen, src_type))) + if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; if (get_codegen_ptr_type(src_type) != nullptr) { @@ -20646,6 +20646,16 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } + uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); + uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); + if (dest_size_bits != src_size_bits) { + ir_add_error(ira, &instruction->base, + buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", + buf_ptr(&dest_type->name), dest_size_bits, + buf_ptr(&src_type->name), src_size_bits)); + return ira->codegen->invalid_instruction; + } + if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) diff --git a/std/io.zig b/std/io.zig index 57f2ef3df5..46625cd34b 100644 --- a/std/io.zig +++ b/std/io.zig @@ -503,13 +503,13 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { /// containing them in the least significant end. The number of bits successfully /// read is placed in `out_bits`, as reaching the end of the stream is not an error. pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U { - debug.assert(trait.isUnsignedInt(U)); + comptime assert(trait.isUnsignedInt(U)); //by extending the buffer to a minimum of u8 we can cover a number of edge cases // related to shifting and casting. const u_bit_count = comptime meta.bitCount(U); const buf_bit_count = bc: { - debug.assert(u_bit_count >= bits); + assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; const Buf = @IntType(false, buf_bit_count); @@ -664,7 +664,7 @@ test "io.SliceOutStream" { const stream = &slice_stream.stream; try stream.print("{}{}!", "Hello", "World"); - debug.assert(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); + debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); } var null_out_stream_state = NullOutStream.init(); @@ -726,7 +726,7 @@ test "io.CountingOutStream" { const bytes = "yay" ** 10000; stream.write(bytes) catch unreachable; - debug.assert(counting_stream.bytes_written == bytes.len); + debug.assertOrPanic(counting_stream.bytes_written == bytes.len); } pub fn BufferedOutStream(comptime Error: type) type { @@ -835,13 +835,13 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { if (bits == 0) return; const U = @typeOf(value); - debug.assert(trait.isUnsignedInt(U)); + comptime assert(trait.isUnsignedInt(U)); //by extending the buffer to a minimum of u8 we can cover a number of edge cases // related to shifting and casting. const u_bit_count = comptime meta.bitCount(U); const buf_bit_count = bc: { - debug.assert(u_bit_count >= bits); + assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; const Buf = @IntType(false, buf_bit_count); @@ -1013,10 +1013,10 @@ test "io.readLineFrom" { ); const stream = &mem_stream.stream; - debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); - debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); + debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); + debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); - debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); + debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); } pub fn readLineSlice(slice: []u8) ![]u8 { @@ -1044,7 +1044,7 @@ test "io.readLineSliceFrom" { ); const stream = &mem_stream.stream; - debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); + debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); } @@ -1057,7 +1057,7 @@ test "io.readLineSliceFrom" { /// which will be called when the deserializer is used to deserialize /// that type. It will pass a pointer to the type instance to deserialize /// into and a pointer to the deserializer struct. -pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { +pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime Error: type) type { return struct { const Self = @This(); @@ -1079,9 +1079,9 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Stream.Error || error{EndOfStream})!T { - debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); - const u8_bit_count = comptime meta.bitCount(u8); + const u8_bit_count = 8; const t_bit_count = comptime meta.bitCount(T); const U = @IntType(false, t_bit_count); @@ -1097,13 +1097,17 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ const read_size = try self.in_stream.read(buffer[0..]); if (read_size < int_size) return error.EndOfStream; - if (int_size == 1) return @bitCast(T, buffer[0]); + if (int_size == 1) { + if (t_bit_count == 8) return @bitCast(T, buffer[0]); + const PossiblySignedByte = @IntType(T.is_signed, 8); + return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); + } var result = U(0); for (buffer) |byte, i| { switch (endian) { builtin.Endian.Big => { - result = (result << @intCast(u4, u8_bit_count)) | byte; + result = (result << u8_bit_count) | byte; }, builtin.Endian.Little => { result |= U(byte) << @intCast(Log2U, u8_bit_count * i); @@ -1118,12 +1122,12 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ // see: #1315 fn setTag(ptr: var, tag: var) void { const T = @typeOf(ptr); - comptime debug.assert(trait.isPtrTo(builtin.TypeId.Union)(T)); + comptime assert(trait.isPtrTo(builtin.TypeId.Union)(T)); const U = meta.Child(T); const info = @typeInfo(U).Union; if (info.tag_type) |TagType| { - debug.assert(TagType == @typeOf(tag)); + comptime assert(TagType == @typeOf(tag)); var ptr_tag = ptr: { if (@alignOf(TagType) >= @alignOf(U)) break :ptr @ptrCast(*TagType, ptr); @@ -1151,7 +1155,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ /// Deserializes data into the type pointed to by `ptr` pub fn deserializeInto(self: *Self, ptr: var) !void { const T = @typeOf(ptr); - debug.assert(trait.is(builtin.TypeId.Pointer)(T)); + comptime assert(trait.is(builtin.TypeId.Pointer)(T)); if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) { for (ptr) |*v| @@ -1159,7 +1163,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ return; } - comptime debug.assert(trait.isSingleItemPtr(T)); + comptime assert(trait.isSingleItemPtr(T)); const C = comptime meta.Child(T); const child_type_id = @typeId(C); @@ -1266,7 +1270,7 @@ pub fn Deserializer(endian: builtin.Endian, is_packed: bool, comptime Error: typ /// which will be called when the serializer is used to serialize that type. It will /// pass a const pointer to the type instance to be serialized and a pointer /// to the serializer struct. -pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) type { +pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, comptime Error: type) type { return struct { const Self = @This(); @@ -1288,7 +1292,7 @@ pub fn Serializer(endian: builtin.Endian, is_packed: bool, comptime Error: type) fn serializeInt(self: *Self, value: var) !void { const T = @typeOf(value); - debug.assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); const t_bit_count = comptime meta.bitCount(T); const u8_bit_count = comptime meta.bitCount(u8); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f2a2ba2641..74602b77ff 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "@bitCast same size but bit count mismatch", + \\export fn entry(byte: u8) void { + \\ var oops = @bitCast(u7, byte); + \\} + , + ".tmp_source.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits", + ); + cases.add( "attempted `&&`", \\export fn entry(a: bool, b: bool) i32 { -- cgit v1.2.3 From 8bedb10939b511e39787b2693249d2d3e8102854 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Fri, 1 Feb 2019 03:12:56 -0800 Subject: Fix runtime assignment to comptime aggregate field This was causing a segfault --- src/ir.cpp | 6 ++++-- test/compile_errors.zig | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index dc700c4178..d676e7a6c5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16533,7 +16533,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) + || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || !type_has_bits(casted_field_value->value.type)) { @@ -16584,7 +16585,8 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstructionStructInitField *new_fields = allocate(actual_field_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); + bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) + || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 74602b77ff..30d9ca5d70 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5367,4 +5367,32 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { , ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", ); + + cases.add( + "runtime assignment to comptime struct type", + \\const Foo = struct { + \\ Bar: u8, + \\ Baz: type, + \\}; + \\export fn f() void { + \\ var x: u8 = 0; + \\ const foo = Foo { .Bar = x, .Baz = u8 }; + \\} + , + ".tmp_source.zig:7:30: error: unable to evaluate constant expression", + ); + + cases.add( + "runtime assignment to comptime union type", + \\const Foo = union { + \\ Bar: u8, + \\ Baz: type, + \\}; + \\export fn f() void { + \\ var x: u8 = 0; + \\ const foo = Foo { .Bar = x }; + \\} + , + ".tmp_source.zig:7:30: error: unable to evaluate constant expression", + ); } -- cgit v1.2.3 From c90c256868a80cd35e9ba679ba082330592620c9 Mon Sep 17 00:00:00 2001 From: Matthew McAllister Date: Sat, 2 Feb 2019 13:57:53 -0800 Subject: Fix slice concatenation This was causing an underflow error --- src/ir.cpp | 33 ++++++++++++--------------------- test/stage1/behavior/eval.zig | 4 ++-- 2 files changed, 14 insertions(+), 23 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index d676e7a6c5..3d3c501df3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12369,7 +12369,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; - op1_array_end = bigint_as_unsigned(&len_val->data.x_bigint); + op1_array_end = op1_array_index + bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op1, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); @@ -12379,13 +12379,9 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i ConstExprValue *op2_array_val; size_t op2_array_index; size_t op2_array_end; + bool op2_type_valid; if (op2_type->id == ZigTypeIdArray) { - if (op2_type->data.array.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = op2_type->data.array.child_type == child_type; op2_array_val = op2_val; op2_array_index = 0; op2_array_end = op2_array_val->type->data.array.len; @@ -12394,35 +12390,30 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && op2_val->data.x_ptr.data.base_array.is_cstr) { - if (child_type != ira->codegen->builtin_types.entry_u8) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8; op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; op2_array_end = op2_array_val->type->data.array.len - 1; } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index].type_entry; - if (ptr_type->data.pointer.child_type != child_type) { - ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", - buf_ptr(&child_type->name), - buf_ptr(&op2->value.type->name))); - return ira->codegen->invalid_instruction; - } + op2_type_valid = ptr_type->data.pointer.child_type == child_type; ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; - op2_array_end = op2_array_val->type->data.array.len; ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; - op2_array_end = bigint_as_unsigned(&len_val->data.x_bigint); + op2_array_end = op2_array_index + bigint_as_unsigned(&len_val->data.x_bigint); } else { ir_add_error(ira, op2, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); return ira->codegen->invalid_instruction; } + if (!op2_type_valid) { + ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", + buf_ptr(&child_type->name), + buf_ptr(&op2->value.type->name))); + return ira->codegen->invalid_instruction; + } // The type of result is populated in the following if blocks IrInstruction *result = ir_const(ira, &instruction->base, nullptr); diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 2d8494eb0b..3e8af0524f 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -728,8 +728,8 @@ test "comptime pointer cast array and then slice" { test "slice bounds in comptime concatenation" { const bs = comptime blk: { - const b = c"11"; - break :blk b[0..1]; + const b = c"........1........"; + break :blk b[8..9]; }; const str = "" ++ bs; assertOrPanic(str.len == 1); -- cgit v1.2.3 From 8c6fa982cd0a02775264b616c37da9907cc603bb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Feb 2019 20:30:00 -0500 Subject: SIMD: array to vector, vector to array, wrapping int add also vectors and arrays now use the same ConstExprVal representation See #903 --- src/all_types.hpp | 20 ++- src/analyze.cpp | 178 ++++++++++++------------ src/analyze.hpp | 1 + src/codegen.cpp | 98 +++++++++++--- src/ir.cpp | 291 +++++++++++++++++++++++++--------------- src/ir_print.cpp | 18 +++ test/stage1/behavior.zig | 1 + test/stage1/behavior/vector.zig | 20 +++ 8 files changed, 403 insertions(+), 224 deletions(-) create mode 100644 test/stage1/behavior/vector.zig (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 3fc6772b31..c4c9e13cfb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -252,10 +252,6 @@ struct ConstArgTuple { size_t end_index; }; -struct ConstVector { - ConstExprValue *elements; -}; - enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, @@ -322,7 +318,6 @@ struct ConstExprValue { ConstPtrValue x_ptr; ImportTableEntry *x_import; ConstArgTuple x_arg_tuple; - ConstVector x_vector; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -2239,6 +2234,8 @@ enum IrInstructionId { IrInstructionIdToBytes, IrInstructionIdFromBytes, IrInstructionIdCheckRuntimeScope, + IrInstructionIdVectorToArray, + IrInstructionIdArrayToVector, }; struct IrInstruction { @@ -3368,6 +3365,19 @@ struct IrInstructionBitReverse { IrInstruction *op; }; +struct IrInstructionArrayToVector { + IrInstruction base; + + IrInstruction *array; +}; + +struct IrInstructionVectorToArray { + IrInstruction base; + + IrInstruction *vector; + LLVMValueRef tmp_ptr; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 99378eb7a8..ff961a7044 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4457,7 +4457,15 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return new_entry; } +bool is_valid_vector_elem_type(ZigType *elem_type) { + return elem_type->id == ZigTypeIdInt || + elem_type->id == ZigTypeIdFloat || + get_codegen_ptr_type(elem_type) != nullptr; +} + ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { + assert(is_valid_vector_elem_type(elem_type)); + TypeId type_id = {}; type_id.id = ZigTypeIdVector; type_id.data.vector.len = len; @@ -5749,6 +5757,28 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { zig_unreachable(); } +static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprValue *b, size_t len) { + assert(a->data.x_array.special != ConstArraySpecialUndef); + assert(b->data.x_array.special != ConstArraySpecialUndef); + if (a->data.x_array.special == ConstArraySpecialBuf && + b->data.x_array.special == ConstArraySpecialBuf) + { + return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); + } + expand_undef_array(g, a); + expand_undef_array(g, b); + + ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; + ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; + + for (size_t i = 0; i < len; i += 1) { + if (!const_values_equal(g, &a_elems[i], &b_elems[i])) + return false; + } + + return true; +} + bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { assert(a->type->id == b->type->id); assert(a->special == ConstValSpecialStatic); @@ -5803,28 +5833,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdPointer: case ZigTypeIdFn: return const_values_equal_ptr(a, b); + case ZigTypeIdVector: + assert(a->type->data.vector.len == b->type->data.vector.len); + return const_values_equal_array(g, a, b, a->type->data.vector.len); case ZigTypeIdArray: { assert(a->type->data.array.len == b->type->data.array.len); - assert(a->data.x_array.special != ConstArraySpecialUndef); - assert(b->data.x_array.special != ConstArraySpecialUndef); - if (a->data.x_array.special == ConstArraySpecialBuf && - b->data.x_array.special == ConstArraySpecialBuf) - { - return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); - } - expand_undef_array(g, a); - expand_undef_array(g, b); - - size_t len = a->type->data.array.len; - ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; - ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; + return const_values_equal_array(g, a, b, a->type->data.array.len); } case ZigTypeIdStruct: for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { @@ -5853,20 +5867,6 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdArgTuple: return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index && a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index; - case ZigTypeIdVector: { - assert(a->type->data.vector.len == b->type->data.vector.len); - - size_t len = a->type->data.vector.len; - ConstExprValue *a_elems = a->data.x_vector.elements; - ConstExprValue *b_elems = b->data.x_vector.elements; - - for (size_t i = 0; i < len; i += 1) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; - } case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -5985,6 +5985,40 @@ static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const } } +static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + buf_append_str(buf, "undefined"); + return; + case ConstArraySpecialBuf: { + Buf *array_buf = const_val->data.x_array.data.s_buf; + buf_append_char(buf, '"'); + for (size_t i = 0; i < buf_len(array_buf); i += 1) { + uint8_t c = buf_ptr(array_buf)[i]; + if (c == '"') { + buf_append_str(buf, "\\\""); + } else { + buf_append_char(buf, c); + } + } + buf_append_char(buf, '"'); + return; + } + case ConstArraySpecialNone: { + buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name)); + for (uint64_t i = 0; i < len; i += 1) { + if (i != 0) + buf_appendf(buf, ","); + ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; + render_const_value(g, buf, child_value); + } + buf_appendf(buf, "}"); + return; + } + } + zig_unreachable(); +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -6065,51 +6099,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdPointer: return render_const_val_ptr(g, buf, const_val, type_entry); + case ZigTypeIdVector: + return render_const_val_array(g, buf, const_val, type_entry->data.vector.len); case ZigTypeIdArray: - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - buf_append_str(buf, "undefined"); - return; - case ConstArraySpecialBuf: { - Buf *array_buf = const_val->data.x_array.data.s_buf; - buf_append_char(buf, '"'); - for (size_t i = 0; i < buf_len(array_buf); i += 1) { - uint8_t c = buf_ptr(array_buf)[i]; - if (c == '"') { - buf_append_str(buf, "\\\""); - } else { - buf_append_char(buf, c); - } - } - buf_append_char(buf, '"'); - return; - } - case ConstArraySpecialNone: { - buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); - uint64_t len = type_entry->data.array.len; - for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; - render_const_value(g, buf, child_value); - } - buf_appendf(buf, "}"); - return; - } - } - zig_unreachable(); - case ZigTypeIdVector: { - buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); - uint64_t len = type_entry->data.vector.len; - for (uint32_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_vector.elements[i]; - render_const_value(g, buf, child_value); - } - buf_appendf(buf, "}"); - return; - } + return render_const_val_array(g, buf, const_val, type_entry->data.array.len); case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -6379,7 +6372,17 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { - assert(const_val->type->id == ZigTypeIdArray); + size_t elem_count; + ZigType *elem_type; + if (const_val->type->id == ZigTypeIdArray) { + elem_count = const_val->type->data.array.len; + elem_type = const_val->type->data.array.child_type; + } else if (const_val->type->id == ZigTypeIdVector) { + elem_count = const_val->type->data.vector.len; + elem_type = const_val->type->data.vector.elem_type; + } else { + zig_unreachable(); + } if (const_val->special == ConstValSpecialUndef) { const_val->special = ConstValSpecialStatic; const_val->data.x_array.special = ConstArraySpecialUndef; @@ -6389,18 +6392,14 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { return; case ConstArraySpecialUndef: { const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; - element_val->type = const_val->type->data.array.child_type; + element_val->type = elem_type; init_const_undefined(g, element_val); - ConstParent *parent = get_const_val_parent(g, element_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = const_val; - parent->data.p_array.elem_index = i; - } + element_val->parent.id = ConstParentIdArray; + element_val->parent.data.p_array.array_val = const_val; + element_val->parent.data.p_array.elem_index = i; } return; } @@ -6411,7 +6410,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { g->string_literals_table.maybe_remove(buf); const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; assert(elem_count == buf_len(buf)); const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { @@ -6419,6 +6417,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { this_char->special = ConstValSpecialStatic; this_char->type = g->builtin_types.entry_u8; bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); + this_char->parent.id = ConstParentIdArray; + this_char->parent.data.p_array.array_val = const_val; + this_char->parent.data.p_array.elem_index = i; } return; } @@ -6426,6 +6427,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { zig_unreachable(); } +// Deprecated. Reference the parent field directly. ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { return &value->parent; } diff --git a/src/analyze.hpp b/src/analyze.hpp index da5265a594..f558fa44b0 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -74,6 +74,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag); bool is_ref(ZigType *type_entry); bool is_array_ref(ZigType *type_entry); bool is_container_ref(ZigType *type_entry); +bool is_valid_vector_elem_type(ZigType *elem_type); void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); void scan_import(CodeGen *g, ImportTableEntry *import); void preview_use_decl(CodeGen *g, AstNode *node); diff --git a/src/codegen.cpp b/src/codegen.cpp index b73fda59d1..de2222afb7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1921,9 +1921,8 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { } static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { - assert(alignment > 0); LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); - LLVMSetAlignment(result, alignment); + LLVMSetAlignment(result, (alignment == 0) ? get_abi_alignment(g, type_entry) : alignment); return result; } @@ -3246,6 +3245,22 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, ""); } +static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return true; + case ConstArraySpecialBuf: + return false; + case ConstArraySpecialNone: + for (size_t i = 0; i < len; i += 1) { + if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) + return false; + } + return true; + } + zig_unreachable(); +} + static bool value_is_all_undef(ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -3260,19 +3275,9 @@ static bool value_is_all_undef(ConstExprValue *const_val) { } return true; } else if (const_val->type->id == ZigTypeIdArray) { - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - return true; - case ConstArraySpecialBuf: - return false; - case ConstArraySpecialNone: - for (size_t i = 0; i < const_val->type->data.array.len; i += 1) { - if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i])) - return false; - } - return true; - } - zig_unreachable(); + return value_is_all_undef_array(const_val, const_val->type->data.array.len); + } else if (const_val->type->id == ZigTypeIdVector) { + return value_is_all_undef_array(const_val, const_val->type->data.vector.len); } else { return false; } @@ -5194,6 +5199,32 @@ static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); } +static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executable, + IrInstructionVectorToArray *instruction) +{ + ZigType *array_type = instruction->base.value.type; + assert(array_type->id == ZigTypeIdArray); + assert(handle_is_ptr(array_type)); + assert(instruction->tmp_ptr); + LLVMValueRef vector = ir_llvm_value(g, instruction->vector); + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMPointerType(instruction->vector->value.type->type_ref, 0), ""); + gen_store_untyped(g, vector, casted_ptr, 0, false); + return instruction->tmp_ptr; +} + +static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, + IrInstructionArrayToVector *instruction) +{ + ZigType *vector_type = instruction->base.value.type; + assert(vector_type->id == ZigTypeIdVector); + assert(!handle_is_ptr(vector_type)); + LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, + LLVMPointerType(vector_type->type_ref, 0), ""); + return gen_load_untyped(g, casted_ptr, 0, false, ""); +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5439,6 +5470,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction); case IrInstructionIdBitReverse: return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); + case IrInstructionIdArrayToVector: + return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); + case IrInstructionIdVectorToArray: + return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); } zig_unreachable(); } @@ -6016,14 +6051,32 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true); } } + zig_unreachable(); } case ZigTypeIdVector: { uint32_t len = type_entry->data.vector.len; - LLVMValueRef *values = allocate(len); - for (uint32_t i = 0; i < len; i += 1) { - values[i] = gen_const_val(g, &const_val->data.x_vector.elements[i], ""); + switch (const_val->data.x_array.special) { + case ConstArraySpecialUndef: + return LLVMGetUndef(type_entry->type_ref); + case ConstArraySpecialNone: { + LLVMValueRef *values = allocate(len); + for (uint64_t i = 0; i < len; i += 1) { + ConstExprValue *elem_value = &const_val->data.x_array.data.s_none.elements[i]; + values[i] = gen_const_val(g, elem_value, ""); + } + return LLVMConstVector(values, len); + } + case ConstArraySpecialBuf: { + Buf *buf = const_val->data.x_array.data.s_buf; + assert(buf_len(buf) == len); + LLVMValueRef *values = allocate(len); + for (uint64_t i = 0; i < len; i += 1) { + values[i] = LLVMConstInt(g->builtin_types.entry_u8->type_ref, buf_ptr(buf)[i], false); + } + return LLVMConstVector(values, len); + } } - return LLVMConstVector(values, len); + zig_unreachable(); } case ZigTypeIdUnion: { @@ -6467,6 +6520,7 @@ static void do_code_gen(CodeGen *g) { IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); LLVMValueRef *slot; ZigType *slot_type = instruction->value.type; + uint32_t alignment_bytes = 0; if (instruction->id == IrInstructionIdCast) { IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; slot = &cast_instruction->tmp_ptr; @@ -6502,10 +6556,14 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdCmpxchgGen) { IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdVectorToArray) { + IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; + alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); + slot = &vector_to_array_instruction->tmp_ptr; } else { zig_unreachable(); } - *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type)); + *slot = build_alloca(g, slot_type, "", alignment_bytes); } ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); diff --git a/src/ir.cpp b/src/ir.cpp index 3d3c501df3..3cbbdc8103 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -168,6 +168,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); +static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -899,6 +900,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop return IrInstructionIdCheckRuntimeScope; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorToArray *) { + return IrInstructionIdVectorToArray; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) { + return IrInstructionIdArrayToVector; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2821,6 +2830,34 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *vector, ZigType *result_type) +{ + IrInstructionVectorToArray *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->vector = vector; + + ir_ref_instruction(vector, ira->new_irb.current_basic_block); + + ir_add_alloca(ira, &instruction->base, result_type); + + return &instruction->base; +} + +static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *array, ZigType *result_type) +{ + IrInstructionArrayToVector *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->array = array; + + ir_ref_instruction(array, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -8270,6 +8307,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); + assert(const_val_is_int || const_val_is_float); if (other_type->id == ZigTypeIdFloat) { if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) { @@ -10714,6 +10752,32 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } } +static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *array, ZigType *vector_type) +{ + if (instr_is_comptime(array)) { + // arrays and vectors have the same ConstExprValue representation + IrInstruction *result = ir_const(ira, source_instr, vector_type); + copy_const_val(&result->value, &array->value, false); + result->value.type = vector_type; + return result; + } + return ir_build_array_to_vector(ira, source_instr, array, vector_type); +} + +static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *vector, ZigType *array_type) +{ + if (instr_is_comptime(vector)) { + // arrays and vectors have the same ConstExprValue representation + IrInstruction *result = ir_const(ira, source_instr, array_type); + copy_const_val(&result->value, &vector->value, false); + result->value.type = array_type; + return result; + } + return ir_build_vector_to_array(ira, source_instr, vector, array_type); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, ZigType *wanted_type, IrInstruction *value) { @@ -11102,6 +11166,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } + // cast from @Vector(N, T) to [N]T + if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdVector && + wanted_type->data.array.len == actual_type->data.vector.len && + types_match_const_cast_only(ira, wanted_type->data.array.child_type, + actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) + { + return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type); + } + + // cast from [N]T to @Vector(N, T) + if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdVector && + actual_type->data.array.len == wanted_type->data.vector.len && + types_match_const_cast_only(ira, actual_type->data.array.child_type, + wanted_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) + { + return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); + } // cast from undefined to anything if (actual_type->id == ZigTypeIdUndefined) { @@ -11780,8 +11861,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * return result; } -static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, - IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) +static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *type_entry, + ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val, ConstExprValue *out_val) { bool is_int; bool is_float; @@ -11803,10 +11884,10 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, if ((op_id == IrBinOpDivUnspecified || op_id == IrBinOpRemRem || op_id == IrBinOpRemMod || op_id == IrBinOpDivTrunc || op_id == IrBinOpDivFloor) && op2_zcmp == CmpEQ) { - return ErrorDivByZero; + return ir_add_error(ira, source_instr, buf_sprintf("division by zero")); } if ((op_id == IrBinOpRemRem || op_id == IrBinOpRemMod) && op2_zcmp == CmpLT) { - return ErrorNegativeDenominator; + return ir_add_error(ira, source_instr, buf_sprintf("negative denominator")); } switch (op_id) { @@ -11852,7 +11933,7 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, BigInt orig_bigint; bigint_shl(&orig_bigint, &out_val->data.x_bigint, &op2_val->data.x_bigint); if (bigint_cmp(&op1_val->data.x_bigint, &orig_bigint) != CmpEQ) { - return ErrorShiftedOutOneBits; + return ir_add_error(ira, source_instr, buf_sprintf("exact shift shifted out 1 bits")); } break; } @@ -11920,14 +12001,14 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, BigInt remainder; bigint_rem(&remainder, &op1_val->data.x_bigint, &op2_val->data.x_bigint); if (bigint_cmp_zero(&remainder) != CmpEQ) { - return ErrorExactDivRemainder; + return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); } } else { float_div_trunc(out_val, op1_val, op2_val); ConstExprValue remainder; float_rem(&remainder, op1_val, op2_val); if (float_cmp_zero(&remainder) != CmpEQ) { - return ErrorExactDivRemainder; + return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); } } break; @@ -11951,13 +12032,51 @@ static int ir_eval_math_op(ZigType *type_entry, ConstExprValue *op1_val, if (!bigint_fits_in_bits(&out_val->data.x_bigint, type_entry->data.integral.bit_count, type_entry->data.integral.is_signed)) { - return ErrorOverflow; + return ir_add_error(ira, source_instr, buf_sprintf("operation caused overflow")); } } out_val->type = type_entry; out_val->special = ConstValSpecialStatic; - return 0; + return nullptr; +} + +// This works on operands that have already been checked to be comptime known. +static IrInstruction *ir_analyze_math_op(IrAnalyze *ira, IrInstruction *source_instr, + ZigType *type_entry, ConstExprValue *op1_val, IrBinOp op_id, ConstExprValue *op2_val) +{ + IrInstruction *result_instruction = ir_const(ira, source_instr, type_entry); + ConstExprValue *out_val = &result_instruction->value; + if (type_entry->id == ZigTypeIdVector) { + expand_undef_array(ira->codegen, op1_val); + expand_undef_array(ira->codegen, op2_val); + out_val->special = ConstValSpecialUndef; + expand_undef_array(ira->codegen, out_val); + size_t len = type_entry->data.vector.len; + ZigType *scalar_type = type_entry->data.vector.elem_type; + for (size_t i = 0; i < len; i += 1) { + ConstExprValue *scalar_op1_val = &op1_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *scalar_op2_val = &op2_val->data.x_array.data.s_none.elements[i]; + ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i]; + assert(scalar_op1_val->type == scalar_type); + assert(scalar_op2_val->type == scalar_type); + assert(scalar_out_val->type == scalar_type); + ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type, + scalar_op1_val, op_id, scalar_op2_val, scalar_out_val); + if (msg != nullptr) { + add_error_note(ira->codegen, msg, source_instr->source_node, + buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i)); + return ira->codegen->invalid_instruction; + } + } + out_val->type = type_entry; + out_val->special = ConstValSpecialStatic; + } else { + if (ir_eval_math_op_scalar(ira, source_instr, type_entry, op1_val, op_id, op2_val, out_val) != nullptr) { + return ira->codegen->invalid_instruction; + } + } + return ir_implicit_cast(ira, result_instruction, type_entry); } static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { @@ -12029,24 +12148,7 @@ static IrInstruction *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *b if (op2_val == nullptr) return ira->codegen->invalid_instruction; - IrInstruction *result_instruction = ir_const(ira, &bin_op_instruction->base, op1->value.type); - - int err; - if ((err = ir_eval_math_op(op1->value.type, op1_val, op_id, op2_val, &result_instruction->value))) { - if (err == ErrorOverflow) { - ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("operation caused overflow")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorShiftedOutOneBits) { - ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("exact shift shifted out 1 bits")); - return ira->codegen->invalid_instruction; - } else { - zig_unreachable(); - } - return ira->codegen->invalid_instruction; - } - - ir_num_lit_fits_in_other_type(ira, result_instruction, op1->value.type, false); - return result_instruction; + return ir_analyze_math_op(ira, &bin_op_instruction->base, op1->value.type, op1_val, op_id, op2_val); } else if (op1->value.type->id == ZigTypeIdComptimeInt) { ir_add_error(ira, &bin_op_instruction->base, buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known")); @@ -12292,30 +12394,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp if (op2_val == nullptr) return ira->codegen->invalid_instruction; - IrInstruction *result_instruction = ir_const(ira, &instruction->base, resolved_type); - - int err; - if ((err = ir_eval_math_op(resolved_type, op1_val, op_id, op2_val, &result_instruction->value))) { - if (err == ErrorDivByZero) { - ir_add_error(ira, &instruction->base, buf_sprintf("division by zero")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorOverflow) { - ir_add_error(ira, &instruction->base, buf_sprintf("operation caused overflow")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorExactDivRemainder) { - ir_add_error(ira, &instruction->base, buf_sprintf("exact division had a remainder")); - return ira->codegen->invalid_instruction; - } else if (err == ErrorNegativeDenominator) { - ir_add_error(ira, &instruction->base, buf_sprintf("negative denominator")); - return ira->codegen->invalid_instruction; - } else { - zig_unreachable(); - } - return ira->codegen->invalid_instruction; - } - - ir_num_lit_fits_in_other_type(ira, result_instruction, resolved_type, false); - return result_instruction; + return ir_analyze_math_op(ira, &instruction->base, resolved_type, op1_val, op_id, op2_val); } IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, @@ -18745,10 +18824,7 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr if (type_is_invalid(elem_type)) return ira->codegen->invalid_instruction; - if (elem_type->id != ZigTypeIdInt && - elem_type->id != ZigTypeIdFloat && - get_codegen_ptr_type(elem_type) == nullptr) - { + if (!is_valid_vector_elem_type(elem_type)) { ir_add_error(ira, instruction->elem_type, buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", buf_ptr(&elem_type->name))); @@ -20345,6 +20421,17 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); } +static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { + size_t buf_i = 0; + // TODO optimize the buf case + expand_undef_array(codegen, val); + for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; + buf_write_value_bytes(codegen, &buf[buf_i], elem); + buf_i += type_size(codegen, elem->type); + } +} + static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { if (val->special == ConstValSpecialUndef) val->special = ConstValSpecialStatic; @@ -20390,26 +20477,9 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } case ZigTypeIdArray: - { - size_t buf_i = 0; - // TODO optimize the buf case - expand_undef_array(codegen, val); - for (size_t elem_i = 0; elem_i < val->type->data.array.len; elem_i += 1) { - ConstExprValue *elem = &val->data.x_array.data.s_none.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - } - return; - case ZigTypeIdVector: { - size_t buf_i = 0; - for (uint32_t elem_i = 0; elem_i < val->type->data.vector.len; elem_i += 1) { - ConstExprValue *elem = &val->data.x_vector.elements[elem_i]; - buf_write_value_bytes(codegen, &buf[buf_i], elem); - buf_i += type_size(codegen, elem->type); - } - return; - } + return buf_write_value_bytes_array(codegen, buf, val, val->type->data.array.len); + case ZigTypeIdVector: + return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len); case ZigTypeIdStruct: zig_panic("TODO buf_write_value_bytes struct type"); case ZigTypeIdOptional: @@ -20426,6 +20496,31 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_unreachable(); } +static Error buf_read_value_bytes_array(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, + ConstExprValue *val, ZigType *elem_type, size_t len) +{ + Error err; + uint64_t elem_size = type_size(codegen, elem_type); + + switch (val->data.x_array.special) { + case ConstArraySpecialNone: + val->data.x_array.data.s_none.elements = create_const_vals(len); + for (size_t i = 0; i < len; i++) { + ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; + elem->special = ConstValSpecialStatic; + elem->type = elem_type; + if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) + return err; + } + return ErrorNone; + case ConstArraySpecialUndef: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); + case ConstArraySpecialBuf: + zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); + } + zig_unreachable(); +} + static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val) { Error err; assert(val->special == ConstValSpecialStatic); @@ -20464,42 +20559,12 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); return ErrorNone; } - case ZigTypeIdArray: { - uint64_t elem_size = type_size(codegen, val->type->data.array.child_type); - size_t len = val->type->data.array.len; - - switch (val->data.x_array.special) { - case ConstArraySpecialNone: - val->data.x_array.data.s_none.elements = create_const_vals(len); - for (size_t i = 0; i < len; i++) { - ConstExprValue *elem = &val->data.x_array.data.s_none.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = val->type->data.array.child_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - case ConstArraySpecialUndef: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type"); - case ConstArraySpecialBuf: - zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type"); - } - zig_unreachable(); - } - case ZigTypeIdVector: { - uint64_t elem_size = type_size(codegen, val->type->data.vector.elem_type); - uint32_t len = val->type->data.vector.len; - - val->data.x_vector.elements = create_const_vals(len); - for (uint32_t i = 0; i < len; i += 1) { - ConstExprValue *elem = &val->data.x_vector.elements[i]; - elem->special = ConstValSpecialStatic; - elem->type = val->type->data.vector.elem_type; - if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem))) - return err; - } - return ErrorNone; - } + case ZigTypeIdArray: + return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.array.child_type, + val->type->data.array.len); + case ZigTypeIdVector: + return buf_read_value_bytes_array(ira, codegen, source_node, buf, val, val->type->data.vector.elem_type, + val->type->data.vector.len); case ZigTypeIdEnum: switch (val->type->data.enumeration.layout) { case ContainerLayoutAuto: @@ -21634,6 +21699,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdDeclVarGen: case IrInstructionIdPtrCastGen: case IrInstructionIdCmpxchgGen: + case IrInstructionIdArrayToVector: + case IrInstructionIdVectorToArray: zig_unreachable(); case IrInstructionIdReturn: @@ -22129,6 +22196,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: + case IrInstructionIdVectorToArray: + case IrInstructionIdArrayToVector: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a1fd450b65..e19aa6dda8 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -972,6 +972,18 @@ static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntime fprintf(irp->f, ")"); } +static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *instruction) { + fprintf(irp->f, "ArrayToVector("); + ir_print_other_instruction(irp, instruction->array); + fprintf(irp->f, ")"); +} + +static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) { + fprintf(irp->f, "VectorToArray("); + ir_print_other_instruction(irp, instruction->vector); + fprintf(irp->f, ")"); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1825,6 +1837,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdDeclVarGen: ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction); break; + case IrInstructionIdArrayToVector: + ir_print_array_to_vector(irp, (IrInstructionArrayToVector *)instruction); + break; + case IrInstructionIdVectorToArray: + ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index e545a4c418..1fa00b34fd 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -74,6 +74,7 @@ comptime { _ = @import("behavior/underscore.zig"); _ = @import("behavior/union.zig"); _ = @import("behavior/var_args.zig"); + _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); _ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig new file mode 100644 index 0000000000..53c5d01381 --- /dev/null +++ b/test/stage1/behavior/vector.zig @@ -0,0 +1,20 @@ +const std = @import("std"); +const assertOrPanic = std.debug.assertOrPanic; + +test "implicit array to vector and vector to array" { + const S = struct { + fn doTheTest() void { + var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40}; + const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4}; + v +%= x; + const result: [4]i32 = v; + assertOrPanic(result[0] == 11); + assertOrPanic(result[1] == 22); + assertOrPanic(result[2] == 33); + assertOrPanic(result[3] == 44); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + -- cgit v1.2.3 From b1775ca168e0bcfba6753346c5226881da49c6c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Feb 2019 13:48:04 -0500 Subject: thread local storage working for linux x86_64 --- CMakeLists.txt | 1 + src/all_types.hpp | 13 +++-- src/analyze.cpp | 69 +++++++++++++++--------- src/analyze.hpp | 1 + src/ast_render.cpp | 7 ++- src/codegen.cpp | 7 +++ src/ir.cpp | 4 ++ src/parser.cpp | 22 +++++--- src/tokenizer.cpp | 2 + src/tokenizer.hpp | 1 + std/debug/index.zig | 1 - std/heap.zig | 7 +-- std/index.zig | 3 +- std/mem.zig | 20 +++++++ std/os/index.zig | 119 +++++++++++++++++++++++------------------- std/os/startup.zig | 26 +++++++++ std/os/test.zig | 16 ++++++ std/special/bootstrap.zig | 63 ++++++++++++++++++++-- test/compile_errors.zig | 19 +++++++ test/stage1/behavior/misc.zig | 8 +++ 20 files changed, 306 insertions(+), 103 deletions(-) create mode 100644 std/os/startup.zig (limited to 'src/ir.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dd6a1dcfa..a093bfbfd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,7 @@ set(ZIG_STD_FILES "os/linux/vdso.zig" "os/linux/x86_64.zig" "os/path.zig" + "os/startup.zig" "os/time.zig" "os/uefi.zig" "os/windows/advapi32.zig" diff --git a/src/all_types.hpp b/src/all_types.hpp index c4c9e13cfb..5af4e71157 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -544,12 +544,7 @@ struct AstNodeDefer { }; struct AstNodeVariableDeclaration { - VisibMod visib_mod; Buf *symbol; - bool is_const; - bool is_comptime; - bool is_export; - bool is_extern; // one or both of type and expr will be non null AstNode *type; AstNode *expr; @@ -559,6 +554,13 @@ struct AstNodeVariableDeclaration { AstNode *align_expr; // populated if the "section(S)" is present AstNode *section_expr; + Token *threadlocal_tok; + + VisibMod visib_mod; + bool is_const; + bool is_comptime; + bool is_export; + bool is_extern; }; struct AstNodeTestDecl { @@ -1873,6 +1875,7 @@ struct ZigVar { bool shadowable; bool src_is_const; bool gen_is_const; + bool is_thread_local; }; struct ErrorTableEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index ff961a7044..96f1faaaa9 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -28,28 +28,10 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type); static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - if (node->owner->c_import_node != nullptr) { - // if this happens, then translate_c generated code that - // failed semantic analysis, which isn't supposed to happen - ErrorMsg *err = add_node_error(g, node->owner->c_import_node, - buf_sprintf("compiler bug: @cImport generated invalid zig code")); - - add_error_note(g, err, node, msg); - - g->errors.append(err); - return err; - } - - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); - - g->errors.append(err); - return err; -} - -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { - if (node->owner->c_import_node != nullptr) { +static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token, + Buf *msg) +{ + if (owner->c_import_node != nullptr) { // if this happens, then translate_c generated code that // failed semantic analysis, which isn't supposed to happen @@ -64,13 +46,46 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m return note; } - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); + ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column, + owner->source_code, owner->line_offsets, msg); err_msg_add_note(parent_msg, err); return err; } +ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) { + if (owner->c_import_node != nullptr) { + // if this happens, then translate_c generated code that + // failed semantic analysis, which isn't supposed to happen + ErrorMsg *err = add_node_error(g, owner->c_import_node, + buf_sprintf("compiler bug: @cImport generated invalid zig code")); + + add_error_note_token(g, err, owner, token, msg); + + g->errors.append(err); + return err; + } + ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column, + owner->source_code, owner->line_offsets, msg); + + g->errors.append(err); + return err; +} + +ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { + Token fake_token; + fake_token.start_line = node->line; + fake_token.start_column = node->column; + return add_token_error(g, node->owner, &fake_token, msg); +} + +ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { + Token fake_token; + fake_token.start_line = node->line; + fake_token.start_column = node->column; + return add_error_note_token(g, parent_msg, node->owner, &fake_token, msg); +} + ZigType *new_type_table_entry(ZigTypeId id) { ZigType *entry = allocate(1); entry->id = id; @@ -3668,6 +3683,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { bool is_const = var_decl->is_const; bool is_extern = var_decl->is_extern; bool is_export = var_decl->is_export; + bool is_thread_local = var_decl->threadlocal_tok != nullptr; ZigType *explicit_type = nullptr; if (var_decl->type) { @@ -3727,6 +3743,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, is_const, init_val, &tld_var->base, type); tld_var->var->linkage = linkage; + tld_var->var->is_thread_local = is_thread_local; if (implicit_type != nullptr && type_is_invalid(implicit_type)) { tld_var->var->var_type = g->builtin_types.entry_invalid; @@ -3747,6 +3764,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } } + if (is_thread_local && is_const) { + add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant")); + } + g->global_vars.append(tld_var); } diff --git a/src/analyze.hpp b/src/analyze.hpp index f558fa44b0..9773782510 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -12,6 +12,7 @@ void semantic_analyze(CodeGen *g); ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); +ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg); ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg); ZigType *new_type_table_entry(ZigTypeId id); ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 994ba5f5b1..34a7faa2a5 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -132,6 +132,10 @@ static const char *const_or_var_string(bool is_const) { return is_const ? "const" : "var"; } +static const char *thread_local_string(Token *tok) { + return (tok == nullptr) ? "" : "threadlocal "; +} + const char *container_string(ContainerKind kind) { switch (kind) { case ContainerKindEnum: return "enum"; @@ -554,8 +558,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { { const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod); const char *extern_str = extern_string(node->data.variable_declaration.is_extern); + const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok); const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const); - fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var); + fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var); print_symbol(ar, node->data.variable_declaration.symbol); if (node->data.variable_declaration.type) { diff --git a/src/codegen.cpp b/src/codegen.cpp index de2222afb7..d8fc077efc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6445,6 +6445,9 @@ static void do_code_gen(CodeGen *g) { maybe_import_dll(g, global_value, GlobalLinkageIdStrong); LLVMSetAlignment(global_value, var->align_bytes); LLVMSetGlobalConstant(global_value, var->gen_is_const); + if (var->is_thread_local && !g->is_single_threaded) { + LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); + } } } else { bool exported = (var->linkage == VarLinkageExport); @@ -6470,6 +6473,9 @@ static void do_code_gen(CodeGen *g) { } LLVMSetGlobalConstant(global_value, var->gen_is_const); + if (var->is_thread_local && !g->is_single_threaded) { + LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel); + } } var->value_ref = global_value; @@ -7520,6 +7526,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename); g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); + g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents); scan_import(g, g->compile_var_import); diff --git a/src/ir.cpp b/src/ir.cpp index 3cbbdc8103..02b2b12230 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5204,6 +5204,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod add_node_error(irb->codegen, variable_declaration->section_expr, buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); } + if (variable_declaration->threadlocal_tok != nullptr) { + add_token_error(irb->codegen, node->owner, variable_declaration->threadlocal_tok, + buf_sprintf("function-local variable '%s' cannot be threadlocal", buf_ptr(variable_declaration->symbol))); + } // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. diff --git a/src/parser.cpp b/src/parser.cpp index 81bd469d1c..1c1af87c51 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -844,12 +844,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON static AstNode *ast_parse_var_decl(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordConst); - if (first == nullptr) - first = eat_token_if(pc, TokenIdKeywordVar); - if (first == nullptr) - return nullptr; - + Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); + Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); + if (mut_kw == nullptr) + mut_kw = eat_token_if(pc, TokenIdKeywordVar); + if (mut_kw == nullptr) { + if (thread_local_kw == nullptr) { + return nullptr; + } else { + ast_invalid_token_error(pc, peek_token(pc)); + } + } Token *identifier = expect_token(pc, TokenIdSymbol); AstNode *type_expr = nullptr; if (eat_token_if(pc, TokenIdColon) != nullptr) @@ -863,8 +868,9 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { expect_token(pc, TokenIdSemicolon); - AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, first); - res->data.variable_declaration.is_const = first->id == TokenIdKeywordConst; + AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); + res->data.variable_declaration.threadlocal_tok = thread_local_kw; + res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; res->data.variable_declaration.symbol = token_buf(identifier); res->data.variable_declaration.type = type_expr; res->data.variable_declaration.align_expr = align_expr; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d43bfabf6d..3acd605748 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -146,6 +146,7 @@ static const struct ZigKeyword zig_keywords[] = { {"suspend", TokenIdKeywordSuspend}, {"switch", TokenIdKeywordSwitch}, {"test", TokenIdKeywordTest}, + {"threadlocal", TokenIdKeywordThreadLocal}, {"true", TokenIdKeywordTrue}, {"try", TokenIdKeywordTry}, {"undefined", TokenIdKeywordUndefined}, @@ -1586,6 +1587,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordSwitch: return "switch"; case TokenIdKeywordTest: return "test"; + case TokenIdKeywordThreadLocal: return "threadlocal"; case TokenIdKeywordTrue: return "true"; case TokenIdKeywordTry: return "try"; case TokenIdKeywordUndefined: return "undefined"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 1574e95571..17f36699b3 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -88,6 +88,7 @@ enum TokenId { TokenIdKeywordSuspend, TokenIdKeywordSwitch, TokenIdKeywordTest, + TokenIdKeywordThreadLocal, TokenIdKeywordTrue, TokenIdKeywordTry, TokenIdKeywordUndefined, diff --git a/std/debug/index.zig b/std/debug/index.zig index 838bd0c166..b4ef849509 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -37,7 +37,6 @@ const Module = struct { var stderr_file: os.File = undefined; var stderr_file_out_stream: os.File.OutStream = undefined; -/// TODO multithreaded awareness var stderr_stream: ?*io.OutStream(os.File.WriteError) = null; var stderr_mutex = std.Mutex.init(); pub fn warn(comptime fmt: []const u8, args: ...) void { diff --git a/std/heap.zig b/std/heap.zig index fd2ce1e965..1403f8e831 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -106,9 +106,7 @@ pub const DirectAllocator = struct { }; const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory; const root_addr = @ptrToInt(ptr); - const rem = @rem(root_addr, alignment); - const march_forward_bytes = if (rem == 0) 0 else (alignment - rem); - const adjusted_addr = root_addr + march_forward_bytes; + const adjusted_addr = mem.alignForward(root_addr, alignment); const record_addr = adjusted_addr + n; @intToPtr(*align(1) usize, record_addr).* = root_addr; return @intToPtr([*]u8, adjusted_addr)[0..n]; @@ -126,8 +124,7 @@ pub const DirectAllocator = struct { const base_addr = @ptrToInt(old_mem.ptr); const old_addr_end = base_addr + old_mem.len; const new_addr_end = base_addr + new_size; - const rem = @rem(new_addr_end, os.page_size); - const new_addr_end_rounded = new_addr_end + if (rem == 0) 0 else (os.page_size - rem); + const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size); if (old_addr_end > new_addr_end_rounded) { _ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded); } diff --git a/std/index.zig b/std/index.zig index 80d1e46bb6..ef3988460f 100644 --- a/std/index.zig +++ b/std/index.zig @@ -33,8 +33,8 @@ pub const io = @import("io.zig"); pub const json = @import("json.zig"); pub const macho = @import("macho.zig"); pub const math = @import("math/index.zig"); -pub const meta = @import("meta/index.zig"); pub const mem = @import("mem.zig"); +pub const meta = @import("meta/index.zig"); pub const net = @import("net.zig"); pub const os = @import("os/index.zig"); pub const pdb = @import("pdb.zig"); @@ -45,6 +45,7 @@ pub const unicode = @import("unicode.zig"); pub const zig = @import("zig/index.zig"); pub const lazyInit = @import("lazy_init.zig").lazyInit; +pub const startup = @import("os/startup.zig"); test "std" { // run tests from these diff --git a/std/mem.zig b/std/mem.zig index 26ae4ef089..178a5f6c6f 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -1366,3 +1366,23 @@ test "std.mem.subArrayPtr" { sub2[1] = 'X'; debug.assert(std.mem.eql(u8, a2, "abcXef")); } + +/// Round an address up to the nearest aligned address +pub fn alignForward(addr: usize, alignment: usize) usize { + return (addr + alignment - 1) & ~(alignment - 1); +} + +test "std.mem.alignForward" { + debug.assertOrPanic(alignForward(1, 1) == 1); + debug.assertOrPanic(alignForward(2, 1) == 2); + debug.assertOrPanic(alignForward(1, 2) == 2); + debug.assertOrPanic(alignForward(2, 2) == 2); + debug.assertOrPanic(alignForward(3, 2) == 4); + debug.assertOrPanic(alignForward(4, 2) == 4); + debug.assertOrPanic(alignForward(7, 8) == 8); + debug.assertOrPanic(alignForward(8, 8) == 8); + debug.assertOrPanic(alignForward(9, 8) == 16); + debug.assertOrPanic(alignForward(15, 8) == 16); + debug.assertOrPanic(alignForward(16, 8) == 16); + debug.assertOrPanic(alignForward(17, 8) == 24); +} diff --git a/std/os/index.zig b/std/os/index.zig index 451c0a3436..68b3409757 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -8,6 +8,9 @@ const is_posix = switch (builtin.os) { }; const os = @This(); +// See the comment in startup.zig for why this does not use the `std` global above. +const startup = @import("std").startup; + test "std.os" { _ = @import("child_process.zig"); _ = @import("darwin.zig"); @@ -667,14 +670,11 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { } } -pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; -pub var posix_environ_raw: [][*]u8 = undefined; - /// See std.elf for the constants. pub fn linuxGetAuxVal(index: usize) usize { if (builtin.link_libc) { return usize(std.c.getauxval(index)); - } else if (linux_elf_aux_maybe) |auxv| { + } else if (startup.linux_elf_aux_maybe) |auxv| { var i: usize = 0; while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { if (auxv[i].a_type == index) @@ -692,12 +692,7 @@ pub fn getBaseAddress() usize { return base; } const phdr = linuxGetAuxVal(std.elf.AT_PHDR); - const ElfHeader = switch (@sizeOf(usize)) { - 4 => std.elf.Elf32_Ehdr, - 8 => std.elf.Elf64_Ehdr, - else => @compileError("Unsupported architecture"), - }; - return phdr - @sizeOf(ElfHeader); + return phdr - @sizeOf(std.elf.Ehdr); }, builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header), builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), @@ -739,7 +734,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { try result.setMove(key, value); } } else { - for (posix_environ_raw) |ptr| { + for (startup.posix_environ_raw) |ptr| { var line_i: usize = 0; while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} const key = ptr[0..line_i]; @@ -761,7 +756,7 @@ test "os.getEnvMap" { /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { - for (posix_environ_raw) |ptr| { + for (startup.posix_environ_raw) |ptr| { var line_i: usize = 0; while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} const this_key = ptr[0..line_i]; @@ -1942,14 +1937,14 @@ pub const ArgIteratorPosix = struct { pub fn init() ArgIteratorPosix { return ArgIteratorPosix{ .index = 0, - .count = raw.len, + .count = startup.posix_argv_raw.len, }; } pub fn next(self: *ArgIteratorPosix) ?[]const u8 { if (self.index == self.count) return null; - const s = raw[self.index]; + const s = startup.posix_argv_raw[self.index]; self.index += 1; return cstr.toSlice(s); } @@ -1960,10 +1955,6 @@ pub const ArgIteratorPosix = struct { self.index += 1; return true; } - - /// This is marked as public but actually it's only meant to be used - /// internally by zig's startup code. - pub var raw: [][*]u8 = undefined; }; pub const ArgIteratorWindows = struct { @@ -2908,14 +2899,15 @@ pub const Thread = struct { pub const Data = if (use_pthreads) struct { handle: Thread.Handle, - stack_addr: usize, - stack_len: usize, + mmap_addr: usize, + mmap_len: usize, } else switch (builtin.os) { builtin.Os.linux => struct { handle: Thread.Handle, - stack_addr: usize, - stack_len: usize, + mmap_addr: usize, + mmap_len: usize, + tls_end_addr: usize, }, builtin.Os.windows => struct { handle: Thread.Handle, @@ -2955,7 +2947,7 @@ pub const Thread = struct { posix.EDEADLK => unreachable, else => unreachable, } - assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0); } else switch (builtin.os) { builtin.Os.linux => { while (true) { @@ -2969,7 +2961,7 @@ pub const Thread = struct { else => unreachable, } } - assert(posix.munmap(self.data.stack_addr, self.data.stack_len) == 0); + assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0); }, builtin.Os.windows => { assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0); @@ -3097,42 +3089,56 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0; - const mmap_len = default_stack_size; - const stack_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); - if (stack_addr == posix.MAP_FAILED) return error.OutOfMemory; - errdefer assert(posix.munmap(stack_addr, mmap_len) == 0); + var stack_end_offset: usize = undefined; + var thread_start_offset: usize = undefined; + var context_start_offset: usize = undefined; + var tls_start_offset: usize = undefined; + const mmap_len = blk: { + // First in memory will be the stack, which grows downwards. + var l: usize = mem.alignForward(default_stack_size, os.page_size); + stack_end_offset = l; + // Above the stack, so that it can be in the same mmap call, put the Thread object. + l = mem.alignForward(l, @alignOf(Thread)); + thread_start_offset = l; + l += @sizeOf(Thread); + // Next, the Context object. + if (@sizeOf(Context) != 0) { + l = mem.alignForward(l, @alignOf(Context)); + context_start_offset = l; + l += @sizeOf(Context); + } + // Finally, the Thread Local Storage, if any. + if (!Thread.use_pthreads) { + if (startup.linux_tls_phdr) |tls_phdr| { + l = mem.alignForward(l, tls_phdr.p_align); + tls_start_offset = l; + l += tls_phdr.p_memsz; + } + } + break :blk l; + }; + const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0); + if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory; + errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0); + + const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset)); + thread_ptr.data.mmap_addr = mmap_addr; + thread_ptr.data.mmap_len = mmap_len; - var stack_end: usize = stack_addr + mmap_len; var arg: usize = undefined; if (@sizeOf(Context) != 0) { - stack_end -= @sizeOf(Context); - stack_end -= stack_end % @alignOf(Context); - assert(stack_end >= stack_addr); - const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, stack_end)); + arg = mmap_addr + context_start_offset; + const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg)); context_ptr.* = context; - arg = stack_end; } - stack_end -= @sizeOf(Thread); - stack_end -= stack_end % @alignOf(Thread); - assert(stack_end >= stack_addr); - const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, stack_end)); - - thread_ptr.data.stack_addr = stack_addr; - thread_ptr.data.stack_len = mmap_len; - - if (builtin.os == builtin.Os.windows) { - // use windows API directly - @compileError("TODO support spawnThread for Windows"); - } else if (Thread.use_pthreads) { + if (Thread.use_pthreads) { // use pthreads var attr: c.pthread_attr_t = undefined; if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources; defer assert(c.pthread_attr_destroy(&attr) == 0); - // align to page - stack_end -= stack_end % os.page_size; - assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, stack_addr), stack_end - stack_addr) == 0); + assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0); const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg)); switch (err) { @@ -3143,10 +3149,17 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread else => return unexpectedErrorPosix(@intCast(usize, err)), } } else if (builtin.os == builtin.Os.linux) { - // use linux API directly. TODO use posix.CLONE_SETTLS and initialize thread local storage correctly - const flags = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | posix.CLONE_DETACHED; - const newtls: usize = 0; - const rc = posix.clone(MainFuncs.linuxThreadMain, stack_end, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); + var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND | + posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID | + posix.CLONE_DETACHED; + var newtls: usize = undefined; + if (startup.linux_tls_phdr) |tls_phdr| { + @memcpy(@intToPtr([*]u8, mmap_addr + tls_start_offset), startup.linux_tls_img_src, tls_phdr.p_filesz); + thread_ptr.data.tls_end_addr = mmap_addr + mmap_len; + newtls = @ptrToInt(&thread_ptr.data.tls_end_addr); + flags |= posix.CLONE_SETTLS; + } + const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle); const err = posix.getErrno(rc); switch (err) { 0 => return thread_ptr, diff --git a/std/os/startup.zig b/std/os/startup.zig new file mode 100644 index 0000000000..c54d274c5d --- /dev/null +++ b/std/os/startup.zig @@ -0,0 +1,26 @@ +// This file contains global variables that are initialized on startup from +// std/special/bootstrap.zig. There are a few things to be aware of here. +// +// First, when building an object or library, and no entry point is defined +// (such as pub fn main), std/special/bootstrap.zig is not included in the +// compilation. And so these global variables will remain set to the values +// you see here. +// +// Second, when using `zig test` to test the standard library, note that +// `zig test` is self-hosted. This means that it uses std/special/bootstrap.zig +// and an @import("std") from the install directory, which is distinct from +// the standard library files that we are directly testing with `zig test`. +// This means that these global variables would not get set. So the workaround +// here is that references to these globals from the standard library must +// use `@import("std").startup` rather than +// `@import("path/to/std/index.zig").startup` (and rather than the file path of +// this file directly). We also put "std" as a reference to itself in the +// standard library package so that this can work. + +const std = @import("../index.zig"); + +pub var linux_tls_phdr: ?*std.elf.Phdr = null; +pub var linux_tls_img_src: [*]const u8 = undefined; // defined when linux_tls_phdr is non-null +pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; +pub var posix_environ_raw: [][*]u8 = undefined; +pub var posix_argv_raw: [][*]u8 = undefined; diff --git a/std/os/test.zig b/std/os/test.zig index f14cf47786..bd9148d1b1 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -105,3 +105,19 @@ test "AtomicFile" { try os.deleteFile(test_out_file); } + +test "thread local storage" { + if (builtin.single_threaded) return error.SkipZigTest; + const thread1 = try std.os.spawnThread({}, testTls); + const thread2 = try std.os.spawnThread({}, testTls); + testTls({}); + thread1.wait(); + thread2.wait(); +} + +threadlocal var x: i32 = 1234; +fn testTls(context: void) void { + if (x != 1234) @panic("bad start value"); + x += 1; + if (x != 1235) @panic("bad end value"); +} diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 129bde913f..0e84f67481 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -4,6 +4,7 @@ const root = @import("@root"); const std = @import("std"); const builtin = @import("builtin"); +const assert = std.debug.assert; var argc_ptr: [*]usize = undefined; @@ -61,9 +62,23 @@ fn posixCallMainAndExit() noreturn { while (envp_optional[envp_count]) |_| : (envp_count += 1) {} const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; if (builtin.os == builtin.Os.linux) { - const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1); - std.os.linux_elf_aux_maybe = @ptrCast([*]std.elf.Auxv, auxv); - std.debug.assert(std.os.linuxGetAuxVal(std.elf.AT_PAGESZ) == std.os.page_size); + // Scan auxiliary vector. + const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + std.startup.linux_elf_aux_maybe = auxv; + var i: usize = 0; + var at_phdr: usize = 0; + var at_phnum: usize = 0; + var at_phent: usize = 0; + while (auxv[i].a_un.a_val != 0) : (i += 1) { + switch (auxv[i].a_type) { + std.elf.AT_PAGESZ => assert(auxv[i].a_un.a_val == std.os.page_size), + std.elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, + std.elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, + std.elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, + else => {}, + } + } + if (!builtin.single_threaded) linuxInitializeThreadLocalStorage(at_phdr, at_phnum, at_phent); } std.os.posix.exit(callMainWithArgs(argc, argv, envp)); @@ -72,8 +87,8 @@ fn posixCallMainAndExit() noreturn { // This is marked inline because for some reason LLVM in release mode fails to inline it, // and we want fewer call frames in stack traces. inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { - std.os.ArgIteratorPosix.raw = argv[0..argc]; - std.os.posix_environ_raw = envp; + std.startup.posix_argv_raw = argv[0..argc]; + std.startup.posix_environ_raw = envp; return callMain(); } @@ -116,3 +131,41 @@ inline fn callMain() u8 { else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), } } + +var tls_end_addr: usize = undefined; +const main_thread_tls_align = 32; +var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; + +fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent: usize) void { + var phdr_addr = at_phdr; + var n = at_phnum; + var base: usize = 0; + while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) { + const phdr = @intToPtr(*std.elf.Phdr, phdr_addr); + // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917 + switch (phdr.p_type) { + std.elf.PT_PHDR => base = at_phdr - phdr.p_vaddr, + std.elf.PT_TLS => std.startup.linux_tls_phdr = phdr, + else => continue, + } + } + const tls_phdr = std.startup.linux_tls_phdr orelse return; + std.startup.linux_tls_img_src = @intToPtr([*]const u8, base + tls_phdr.p_vaddr); + assert(main_thread_tls_bytes.len >= tls_phdr.p_memsz); // not enough preallocated Thread Local Storage + assert(main_thread_tls_align >= tls_phdr.p_align); // preallocated Thread Local Storage not aligned enough + @memcpy(&main_thread_tls_bytes, std.startup.linux_tls_img_src, tls_phdr.p_filesz); + tls_end_addr = @ptrToInt(&main_thread_tls_bytes) + tls_phdr.p_memsz; + linuxSetThreadArea(@ptrToInt(&tls_end_addr)); +} + +fn linuxSetThreadArea(addr: usize) void { + switch (builtin.arch) { + builtin.Arch.x86_64 => { + const ARCH_SET_FS = 0x1002; + const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, ARCH_SET_FS, addr); + // acrh_prctl is documented to never fail + assert(rc == 0); + }, + else => @compileError("Unsupported architecture"), + } +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 30d9ca5d70..acd1eada06 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,25 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "threadlocal qualifier on const", + \\threadlocal const x: i32 = 1234; + \\export fn entry() i32 { + \\ return x; + \\} + , + ".tmp_source.zig:1:13: error: threadlocal variable cannot be constant", + ); + + cases.add( + "threadlocal qualifier on local variable", + \\export fn entry() void { + \\ threadlocal var x: i32 = 1234; + \\} + , + ".tmp_source.zig:2:5: error: function-local variable 'x' cannot be threadlocal", + ); + cases.add( "@bitCast same size but bit count mismatch", \\export fn entry(byte: u8) void { diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 8d2555dddd..3cc8e5f31e 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -685,3 +685,11 @@ test "fn call returning scalar optional in equality expression" { fn getNull() ?*i32 { return null; } + +test "thread local variable" { + const S = struct { + threadlocal var t: i32 = 1234; + }; + S.t += 1; + assertOrPanic(S.t == 1235); +} -- cgit v1.2.3 From f330eebe4bc6a036846cf05706f72855627c705a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Feb 2019 16:02:45 -0500 Subject: fix using the result of @intCast to u0 closes #1817 --- src/all_types.hpp | 7 +++++++ src/codegen.cpp | 40 +++++++++++++++++++++++++++++----------- src/ir.cpp | 31 +++++++++++++++++++++++++++++++ src/ir_print.cpp | 9 +++++++++ test/runtime_safety.zig | 17 +++++++++++++++++ test/stage1/behavior/cast.zig | 11 +++++++++++ test/stage1/behavior/eval.zig | 6 ------ 7 files changed, 104 insertions(+), 17 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 5af4e71157..842c9ae904 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2239,6 +2239,7 @@ enum IrInstructionId { IrInstructionIdCheckRuntimeScope, IrInstructionIdVectorToArray, IrInstructionIdArrayToVector, + IrInstructionIdAssertZero, }; struct IrInstruction { @@ -3381,6 +3382,12 @@ struct IrInstructionVectorToArray { LLVMValueRef tmp_ptr; }; +struct IrInstructionAssertZero { + IrInstruction base; + + IrInstruction *target; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index f010430e14..3bfd7cdfc5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1651,10 +1651,25 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } +static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) { + LLVMValueRef zero = LLVMConstNull(int_type->type_ref); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdCastTruncatedData); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return nullptr; +} + static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, ZigType *actual_type, ZigType *wanted_type, LLVMValueRef expr_val) { assert(actual_type->id == wanted_type->id); + assert(expr_val != nullptr); uint64_t actual_bits; uint64_t wanted_bits; @@ -1707,17 +1722,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z if (!want_runtime_safety) return nullptr; - LLVMValueRef zero = LLVMConstNull(actual_type->type_ref); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdCastTruncatedData); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - return nullptr; + return gen_assert_zero(g, expr_val, actual_type); } LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, ""); if (!want_runtime_safety) { @@ -5209,6 +5214,17 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab return gen_load_untyped(g, casted_ptr, 0, false, ""); } +static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable, + IrInstructionAssertZero *instruction) +{ + LLVMValueRef target = ir_llvm_value(g, instruction->target); + ZigType *int_type = instruction->target->value.type; + if (ir_want_runtime_safety(g, &instruction->base)) { + return gen_assert_zero(g, target, int_type); + } + return nullptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -5458,6 +5474,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); case IrInstructionIdVectorToArray: return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction); + case IrInstructionIdAssertZero: + return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 02b2b12230..00d358552a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -908,6 +908,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToVector *) return IrInstructionIdArrayToVector; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertZero *) { + return IrInstructionIdAssertZero; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2858,6 +2862,19 @@ static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *so return &instruction->base; } +static IrInstruction *ir_build_assert_zero(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *target) +{ + IrInstructionAssertZero *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ira->codegen->builtin_types.entry_void; + instruction->target = target; + + ir_ref_instruction(target, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -10395,6 +10412,18 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction return result; } + // If the destination integer type has no bits, then we can emit a comptime + // zero. However, we still want to emit a runtime safety check to make sure + // the target is zero. + if (!type_has_bits(wanted_type)) { + assert(wanted_type->id == ZigTypeIdInt); + assert(type_has_bits(target->value.type)); + ir_build_assert_zero(ira, source_instr, target); + IrInstruction *result = ir_const_unsigned(ira, source_instr, 0); + result->value.type = wanted_type; + return result; + } + IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope, source_instr->source_node, target); result->value.type = wanted_type; @@ -21705,6 +21734,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdCmpxchgGen: case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: + case IrInstructionIdAssertZero: zig_unreachable(); case IrInstructionIdReturn: @@ -22103,6 +22133,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdAtomicRmw: case IrInstructionIdCmpxchgGen: case IrInstructionIdCmpxchgSrc: + case IrInstructionIdAssertZero: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e19aa6dda8..75da24d1a9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -984,6 +984,12 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i fprintf(irp->f, ")"); } +static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) { + fprintf(irp->f, "AssertZero("); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1843,6 +1849,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdVectorToArray: ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); break; + case IrInstructionIdAssertZero: + ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 7c13f5b6fa..7de43b45f4 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -362,6 +362,23 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} ); + // @intCast a runtime integer to u0 actually results in a comptime-known value, + // but we still emit a safety check to ensure the integer was 0 and thus + // did not truncate information. + cases.addRuntimeSafety("@intCast to u0", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\ + \\pub fn main() void { + \\ bar(1, 1); + \\} + \\ + \\fn bar(one: u1, not_zero: i32) void { + \\ var x = one << @intCast(u0, not_zero); + \\} + ); + // This case makes sure that the code compiles and runs. There is not actually a special // runtime safety check having to do specifically with error return traces across suspend points. cases.addRuntimeSafety("error return trace across suspend points", diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 61ddcd8135..27f685a96e 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -471,3 +471,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" { const x = @intToEnum(E, 0); assertOrPanic(x == E.A); } + +test "@intCast to u0 and use the result" { + const S = struct { + fn doTheTest(zero: u1, one: u1, bigzero: i32) void { + assertOrPanic((one << @intCast(u0, bigzero)) == 1); + assertOrPanic((zero << @intCast(u0, bigzero)) == 0); + } + }; + S.doTheTest(0, 1, 0); + comptime S.doTheTest(0, 1, 0); +} diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 3e8af0524f..0d1ecfab5b 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -697,12 +697,6 @@ test "bit shift a u1" { assertOrPanic(y == 1); } -test "@intCast to a u0" { - var x: u8 = 0; - var y: u0 = @intCast(u0, x); - assertOrPanic(y == 0); -} - test "@bytesToslice on a packed struct" { const F = packed struct { a: u8, -- cgit v1.2.3 From c2db077574be841da586fa62d67619c901dd535d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Feb 2019 18:18:47 -0500 Subject: std.debug.assert: remove special case for test builds Previously, std.debug.assert would `@panic` in test builds, if the assertion failed. Now, it's always `unreachable`. This makes release mode test builds more accurately test the actual code that will be run. However this requires tests to call `std.testing.expect` rather than `std.debug.assert` to make sure output is correct. Here is the explanation of when to use either one, copied from the assert doc comments: Inside a test block, it is best to use the `std.testing` module rather than assert, because assert may not detect a test failure in ReleaseFast and ReleaseSafe mode. Outside of a test block, assert is the correct function to use. closes #1304 --- CMakeLists.txt | 1 + doc/docgen.zig | 4 +- src-self-hosted/arg.zig | 23 +- src-self-hosted/test.zig | 4 +- src/ir.cpp | 24 +- std/array_list.zig | 106 +++--- std/atomic/queue.zig | 23 +- std/atomic/stack.zig | 5 +- std/base64.zig | 13 +- std/buf_map.zig | 16 +- std/buf_set.zig | 6 +- std/buffer.zig | 15 +- std/crypto/chacha20.zig | 15 +- std/crypto/poly1305.zig | 2 +- std/crypto/test.zig | 9 +- std/crypto/x25519.zig | 24 +- std/cstr.zig | 6 +- std/debug/index.zig | 38 +-- std/dynamic_library.zig | 3 +- std/event/channel.zig | 9 +- std/event/fs.zig | 9 +- std/event/future.zig | 3 +- std/event/group.zig | 6 +- std/event/lock.zig | 3 +- std/event/loop.zig | 5 +- std/event/net.zig | 4 +- std/event/rwlock.zig | 7 +- std/fmt/index.zig | 158 ++++----- std/hash/adler.zig | 12 +- std/hash/crc.zig | 25 +- std/hash/fnv.zig | 18 +- std/hash/siphash.zig | 15 +- std/hash_map.zig | 59 ++-- std/heap.zig | 55 +-- std/index.zig | 15 +- std/io.zig | 17 +- std/io_test.zig | 202 ++++++------ std/json.zig | 17 +- std/json_test.zig | 6 +- std/lazy_init.zig | 9 +- std/linked_list.zig | 29 +- std/math/acos.zig | 38 +-- std/math/acosh.zig | 30 +- std/math/asin.zig | 46 +-- std/math/asinh.zig | 54 +-- std/math/atan.zig | 42 +-- std/math/atan2.zig | 110 +++--- std/math/atanh.zig | 38 +-- std/math/big/int.zig | 367 ++++++++++----------- std/math/cbrt.zig | 50 +-- std/math/ceil.zig | 38 +-- std/math/complex/abs.zig | 4 +- std/math/complex/acos.zig | 6 +- std/math/complex/acosh.zig | 6 +- std/math/complex/arg.zig | 4 +- std/math/complex/asin.zig | 6 +- std/math/complex/asinh.zig | 6 +- std/math/complex/atan.zig | 10 +- std/math/complex/atanh.zig | 6 +- std/math/complex/conj.zig | 4 +- std/math/complex/cos.zig | 6 +- std/math/complex/cosh.zig | 10 +- std/math/complex/exp.zig | 10 +- std/math/complex/index.zig | 16 +- std/math/complex/log.zig | 6 +- std/math/complex/pow.zig | 6 +- std/math/complex/proj.zig | 4 +- std/math/complex/sin.zig | 6 +- std/math/complex/sinh.zig | 10 +- std/math/complex/sqrt.zig | 10 +- std/math/complex/tan.zig | 6 +- std/math/complex/tanh.zig | 10 +- std/math/copysign.zig | 32 +- std/math/cos.zig | 42 +-- std/math/cosh.zig | 42 +-- std/math/exp2.zig | 32 +- std/math/expm1.zig | 38 +-- std/math/fabs.zig | 38 +-- std/math/floor.zig | 56 ++-- std/math/fma.zig | 34 +- std/math/frexp.zig | 34 +- std/math/hypot.zig | 58 ++-- std/math/ilogb.zig | 46 +-- std/math/index.zig | 343 +++++++++---------- std/math/isfinite.zig | 26 +- std/math/isinf.zig | 74 ++--- std/math/isnan.zig | 14 +- std/math/isnormal.zig | 20 +- std/math/ln.zig | 46 +-- std/math/log.zig | 26 +- std/math/log10.zig | 46 +-- std/math/log1p.zig | 58 ++-- std/math/log2.zig | 42 +-- std/math/modf.zig | 58 ++-- std/math/pow.zig | 96 +++--- std/math/powi.zig | 138 ++++---- std/math/round.zig | 42 +-- std/math/scalbn.zig | 10 +- std/math/signbit.zig | 20 +- std/math/sin.zig | 52 +-- std/math/sinh.zig | 42 +-- std/math/sqrt.zig | 104 +++--- std/math/tan.zig | 50 +-- std/math/tanh.zig | 46 +-- std/math/trunc.zig | 38 +-- std/mem.zig | 319 +++++++++--------- std/meta/index.zig | 151 ++++----- std/meta/trait.zig | 133 ++++---- std/mutex.zig | 6 +- std/os/child_process.zig | 1 - std/os/index.zig | 9 +- std/os/linux/test.zig | 12 +- std/os/path.zig | 115 +++---- std/os/test.zig | 16 +- std/os/time.zig | 9 +- std/rand/index.zig | 161 ++++----- std/rb.zig | 5 +- std/segmented_list.zig | 31 +- std/sort.zig | 17 +- std/special/compiler_rt/divti3_test.zig | 4 +- std/special/compiler_rt/extendXfYf2_test.zig | 1 - std/special/compiler_rt/fixdfdi_test.zig | 4 +- std/special/compiler_rt/fixdfsi_test.zig | 4 +- std/special/compiler_rt/fixdfti_test.zig | 4 +- std/special/compiler_rt/fixint_test.zig | 4 +- std/special/compiler_rt/fixsfdi_test.zig | 4 +- std/special/compiler_rt/fixsfsi_test.zig | 4 +- std/special/compiler_rt/fixsfti_test.zig | 4 +- std/special/compiler_rt/fixtfdi_test.zig | 4 +- std/special/compiler_rt/fixtfsi_test.zig | 4 +- std/special/compiler_rt/fixtfti_test.zig | 4 +- std/special/compiler_rt/fixunsdfdi_test.zig | 4 +- std/special/compiler_rt/fixunsdfsi_test.zig | 4 +- std/special/compiler_rt/fixunsdfti_test.zig | 4 +- std/special/compiler_rt/fixunssfdi_test.zig | 4 +- std/special/compiler_rt/fixunssfsi_test.zig | 4 +- std/special/compiler_rt/fixunssfti_test.zig | 4 +- std/special/compiler_rt/fixunstfdi_test.zig | 4 +- std/special/compiler_rt/fixunstfsi_test.zig | 4 +- std/special/compiler_rt/fixunstfti_test.zig | 4 +- std/special/compiler_rt/floattidf_test.zig | 4 +- std/special/compiler_rt/floattisf_test.zig | 4 +- std/special/compiler_rt/floattitf_test.zig | 4 +- std/special/compiler_rt/floatunditf_test.zig | 1 - std/special/compiler_rt/floatunsitf_test.zig | 1 - std/special/compiler_rt/floatuntidf_test.zig | 4 +- std/special/compiler_rt/floatuntisf_test.zig | 4 +- std/special/compiler_rt/floatuntitf_test.zig | 4 +- std/special/compiler_rt/index.zig | 5 +- std/special/compiler_rt/muloti4_test.zig | 4 +- std/special/compiler_rt/multi3_test.zig | 4 +- std/special/compiler_rt/udivmoddi4_test.zig | 6 +- std/special/compiler_rt/udivmodti4_test.zig | 6 +- std/special/init-lib/src/main.zig | 4 +- std/statically_initialized_mutex.zig | 5 +- std/testing.zig | 152 +++++++++ std/unicode.zig | 119 +++---- std/zig/ast.zig | 3 +- std/zig/parser_test.zig | 2 +- std/zig/tokenizer.zig | 2 +- test/cli.zig | 10 +- test/stage1/behavior/align.zig | 72 ++-- test/stage1/behavior/alignof.zig | 6 +- test/stage1/behavior/array.zig | 110 +++--- test/stage1/behavior/asm.zig | 4 +- test/stage1/behavior/atomics.zig | 32 +- test/stage1/behavior/bit_shifting.zig | 10 +- test/stage1/behavior/bitcast.zig | 8 +- test/stage1/behavior/bitreverse.zig | 86 ++--- test/stage1/behavior/bool.zig | 20 +- test/stage1/behavior/bswap.zig | 42 +-- test/stage1/behavior/bugs/1076.zig | 4 +- test/stage1/behavior/bugs/1277.zig | 2 +- test/stage1/behavior/bugs/1322.zig | 4 +- test/stage1/behavior/bugs/1381.zig | 2 +- test/stage1/behavior/bugs/1421.zig | 4 +- test/stage1/behavior/bugs/1442.zig | 2 +- test/stage1/behavior/bugs/1486.zig | 6 +- test/stage1/behavior/bugs/394.zig | 4 +- test/stage1/behavior/bugs/655.zig | 4 +- test/stage1/behavior/bugs/656.zig | 4 +- test/stage1/behavior/bugs/726.zig | 6 +- test/stage1/behavior/bugs/920.zig | 2 +- test/stage1/behavior/byval_arg_var.zig | 2 +- test/stage1/behavior/cancel.zig | 14 +- test/stage1/behavior/cast.zig | 158 ++++----- test/stage1/behavior/const_slice_child.zig | 13 +- test/stage1/behavior/coroutine_await_struct.zig | 6 +- test/stage1/behavior/coroutines.zig | 36 +- test/stage1/behavior/defer.zig | 24 +- test/stage1/behavior/enum.zig | 74 ++--- test/stage1/behavior/enum_with_members.zig | 10 +- test/stage1/behavior/error.zig | 62 ++-- test/stage1/behavior/eval.zig | 232 ++++++------- test/stage1/behavior/field_parent_ptr.zig | 14 +- test/stage1/behavior/fn.zig | 38 +-- test/stage1/behavior/fn_in_struct_in_comptime.zig | 4 +- test/stage1/behavior/for.zig | 10 +- test/stage1/behavior/generics.zig | 46 +-- test/stage1/behavior/if.zig | 4 +- test/stage1/behavior/import.zig | 6 +- .../behavior/incomplete_struct_param_tld.zig | 4 +- test/stage1/behavior/inttoptr.zig | 2 +- test/stage1/behavior/ir_block_deps.zig | 6 +- test/stage1/behavior/math.zig | 262 +++++++-------- test/stage1/behavior/misc.zig | 276 ++++++++-------- .../namespace_depends_on_compile_var/index.zig | 6 +- test/stage1/behavior/new_stack_call.zig | 10 +- test/stage1/behavior/null.zig | 34 +- test/stage1/behavior/optional.zig | 28 +- test/stage1/behavior/pointers.zig | 24 +- test/stage1/behavior/popcount.zig | 10 +- test/stage1/behavior/ptrcast.zig | 8 +- test/stage1/behavior/pub_enum/index.zig | 6 +- .../ref_var_in_if_after_if_2nd_switch_prong.zig | 10 +- test/stage1/behavior/reflection.zig | 78 ++--- test/stage1/behavior/sizeof_and_typeof.zig | 60 ++-- test/stage1/behavior/slice.zig | 16 +- test/stage1/behavior/struct.zig | 184 +++++------ .../behavior/struct_contains_null_ptr_itself.zig | 4 +- .../behavior/struct_contains_slice_of_itself.zig | 26 +- test/stage1/behavior/switch.zig | 66 ++-- test/stage1/behavior/switch_prong_err_enum.zig | 6 +- .../stage1/behavior/switch_prong_implicit_cast.zig | 4 +- test/stage1/behavior/this.zig | 8 +- test/stage1/behavior/truncate.zig | 4 +- test/stage1/behavior/try.zig | 10 +- test/stage1/behavior/type_info.zig | 182 +++++----- test/stage1/behavior/undefined.zig | 28 +- test/stage1/behavior/underscore.zig | 2 +- test/stage1/behavior/union.zig | 76 ++--- test/stage1/behavior/var_args.zig | 34 +- test/stage1/behavior/vector.zig | 8 +- test/stage1/behavior/void.zig | 8 +- test/stage1/behavior/while.zig | 44 +-- test/stage1/behavior/widening.zig | 8 +- test/stage1/c_abi/main.zig | 82 ++--- test/standalone/brace_expansion/main.zig | 9 +- test/standalone/issue_794/main.zig | 4 +- 239 files changed, 4106 insertions(+), 3960 deletions(-) create mode 100644 std/testing.zig (limited to 'src/ir.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index d6bd8a6c2e..ed79f99901 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -658,6 +658,7 @@ set(ZIG_STD_FILES "special/test_runner.zig" "spinlock.zig" "statically_initialized_mutex.zig" + "testing.zig" "unicode.zig" "zig/ast.zig" "zig/index.zig" diff --git a/doc/docgen.zig b/doc/docgen.zig index 14e4700553..7aaf5ebdc7 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -4,7 +4,7 @@ const io = std.io; const os = std.os; const warn = std.debug.warn; const mem = std.mem; -const assert = std.debug.assert; +const testing = std.testing; const max_doc_file_size = 10 * 1024 * 1024; @@ -620,7 +620,7 @@ const TermState = enum { test "term color" { const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; const result = try termColor(std.debug.global_allocator, input_bytes); - assert(mem.eql(u8, result, "AgreenB")); + testing.expectEqualSlices(u8, "AgreenB", result)); } fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 { diff --git a/src-self-hosted/arg.zig b/src-self-hosted/arg.zig index 99e6ecc17a..7bbd233a75 100644 --- a/src-self-hosted/arg.zig +++ b/src-self-hosted/arg.zig @@ -1,5 +1,6 @@ const std = @import("std"); const debug = std.debug; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -272,21 +273,21 @@ test "parse arguments" { var args = try Args.parse(std.debug.global_allocator, spec1, cliargs); - debug.assert(args.present("help")); - debug.assert(!args.present("help2")); - debug.assert(!args.present("init")); + testing.expect(args.present("help")); + testing.expect(!args.present("help2")); + testing.expect(!args.present("init")); - debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig")); - debug.assert(mem.eql(u8, args.single("color").?, "on")); + testing.expect(mem.eql(u8, args.single("build-file").?, "build.zig")); + testing.expect(mem.eql(u8, args.single("color").?, "on")); const objects = args.many("object").?; - debug.assert(mem.eql(u8, objects[0], "obj1")); - debug.assert(mem.eql(u8, objects[1], "obj2")); + testing.expect(mem.eql(u8, objects[0], "obj1")); + testing.expect(mem.eql(u8, objects[1], "obj2")); - debug.assert(mem.eql(u8, args.single("library").?, "lib2")); + testing.expect(mem.eql(u8, args.single("library").?, "lib2")); const pos = args.positionals.toSliceConst(); - debug.assert(mem.eql(u8, pos[0], "build")); - debug.assert(mem.eql(u8, pos[1], "pos1")); - debug.assert(mem.eql(u8, pos[2], "pos2")); + testing.expect(mem.eql(u8, pos[0], "build")); + testing.expect(mem.eql(u8, pos[1], "pos1")); + testing.expect(mem.eql(u8, pos[2], "pos2")); } diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index de551cf7f7..4be6d53932 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -4,7 +4,7 @@ const builtin = @import("builtin"); const Target = @import("target.zig").Target; const Compilation = @import("compilation.zig").Compilation; const introspect = @import("introspect.zig"); -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; const errmsg = @import("errmsg.zig"); const ZigCompiler = @import("compilation.zig").ZigCompiler; @@ -210,7 +210,7 @@ pub const TestContext = struct { @panic("build incorrectly failed"); }, Compilation.Event.Fail => |msgs| { - assertOrPanic(msgs.len != 0); + testing.expect(msgs.len != 0); for (msgs) |msg| { if (mem.endsWith(u8, msg.realpath, path) and mem.eql(u8, msg.text, text)) { const span = msg.getSpan(); diff --git a/src/ir.cpp b/src/ir.cpp index 00d358552a..efda2b321b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17543,21 +17543,16 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val, enum_field_val->data.x_struct.fields = inner_fields; } -static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstExprValue **out) { +static Error ir_make_type_info_value(IrAnalyze *ira, AstNode *source_node, ZigType *type_entry, ConstExprValue **out) { Error err; assert(type_entry != nullptr); assert(!type_is_invalid(type_entry)); - if ((err = ensure_complete_type(ira->codegen, type_entry))) + if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) return err; - if (type_entry == ira->codegen->builtin_types.entry_global_error_set) { - zig_panic("TODO implement @typeInfo for global error set"); - } - ConstExprValue *result = nullptr; - switch (type_entry->id) - { + switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); case ZigTypeIdMetaType: @@ -17778,6 +17773,15 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE ensure_field_index(result->type, "errors", 0); ZigType *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr); + if (!resolve_inferred_error_set(ira->codegen, type_entry, source_node)) { + return ErrorSemanticAnalyzeFail; + } + if (type_is_global_error_set(type_entry)) { + ir_add_error_node(ira, source_node, + buf_sprintf("TODO: compiler bug: implement @typeInfo support for anyerror. https://github.com/ziglang/zig/issues/1936")); + return ErrorSemanticAnalyzeFail; + } + uint32_t error_count = type_entry->data.error_set.err_count; ConstExprValue *error_array = create_const_vals(1); error_array->special = ConstValSpecialStatic; @@ -18103,7 +18107,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE { ZigType *fn_type = type_entry->data.bound_fn.fn_type; assert(fn_type->id == ZigTypeIdFn); - if ((err = ir_make_type_info_value(ira, fn_type, &result))) + if ((err = ir_make_type_info_value(ira, source_node, fn_type, &result))) return err; break; @@ -18128,7 +18132,7 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira, ZigType *result_type = ir_type_info_get_type(ira, nullptr, nullptr); ConstExprValue *payload; - if ((err = ir_make_type_info_value(ira, type_entry, &payload))) + if ((err = ir_make_type_info_value(ira, instruction->base.source_node, type_entry, &payload))) return ira->codegen->invalid_instruction; IrInstruction *result = ir_const(ira, &instruction->base, result_type); diff --git a/std/array_list.zig b/std/array_list.zig index ddad9c989c..e2535d6393 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -1,7 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; -const assertError = debug.assertError; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -212,8 +212,8 @@ test "std.ArrayList.init" { var list = ArrayList(i32).init(allocator); defer list.deinit(); - assert(list.count() == 0); - assert(list.capacity() == 0); + testing.expect(list.count() == 0); + testing.expect(list.capacity() == 0); } test "std.ArrayList.basic" { @@ -224,7 +224,7 @@ test "std.ArrayList.basic" { defer list.deinit(); // setting on empty list is out of bounds - assertError(list.setOrError(0, 1), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.setOrError(0, 1)); { var i: usize = 0; @@ -236,44 +236,44 @@ test "std.ArrayList.basic" { { var i: usize = 0; while (i < 10) : (i += 1) { - assert(list.items[i] == @intCast(i32, i + 1)); + testing.expect(list.items[i] == @intCast(i32, i + 1)); } } for (list.toSlice()) |v, i| { - assert(v == @intCast(i32, i + 1)); + testing.expect(v == @intCast(i32, i + 1)); } for (list.toSliceConst()) |v, i| { - assert(v == @intCast(i32, i + 1)); + testing.expect(v == @intCast(i32, i + 1)); } - assert(list.pop() == 10); - assert(list.len == 9); + testing.expect(list.pop() == 10); + testing.expect(list.len == 9); list.appendSlice([]const i32{ 1, 2, 3, }) catch unreachable; - assert(list.len == 12); - assert(list.pop() == 3); - assert(list.pop() == 2); - assert(list.pop() == 1); - assert(list.len == 9); + testing.expect(list.len == 12); + testing.expect(list.pop() == 3); + testing.expect(list.pop() == 2); + testing.expect(list.pop() == 1); + testing.expect(list.len == 9); list.appendSlice([]const i32{}) catch unreachable; - assert(list.len == 9); + testing.expect(list.len == 9); // can only set on indices < self.len list.set(7, 33); list.set(8, 42); - assertError(list.setOrError(9, 99), error.OutOfBounds); - assertError(list.setOrError(10, 123), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.setOrError(9, 99)); + testing.expectError(error.OutOfBounds, list.setOrError(10, 123)); - assert(list.pop() == 42); - assert(list.pop() == 33); + testing.expect(list.pop() == 42); + testing.expect(list.pop() == 33); } test "std.ArrayList.swapRemove" { @@ -289,18 +289,18 @@ test "std.ArrayList.swapRemove" { try list.append(7); //remove from middle - assert(list.swapRemove(3) == 4); - assert(list.at(3) == 7); - assert(list.len == 6); + testing.expect(list.swapRemove(3) == 4); + testing.expect(list.at(3) == 7); + testing.expect(list.len == 6); //remove from end - assert(list.swapRemove(5) == 6); - assert(list.len == 5); + testing.expect(list.swapRemove(5) == 6); + testing.expect(list.len == 5); //remove from front - assert(list.swapRemove(0) == 1); - assert(list.at(0) == 5); - assert(list.len == 4); + testing.expect(list.swapRemove(0) == 1); + testing.expect(list.at(0) == 5); + testing.expect(list.len == 4); } test "std.ArrayList.swapRemoveOrError" { @@ -308,27 +308,27 @@ test "std.ArrayList.swapRemoveOrError" { defer list.deinit(); // Test just after initialization - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test after adding one item and remote it try list.append(1); - assert((try list.swapRemoveOrError(0)) == 1); - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expect((try list.swapRemoveOrError(0)) == 1); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test after adding two items and remote both try list.append(1); try list.append(2); - assert((try list.swapRemoveOrError(1)) == 2); - assert((try list.swapRemoveOrError(0)) == 1); - assertError(list.swapRemoveOrError(0), error.OutOfBounds); + testing.expect((try list.swapRemoveOrError(1)) == 2); + testing.expect((try list.swapRemoveOrError(0)) == 1); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(0)); // Test out of bounds with one item try list.append(1); - assertError(list.swapRemoveOrError(1), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(1)); // Test out of bounds with two items try list.append(2); - assertError(list.swapRemoveOrError(2), error.OutOfBounds); + testing.expectError(error.OutOfBounds, list.swapRemoveOrError(2)); } test "std.ArrayList.iterator" { @@ -342,22 +342,22 @@ test "std.ArrayList.iterator" { var count: i32 = 0; var it = list.iterator(); while (it.next()) |next| { - assert(next == count + 1); + testing.expect(next == count + 1); count += 1; } - assert(count == 3); - assert(it.next() == null); + testing.expect(count == 3); + testing.expect(it.next() == null); it.reset(); count = 0; while (it.next()) |next| { - assert(next == count + 1); + testing.expect(next == count + 1); count += 1; if (count == 2) break; } it.reset(); - assert(it.next().? == 1); + testing.expect(it.next().? == 1); } test "std.ArrayList.insert" { @@ -368,10 +368,10 @@ test "std.ArrayList.insert" { try list.append(2); try list.append(3); try list.insert(0, 5); - assert(list.items[0] == 5); - assert(list.items[1] == 1); - assert(list.items[2] == 2); - assert(list.items[3] == 3); + testing.expect(list.items[0] == 5); + testing.expect(list.items[1] == 1); + testing.expect(list.items[2] == 2); + testing.expect(list.items[3] == 3); } test "std.ArrayList.insertSlice" { @@ -386,17 +386,17 @@ test "std.ArrayList.insertSlice" { 9, 8, }); - assert(list.items[0] == 1); - assert(list.items[1] == 9); - assert(list.items[2] == 8); - assert(list.items[3] == 2); - assert(list.items[4] == 3); - assert(list.items[5] == 4); + testing.expect(list.items[0] == 1); + testing.expect(list.items[1] == 9); + testing.expect(list.items[2] == 8); + testing.expect(list.items[3] == 2); + testing.expect(list.items[4] == 3); + testing.expect(list.items[5] == 4); const items = []const i32{1}; try list.insertSlice(0, items[0..0]); - assert(list.len == 6); - assert(list.items[0] == 1); + testing.expect(list.len == 6); + testing.expect(list.items[0] == 1); } const Item = struct { @@ -407,5 +407,5 @@ const Item = struct { test "std.ArrayList: ArrayList(T) of struct T" { var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) }; try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } ); - assert(root.sub_items.items[0].integer == 42); + testing.expect(root.sub_items.items[0].integer == 42); } diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig index 183c434dc5..bdc86c0981 100644 --- a/std/atomic/queue.zig +++ b/std/atomic/queue.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; const assert = std.debug.assert; +const expect = std.testing.expect; /// Many producer, many consumer, non-allocating, thread-safe. /// Uses a mutex to protect access. @@ -174,14 +175,14 @@ test "std.atomic.Queue" { { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startPuts(&context) == 0); + expect(startPuts(&context) == 0); } } context.puts_done = 1; { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startGets(&context) == 0); + expect(startGets(&context) == 0); } } } else { @@ -264,7 +265,7 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_1); - assert(queue.get().?.data == 0); + expect(queue.get().?.data == 0); var node_2 = Queue(i32).Node{ .data = 2, @@ -280,9 +281,9 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_3); - assert(queue.get().?.data == 1); + expect(queue.get().?.data == 1); - assert(queue.get().?.data == 2); + expect(queue.get().?.data == 2); var node_4 = Queue(i32).Node{ .data = 4, @@ -291,12 +292,12 @@ test "std.atomic.Queue single-threaded" { }; queue.put(&node_4); - assert(queue.get().?.data == 3); + expect(queue.get().?.data == 3); node_3.next = null; - assert(queue.get().?.data == 4); + expect(queue.get().?.data == 4); - assert(queue.get() == null); + expect(queue.get() == null); } test "std.atomic.Queue dump" { @@ -311,7 +312,7 @@ test "std.atomic.Queue dump" { // Test empty stream sos.reset(); try queue.dumpToStream(SliceOutStream.Error, &sos.stream); - assert(mem.eql(u8, buffer[0..sos.pos], + expect(mem.eql(u8, buffer[0..sos.pos], \\head: (null) \\tail: (null) \\ @@ -335,7 +336,7 @@ test "std.atomic.Queue dump" { \\ (null) \\ , @ptrToInt(queue.head), @ptrToInt(queue.tail)); - assert(mem.eql(u8, buffer[0..sos.pos], expected)); + expect(mem.eql(u8, buffer[0..sos.pos], expected)); // Test a stream with two elements var node_1 = Queue(i32).Node{ @@ -356,5 +357,5 @@ test "std.atomic.Queue dump" { \\ (null) \\ , @ptrToInt(queue.head), @ptrToInt(queue.head.?.next), @ptrToInt(queue.tail)); - assert(mem.eql(u8, buffer[0..sos.pos], expected)); + expect(mem.eql(u8, buffer[0..sos.pos], expected)); } diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig index 503fa0c0ce..4d0d5075e0 100644 --- a/std/atomic/stack.zig +++ b/std/atomic/stack.zig @@ -1,6 +1,7 @@ const assert = std.debug.assert; const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; +const expect = std.testing.expect; /// Many reader, many writer, non-allocating, thread-safe /// Uses a spinlock to protect push() and pop() @@ -108,14 +109,14 @@ test "std.atomic.stack" { { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startPuts(&context) == 0); + expect(startPuts(&context) == 0); } } context.puts_done = 1; { var i: usize = 0; while (i < put_thread_count) : (i += 1) { - std.debug.assertOrPanic(startGets(&context) == 0); + expect(startGets(&context) == 0); } } } else { diff --git a/std/base64.zig b/std/base64.zig index bc0bdb1bd3..cfe8ea95f8 100644 --- a/std/base64.zig +++ b/std/base64.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -394,7 +395,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)]; standard_encoder.encode(encoded, expected_decoded); - assert(mem.eql(u8, encoded, expected_encoded)); + testing.expectEqualSlices(u8, expected_encoded, encoded); } // Base64Decoder @@ -402,7 +403,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..try standard_decoder.calcSize(expected_encoded)]; try standard_decoder.decode(decoded, expected_encoded); - assert(mem.eql(u8, decoded, expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded); } // Base64DecoderWithIgnore @@ -411,8 +412,8 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)]; var written = try standard_decoder_ignore_nothing.decode(decoded, expected_encoded); - assert(written <= decoded.len); - assert(mem.eql(u8, decoded[0..written], expected_decoded)); + testing.expect(written <= decoded.len); + testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); } // Base64DecoderUnsafe @@ -420,7 +421,7 @@ fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) !void var buffer: [0x100]u8 = undefined; var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)]; standard_decoder_unsafe.decode(decoded, expected_encoded); - assert(mem.eql(u8, decoded, expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded); } } @@ -429,7 +430,7 @@ fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) !voi var buffer: [0x100]u8 = undefined; var decoded = buffer[0..Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)]; var written = try standard_decoder_ignore_space.decode(decoded, encoded); - assert(mem.eql(u8, decoded[0..written], expected_decoded)); + testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); } fn testError(encoded: []const u8, expected_err: anyerror) !void { diff --git a/std/buf_map.zig b/std/buf_map.zig index 6de0d20cdb..f8d3d5e04d 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const HashMap = std.HashMap; const mem = std.mem; const Allocator = mem.Allocator; -const assert = std.debug.assert; +const testing = std.testing; /// BufMap copies keys and values before they go into the map, and /// frees them when they get removed. @@ -90,17 +90,17 @@ test "BufMap" { defer bufmap.deinit(); try bufmap.set("x", "1"); - assert(mem.eql(u8, bufmap.get("x").?, "1")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "1")); + testing.expect(1 == bufmap.count()); try bufmap.set("x", "2"); - assert(mem.eql(u8, bufmap.get("x").?, "2")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "2")); + testing.expect(1 == bufmap.count()); try bufmap.set("x", "3"); - assert(mem.eql(u8, bufmap.get("x").?, "3")); - assert(1 == bufmap.count()); + testing.expect(mem.eql(u8, bufmap.get("x").?, "3")); + testing.expect(1 == bufmap.count()); bufmap.delete("x"); - assert(0 == bufmap.count()); + testing.expect(0 == bufmap.count()); } diff --git a/std/buf_set.zig b/std/buf_set.zig index ab2d8e7c34..7ccd94c179 100644 --- a/std/buf_set.zig +++ b/std/buf_set.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const HashMap = @import("hash_map.zig").HashMap; const mem = @import("mem.zig"); const Allocator = mem.Allocator; -const assert = std.debug.assert; +const testing = std.testing; pub const BufSet = struct { hash_map: BufSetHashMap, @@ -68,9 +68,9 @@ test "BufSet" { defer bufset.deinit(); try bufset.put("x"); - assert(bufset.count() == 1); + testing.expect(bufset.count() == 1); bufset.delete("x"); - assert(bufset.count() == 0); + testing.expect(bufset.count() == 0); try bufset.put("x"); try bufset.put("y"); diff --git a/std/buffer.zig b/std/buffer.zig index 2b71c26749..371655f1e5 100644 --- a/std/buffer.zig +++ b/std/buffer.zig @@ -3,6 +3,7 @@ const debug = std.debug; const mem = std.mem; const Allocator = mem.Allocator; const assert = debug.assert; +const testing = std.testing; const ArrayList = std.ArrayList; /// A buffer that allocates memory and maintains a null byte at the end. @@ -141,19 +142,19 @@ test "simple Buffer" { const cstr = @import("cstr.zig"); var buf = try Buffer.init(debug.global_allocator, ""); - assert(buf.len() == 0); + testing.expect(buf.len() == 0); try buf.append("hello"); try buf.append(" "); try buf.append("world"); - assert(buf.eql("hello world")); - assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst())); + testing.expect(buf.eql("hello world")); + testing.expect(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst())); var buf2 = try Buffer.initFromBuffer(buf); - assert(buf.eql(buf2.toSliceConst())); + testing.expect(buf.eql(buf2.toSliceConst())); - assert(buf.startsWith("hell")); - assert(buf.endsWith("orld")); + testing.expect(buf.startsWith("hell")); + testing.expect(buf.endsWith("orld")); try buf2.resize(4); - assert(buf.startsWith(buf2.toSlice())); + testing.expect(buf.startsWith(buf2.toSlice())); } diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 5ec1e79756..d964f4c03d 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -4,6 +4,7 @@ const std = @import("../index.zig"); const mem = std.mem; const endian = std.endian; const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -216,12 +217,12 @@ test "crypto.chacha20 test vector sunscreen" { }; chaCha20IETF(result[0..], input[0..], 1, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); // Chacha20 is self-reversing. var plaintext: [114]u8 = undefined; chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce); - assert(mem.compare(u8, input, plaintext) == mem.Compare.Equal); + testing.expect(mem.compare(u8, input, plaintext) == mem.Compare.Equal); } // https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 @@ -256,7 +257,7 @@ test "crypto.chacha20 test vector 1" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 2" { @@ -290,7 +291,7 @@ test "crypto.chacha20 test vector 2" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 3" { @@ -324,7 +325,7 @@ test "crypto.chacha20 test vector 3" { const nonce = []u8{ 0, 0, 0, 0, 0, 0, 0, 1 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 4" { @@ -358,7 +359,7 @@ test "crypto.chacha20 test vector 4" { const nonce = []u8{ 1, 0, 0, 0, 0, 0, 0, 0 }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } test "crypto.chacha20 test vector 5" { @@ -430,5 +431,5 @@ test "crypto.chacha20 test vector 5" { }; chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce); - assert(mem.eql(u8, expected_result, result)); + testing.expectEqualSlices(u8, expected_result, result); } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index 0d7a4d672d..64adb17c45 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -230,5 +230,5 @@ test "poly1305 rfc7439 vector1" { var mac: [16]u8 = undefined; Poly1305.create(mac[0..], msg, key); - std.debug.assert(std.mem.eql(u8, mac, expected_mac)); + std.testing.expectEqualSlices(u8, expected_mac, mac); } diff --git a/std/crypto/test.zig b/std/crypto/test.zig index 3fa24272e5..258cdf7320 100644 --- a/std/crypto/test.zig +++ b/std/crypto/test.zig @@ -1,6 +1,7 @@ -const debug = @import("../debug/index.zig"); -const mem = @import("../mem.zig"); -const fmt = @import("../fmt/index.zig"); +const std = @import("../index.zig"); +const testing = std.testing; +const mem = std.mem; +const fmt = std.fmt; // Hash using the specified hasher `H` asserting `expected == H(input)`. pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) void { @@ -17,5 +18,5 @@ pub fn assertEqual(comptime expected: []const u8, input: []const u8) void { r.* = fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable; } - debug.assert(mem.eql(u8, expected_bytes, input)); + testing.expectEqualSlices(u8, expected_bytes, input); } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index daccb56808..9349569f97 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -581,8 +581,8 @@ test "x25519 public key calculation from secret key" { var pk_calculated: [32]u8 = undefined; try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50"); - std.debug.assert(X25519.createPublicKey(pk_calculated[0..], sk)); - std.debug.assert(std.mem.eql(u8, pk_calculated, pk_expected)); + std.testing.expect(X25519.createPublicKey(pk_calculated[0..], sk)); + std.testing.expect(std.mem.eql(u8, pk_calculated, pk_expected)); } test "x25519 rfc7748 vector1" { @@ -593,8 +593,8 @@ test "x25519 rfc7748 vector1" { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], secret_key, public_key)); - std.debug.assert(std.mem.eql(u8, output, expected_output)); + std.testing.expect(X25519.create(output[0..], secret_key, public_key)); + std.testing.expect(std.mem.eql(u8, output, expected_output)); } test "x25519 rfc7748 vector2" { @@ -605,8 +605,8 @@ test "x25519 rfc7748 vector2" { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], secret_key, public_key)); - std.debug.assert(std.mem.eql(u8, output, expected_output)); + std.testing.expect(X25519.create(output[0..], secret_key, public_key)); + std.testing.expect(std.mem.eql(u8, output, expected_output)); } test "x25519 rfc7748 one iteration" { @@ -619,13 +619,13 @@ test "x25519 rfc7748 one iteration" { var i: usize = 0; while (i < 1) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } test "x25519 rfc7748 1,000 iterations" { @@ -643,13 +643,13 @@ test "x25519 rfc7748 1,000 iterations" { var i: usize = 0; while (i < 1000) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } test "x25519 rfc7748 1,000,000 iterations" { @@ -666,11 +666,11 @@ test "x25519 rfc7748 1,000,000 iterations" { var i: usize = 0; while (i < 1000000) : (i += 1) { var output: [32]u8 = undefined; - std.debug.assert(X25519.create(output[0..], k, u)); + std.testing.expect(X25519.create(output[0..], k, u)); std.mem.copy(u8, u[0..], k[0..]); std.mem.copy(u8, k[0..], output[0..]); } - std.debug.assert(std.mem.eql(u8, k[0..], expected_output)); + std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); } diff --git a/std/cstr.zig b/std/cstr.zig index a8aaf21279..abd2eac48f 100644 --- a/std/cstr.zig +++ b/std/cstr.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const debug = std.debug; const mem = std.mem; -const assert = debug.assert; +const testing = std.testing; pub const line_sep = switch (builtin.os) { builtin.Os.windows => "\r\n", @@ -42,8 +42,8 @@ test "cstr fns" { } fn testCStrFnsImpl() void { - assert(cmp(c"aoeu", c"aoez") == -1); - assert(len(c"123456789") == 9); + testing.expect(cmp(c"aoeu", c"aoez") == -1); + testing.expect(len(c"123456789") == 9); } /// Returns a mutable slice with 1 more byte of length which is a null byte. diff --git a/std/debug/index.zig b/std/debug/index.zig index a1e2747df5..7e5be9acef 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -107,37 +107,15 @@ pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { /// This function invokes undefined behavior when `ok` is `false`. /// In Debug and ReleaseSafe modes, calls to this function are always /// generated, and the `unreachable` statement triggers a panic. -/// In ReleaseFast and ReleaseSmall modes, calls to this function can be -/// optimized away. +/// In ReleaseFast and ReleaseSmall modes, calls to this function are +/// optimized away, and in fact the optimizer is able to use the assertion +/// in its heuristics. +/// Inside a test block, it is best to use the `std.testing` module rather +/// than this function, because this function may not detect a test failure +/// in ReleaseFast and ReleaseSafe mode. Outside of a test block, this assert +/// function is the correct function to use. pub fn assert(ok: bool) void { - if (!ok) { - // In ReleaseFast test mode, we still want assert(false) to crash, so - // we insert an explicit call to @panic instead of unreachable. - // TODO we should use `assertOrPanic` in tests and remove this logic. - if (builtin.is_test) { - @panic("assertion failure"); - } else { - unreachable; // assertion failure - } - } -} - -/// TODO: add `==` operator for `error_union == error_set`, and then -/// remove this function -pub fn assertError(value: var, expected_error: anyerror) void { - if (value) { - @panic("expected error"); - } else |actual_error| { - assert(actual_error == expected_error); - } -} - -/// Call this function when you want to panic if the condition is not true. -/// If `ok` is `false`, this function will panic in every release mode. -pub fn assertOrPanic(ok: bool) void { - if (!ok) { - @panic("assertion failure"); - } + if (!ok) unreachable; // assertion failure } pub fn panic(comptime format: []const u8, args: ...) noreturn { diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 4d19951318..66026b1f29 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -6,6 +6,7 @@ const mem = std.mem; const cstr = std.cstr; const os = std.os; const assert = std.debug.assert; +const testing = std.testing; const elf = std.elf; const linux = os.linux; const windows = os.windows; @@ -206,7 +207,7 @@ test "dynamic_library" { }; const dynlib = DynLib.open(std.debug.global_allocator, libname) catch |err| { - assert(err == error.FileNotFound); + testing.expect(err == error.FileNotFound); return; }; @panic("Expected error from function"); diff --git a/std/event/channel.zig b/std/event/channel.zig index f8cdae6208..4af9bf612b 100644 --- a/std/event/channel.zig +++ b/std/event/channel.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; const Loop = std.event.Loop; @@ -350,19 +351,19 @@ async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void { const value1_promise = try async channel.get(); const value1 = await value1_promise; - assert(value1 == 1234); + testing.expect(value1 == 1234); const value2_promise = try async channel.get(); const value2 = await value2_promise; - assert(value2 == 4567); + testing.expect(value2 == 4567); const value3_promise = try async channel.getOrNull(); const value3 = await value3_promise; - assert(value3 == null); + testing.expect(value3 == null); const last_put = try async testPut(channel, 4444); const value4 = await try async channel.getOrNull(); - assert(value4.? == 4444); + testing.expect(value4.? == 4444); await last_put; } diff --git a/std/event/fs.zig b/std/event/fs.zig index fd0fe434cb..0e7482ec60 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -2,6 +2,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const event = std.event; const assert = std.debug.assert; +const testing = std.testing; const os = std.os; const mem = std.mem; const posix = os.posix; @@ -1349,13 +1350,13 @@ async fn testFsWatch(loop: *Loop) !void { try await try async writeFile(loop, file_path, contents); const read_contents = try await try async readFile(loop, file_path, 1024 * 1024); - assert(mem.eql(u8, read_contents, contents)); + testing.expectEqualSlices(u8, contents, read_contents); // now watch the file var watch = try Watch(void).create(loop, 0); defer watch.destroy(); - assert((try await try async watch.addFile(file_path, {})) == null); + testing.expect((try await try async watch.addFile(file_path, {})) == null); const ev = try async watch.channel.get(); var ev_consumed = false; @@ -1375,10 +1376,10 @@ async fn testFsWatch(loop: *Loop) !void { WatchEventId.Delete => @panic("wrong event"), } const contents_updated = try await try async readFile(loop, file_path, 1024 * 1024); - assert(mem.eql(u8, contents_updated, + testing.expectEqualSlices(u8, \\line 1 \\lorem ipsum - )); + , contents_updated); // TODO test deleting the file and then re-adding it. we should get events for both } diff --git a/std/event/future.zig b/std/event/future.zig index 55ed01046d..66acac5ad7 100644 --- a/std/event/future.zig +++ b/std/event/future.zig @@ -1,5 +1,6 @@ const std = @import("../index.zig"); const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -114,7 +115,7 @@ async fn testFuture(loop: *Loop) void { const result = (await a) + (await b); cancel c; - assert(result == 12); + testing.expect(result == 12); } async fn waitOnFuture(future: *Future(i32)) i32 { diff --git a/std/event/group.zig b/std/event/group.zig index 7f6b5d953b..25e79640cb 100644 --- a/std/event/group.zig +++ b/std/event/group.zig @@ -4,7 +4,7 @@ const Lock = std.event.Lock; const Loop = std.event.Loop; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; -const assert = std.debug.assert; +const testing = std.testing; /// ReturnType must be `void` or `E!void` pub fn Group(comptime ReturnType: type) type { @@ -146,12 +146,12 @@ async fn testGroup(loop: *Loop) void { group.add(async sleepALittle(&count) catch @panic("memory")) catch @panic("memory"); group.call(increaseByTen, &count) catch @panic("memory"); await (async group.wait() catch @panic("memory")); - assert(count == 11); + testing.expect(count == 11); var another = Group(anyerror!void).init(loop); another.add(async somethingElse() catch @panic("memory")) catch @panic("memory"); another.call(doSomethingThatFails) catch @panic("memory"); - std.debug.assertError(await (async another.wait() catch @panic("memory")), error.ItBroke); + testing.expectError(error.ItBroke, await (async another.wait() catch @panic("memory"))); } async fn sleepALittle(count: *usize) void { diff --git a/std/event/lock.zig b/std/event/lock.zig index 01978e1909..d6a246cee5 100644 --- a/std/event/lock.zig +++ b/std/event/lock.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -141,7 +142,7 @@ test "std.event.Lock" { defer cancel handle; loop.run(); - assert(mem.eql(i32, shared_test_data, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len)); + testing.expectEqualSlices(i32, [1]i32{3 * @intCast(i32, shared_test_data.len)} ** shared_test_data.len, shared_test_data); } async fn testLock(loop: *Loop, lock: *Lock) void { diff --git a/std/event/loop.zig b/std/event/loop.zig index d5228db604..b92bf41982 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -896,7 +897,7 @@ test "std.event.Loop - call" { loop.run(); - assert(did_it); + testing.expect(did_it); } async fn testEventLoop() i32 { @@ -905,6 +906,6 @@ async fn testEventLoop() i32 { async fn testEventLoop2(h: promise->i32, did_it: *bool) void { const value = await h; - assert(value == 1234); + testing.expect(value == 1234); did_it.* = true; } diff --git a/std/event/net.zig b/std/event/net.zig index 9dac6aa566..48461c3d81 100644 --- a/std/event/net.zig +++ b/std/event/net.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); -const assert = std.debug.assert; +const testing = std.testing; const event = std.event; const mem = std.mem; const os = std.os; @@ -326,7 +326,7 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv var buf: [512]u8 = undefined; const amt_read = try socket_file.read(buf[0..]); const msg = buf[0..amt_read]; - assert(mem.eql(u8, msg, "hello from server\n")); + testing.expect(mem.eql(u8, msg, "hello from server\n")); server.close(); } diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig index f272ac71ea..26ccd12b73 100644 --- a/std/event/rwlock.zig +++ b/std/event/rwlock.zig @@ -1,6 +1,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -231,7 +232,7 @@ test "std.event.RwLock" { loop.run(); const expected_result = [1]i32{shared_it_count * @intCast(i32, shared_test_data.len)} ** shared_test_data.len; - assert(mem.eql(i32, shared_test_data, expected_result)); + testing.expectEqualSlices(i32, expected_result, shared_test_data); } async fn testLock(loop: *Loop, lock: *RwLock) void { @@ -293,7 +294,7 @@ async fn readRunner(lock: *RwLock) void { const handle = await lock_promise; defer handle.release(); - assert(shared_test_index == 0); - assert(shared_test_data[i] == @intCast(i32, shared_count)); + testing.expect(shared_test_index == 0); + testing.expect(shared_test_data[i] == @intCast(i32, shared_count)); } } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 6097a12c23..05b028112f 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -2,7 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const debug = std.debug; const assert = debug.assert; -const assertError = debug.assertError; +const testing = std.testing; const mem = std.mem; const builtin = @import("builtin"); const errol = @import("errol/index.zig"); @@ -588,7 +588,7 @@ pub fn formatFloatDecimal( } // Remaining fractional portion, zero-padding if insufficient. - debug.assert(precision >= printed); + assert(precision >= printed); if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) { try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]); return; @@ -798,13 +798,13 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T { } test "fmt.parseInt" { - assert((parseInt(i32, "-10", 10) catch unreachable) == -10); - assert((parseInt(i32, "+10", 10) catch unreachable) == 10); - assert(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); - assert(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); - assert(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); - assert((parseInt(u8, "255", 10) catch unreachable) == 255); - assert(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); + testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10); + testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10); + testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); + testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); + testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); + testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255); + testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); } const ParseUnsignedError = error{ @@ -829,30 +829,30 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned } test "parseUnsigned" { - assert((try parseUnsigned(u16, "050124", 10)) == 50124); - assert((try parseUnsigned(u16, "65535", 10)) == 65535); - assertError(parseUnsigned(u16, "65536", 10), error.Overflow); + testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); + testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); + testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); - assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); - assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow); + testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); + testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); - assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); + testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); - assert((try parseUnsigned(u7, "1", 10)) == 1); - assert((try parseUnsigned(u7, "1000", 2)) == 8); + testing.expect((try parseUnsigned(u7, "1", 10)) == 1); + testing.expect((try parseUnsigned(u7, "1000", 2)) == 8); - assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter); - assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter); + testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); + testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); - assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); + testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); // these numbers should fit even though the radix itself doesn't fit in the destination type - assert((try parseUnsigned(u1, "0", 10)) == 0); - assert((try parseUnsigned(u1, "1", 10)) == 1); - assertError(parseUnsigned(u1, "2", 10), error.Overflow); - assert((try parseUnsigned(u1, "001", 16)) == 1); - assert((try parseUnsigned(u2, "3", 16)) == 3); - assertError(parseUnsigned(u2, "4", 16), error.Overflow); + testing.expect((try parseUnsigned(u1, "0", 10)) == 0); + testing.expect((try parseUnsigned(u1, "1", 10)) == 1); + testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10)); + testing.expect((try parseUnsigned(u1, "001", 16)) == 1); + testing.expect((try parseUnsigned(u2, "3", 16)) == 3); + testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); } pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { @@ -910,19 +910,19 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) { test "buf print int" { var buffer: [max_int_digits]u8 = undefined; const buf = buffer[0..]; - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 2, false, 0), "-101111000110000101001110")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 10, false, 0), "-12345678")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, false, 0), "-bc614e")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-12345678), 16, true, 0), "-BC614E")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(12345678), 10, true, 0), "12345678")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(666), 10, false, 6), "000666")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 6), "001234")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, u32(0x1234), 16, false, 1), "1234")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42")); - assert(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(42), 10, false, 3), "+42")); + testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, i32(-42), 10, false, 3), "-42")); } fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, width: usize) []u8 { @@ -939,7 +939,7 @@ test "parse u64 digit too big" { test "parse unsigned comptime" { comptime { - assert((try parseUnsigned(usize, "2", 10)) == 2); + testing.expect((try parseUnsigned(usize, "2", 10)) == 2); } } @@ -977,17 +977,17 @@ test "fmt.format" { var context = BufPrintContext{ .remaining = buf1[0..] }; try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite); var res = buf1[0 .. buf1.len - context.remaining.len]; - assert(mem.eql(u8, res, "1234")); + testing.expect(mem.eql(u8, res, "1234")); context = BufPrintContext{ .remaining = buf1[0..] }; try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); res = buf1[0 .. buf1.len - context.remaining.len]; - assert(mem.eql(u8, res, "a")); + testing.expect(mem.eql(u8, res, "a")); context = BufPrintContext{ .remaining = buf1[0..] }; try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); res = buf1[0 .. buf1.len - context.remaining.len]; - assert(mem.eql(u8, res, "1100")); + testing.expect(mem.eql(u8, res, "1100")); } { const value: [3]u8 = "abc"; @@ -1053,19 +1053,19 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f32 = 1.34; const result = try bufPrint(buf1[0..], "f32: {e}\n", value); - assert(mem.eql(u8, result, "f32: 1.34000003e+00\n")); + testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n")); } { var buf1: [32]u8 = undefined; const value: f32 = 12.34; const result = try bufPrint(buf1[0..], "f32: {e}\n", value); - assert(mem.eql(u8, result, "f32: 1.23400001e+01\n")); + testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n")); } { var buf1: [32]u8 = undefined; const value: f64 = -12.34e10; const result = try bufPrint(buf1[0..], "f64: {e}\n", value); - assert(mem.eql(u8, result, "f64: -1.234e+11\n")); + testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n")); } { // This fails on release due to a minor rounding difference. @@ -1075,26 +1075,26 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = 9.999960e-40; const result = try bufPrint(buf1[0..], "f64: {e}\n", value); - assert(mem.eql(u8, result, "f64: 9.99996e-40\n")); + testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n")); } } { var buf1: [32]u8 = undefined; const value: f64 = 1.409706e-42; const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); - assert(mem.eql(u8, result, "f64: 1.40971e-42\n")); + testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n")); } { var buf1: [32]u8 = undefined; const value: f64 = @bitCast(f32, u32(814313563)); const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); - assert(mem.eql(u8, result, "f64: 1.00000e-09\n")); + testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n")); } { var buf1: [32]u8 = undefined; const value: f64 = @bitCast(f32, u32(1006632960)); const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); - assert(mem.eql(u8, result, "f64: 7.81250e-03\n")); + testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n")); } { // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05. @@ -1102,47 +1102,47 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = @bitCast(f32, u32(1203982400)); const result = try bufPrint(buf1[0..], "f64: {e5}\n", value); - assert(mem.eql(u8, result, "f64: 1.00001e+05\n")); + testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n")); } { var buf1: [32]u8 = undefined; const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); - assert(mem.eql(u8, result, "f64: nan\n")); + testing.expect(mem.eql(u8, result, "f64: nan\n")); } if (builtin.arch != builtin.Arch.armv8) { // negative nan is not defined by IEE 754, // and ARM thus normalizes it to positive nan var buf1: [32]u8 = undefined; const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64); - assert(mem.eql(u8, result, "f64: -nan\n")); + testing.expect(mem.eql(u8, result, "f64: -nan\n")); } { var buf1: [32]u8 = undefined; const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64); - assert(mem.eql(u8, result, "f64: inf\n")); + testing.expect(mem.eql(u8, result, "f64: inf\n")); } { var buf1: [32]u8 = undefined; const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64); - assert(mem.eql(u8, result, "f64: -inf\n")); + testing.expect(mem.eql(u8, result, "f64: -inf\n")); } { var buf1: [64]u8 = undefined; const value: f64 = 1.52314e+29; const result = try bufPrint(buf1[0..], "f64: {.}\n", value); - assert(mem.eql(u8, result, "f64: 152314000000000000000000000000\n")); + testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n")); } { var buf1: [32]u8 = undefined; const value: f32 = 1.1234; const result = try bufPrint(buf1[0..], "f32: {.1}\n", value); - assert(mem.eql(u8, result, "f32: 1.1\n")); + testing.expect(mem.eql(u8, result, "f32: 1.1\n")); } { var buf1: [32]u8 = undefined; const value: f32 = 1234.567; const result = try bufPrint(buf1[0..], "f32: {.2}\n", value); - assert(mem.eql(u8, result, "f32: 1234.57\n")); + testing.expect(mem.eql(u8, result, "f32: 1234.57\n")); } { var buf1: [32]u8 = undefined; @@ -1150,92 +1150,92 @@ test "fmt.format" { const result = try bufPrint(buf1[0..], "f32: {.4}\n", value); // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64). // -11.12339... is rounded back up to -11.1234 - assert(mem.eql(u8, result, "f32: -11.1234\n")); + testing.expect(mem.eql(u8, result, "f32: -11.1234\n")); } { var buf1: [32]u8 = undefined; const value: f32 = 91.12345; const result = try bufPrint(buf1[0..], "f32: {.5}\n", value); - assert(mem.eql(u8, result, "f32: 91.12345\n")); + testing.expect(mem.eql(u8, result, "f32: 91.12345\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 91.12345678901235; const result = try bufPrint(buf1[0..], "f64: {.10}\n", value); - assert(mem.eql(u8, result, "f64: 91.1234567890\n")); + testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 0.0; const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 5.700; const result = try bufPrint(buf1[0..], "f64: {.0}\n", value); - assert(mem.eql(u8, result, "f64: 6\n")); + testing.expect(mem.eql(u8, result, "f64: 6\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 9.999; const result = try bufPrint(buf1[0..], "f64: {.1}\n", value); - assert(mem.eql(u8, result, "f64: 10.0\n")); + testing.expect(mem.eql(u8, result, "f64: 10.0\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 1.0; const result = try bufPrint(buf1[0..], "f64: {.3}\n", value); - assert(mem.eql(u8, result, "f64: 1.000\n")); + testing.expect(mem.eql(u8, result, "f64: 1.000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 0.0003; const result = try bufPrint(buf1[0..], "f64: {.8}\n", value); - assert(mem.eql(u8, result, "f64: 0.00030000\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00030000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 1.40130e-45; const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = 9.999960e-40; const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00000\n")); } // libc checks { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(916964781))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.00001\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00001\n")); } { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(925353389))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.00001\n")); + testing.expect(mem.eql(u8, result, "f64: 0.00001\n")); } { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(1036831278))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.10000\n")); + testing.expect(mem.eql(u8, result, "f64: 0.10000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(1065353133))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 1.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 1.00000\n")); } { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(1092616192))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 10.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 10.00000\n")); } // libc differences { @@ -1245,7 +1245,7 @@ test "fmt.format" { // floats of the form x.yyyy25 on a precision point. const value: f64 = f64(@bitCast(f32, u32(1015021568))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 0.01563\n")); + testing.expect(mem.eql(u8, result, "f64: 0.01563\n")); } // std-windows-x86_64-Debug-bare test case fails { @@ -1255,7 +1255,7 @@ test "fmt.format" { var buf1: [32]u8 = undefined; const value: f64 = f64(@bitCast(f32, u32(1518338049))); const result = try bufPrint(buf1[0..], "f64: {.5}\n", value); - assert(mem.eql(u8, result, "f64: 18014400656965630.00000\n")); + testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n")); } //custom type format { @@ -1336,10 +1336,10 @@ test "fmt.format" { var buf: [100]u8 = undefined; const uu_result = try bufPrint(buf[0..], "{}", uu_inst); - debug.assert(mem.eql(u8, uu_result[0..3], "UU@")); + testing.expect(mem.eql(u8, uu_result[0..3], "UU@")); const eu_result = try bufPrint(buf[0..], "{}", eu_inst); - debug.assert(mem.eql(u8, uu_result[0..3], "EU@")); + testing.expect(mem.eql(u8, uu_result[0..3], "EU@")); } //enum format { @@ -1398,11 +1398,11 @@ pub fn trim(buf: []const u8) []const u8 { } test "fmt.trim" { - assert(mem.eql(u8, "abc", trim("\n abc \t"))); - assert(mem.eql(u8, "", trim(" "))); - assert(mem.eql(u8, "", trim(""))); - assert(mem.eql(u8, "abc", trim(" abc"))); - assert(mem.eql(u8, "abc", trim("abc "))); + testing.expect(mem.eql(u8, "abc", trim("\n abc \t"))); + testing.expect(mem.eql(u8, "", trim(" "))); + testing.expect(mem.eql(u8, "", trim(""))); + testing.expect(mem.eql(u8, "abc", trim(" abc"))); + testing.expect(mem.eql(u8, "abc", trim("abc "))); } pub fn isWhiteSpace(byte: u8) bool { diff --git a/std/hash/adler.zig b/std/hash/adler.zig index 9c5966f89b..78f960367a 100644 --- a/std/hash/adler.zig +++ b/std/hash/adler.zig @@ -4,7 +4,7 @@ // https://github.com/madler/zlib/blob/master/adler32.c const std = @import("../index.zig"); -const debug = std.debug; +const testing = std.testing; pub const Adler32 = struct { const base = 65521; @@ -89,19 +89,19 @@ pub const Adler32 = struct { }; test "adler32 sanity" { - debug.assert(Adler32.hash("a") == 0x620062); - debug.assert(Adler32.hash("example") == 0xbc002ed); + testing.expect(Adler32.hash("a") == 0x620062); + testing.expect(Adler32.hash("example") == 0xbc002ed); } test "adler32 long" { const long1 = []u8{1} ** 1024; - debug.assert(Adler32.hash(long1[0..]) == 0x06780401); + testing.expect(Adler32.hash(long1[0..]) == 0x06780401); const long2 = []u8{1} ** 1025; - debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402); + testing.expect(Adler32.hash(long2[0..]) == 0x0a7a0402); } test "adler32 very long" { const long = []u8{1} ** 5553; - debug.assert(Adler32.hash(long[0..]) == 0x707f15b2); + testing.expect(Adler32.hash(long[0..]) == 0x707f15b2); } diff --git a/std/hash/crc.zig b/std/hash/crc.zig index c4bd92884a..9bea358bf1 100644 --- a/std/hash/crc.zig +++ b/std/hash/crc.zig @@ -7,6 +7,7 @@ const std = @import("../index.zig"); const debug = std.debug; +const testing = std.testing; pub const Polynomial = struct { const IEEE = 0xedb88320; @@ -101,17 +102,17 @@ pub fn Crc32WithPoly(comptime poly: u32) type { test "crc32 ieee" { const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE); - debug.assert(Crc32Ieee.hash("") == 0x00000000); - debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); - debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); + testing.expect(Crc32Ieee.hash("") == 0x00000000); + testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43); + testing.expect(Crc32Ieee.hash("abc") == 0x352441c2); } test "crc32 castagnoli" { const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli); - debug.assert(Crc32Castagnoli.hash("") == 0x00000000); - debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); - debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); + testing.expect(Crc32Castagnoli.hash("") == 0x00000000); + testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330); + testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); } // half-byte lookup table implementation. @@ -165,15 +166,15 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type { test "small crc32 ieee" { const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE); - debug.assert(Crc32Ieee.hash("") == 0x00000000); - debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43); - debug.assert(Crc32Ieee.hash("abc") == 0x352441c2); + testing.expect(Crc32Ieee.hash("") == 0x00000000); + testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43); + testing.expect(Crc32Ieee.hash("abc") == 0x352441c2); } test "small crc32 castagnoli" { const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli); - debug.assert(Crc32Castagnoli.hash("") == 0x00000000); - debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330); - debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7); + testing.expect(Crc32Castagnoli.hash("") == 0x00000000); + testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330); + testing.expect(Crc32Castagnoli.hash("abc") == 0x364b3fb7); } diff --git a/std/hash/fnv.zig b/std/hash/fnv.zig index 9bb18f14b3..6876b636f6 100644 --- a/std/hash/fnv.zig +++ b/std/hash/fnv.zig @@ -5,7 +5,7 @@ // https://tools.ietf.org/html/draft-eastlake-fnv-14 const std = @import("../index.zig"); -const debug = std.debug; +const testing = std.testing; pub const Fnv1a_32 = Fnv1a(u32, 0x01000193, 0x811c9dc5); pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325); @@ -41,18 +41,18 @@ fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type { } test "fnv1a-32" { - debug.assert(Fnv1a_32.hash("") == 0x811c9dc5); - debug.assert(Fnv1a_32.hash("a") == 0xe40c292c); - debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968); + testing.expect(Fnv1a_32.hash("") == 0x811c9dc5); + testing.expect(Fnv1a_32.hash("a") == 0xe40c292c); + testing.expect(Fnv1a_32.hash("foobar") == 0xbf9cf968); } test "fnv1a-64" { - debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325); - debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); - debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); + testing.expect(Fnv1a_64.hash("") == 0xcbf29ce484222325); + testing.expect(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c); + testing.expect(Fnv1a_64.hash("foobar") == 0x85944171f73967e8); } test "fnv1a-128" { - debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); - debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); + testing.expect(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d); + testing.expect(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964); } diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index ee26950272..c9a6128d35 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -6,7 +6,8 @@ // https://131002.net/siphash/ const std = @import("../index.zig"); -const debug = std.debug; +const assert = std.debug.assert; +const testing = std.testing; const math = std.math; const mem = std.mem; @@ -21,8 +22,8 @@ pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type { } fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { - debug.assert(T == u64 or T == u128); - debug.assert(c_rounds > 0 and d_rounds > 0); + assert(T == u64 or T == u128); + assert(c_rounds > 0 and d_rounds > 0); return struct { const Self = @This(); @@ -40,7 +41,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) msg_len: u8, pub fn init(key: []const u8) Self { - debug.assert(key.len >= 16); + assert(key.len >= 16); const k0 = mem.readIntSliceLittle(u64, key[0..8]); const k1 = mem.readIntSliceLittle(u64, key[8..16]); @@ -119,7 +120,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) } fn round(d: *Self, b: []const u8) void { - debug.assert(b.len == 8); + assert(b.len == 8); const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; @@ -236,7 +237,7 @@ test "siphash64-2-4 sanity" { buffer[i] = @intCast(u8, i); const expected = mem.readIntLittle(u64, &vector); - debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); + testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); } } @@ -315,6 +316,6 @@ test "siphash128-2-4 sanity" { buffer[i] = @intCast(u8, i); const expected = mem.readIntLittle(u128, &vector); - debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); + testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/hash_map.zig b/std/hash_map.zig index a63a549814..716f04ff34 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const math = std.math; const mem = std.mem; const Allocator = mem.Allocator; @@ -342,37 +343,37 @@ test "basic hash map usage" { var map = AutoHashMap(i32, i32).init(&direct_allocator.allocator); defer map.deinit(); - assert((try map.put(1, 11)) == null); - assert((try map.put(2, 22)) == null); - assert((try map.put(3, 33)) == null); - assert((try map.put(4, 44)) == null); - assert((try map.put(5, 55)) == null); + testing.expect((try map.put(1, 11)) == null); + testing.expect((try map.put(2, 22)) == null); + testing.expect((try map.put(3, 33)) == null); + testing.expect((try map.put(4, 44)) == null); + testing.expect((try map.put(5, 55)) == null); - assert((try map.put(5, 66)).?.value == 55); - assert((try map.put(5, 55)).?.value == 66); + testing.expect((try map.put(5, 66)).?.value == 55); + testing.expect((try map.put(5, 55)).?.value == 66); const gop1 = try map.getOrPut(5); - assert(gop1.found_existing == true); - assert(gop1.kv.value == 55); + testing.expect(gop1.found_existing == true); + testing.expect(gop1.kv.value == 55); gop1.kv.value = 77; - assert(map.get(5).?.value == 77); + testing.expect(map.get(5).?.value == 77); const gop2 = try map.getOrPut(99); - assert(gop2.found_existing == false); + testing.expect(gop2.found_existing == false); gop2.kv.value = 42; - assert(map.get(99).?.value == 42); + testing.expect(map.get(99).?.value == 42); const gop3 = try map.getOrPutValue(5, 5); - assert(gop3.value == 77); + testing.expect(gop3.value == 77); const gop4 = try map.getOrPutValue(100, 41); - assert(gop4.value == 41); + testing.expect(gop4.value == 41); - assert(map.contains(2)); - assert(map.get(2).?.value == 22); + testing.expect(map.contains(2)); + testing.expect(map.get(2).?.value == 22); _ = map.remove(2); - assert(map.remove(2) == null); - assert(map.get(2) == null); + testing.expect(map.remove(2) == null); + testing.expect(map.get(2) == null); } test "iterator hash map" { @@ -382,9 +383,9 @@ test "iterator hash map" { var reset_map = AutoHashMap(i32, i32).init(&direct_allocator.allocator); defer reset_map.deinit(); - assert((try reset_map.put(1, 11)) == null); - assert((try reset_map.put(2, 22)) == null); - assert((try reset_map.put(3, 33)) == null); + testing.expect((try reset_map.put(1, 11)) == null); + testing.expect((try reset_map.put(2, 22)) == null); + testing.expect((try reset_map.put(3, 33)) == null); var keys = []i32{ 3, @@ -400,26 +401,26 @@ test "iterator hash map" { var it = reset_map.iterator(); var count: usize = 0; while (it.next()) |next| { - assert(next.key == keys[count]); - assert(next.value == values[count]); + testing.expect(next.key == keys[count]); + testing.expect(next.value == values[count]); count += 1; } - assert(count == 3); - assert(it.next() == null); + testing.expect(count == 3); + testing.expect(it.next() == null); it.reset(); count = 0; while (it.next()) |next| { - assert(next.key == keys[count]); - assert(next.value == values[count]); + testing.expect(next.key == keys[count]); + testing.expect(next.value == values[count]); count += 1; if (count == 2) break; } it.reset(); var entry = it.next().?; - assert(entry.key == keys[0]); - assert(entry.value == values[0]); + testing.expect(entry.key == keys[0]); + testing.expect(entry.value == values[0]); } pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) { diff --git a/std/heap.zig b/std/heap.zig index 8a5ebf134c..e7088150a8 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const os = std.os; const builtin = @import("builtin"); @@ -487,11 +488,11 @@ test "FixedBufferAllocator Reuse memory on realloc" { var fixed_buffer_allocator = FixedBufferAllocator.init(small_fixed_buffer[0..]); var slice0 = try fixed_buffer_allocator.allocator.alloc(u8, 5); - assert(slice0.len == 5); + testing.expect(slice0.len == 5); var slice1 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 10); - assert(slice1.ptr == slice0.ptr); - assert(slice1.len == 10); - debug.assertError(fixed_buffer_allocator.allocator.realloc(u8, slice1, 11), error.OutOfMemory); + testing.expect(slice1.ptr == slice0.ptr); + testing.expect(slice1.len == 10); + testing.expectError(error.OutOfMemory, fixed_buffer_allocator.allocator.realloc(u8, slice1, 11)); } // check that we don't re-use the memory if it's not the most recent block { @@ -502,10 +503,10 @@ test "FixedBufferAllocator Reuse memory on realloc" { slice0[1] = 2; var slice1 = try fixed_buffer_allocator.allocator.alloc(u8, 2); var slice2 = try fixed_buffer_allocator.allocator.realloc(u8, slice0, 4); - assert(slice0.ptr != slice2.ptr); - assert(slice1.ptr != slice2.ptr); - assert(slice2[0] == 1); - assert(slice2[1] == 2); + testing.expect(slice0.ptr != slice2.ptr); + testing.expect(slice1.ptr != slice2.ptr); + testing.expect(slice2[0] == 1); + testing.expect(slice2[1] == 2); } } @@ -519,28 +520,28 @@ test "ThreadSafeFixedBufferAllocator" { fn testAllocator(allocator: *mem.Allocator) !void { var slice = try allocator.alloc(*i32, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); for (slice) |*item, i| { item.* = try allocator.create(i32); item.*.* = @intCast(i32, i); } slice = try allocator.realloc(*i32, slice, 20000); - assert(slice.len == 20000); + testing.expect(slice.len == 20000); for (slice[0..100]) |item, i| { - assert(item.* == @intCast(i32, i)); + testing.expect(item.* == @intCast(i32, i)); allocator.destroy(item); } slice = try allocator.realloc(*i32, slice, 50); - assert(slice.len == 50); + testing.expect(slice.len == 50); slice = try allocator.realloc(*i32, slice, 25); - assert(slice.len == 25); + testing.expect(slice.len == 25); slice = try allocator.realloc(*i32, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); slice = try allocator.realloc(*i32, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); allocator.free(slice); } @@ -548,25 +549,25 @@ fn testAllocator(allocator: *mem.Allocator) !void { fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !void { // initial var slice = try allocator.alignedAlloc(u8, alignment, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // grow slice = try allocator.alignedRealloc(u8, alignment, slice, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); // shrink slice = try allocator.alignedRealloc(u8, alignment, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // go to zero slice = try allocator.alignedRealloc(u8, alignment, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); // realloc from zero slice = try allocator.alignedRealloc(u8, alignment, slice, 100); - assert(slice.len == 100); + testing.expect(slice.len == 100); // shrink with shrink slice = allocator.alignedShrink(u8, alignment, slice, 10); - assert(slice.len == 10); + testing.expect(slice.len == 10); // shrink to zero slice = allocator.alignedShrink(u8, alignment, slice, 0); - assert(slice.len == 0); + testing.expect(slice.len == 0); } fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { @@ -581,19 +582,19 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(large_align)), &align_mask); var slice = try allocator.allocFn(allocator, 500, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 100, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 5000, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 10, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); slice = try allocator.reallocFn(allocator, slice, 20000, large_align); - debug.assert(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); + testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); allocator.free(slice); } diff --git a/std/index.zig b/std/index.zig index 2a63244004..9d9b7ee8d6 100644 --- a/std/index.zig +++ b/std/index.zig @@ -31,6 +31,7 @@ pub const hash_map = @import("hash_map.zig"); pub const heap = @import("heap.zig"); pub const io = @import("io.zig"); pub const json = @import("json.zig"); +pub const lazyInit = @import("lazy_init.zig").lazyInit; pub const macho = @import("macho.zig"); pub const math = @import("math/index.zig"); pub const mem = @import("mem.zig"); @@ -41,11 +42,10 @@ pub const pdb = @import("pdb.zig"); pub const rand = @import("rand/index.zig"); pub const rb = @import("rb.zig"); pub const sort = @import("sort.zig"); +pub const testing = @import("testing.zig"); pub const unicode = @import("unicode.zig"); pub const zig = @import("zig/index.zig"); -pub const lazyInit = @import("lazy_init.zig").lazyInit; - test "std" { // run tests from these _ = @import("array_list.zig"); @@ -60,7 +60,6 @@ test "std" { _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); - _ = @import("dynamic_library.zig"); _ = @import("base64.zig"); _ = @import("build.zig"); _ = @import("c/index.zig"); @@ -69,24 +68,26 @@ test "std" { _ = @import("cstr.zig"); _ = @import("debug/index.zig"); _ = @import("dwarf.zig"); + _ = @import("dynamic_library.zig"); _ = @import("elf.zig"); _ = @import("empty.zig"); _ = @import("event.zig"); _ = @import("fmt/index.zig"); _ = @import("hash/index.zig"); + _ = @import("heap.zig"); _ = @import("io.zig"); _ = @import("json.zig"); + _ = @import("lazy_init.zig"); _ = @import("macho.zig"); _ = @import("math/index.zig"); - _ = @import("meta/index.zig"); _ = @import("mem.zig"); + _ = @import("meta/index.zig"); _ = @import("net.zig"); - _ = @import("heap.zig"); _ = @import("os/index.zig"); - _ = @import("rand/index.zig"); _ = @import("pdb.zig"); + _ = @import("rand/index.zig"); _ = @import("sort.zig"); + _ = @import("testing.zig"); _ = @import("unicode.zig"); _ = @import("zig/index.zig"); - _ = @import("lazy_init.zig"); } diff --git a/std/io.zig b/std/io.zig index 81d90def6e..d7e8507f9b 100644 --- a/std/io.zig +++ b/std/io.zig @@ -13,6 +13,7 @@ const trait = meta.trait; const Buffer = std.Buffer; const fmt = std.fmt; const File = std.os.File; +const testing = std.testing; const is_posix = builtin.os != builtin.Os.windows; const is_windows = builtin.os == builtin.Os.windows; @@ -664,7 +665,7 @@ test "io.SliceOutStream" { const stream = &slice_stream.stream; try stream.print("{}{}!", "Hello", "World"); - debug.assertOrPanic(mem.eql(u8, "HelloWorld!", slice_stream.getWritten())); + testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten()); } var null_out_stream_state = NullOutStream.init(); @@ -726,7 +727,7 @@ test "io.CountingOutStream" { const bytes = "yay" ** 10000; stream.write(bytes) catch unreachable; - debug.assertOrPanic(counting_stream.bytes_written == bytes.len); + testing.expect(counting_stream.bytes_written == bytes.len); } pub fn BufferedOutStream(comptime Error: type) type { @@ -1014,10 +1015,10 @@ test "io.readLineFrom" { ); const stream = &mem_stream.stream; - debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); - debug.assertOrPanic(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); - debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); - debug.assertOrPanic(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); + testing.expectEqualSlices(u8, "Line 1", try readLineFrom(stream, &buf)); + testing.expectEqualSlices(u8, "Line 22", try readLineFrom(stream, &buf)); + testing.expectError(error.EndOfStream, readLineFrom(stream, &buf)); + testing.expectEqualSlices(u8, "Line 1Line 22Line 333", buf.toSlice()); } pub fn readLineSlice(slice: []u8) ![]u8 { @@ -1045,8 +1046,8 @@ test "io.readLineSliceFrom" { ); const stream = &mem_stream.stream; - debug.assertOrPanic(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); - debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); + testing.expectEqualSlices(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])); + testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..])); } /// Creates a deserializer that deserializes types from any stream. diff --git a/std/io_test.zig b/std/io_test.zig index 9a0687ec69..fb6e0ae7e9 100644 --- a/std/io_test.zig +++ b/std/io_test.zig @@ -3,8 +3,8 @@ const io = std.io; const meta = std.meta; const trait = std.trait; const DefaultPrng = std.rand.DefaultPrng; -const assert = std.debug.assert; -const assertError = std.debug.assertError; +const expect = std.testing.expect; +const expectError = std.testing.expectError; const mem = std.mem; const os = std.os; const builtin = @import("builtin"); @@ -35,7 +35,7 @@ test "write a file, read it, then delete it" { const file_size = try file.getEndPos(); const expected_file_size = "begin".len + data.len + "end".len; - assert(file_size == expected_file_size); + expect(file_size == expected_file_size); var file_in_stream = file.inStream(); var buf_stream = io.BufferedInStream(os.File.ReadError).init(&file_in_stream.stream); @@ -43,9 +43,9 @@ test "write a file, read it, then delete it" { const contents = try st.readAllAlloc(allocator, 2 * 1024); defer allocator.free(contents); - assert(mem.eql(u8, contents[0.."begin".len], "begin")); - assert(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); - assert(mem.eql(u8, contents[contents.len - "end".len ..], "end")); + expect(mem.eql(u8, contents[0.."begin".len], "begin")); + expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data)); + expect(mem.eql(u8, contents[contents.len - "end".len ..], "end")); } try os.deleteFile(tmp_file_name); } @@ -61,7 +61,7 @@ test "BufferOutStream" { const y: i32 = 1234; try buf_stream.print("x: {}\ny: {}\n", x, y); - assert(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n")); + expect(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n")); } test "SliceInStream" { @@ -71,15 +71,15 @@ test "SliceInStream" { var dest: [4]u8 = undefined; var read = try ss.stream.read(dest[0..4]); - assert(read == 4); - assert(mem.eql(u8, dest[0..4], bytes[0..4])); + expect(read == 4); + expect(mem.eql(u8, dest[0..4], bytes[0..4])); read = try ss.stream.read(dest[0..4]); - assert(read == 3); - assert(mem.eql(u8, dest[0..3], bytes[4..7])); + expect(read == 3); + expect(mem.eql(u8, dest[0..3], bytes[4..7])); read = try ss.stream.read(dest[0..4]); - assert(read == 0); + expect(read == 0); } test "PeekStream" { @@ -93,26 +93,26 @@ test "PeekStream" { ps.putBackByte(10); var read = try ps.stream.read(dest[0..4]); - assert(read == 4); - assert(dest[0] == 10); - assert(dest[1] == 9); - assert(mem.eql(u8, dest[2..4], bytes[0..2])); + expect(read == 4); + expect(dest[0] == 10); + expect(dest[1] == 9); + expect(mem.eql(u8, dest[2..4], bytes[0..2])); read = try ps.stream.read(dest[0..4]); - assert(read == 4); - assert(mem.eql(u8, dest[0..4], bytes[2..6])); + expect(read == 4); + expect(mem.eql(u8, dest[0..4], bytes[2..6])); read = try ps.stream.read(dest[0..4]); - assert(read == 2); - assert(mem.eql(u8, dest[0..2], bytes[6..8])); + expect(read == 2); + expect(mem.eql(u8, dest[0..2], bytes[6..8])); ps.putBackByte(11); ps.putBackByte(12); read = try ps.stream.read(dest[0..4]); - assert(read == 2); - assert(dest[0] == 12); - assert(dest[1] == 11); + expect(read == 2); + expect(dest[0] == 12); + expect(dest[1] == 11); } test "SliceOutStream" { @@ -120,19 +120,19 @@ test "SliceOutStream" { var ss = io.SliceOutStream.init(buffer[0..]); try ss.stream.write("Hello"); - assert(mem.eql(u8, ss.getWritten(), "Hello")); + expect(mem.eql(u8, ss.getWritten(), "Hello")); try ss.stream.write("world"); - assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + expect(mem.eql(u8, ss.getWritten(), "Helloworld")); - assertError(ss.stream.write("!"), error.OutOfSpace); - assert(mem.eql(u8, ss.getWritten(), "Helloworld")); + expectError(error.OutOfSpace, ss.stream.write("!")); + expect(mem.eql(u8, ss.getWritten(), "Helloworld")); ss.reset(); - assert(ss.getWritten().len == 0); + expect(ss.getWritten().len == 0); - assertError(ss.stream.write("Hello world!"), error.OutOfSpace); - assert(mem.eql(u8, ss.getWritten(), "Hello worl")); + expectError(error.OutOfSpace, ss.stream.write("Hello world!")); + expect(mem.eql(u8, ss.getWritten(), "Hello worl")); } test "BitInStream" { @@ -145,66 +145,66 @@ test "BitInStream" { var out_bits: usize = undefined; - assert(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); mem_in_be.pos = 0; bit_stream_be.bit_count = 0; - assert(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); - assert(out_bits == 15); + expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits)); + expect(out_bits == 15); mem_in_be.pos = 0; bit_stream_be.bit_count = 0; - assert(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); - assert(out_bits == 16); + expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits)); + expect(out_bits == 16); _ = try bit_stream_be.readBits(u0, 0, &out_bits); - assert(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); - assert(out_bits == 0); - assertError(bit_stream_be.readBitsNoEof(u1, 1), error.EndOfStream); + expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits)); + expect(out_bits == 0); + expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1)); var mem_in_le = io.SliceInStream.init(mem_le[0..]); var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream); - assert(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); mem_in_le.pos = 0; bit_stream_le.bit_count = 0; - assert(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); - assert(out_bits == 15); + expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits)); + expect(out_bits == 15); mem_in_le.pos = 0; bit_stream_le.bit_count = 0; - assert(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); - assert(out_bits == 16); + expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits)); + expect(out_bits == 16); _ = try bit_stream_le.readBits(u0, 0, &out_bits); - assert(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); - assert(out_bits == 0); - assertError(bit_stream_le.readBitsNoEof(u1, 1), error.EndOfStream); + expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits)); + expect(out_bits == 0); + expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1)); } test "BitOutStream" { @@ -222,17 +222,17 @@ test "BitOutStream" { try bit_stream_be.writeBits(u9(5), 5); try bit_stream_be.writeBits(u1(1), 1); - assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); + expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011); mem_out_be.pos = 0; try bit_stream_be.writeBits(u15(0b110011010000101), 15); try bit_stream_be.flushBits(); - assert(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); + expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010); mem_out_be.pos = 0; try bit_stream_be.writeBits(u32(0b110011010000101), 16); - assert(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); + expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101); try bit_stream_be.writeBits(u0(0), 0); @@ -246,16 +246,16 @@ test "BitOutStream" { try bit_stream_le.writeBits(u9(5), 5); try bit_stream_le.writeBits(u1(1), 1); - assert(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); + expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101); mem_out_le.pos = 0; try bit_stream_le.writeBits(u15(0b110011010000101), 15); try bit_stream_le.flushBits(); - assert(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); + expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110); mem_out_le.pos = 0; try bit_stream_le.writeBits(u32(0b1100110100001011), 16); - assert(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); + expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101); try bit_stream_le.writeBits(u0(0), 0); } @@ -290,20 +290,20 @@ test "BitStreams with File Stream" { var out_bits: usize = undefined; - assert(1 == try bit_stream.readBits(u2, 1, &out_bits)); - assert(out_bits == 1); - assert(2 == try bit_stream.readBits(u5, 2, &out_bits)); - assert(out_bits == 2); - assert(3 == try bit_stream.readBits(u128, 3, &out_bits)); - assert(out_bits == 3); - assert(4 == try bit_stream.readBits(u8, 4, &out_bits)); - assert(out_bits == 4); - assert(5 == try bit_stream.readBits(u9, 5, &out_bits)); - assert(out_bits == 5); - assert(1 == try bit_stream.readBits(u1, 1, &out_bits)); - assert(out_bits == 1); + expect(1 == try bit_stream.readBits(u2, 1, &out_bits)); + expect(out_bits == 1); + expect(2 == try bit_stream.readBits(u5, 2, &out_bits)); + expect(out_bits == 2); + expect(3 == try bit_stream.readBits(u128, 3, &out_bits)); + expect(out_bits == 3); + expect(4 == try bit_stream.readBits(u8, 4, &out_bits)); + expect(out_bits == 4); + expect(5 == try bit_stream.readBits(u9, 5, &out_bits)); + expect(out_bits == 5); + expect(1 == try bit_stream.readBits(u1, 1, &out_bits)); + expect(out_bits == 1); - assertError(bit_stream.readBitsNoEof(u1, 1), error.EndOfStream); + expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1)); } try os.deleteFile(tmp_file_name); } @@ -345,8 +345,8 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const S = @IntType(true, i); const x = try deserializer.deserializeInt(U); const y = try deserializer.deserializeInt(S); - assert(x == U(i)); - if (i != 0) assert(y == S(-1)) else assert(y == 0); + expect(x == U(i)); + if (i != 0) expect(y == S(-1)) else expect(y == 0); } const u8_bit_count = comptime meta.bitCount(u8); @@ -356,7 +356,7 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime is_pa const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0); const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte; - assert(in.pos == if (is_packed) total_packed_bytes else total_bytes); + expect(in.pos == if (is_packed) total_packed_bytes else total_bytes); //Verify that empty error set works with serializer. //deserializer is covered by SliceInStream @@ -408,14 +408,14 @@ fn testIntSerializerDeserializerInfNaN(comptime endian: builtin.Endian, const inf_check_f64 = try deserializer.deserialize(f64); //const nan_check_f128 = try deserializer.deserialize(f128); //const inf_check_f128 = try deserializer.deserialize(f128); - assert(std.math.isNan(nan_check_f16)); - assert(std.math.isInf(inf_check_f16)); - assert(std.math.isNan(nan_check_f32)); - assert(std.math.isInf(inf_check_f32)); - assert(std.math.isNan(nan_check_f64)); - assert(std.math.isInf(inf_check_f64)); - //assert(std.math.isNan(nan_check_f128)); - //assert(std.math.isInf(inf_check_f128)); + expect(std.math.isNan(nan_check_f16)); + expect(std.math.isInf(inf_check_f16)); + expect(std.math.isNan(nan_check_f32)); + expect(std.math.isInf(inf_check_f32)); + expect(std.math.isNan(nan_check_f64)); + expect(std.math.isInf(inf_check_f64)); + //expect(std.math.isNan(nan_check_f128)); + //expect(std.math.isInf(inf_check_f128)); } test "Serializer/Deserializer Int: Inf/NaN" { @@ -528,7 +528,7 @@ fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime is_packe try serializer.serialize(my_inst); const my_copy = try deserializer.deserialize(MyStruct); - assert(meta.eql(my_copy, my_inst)); + expect(meta.eql(my_copy, my_inst)); } test "Serializer/Deserializer generic" { @@ -565,11 +565,11 @@ fn testBadData(comptime endian: builtin.Endian, comptime is_packed: bool) !void var deserializer = io.Deserializer(endian, is_packed, InError).init(in_stream); try serializer.serialize(u14(3)); - assertError(deserializer.deserialize(A), error.InvalidEnumTag); + expectError(error.InvalidEnumTag, deserializer.deserialize(A)); out.pos = 0; try serializer.serialize(u14(3)); try serializer.serialize(u14(88)); - assertError(deserializer.deserialize(C), error.InvalidEnumTag); + expectError(error.InvalidEnumTag, deserializer.deserialize(C)); } test "Deserializer bad data" { diff --git a/std/json.zig b/std/json.zig index 4d07d7b89d..d8f28560e5 100644 --- a/std/json.zig +++ b/std/json.zig @@ -4,6 +4,7 @@ const std = @import("index.zig"); const debug = std.debug; +const testing = std.testing; const mem = std.mem; const maxInt = std.math.maxInt; @@ -960,7 +961,7 @@ test "json.token" { checkNext(&p, Token.Id.ObjectEnd); checkNext(&p, Token.Id.ObjectEnd); - debug.assert((try p.next()) == null); + testing.expect((try p.next()) == null); } // Validate a JSON string. This does not limit number precision so a decoder may not necessarily @@ -981,7 +982,7 @@ pub fn validate(s: []const u8) bool { } test "json.validate" { - debug.assert(validate("{}")); + testing.expect(validate("{}")); } const Allocator = std.mem.Allocator; @@ -1378,20 +1379,20 @@ test "json.parser.dynamic" { var image = root.Object.get("Image").?.value; const width = image.Object.get("Width").?.value; - debug.assert(width.Integer == 800); + testing.expect(width.Integer == 800); const height = image.Object.get("Height").?.value; - debug.assert(height.Integer == 600); + testing.expect(height.Integer == 600); const title = image.Object.get("Title").?.value; - debug.assert(mem.eql(u8, title.String, "View from 15th Floor")); + testing.expect(mem.eql(u8, title.String, "View from 15th Floor")); const animated = image.Object.get("Animated").?.value; - debug.assert(animated.Bool == false); + testing.expect(animated.Bool == false); const array_of_object = image.Object.get("ArrayOfObject").?.value; - debug.assert(array_of_object.Array.len == 1); + testing.expect(array_of_object.Array.len == 1); const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; - debug.assert(mem.eql(u8, obj0.String, "m")); + testing.expect(mem.eql(u8, obj0.String, "m")); } diff --git a/std/json_test.zig b/std/json_test.zig index 9e19ec592a..edc50be8cb 100644 --- a/std/json_test.zig +++ b/std/json_test.zig @@ -6,15 +6,15 @@ const std = @import("index.zig"); fn ok(comptime s: []const u8) void { - std.debug.assert(std.json.validate(s)); + std.testing.expect(std.json.validate(s)); } fn err(comptime s: []const u8) void { - std.debug.assert(!std.json.validate(s)); + std.testing.expect(!std.json.validate(s)); } fn any(comptime s: []const u8) void { - std.debug.assert(true); + std.testing.expect(true); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/std/lazy_init.zig b/std/lazy_init.zig index f08c01e874..a09168786b 100644 --- a/std/lazy_init.zig +++ b/std/lazy_init.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const testing = std.testing; const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -63,12 +64,12 @@ test "std.lazyInit" { global_number.resolve(); } if (global_number.get()) |x| { - assert(x.* == 1234); + testing.expect(x.* == 1234); } else { @panic("bad"); } if (global_number.get()) |x| { - assert(x.* == 1234); + testing.expect(x.* == 1234); } else { @panic("bad"); } @@ -80,6 +81,6 @@ test "std.lazyInit(void)" { if (global_void.get()) |_| @panic("bad") else { global_void.resolve(); } - assert(global_void.get() != null); - assert(global_void.get() != null); + testing.expect(global_void.get() != null); + testing.expect(global_void.get() != null); } diff --git a/std/linked_list.zig b/std/linked_list.zig index 7021cac707..86e5cd056e 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -1,6 +1,7 @@ const std = @import("index.zig"); const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const Allocator = mem.Allocator; @@ -246,7 +247,7 @@ test "basic linked list test" { var it = list.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -256,7 +257,7 @@ test "basic linked list test" { var it = list.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } @@ -265,9 +266,9 @@ test "basic linked list test" { var last = list.pop(); // {2, 3, 4} list.remove(three); // {2, 4} - assert(list.first.?.data == 2); - assert(list.last.?.data == 4); - assert(list.len == 2); + testing.expect(list.first.?.data == 2); + testing.expect(list.last.?.data == 4); + testing.expect(list.len == 2); } test "linked list concatenation" { @@ -294,18 +295,18 @@ test "linked list concatenation" { list1.concatByMoving(&list2); - assert(list1.last == five); - assert(list1.len == 5); - assert(list2.first == null); - assert(list2.last == null); - assert(list2.len == 0); + testing.expect(list1.last == five); + testing.expect(list1.len == 5); + testing.expect(list2.first == null); + testing.expect(list2.last == null); + testing.expect(list2.len == 0); // Traverse forwards. { var it = list1.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -315,7 +316,7 @@ test "linked list concatenation" { var it = list1.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } @@ -328,7 +329,7 @@ test "linked list concatenation" { var it = list2.first; var index: u32 = 1; while (it) |node| : (it = node.next) { - assert(node.data == index); + testing.expect(node.data == index); index += 1; } } @@ -338,7 +339,7 @@ test "linked list concatenation" { var it = list2.last; var index: u32 = 1; while (it) |node| : (it = node.prev) { - assert(node.data == (6 - index)); + testing.expect(node.data == (6 - index)); index += 1; } } diff --git a/std/math/acos.zig b/std/math/acos.zig index 54844e8f6e..734f7a8651 100644 --- a/std/math/acos.zig +++ b/std/math/acos.zig @@ -4,7 +4,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn acos(x: var) @typeOf(x) { const T = @typeOf(x); @@ -143,38 +143,38 @@ fn acos64(x: f64) f64 { } test "math.acos" { - assert(acos(f32(0.0)) == acos32(0.0)); - assert(acos(f64(0.0)) == acos64(0.0)); + expect(acos(f32(0.0)) == acos32(0.0)); + expect(acos(f64(0.0)) == acos64(0.0)); } test "math.acos32" { const epsilon = 0.000001; - assert(math.approxEq(f32, acos32(0.0), 1.570796, epsilon)); - assert(math.approxEq(f32, acos32(0.2), 1.369438, epsilon)); - assert(math.approxEq(f32, acos32(0.3434), 1.220262, epsilon)); - assert(math.approxEq(f32, acos32(0.5), 1.047198, epsilon)); - assert(math.approxEq(f32, acos32(0.8923), 0.468382, epsilon)); - assert(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon)); + expect(math.approxEq(f32, acos32(0.0), 1.570796, epsilon)); + expect(math.approxEq(f32, acos32(0.2), 1.369438, epsilon)); + expect(math.approxEq(f32, acos32(0.3434), 1.220262, epsilon)); + expect(math.approxEq(f32, acos32(0.5), 1.047198, epsilon)); + expect(math.approxEq(f32, acos32(0.8923), 0.468382, epsilon)); + expect(math.approxEq(f32, acos32(-0.2), 1.772154, epsilon)); } test "math.acos64" { const epsilon = 0.000001; - assert(math.approxEq(f64, acos64(0.0), 1.570796, epsilon)); - assert(math.approxEq(f64, acos64(0.2), 1.369438, epsilon)); - assert(math.approxEq(f64, acos64(0.3434), 1.220262, epsilon)); - assert(math.approxEq(f64, acos64(0.5), 1.047198, epsilon)); - assert(math.approxEq(f64, acos64(0.8923), 0.468382, epsilon)); - assert(math.approxEq(f64, acos64(-0.2), 1.772154, epsilon)); + expect(math.approxEq(f64, acos64(0.0), 1.570796, epsilon)); + expect(math.approxEq(f64, acos64(0.2), 1.369438, epsilon)); + expect(math.approxEq(f64, acos64(0.3434), 1.220262, epsilon)); + expect(math.approxEq(f64, acos64(0.5), 1.047198, epsilon)); + expect(math.approxEq(f64, acos64(0.8923), 0.468382, epsilon)); + expect(math.approxEq(f64, acos64(-0.2), 1.772154, epsilon)); } test "math.acos32.special" { - assert(math.isNan(acos32(-2))); - assert(math.isNan(acos32(1.5))); + expect(math.isNan(acos32(-2))); + expect(math.isNan(acos32(1.5))); } test "math.acos64.special" { - assert(math.isNan(acos64(-2))); - assert(math.isNan(acos64(1.5))); + expect(math.isNan(acos64(-2))); + expect(math.isNan(acos64(1.5))); } diff --git a/std/math/acosh.zig b/std/math/acosh.zig index 9be323e1f6..a9c4a908ef 100644 --- a/std/math/acosh.zig +++ b/std/math/acosh.zig @@ -6,7 +6,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn acosh(x: var) @typeOf(x) { const T = @typeOf(x); @@ -55,34 +55,34 @@ fn acosh64(x: f64) f64 { } test "math.acosh" { - assert(acosh(f32(1.5)) == acosh32(1.5)); - assert(acosh(f64(1.5)) == acosh64(1.5)); + expect(acosh(f32(1.5)) == acosh32(1.5)); + expect(acosh(f64(1.5)) == acosh64(1.5)); } test "math.acosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon)); - assert(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon)); - assert(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon)); - assert(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f32, acosh32(1.5), 0.962424, epsilon)); + expect(math.approxEq(f32, acosh32(37.45), 4.315976, epsilon)); + expect(math.approxEq(f32, acosh32(89.123), 5.183133, epsilon)); + expect(math.approxEq(f32, acosh32(123123.234375), 12.414088, epsilon)); } test "math.acosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon)); - assert(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon)); - assert(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon)); - assert(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f64, acosh64(1.5), 0.962424, epsilon)); + expect(math.approxEq(f64, acosh64(37.45), 4.315976, epsilon)); + expect(math.approxEq(f64, acosh64(89.123), 5.183133, epsilon)); + expect(math.approxEq(f64, acosh64(123123.234375), 12.414088, epsilon)); } test "math.acosh32.special" { - assert(math.isNan(acosh32(math.nan(f32)))); - assert(math.isSignalNan(acosh32(0.5))); + expect(math.isNan(acosh32(math.nan(f32)))); + expect(math.isSignalNan(acosh32(0.5))); } test "math.acosh64.special" { - assert(math.isNan(acosh64(math.nan(f64)))); - assert(math.isSignalNan(acosh64(0.5))); + expect(math.isNan(acosh64(math.nan(f64)))); + expect(math.isSignalNan(acosh64(0.5))); } diff --git a/std/math/asin.zig b/std/math/asin.zig index 30b3a57e32..c9dbdf704f 100644 --- a/std/math/asin.zig +++ b/std/math/asin.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn asin(x: var) @typeOf(x) { const T = @typeOf(x); @@ -136,42 +136,42 @@ fn asin64(x: f64) f64 { } test "math.asin" { - assert(asin(f32(0.0)) == asin32(0.0)); - assert(asin(f64(0.0)) == asin64(0.0)); + expect(asin(f32(0.0)) == asin32(0.0)); + expect(asin(f64(0.0)) == asin64(0.0)); } test "math.asin32" { const epsilon = 0.000001; - assert(math.approxEq(f32, asin32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, asin32(0.2), 0.201358, epsilon)); - assert(math.approxEq(f32, asin32(-0.2), -0.201358, epsilon)); - assert(math.approxEq(f32, asin32(0.3434), 0.350535, epsilon)); - assert(math.approxEq(f32, asin32(0.5), 0.523599, epsilon)); - assert(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon)); + expect(math.approxEq(f32, asin32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, asin32(0.2), 0.201358, epsilon)); + expect(math.approxEq(f32, asin32(-0.2), -0.201358, epsilon)); + expect(math.approxEq(f32, asin32(0.3434), 0.350535, epsilon)); + expect(math.approxEq(f32, asin32(0.5), 0.523599, epsilon)); + expect(math.approxEq(f32, asin32(0.8923), 1.102415, epsilon)); } test "math.asin64" { const epsilon = 0.000001; - assert(math.approxEq(f64, asin64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, asin64(0.2), 0.201358, epsilon)); - assert(math.approxEq(f64, asin64(-0.2), -0.201358, epsilon)); - assert(math.approxEq(f64, asin64(0.3434), 0.350535, epsilon)); - assert(math.approxEq(f64, asin64(0.5), 0.523599, epsilon)); - assert(math.approxEq(f64, asin64(0.8923), 1.102415, epsilon)); + expect(math.approxEq(f64, asin64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, asin64(0.2), 0.201358, epsilon)); + expect(math.approxEq(f64, asin64(-0.2), -0.201358, epsilon)); + expect(math.approxEq(f64, asin64(0.3434), 0.350535, epsilon)); + expect(math.approxEq(f64, asin64(0.5), 0.523599, epsilon)); + expect(math.approxEq(f64, asin64(0.8923), 1.102415, epsilon)); } test "math.asin32.special" { - assert(asin32(0.0) == 0.0); - assert(asin32(-0.0) == -0.0); - assert(math.isNan(asin32(-2))); - assert(math.isNan(asin32(1.5))); + expect(asin32(0.0) == 0.0); + expect(asin32(-0.0) == -0.0); + expect(math.isNan(asin32(-2))); + expect(math.isNan(asin32(1.5))); } test "math.asin64.special" { - assert(asin64(0.0) == 0.0); - assert(asin64(-0.0) == -0.0); - assert(math.isNan(asin64(-2))); - assert(math.isNan(asin64(1.5))); + expect(asin64(0.0) == 0.0); + expect(asin64(-0.0) == -0.0); + expect(math.isNan(asin64(-2))); + expect(math.isNan(asin64(1.5))); } diff --git a/std/math/asinh.zig b/std/math/asinh.zig index 98892bcbcb..05bd8d008e 100644 --- a/std/math/asinh.zig +++ b/std/math/asinh.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn asinh(x: var) @typeOf(x) { @@ -83,46 +83,46 @@ fn asinh64(x: f64) f64 { } test "math.asinh" { - assert(asinh(f32(0.0)) == asinh32(0.0)); - assert(asinh(f64(0.0)) == asinh64(0.0)); + expect(asinh(f32(0.0)) == asinh32(0.0)); + expect(asinh(f64(0.0)) == asinh64(0.0)); } test "math.asinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, asinh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon)); - assert(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon)); - assert(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon)); - assert(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon)); - assert(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f32, asinh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, asinh32(0.2), 0.198690, epsilon)); + expect(math.approxEq(f32, asinh32(0.8923), 0.803133, epsilon)); + expect(math.approxEq(f32, asinh32(1.5), 1.194763, epsilon)); + expect(math.approxEq(f32, asinh32(37.45), 4.316332, epsilon)); + expect(math.approxEq(f32, asinh32(89.123), 5.183196, epsilon)); + expect(math.approxEq(f32, asinh32(123123.234375), 12.414088, epsilon)); } test "math.asinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, asinh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon)); - assert(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon)); - assert(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon)); - assert(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon)); - assert(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon)); - assert(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon)); + expect(math.approxEq(f64, asinh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, asinh64(0.2), 0.198690, epsilon)); + expect(math.approxEq(f64, asinh64(0.8923), 0.803133, epsilon)); + expect(math.approxEq(f64, asinh64(1.5), 1.194763, epsilon)); + expect(math.approxEq(f64, asinh64(37.45), 4.316332, epsilon)); + expect(math.approxEq(f64, asinh64(89.123), 5.183196, epsilon)); + expect(math.approxEq(f64, asinh64(123123.234375), 12.414088, epsilon)); } test "math.asinh32.special" { - assert(asinh32(0.0) == 0.0); - assert(asinh32(-0.0) == -0.0); - assert(math.isPositiveInf(asinh32(math.inf(f32)))); - assert(math.isNegativeInf(asinh32(-math.inf(f32)))); - assert(math.isNan(asinh32(math.nan(f32)))); + expect(asinh32(0.0) == 0.0); + expect(asinh32(-0.0) == -0.0); + expect(math.isPositiveInf(asinh32(math.inf(f32)))); + expect(math.isNegativeInf(asinh32(-math.inf(f32)))); + expect(math.isNan(asinh32(math.nan(f32)))); } test "math.asinh64.special" { - assert(asinh64(0.0) == 0.0); - assert(asinh64(-0.0) == -0.0); - assert(math.isPositiveInf(asinh64(math.inf(f64)))); - assert(math.isNegativeInf(asinh64(-math.inf(f64)))); - assert(math.isNan(asinh64(math.nan(f64)))); + expect(asinh64(0.0) == 0.0); + expect(asinh64(-0.0) == -0.0); + expect(math.isPositiveInf(asinh64(math.inf(f64)))); + expect(math.isNegativeInf(asinh64(-math.inf(f64)))); + expect(math.isNan(asinh64(math.nan(f64)))); } diff --git a/std/math/atan.zig b/std/math/atan.zig index 6ca94dd84a..72d17b4db2 100644 --- a/std/math/atan.zig +++ b/std/math/atan.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn atan(x: var) @typeOf(x) { const T = @typeOf(x); @@ -206,44 +206,44 @@ fn atan64(x_: f64) f64 { } test "math.atan" { - assert(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2))); - assert(atan(f64(0.2)) == atan64(0.2)); + expect(@bitCast(u32, atan(f32(0.2))) == @bitCast(u32, atan32(0.2))); + expect(atan(f64(0.2)) == atan64(0.2)); } test "math.atan32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atan32(0.2), 0.197396, epsilon)); - assert(math.approxEq(f32, atan32(-0.2), -0.197396, epsilon)); - assert(math.approxEq(f32, atan32(0.3434), 0.330783, epsilon)); - assert(math.approxEq(f32, atan32(0.8923), 0.728545, epsilon)); - assert(math.approxEq(f32, atan32(1.5), 0.982794, epsilon)); + expect(math.approxEq(f32, atan32(0.2), 0.197396, epsilon)); + expect(math.approxEq(f32, atan32(-0.2), -0.197396, epsilon)); + expect(math.approxEq(f32, atan32(0.3434), 0.330783, epsilon)); + expect(math.approxEq(f32, atan32(0.8923), 0.728545, epsilon)); + expect(math.approxEq(f32, atan32(1.5), 0.982794, epsilon)); } test "math.atan64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atan64(0.2), 0.197396, epsilon)); - assert(math.approxEq(f64, atan64(-0.2), -0.197396, epsilon)); - assert(math.approxEq(f64, atan64(0.3434), 0.330783, epsilon)); - assert(math.approxEq(f64, atan64(0.8923), 0.728545, epsilon)); - assert(math.approxEq(f64, atan64(1.5), 0.982794, epsilon)); + expect(math.approxEq(f64, atan64(0.2), 0.197396, epsilon)); + expect(math.approxEq(f64, atan64(-0.2), -0.197396, epsilon)); + expect(math.approxEq(f64, atan64(0.3434), 0.330783, epsilon)); + expect(math.approxEq(f64, atan64(0.8923), 0.728545, epsilon)); + expect(math.approxEq(f64, atan64(1.5), 0.982794, epsilon)); } test "math.atan32.special" { const epsilon = 0.000001; - assert(atan32(0.0) == 0.0); - assert(atan32(-0.0) == -0.0); - assert(math.approxEq(f32, atan32(math.inf(f32)), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan32(-math.inf(f32)), -math.pi / 2.0, epsilon)); + expect(atan32(0.0) == 0.0); + expect(atan32(-0.0) == -0.0); + expect(math.approxEq(f32, atan32(math.inf(f32)), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan32(-math.inf(f32)), -math.pi / 2.0, epsilon)); } test "math.atan64.special" { const epsilon = 0.000001; - assert(atan64(0.0) == 0.0); - assert(atan64(-0.0) == -0.0); - assert(math.approxEq(f64, atan64(math.inf(f64)), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan64(-math.inf(f64)), -math.pi / 2.0, epsilon)); + expect(atan64(0.0) == 0.0); + expect(atan64(-0.0) == -0.0); + expect(math.approxEq(f64, atan64(math.inf(f64)), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan64(-math.inf(f64)), -math.pi / 2.0, epsilon)); } diff --git a/std/math/atan2.zig b/std/math/atan2.zig index a7757132d7..6e1f67cfbb 100644 --- a/std/math/atan2.zig +++ b/std/math/atan2.zig @@ -20,7 +20,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn atan2(comptime T: type, y: T, x: T) T { return switch (T) { @@ -206,78 +206,78 @@ fn atan2_64(y: f64, x: f64) f64 { } test "math.atan2" { - assert(atan2(f32, 0.2, 0.21) == atan2_32(0.2, 0.21)); - assert(atan2(f64, 0.2, 0.21) == atan2_64(0.2, 0.21)); + expect(atan2(f32, 0.2, 0.21) == atan2_32(0.2, 0.21)); + expect(atan2(f64, 0.2, 0.21) == atan2_64(0.2, 0.21)); } test "math.atan2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon)); + expect(math.approxEq(f32, atan2_32(0.0, 0.0), 0.0, epsilon)); + expect(math.approxEq(f32, atan2_32(0.2, 0.2), 0.785398, epsilon)); + expect(math.approxEq(f32, atan2_32(-0.2, 0.2), -0.785398, epsilon)); + expect(math.approxEq(f32, atan2_32(0.2, -0.2), 2.356194, epsilon)); + expect(math.approxEq(f32, atan2_32(-0.2, -0.2), -2.356194, epsilon)); + expect(math.approxEq(f32, atan2_32(0.34, -0.4), 2.437099, epsilon)); + expect(math.approxEq(f32, atan2_32(0.34, 1.243), 0.267001, epsilon)); } test "math.atan2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon)); - assert(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon)); - assert(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon)); - assert(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon)); - assert(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon)); - assert(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon)); + expect(math.approxEq(f64, atan2_64(0.0, 0.0), 0.0, epsilon)); + expect(math.approxEq(f64, atan2_64(0.2, 0.2), 0.785398, epsilon)); + expect(math.approxEq(f64, atan2_64(-0.2, 0.2), -0.785398, epsilon)); + expect(math.approxEq(f64, atan2_64(0.2, -0.2), 2.356194, epsilon)); + expect(math.approxEq(f64, atan2_64(-0.2, -0.2), -2.356194, epsilon)); + expect(math.approxEq(f64, atan2_64(0.34, -0.4), 2.437099, epsilon)); + expect(math.approxEq(f64, atan2_64(0.34, 1.243), 0.267001, epsilon)); } test "math.atan2_32.special" { const epsilon = 0.000001; - assert(math.isNan(atan2_32(1.0, math.nan(f32)))); - assert(math.isNan(atan2_32(math.nan(f32), 1.0))); - assert(atan2_32(0.0, 5.0) == 0.0); - assert(atan2_32(-0.0, 5.0) == -0.0); - assert(math.approxEq(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); - //assert(math.approxEq(f32, atan2_32(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? - assert(math.approxEq(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(1.0, -0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, 0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, -0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), math.inf(f32)), math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), math.inf(f32)), -math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), -math.inf(f32)), 3.0 * math.pi / 4.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), -math.inf(f32)), -3.0 * math.pi / 4.0, epsilon)); - assert(atan2_32(1.0, math.inf(f32)) == 0.0); - assert(math.approxEq(f32, atan2_32(1.0, -math.inf(f32)), math.pi, epsilon)); - assert(math.approxEq(f32, atan2_32(-1.0, -math.inf(f32)), -math.pi, epsilon)); - assert(math.approxEq(f32, atan2_32(math.inf(f32), 1.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f32, atan2_32(-math.inf(f32), 1.0), -math.pi / 2.0, epsilon)); + expect(math.isNan(atan2_32(1.0, math.nan(f32)))); + expect(math.isNan(atan2_32(math.nan(f32), 1.0))); + expect(atan2_32(0.0, 5.0) == 0.0); + expect(atan2_32(-0.0, 5.0) == -0.0); + expect(math.approxEq(f32, atan2_32(0.0, -5.0), math.pi, epsilon)); + //expect(math.approxEq(f32, atan2_32(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? + expect(math.approxEq(f32, atan2_32(1.0, 0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(1.0, -0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, 0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, -0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), math.inf(f32)), math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), math.inf(f32)), -math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), -math.inf(f32)), 3.0 * math.pi / 4.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), -math.inf(f32)), -3.0 * math.pi / 4.0, epsilon)); + expect(atan2_32(1.0, math.inf(f32)) == 0.0); + expect(math.approxEq(f32, atan2_32(1.0, -math.inf(f32)), math.pi, epsilon)); + expect(math.approxEq(f32, atan2_32(-1.0, -math.inf(f32)), -math.pi, epsilon)); + expect(math.approxEq(f32, atan2_32(math.inf(f32), 1.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f32, atan2_32(-math.inf(f32), 1.0), -math.pi / 2.0, epsilon)); } test "math.atan2_64.special" { const epsilon = 0.000001; - assert(math.isNan(atan2_64(1.0, math.nan(f64)))); - assert(math.isNan(atan2_64(math.nan(f64), 1.0))); - assert(atan2_64(0.0, 5.0) == 0.0); - assert(atan2_64(-0.0, 5.0) == -0.0); - assert(math.approxEq(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); - //assert(math.approxEq(f64, atan2_64(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? - assert(math.approxEq(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(1.0, -0.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, 0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, -0.0), -math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), math.inf(f64)), math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), math.inf(f64)), -math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), -math.inf(f64)), 3.0 * math.pi / 4.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), -math.inf(f64)), -3.0 * math.pi / 4.0, epsilon)); - assert(atan2_64(1.0, math.inf(f64)) == 0.0); - assert(math.approxEq(f64, atan2_64(1.0, -math.inf(f64)), math.pi, epsilon)); - assert(math.approxEq(f64, atan2_64(-1.0, -math.inf(f64)), -math.pi, epsilon)); - assert(math.approxEq(f64, atan2_64(math.inf(f64), 1.0), math.pi / 2.0, epsilon)); - assert(math.approxEq(f64, atan2_64(-math.inf(f64), 1.0), -math.pi / 2.0, epsilon)); + expect(math.isNan(atan2_64(1.0, math.nan(f64)))); + expect(math.isNan(atan2_64(math.nan(f64), 1.0))); + expect(atan2_64(0.0, 5.0) == 0.0); + expect(atan2_64(-0.0, 5.0) == -0.0); + expect(math.approxEq(f64, atan2_64(0.0, -5.0), math.pi, epsilon)); + //expect(math.approxEq(f64, atan2_64(-0.0, -5.0), -math.pi, epsilon)); TODO support negative zero? + expect(math.approxEq(f64, atan2_64(1.0, 0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(1.0, -0.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, 0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, -0.0), -math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), math.inf(f64)), math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), math.inf(f64)), -math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), -math.inf(f64)), 3.0 * math.pi / 4.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), -math.inf(f64)), -3.0 * math.pi / 4.0, epsilon)); + expect(atan2_64(1.0, math.inf(f64)) == 0.0); + expect(math.approxEq(f64, atan2_64(1.0, -math.inf(f64)), math.pi, epsilon)); + expect(math.approxEq(f64, atan2_64(-1.0, -math.inf(f64)), -math.pi, epsilon)); + expect(math.approxEq(f64, atan2_64(math.inf(f64), 1.0), math.pi / 2.0, epsilon)); + expect(math.approxEq(f64, atan2_64(-math.inf(f64), 1.0), -math.pi / 2.0, epsilon)); } diff --git a/std/math/atanh.zig b/std/math/atanh.zig index c97855c234..f2feab0207 100644 --- a/std/math/atanh.zig +++ b/std/math/atanh.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn atanh(x: var) @typeOf(x) { @@ -78,38 +78,38 @@ fn atanh_64(x: f64) f64 { } test "math.atanh" { - assert(atanh(f32(0.0)) == atanh_32(0.0)); - assert(atanh(f64(0.0)) == atanh_64(0.0)); + expect(atanh(f32(0.0)) == atanh_32(0.0)); + expect(atanh(f64(0.0)) == atanh_64(0.0)); } test "math.atanh_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon)); - assert(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon)); + expect(math.approxEq(f32, atanh_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, atanh_32(0.2), 0.202733, epsilon)); + expect(math.approxEq(f32, atanh_32(0.8923), 1.433099, epsilon)); } test "math.atanh_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon)); - assert(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon)); + expect(math.approxEq(f64, atanh_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, atanh_64(0.2), 0.202733, epsilon)); + expect(math.approxEq(f64, atanh_64(0.8923), 1.433099, epsilon)); } test "math.atanh32.special" { - assert(math.isPositiveInf(atanh_32(1))); - assert(math.isNegativeInf(atanh_32(-1))); - assert(math.isSignalNan(atanh_32(1.5))); - assert(math.isSignalNan(atanh_32(-1.5))); - assert(math.isNan(atanh_32(math.nan(f32)))); + expect(math.isPositiveInf(atanh_32(1))); + expect(math.isNegativeInf(atanh_32(-1))); + expect(math.isSignalNan(atanh_32(1.5))); + expect(math.isSignalNan(atanh_32(-1.5))); + expect(math.isNan(atanh_32(math.nan(f32)))); } test "math.atanh64.special" { - assert(math.isPositiveInf(atanh_64(1))); - assert(math.isNegativeInf(atanh_64(-1))); - assert(math.isSignalNan(atanh_64(1.5))); - assert(math.isSignalNan(atanh_64(-1.5))); - assert(math.isNan(atanh_64(math.nan(f64)))); + expect(math.isPositiveInf(atanh_64(1))); + expect(math.isNegativeInf(atanh_64(-1))); + expect(math.isSignalNan(atanh_64(1.5))); + expect(math.isSignalNan(atanh_64(-1.5))); + expect(math.isNan(atanh_64(math.nan(f64)))); } diff --git a/std/math/big/int.zig b/std/math/big/int.zig index cda2e1419f..f21e5df8aa 100644 --- a/std/math/big/int.zig +++ b/std/math/big/int.zig @@ -1,6 +1,7 @@ const std = @import("../../index.zig"); const builtin = @import("builtin"); const debug = std.debug; +const testing = std.testing; const math = std.math; const mem = std.mem; const Allocator = mem.Allocator; @@ -1086,44 +1087,40 @@ test "big.int comptime_int set" { const result = Limb(s & maxInt(Limb)); s >>= Limb.bit_count / 2; s >>= Limb.bit_count / 2; - debug.assert(a.limbs[i] == result); + testing.expect(a.limbs[i] == result); } } test "big.int comptime_int set negative" { var a = try Int.initSet(al, -10); - debug.assert(a.limbs[0] == 10); - debug.assert(a.positive == false); + testing.expect(a.limbs[0] == 10); + testing.expect(a.positive == false); } test "big.int int set unaligned small" { var a = try Int.initSet(al, u7(45)); - debug.assert(a.limbs[0] == 45); - debug.assert(a.positive == true); + testing.expect(a.limbs[0] == 45); + testing.expect(a.positive == true); } test "big.int comptime_int to" { const a = try Int.initSet(al, 0xefffffff00000001eeeeeeefaaaaaaab); - debug.assert((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab); + testing.expect((try a.to(u128)) == 0xefffffff00000001eeeeeeefaaaaaaab); } test "big.int sub-limb to" { const a = try Int.initSet(al, 10); - debug.assert((try a.to(u8)) == 10); + testing.expect((try a.to(u8)) == 10); } test "big.int to target too small error" { const a = try Int.initSet(al, 0xffffffff); - if (a.to(u8)) |_| { - unreachable; - } else |err| { - debug.assert(err == error.TargetTooSmall); - } + testing.expectError(error.TargetTooSmall, a.to(u8)); } test "big.int norm1" { @@ -1135,22 +1132,22 @@ test "big.int norm1" { a.limbs[2] = 3; a.limbs[3] = 0; a.norm1(4); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; a.norm1(3); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 0; a.limbs[1] = 0; a.norm1(2); - debug.assert(a.len == 1); + testing.expect(a.len == 1); a.limbs[0] = 0; a.norm1(1); - debug.assert(a.len == 1); + testing.expect(a.len == 1); } test "big.int normN" { @@ -1162,144 +1159,144 @@ test "big.int normN" { a.limbs[2] = 0; a.limbs[3] = 0; a.normN(4); - debug.assert(a.len == 2); + testing.expect(a.len == 2); a.limbs[0] = 1; a.limbs[1] = 2; a.limbs[2] = 3; a.normN(3); - debug.assert(a.len == 3); + testing.expect(a.len == 3); a.limbs[0] = 0; a.limbs[1] = 0; a.limbs[2] = 0; a.limbs[3] = 0; a.normN(4); - debug.assert(a.len == 1); + testing.expect(a.len == 1); a.limbs[0] = 0; a.normN(1); - debug.assert(a.len == 1); + testing.expect(a.len == 1); } test "big.int parity" { var a = try Int.init(al); try a.set(0); - debug.assert(a.isEven()); - debug.assert(!a.isOdd()); + testing.expect(a.isEven()); + testing.expect(!a.isOdd()); try a.set(7); - debug.assert(!a.isEven()); - debug.assert(a.isOdd()); + testing.expect(!a.isEven()); + testing.expect(a.isOdd()); } test "big.int bitcount + sizeInBase" { var a = try Int.init(al); try a.set(0b100); - debug.assert(a.bitCountAbs() == 3); - debug.assert(a.sizeInBase(2) >= 3); - debug.assert(a.sizeInBase(10) >= 1); + testing.expect(a.bitCountAbs() == 3); + testing.expect(a.sizeInBase(2) >= 3); + testing.expect(a.sizeInBase(10) >= 1); a.negate(); - debug.assert(a.bitCountAbs() == 3); - debug.assert(a.sizeInBase(2) >= 4); - debug.assert(a.sizeInBase(10) >= 2); + testing.expect(a.bitCountAbs() == 3); + testing.expect(a.sizeInBase(2) >= 4); + testing.expect(a.sizeInBase(10) >= 2); try a.set(0xffffffff); - debug.assert(a.bitCountAbs() == 32); - debug.assert(a.sizeInBase(2) >= 32); - debug.assert(a.sizeInBase(10) >= 10); + testing.expect(a.bitCountAbs() == 32); + testing.expect(a.sizeInBase(2) >= 32); + testing.expect(a.sizeInBase(10) >= 10); try a.shiftLeft(a, 5000); - debug.assert(a.bitCountAbs() == 5032); - debug.assert(a.sizeInBase(2) >= 5032); + testing.expect(a.bitCountAbs() == 5032); + testing.expect(a.sizeInBase(2) >= 5032); a.positive = false; - debug.assert(a.bitCountAbs() == 5032); - debug.assert(a.sizeInBase(2) >= 5033); + testing.expect(a.bitCountAbs() == 5032); + testing.expect(a.sizeInBase(2) >= 5033); } test "big.int bitcount/to" { var a = try Int.init(al); try a.set(0); - debug.assert(a.bitCountTwosComp() == 0); + testing.expect(a.bitCountTwosComp() == 0); // TODO: stack smashing - // debug.assert((try a.to(u0)) == 0); + // testing.expect((try a.to(u0)) == 0); // TODO: sigsegv - // debug.assert((try a.to(i0)) == 0); + // testing.expect((try a.to(i0)) == 0); try a.set(-1); - debug.assert(a.bitCountTwosComp() == 1); - debug.assert((try a.to(i1)) == -1); + testing.expect(a.bitCountTwosComp() == 1); + testing.expect((try a.to(i1)) == -1); try a.set(-8); - debug.assert(a.bitCountTwosComp() == 4); - debug.assert((try a.to(i4)) == -8); + testing.expect(a.bitCountTwosComp() == 4); + testing.expect((try a.to(i4)) == -8); try a.set(127); - debug.assert(a.bitCountTwosComp() == 7); - debug.assert((try a.to(u7)) == 127); + testing.expect(a.bitCountTwosComp() == 7); + testing.expect((try a.to(u7)) == 127); try a.set(-128); - debug.assert(a.bitCountTwosComp() == 8); - debug.assert((try a.to(i8)) == -128); + testing.expect(a.bitCountTwosComp() == 8); + testing.expect((try a.to(i8)) == -128); try a.set(-129); - debug.assert(a.bitCountTwosComp() == 9); - debug.assert((try a.to(i9)) == -129); + testing.expect(a.bitCountTwosComp() == 9); + testing.expect((try a.to(i9)) == -129); } test "big.int fits" { var a = try Int.init(al); try a.set(0); - debug.assert(a.fits(u0)); - debug.assert(a.fits(i0)); + testing.expect(a.fits(u0)); + testing.expect(a.fits(i0)); try a.set(255); - debug.assert(!a.fits(u0)); - debug.assert(!a.fits(u1)); - debug.assert(!a.fits(i8)); - debug.assert(a.fits(u8)); - debug.assert(a.fits(u9)); - debug.assert(a.fits(i9)); + testing.expect(!a.fits(u0)); + testing.expect(!a.fits(u1)); + testing.expect(!a.fits(i8)); + testing.expect(a.fits(u8)); + testing.expect(a.fits(u9)); + testing.expect(a.fits(i9)); try a.set(-128); - debug.assert(!a.fits(i7)); - debug.assert(a.fits(i8)); - debug.assert(a.fits(i9)); - debug.assert(!a.fits(u9)); + testing.expect(!a.fits(i7)); + testing.expect(a.fits(i8)); + testing.expect(a.fits(i9)); + testing.expect(!a.fits(u9)); try a.set(0x1ffffffffeeeeeeee); - debug.assert(!a.fits(u32)); - debug.assert(!a.fits(u64)); - debug.assert(a.fits(u65)); + testing.expect(!a.fits(u32)); + testing.expect(!a.fits(u64)); + testing.expect(a.fits(u65)); } test "big.int string set" { var a = try Int.init(al); try a.setString(10, "120317241209124781241290847124"); - debug.assert((try a.to(u128)) == 120317241209124781241290847124); + testing.expect((try a.to(u128)) == 120317241209124781241290847124); } test "big.int string negative" { var a = try Int.init(al); try a.setString(10, "-1023"); - debug.assert((try a.to(i32)) == -1023); + testing.expect((try a.to(i32)) == -1023); } test "big.int string set bad char error" { var a = try Int.init(al); - a.setString(10, "x") catch |err| debug.assert(err == error.InvalidCharForDigit); + testing.expectError(error.InvalidCharForDigit, a.setString(10, "x")); } test "big.int string set bad base error" { var a = try Int.init(al); - a.setString(45, "10") catch |err| debug.assert(err == error.InvalidBase); + testing.expectError(error.InvalidBase, a.setString(45, "10")); } test "big.int string to" { @@ -1308,17 +1305,13 @@ test "big.int string to" { const as = try a.toString(al, 10); const es = "120317241209124781241290847124"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int string to base base error" { const a = try Int.initSet(al, 0xffffffff); - if (a.toString(al, 45)) |_| { - unreachable; - } else |err| { - debug.assert(err == error.InvalidBase); - } + testing.expectError(error.InvalidBase, a.toString(al, 45)); } test "big.int string to base 2" { @@ -1327,7 +1320,7 @@ test "big.int string to base 2" { const as = try a.toString(al, 2); const es = "-1011"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int string to base 16" { @@ -1336,7 +1329,7 @@ test "big.int string to base 16" { const as = try a.toString(al, 16); const es = "efffffff00000001eeeeeeefaaaaaaab"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int neg string to" { @@ -1345,7 +1338,7 @@ test "big.int neg string to" { const as = try a.toString(al, 10); const es = "-123907434"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int zero string to" { @@ -1354,98 +1347,98 @@ test "big.int zero string to" { const as = try a.toString(al, 10); const es = "0"; - debug.assert(mem.eql(u8, as, es)); + testing.expect(mem.eql(u8, as, es)); } test "big.int clone" { var a = try Int.initSet(al, 1234); const b = try a.clone(); - debug.assert((try a.to(u32)) == 1234); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 1234); + testing.expect((try b.to(u32)) == 1234); try a.set(77); - debug.assert((try a.to(u32)) == 77); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 77); + testing.expect((try b.to(u32)) == 1234); } test "big.int swap" { var a = try Int.initSet(al, 1234); var b = try Int.initSet(al, 5678); - debug.assert((try a.to(u32)) == 1234); - debug.assert((try b.to(u32)) == 5678); + testing.expect((try a.to(u32)) == 1234); + testing.expect((try b.to(u32)) == 5678); a.swap(&b); - debug.assert((try a.to(u32)) == 5678); - debug.assert((try b.to(u32)) == 1234); + testing.expect((try a.to(u32)) == 5678); + testing.expect((try b.to(u32)) == 1234); } test "big.int to negative" { var a = try Int.initSet(al, -10); - debug.assert((try a.to(i32)) == -10); + testing.expect((try a.to(i32)) == -10); } test "big.int compare" { var a = try Int.initSet(al, -11); var b = try Int.initSet(al, 10); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(a.cmp(b) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(a.cmp(b) == -1); } test "big.int compare similar" { var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee); var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef); - debug.assert(a.cmpAbs(b) == -1); - debug.assert(b.cmpAbs(a) == 1); + testing.expect(a.cmpAbs(b) == -1); + testing.expect(b.cmpAbs(a) == 1); } test "big.int compare different limb size" { var a = try Int.initSet(al, maxInt(Limb) + 1); var b = try Int.initSet(al, 1); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(b.cmpAbs(a) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(b.cmpAbs(a) == -1); } test "big.int compare multi-limb" { var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef); var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee); - debug.assert(a.cmpAbs(b) == 1); - debug.assert(a.cmp(b) == -1); + testing.expect(a.cmpAbs(b) == 1); + testing.expect(a.cmp(b) == -1); } test "big.int equality" { var a = try Int.initSet(al, 0xffffffff1); var b = try Int.initSet(al, -0xffffffff1); - debug.assert(a.eqAbs(b)); - debug.assert(!a.eq(b)); + testing.expect(a.eqAbs(b)); + testing.expect(!a.eq(b)); } test "big.int abs" { var a = try Int.initSet(al, -5); a.abs(); - debug.assert((try a.to(u32)) == 5); + testing.expect((try a.to(u32)) == 5); a.abs(); - debug.assert((try a.to(u32)) == 5); + testing.expect((try a.to(u32)) == 5); } test "big.int negate" { var a = try Int.initSet(al, 5); a.negate(); - debug.assert((try a.to(i32)) == -5); + testing.expect((try a.to(i32)) == -5); a.negate(); - debug.assert((try a.to(i32)) == 5); + testing.expect((try a.to(i32)) == 5); } test "big.int add single-single" { @@ -1455,7 +1448,7 @@ test "big.int add single-single" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u32)) == 55); + testing.expect((try c.to(u32)) == 55); } test "big.int add multi-single" { @@ -1465,10 +1458,10 @@ test "big.int add multi-single" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(DoubleLimb)) == maxInt(Limb) + 2); + testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2); try c.add(b, a); - debug.assert((try c.to(DoubleLimb)) == maxInt(Limb) + 2); + testing.expect((try c.to(DoubleLimb)) == maxInt(Limb) + 2); } test "big.int add multi-multi" { @@ -1480,7 +1473,7 @@ test "big.int add multi-multi" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u128)) == op1 + op2); + testing.expect((try c.to(u128)) == op1 + op2); } test "big.int add zero-zero" { @@ -1490,7 +1483,7 @@ test "big.int add zero-zero" { var c = try Int.init(al); try c.add(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int add alias multi-limb nonzero-zero" { @@ -1500,7 +1493,7 @@ test "big.int add alias multi-limb nonzero-zero" { try a.add(a, b); - debug.assert((try a.to(u128)) == op1); + testing.expect((try a.to(u128)) == op1); } test "big.int add sign" { @@ -1512,16 +1505,16 @@ test "big.int add sign" { const neg_two = try Int.initSet(al, -2); try a.add(one, two); - debug.assert((try a.to(i32)) == 3); + testing.expect((try a.to(i32)) == 3); try a.add(neg_one, two); - debug.assert((try a.to(i32)) == 1); + testing.expect((try a.to(i32)) == 1); try a.add(one, neg_two); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); try a.add(neg_one, neg_two); - debug.assert((try a.to(i32)) == -3); + testing.expect((try a.to(i32)) == -3); } test "big.int sub single-single" { @@ -1531,7 +1524,7 @@ test "big.int sub single-single" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u32)) == 45); + testing.expect((try c.to(u32)) == 45); } test "big.int sub multi-single" { @@ -1541,7 +1534,7 @@ test "big.int sub multi-single" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(Limb)) == maxInt(Limb)); + testing.expect((try c.to(Limb)) == maxInt(Limb)); } test "big.int sub multi-multi" { @@ -1554,7 +1547,7 @@ test "big.int sub multi-multi" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u128)) == op1 - op2); + testing.expect((try c.to(u128)) == op1 - op2); } test "big.int sub equal" { @@ -1564,7 +1557,7 @@ test "big.int sub equal" { var c = try Int.init(al); try c.sub(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int sub sign" { @@ -1576,19 +1569,19 @@ test "big.int sub sign" { const neg_two = try Int.initSet(al, -2); try a.sub(one, two); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); try a.sub(neg_one, two); - debug.assert((try a.to(i32)) == -3); + testing.expect((try a.to(i32)) == -3); try a.sub(one, neg_two); - debug.assert((try a.to(i32)) == 3); + testing.expect((try a.to(i32)) == 3); try a.sub(neg_one, neg_two); - debug.assert((try a.to(i32)) == 1); + testing.expect((try a.to(i32)) == 1); try a.sub(neg_two, neg_one); - debug.assert((try a.to(i32)) == -1); + testing.expect((try a.to(i32)) == -1); } test "big.int mul single-single" { @@ -1598,7 +1591,7 @@ test "big.int mul single-single" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u64)) == 250); + testing.expect((try c.to(u64)) == 250); } test "big.int mul multi-single" { @@ -1608,7 +1601,7 @@ test "big.int mul multi-single" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try c.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul multi-multi" { @@ -1620,7 +1613,7 @@ test "big.int mul multi-multi" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u256)) == op1 * op2); + testing.expect((try c.to(u256)) == op1 * op2); } test "big.int mul alias r with a" { @@ -1629,7 +1622,7 @@ test "big.int mul alias r with a" { try a.mul(a, b); - debug.assert((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul alias r with b" { @@ -1638,7 +1631,7 @@ test "big.int mul alias r with b" { try a.mul(b, a); - debug.assert((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == 2 * maxInt(Limb)); } test "big.int mul alias r with a and b" { @@ -1646,7 +1639,7 @@ test "big.int mul alias r with a and b" { try a.mul(a, a); - debug.assert((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == maxInt(Limb) * maxInt(Limb)); } test "big.int mul a*0" { @@ -1656,7 +1649,7 @@ test "big.int mul a*0" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int mul 0*0" { @@ -1666,7 +1659,7 @@ test "big.int mul 0*0" { var c = try Int.init(al); try c.mul(a, b); - debug.assert((try c.to(u32)) == 0); + testing.expect((try c.to(u32)) == 0); } test "big.int div single-single no rem" { @@ -1677,8 +1670,8 @@ test "big.int div single-single no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u32)) == 10); - debug.assert((try r.to(u32)) == 0); + testing.expect((try q.to(u32)) == 10); + testing.expect((try r.to(u32)) == 0); } test "big.int div single-single with rem" { @@ -1689,8 +1682,8 @@ test "big.int div single-single with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u32)) == 9); - debug.assert((try r.to(u32)) == 4); + testing.expect((try q.to(u32)) == 9); + testing.expect((try r.to(u32)) == 4); } test "big.int div multi-single no rem" { @@ -1704,8 +1697,8 @@ test "big.int div multi-single no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == op1 / op2); - debug.assert((try r.to(u64)) == 0); + testing.expect((try q.to(u64)) == op1 / op2); + testing.expect((try r.to(u64)) == 0); } test "big.int div multi-single with rem" { @@ -1719,8 +1712,8 @@ test "big.int div multi-single with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == op1 / op2); - debug.assert((try r.to(u64)) == 3); + testing.expect((try q.to(u64)) == op1 / op2); + testing.expect((try r.to(u64)) == 3); } test "big.int div multi>2-single" { @@ -1734,8 +1727,8 @@ test "big.int div multi>2-single" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == op1 / op2); - debug.assert((try r.to(u32)) == 0x3e4e); + testing.expect((try q.to(u128)) == op1 / op2); + testing.expect((try r.to(u32)) == 0x3e4e); } test "big.int div single-single q < r" { @@ -1746,8 +1739,8 @@ test "big.int div single-single q < r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == 0); - debug.assert((try r.to(u64)) == 0x0078f432); + testing.expect((try q.to(u64)) == 0); + testing.expect((try r.to(u64)) == 0x0078f432); } test "big.int div single-single q == r" { @@ -1758,8 +1751,8 @@ test "big.int div single-single q == r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u64)) == 1); - debug.assert((try r.to(u64)) == 0); + testing.expect((try q.to(u64)) == 1); + testing.expect((try r.to(u64)) == 0); } test "big.int div q=0 alias" { @@ -1768,8 +1761,8 @@ test "big.int div q=0 alias" { try Int.divTrunc(&a, &b, a, b); - debug.assert((try a.to(u64)) == 0); - debug.assert((try b.to(u64)) == 3); + testing.expect((try a.to(u64)) == 0); + testing.expect((try b.to(u64)) == 3); } test "big.int div multi-multi q < r" { @@ -1782,8 +1775,8 @@ test "big.int div multi-multi q < r" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0); - debug.assert((try r.to(u128)) == op1); + testing.expect((try q.to(u128)) == 0); + testing.expect((try r.to(u128)) == op1); } test "big.int div trunc single-single +/+" { @@ -1802,8 +1795,8 @@ test "big.int div trunc single-single +/+" { const eq = @divTrunc(u, v); const er = @mod(u, v); - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single -/+" { @@ -1822,8 +1815,8 @@ test "big.int div trunc single-single -/+" { const eq = -1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single +/-" { @@ -1842,8 +1835,8 @@ test "big.int div trunc single-single +/-" { const eq = -1; const er = 2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div trunc single-single -/-" { @@ -1862,8 +1855,8 @@ test "big.int div trunc single-single -/-" { const eq = 1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single +/+" { @@ -1882,8 +1875,8 @@ test "big.int div floor single-single +/+" { const eq = 1; const er = 2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single -/+" { @@ -1902,8 +1895,8 @@ test "big.int div floor single-single -/+" { const eq = -2; const er = 1; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single +/-" { @@ -1922,8 +1915,8 @@ test "big.int div floor single-single +/-" { const eq = -2; const er = -1; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div floor single-single -/-" { @@ -1942,8 +1935,8 @@ test "big.int div floor single-single -/-" { const eq = 1; const er = -2; - debug.assert((try q.to(i32)) == eq); - debug.assert((try r.to(i32)) == er); + testing.expect((try q.to(i32)) == eq); + testing.expect((try r.to(i32)) == er); } test "big.int div multi-multi with rem" { @@ -1954,8 +1947,8 @@ test "big.int div multi-multi with rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); - debug.assert((try r.to(u128)) == 0x28de0acacd806823638); + testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); + testing.expect((try r.to(u128)) == 0x28de0acacd806823638); } test "big.int div multi-multi no rem" { @@ -1966,8 +1959,8 @@ test "big.int div multi-multi no rem" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); - debug.assert((try r.to(u128)) == 0); + testing.expect((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b); + testing.expect((try r.to(u128)) == 0); } test "big.int div multi-multi (2 branch)" { @@ -1978,8 +1971,8 @@ test "big.int div multi-multi (2 branch)" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0x10000000000000000); - debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111); + testing.expect((try q.to(u128)) == 0x10000000000000000); + testing.expect((try r.to(u128)) == 0x44444443444444431111111111111111); } test "big.int div multi-multi (3.1/3.3 branch)" { @@ -1990,53 +1983,53 @@ test "big.int div multi-multi (3.1/3.3 branch)" { var r = try Int.init(al); try Int.divTrunc(&q, &r, a, b); - debug.assert((try q.to(u128)) == 0xfffffffffffffffffff); - debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); + testing.expect((try q.to(u128)) == 0xfffffffffffffffffff); + testing.expect((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282); } test "big.int shift-right single" { var a = try Int.initSet(al, 0xffff0000); try a.shiftRight(a, 16); - debug.assert((try a.to(u32)) == 0xffff); + testing.expect((try a.to(u32)) == 0xffff); } test "big.int shift-right multi" { var a = try Int.initSet(al, 0xffff0000eeee1111dddd2222cccc3333); try a.shiftRight(a, 67); - debug.assert((try a.to(u64)) == 0x1fffe0001dddc222); + testing.expect((try a.to(u64)) == 0x1fffe0001dddc222); } test "big.int shift-left single" { var a = try Int.initSet(al, 0xffff); try a.shiftLeft(a, 16); - debug.assert((try a.to(u64)) == 0xffff0000); + testing.expect((try a.to(u64)) == 0xffff0000); } test "big.int shift-left multi" { var a = try Int.initSet(al, 0x1fffe0001dddc222); try a.shiftLeft(a, 67); - debug.assert((try a.to(u128)) == 0xffff0000eeee11100000000000000000); + testing.expect((try a.to(u128)) == 0xffff0000eeee11100000000000000000); } test "big.int shift-right negative" { var a = try Int.init(al); try a.shiftRight(try Int.initSet(al, -20), 2); - debug.assert((try a.to(i32)) == -20 >> 2); + testing.expect((try a.to(i32)) == -20 >> 2); try a.shiftRight(try Int.initSet(al, -5), 10); - debug.assert((try a.to(i32)) == -5 >> 10); + testing.expect((try a.to(i32)) == -5 >> 10); } test "big.int shift-left negative" { var a = try Int.init(al); try a.shiftRight(try Int.initSet(al, -10), 1232); - debug.assert((try a.to(i32)) == -10 >> 1232); + testing.expect((try a.to(i32)) == -10 >> 1232); } test "big.int bitwise and simple" { @@ -2045,7 +2038,7 @@ test "big.int bitwise and simple" { try a.bitAnd(a, b); - debug.assert((try a.to(u64)) == 0xeeeeeeee00000000); + testing.expect((try a.to(u64)) == 0xeeeeeeee00000000); } test "big.int bitwise and multi-limb" { @@ -2054,7 +2047,7 @@ test "big.int bitwise and multi-limb" { try a.bitAnd(a, b); - debug.assert((try a.to(u128)) == 0); + testing.expect((try a.to(u128)) == 0); } test "big.int bitwise xor simple" { @@ -2063,7 +2056,7 @@ test "big.int bitwise xor simple" { try a.bitXor(a, b); - debug.assert((try a.to(u64)) == 0x1111111133333333); + testing.expect((try a.to(u64)) == 0x1111111133333333); } test "big.int bitwise xor multi-limb" { @@ -2072,7 +2065,7 @@ test "big.int bitwise xor multi-limb" { try a.bitXor(a, b); - debug.assert((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) ^ maxInt(Limb)); } test "big.int bitwise or simple" { @@ -2081,7 +2074,7 @@ test "big.int bitwise or simple" { try a.bitOr(a, b); - debug.assert((try a.to(u64)) == 0xffffffff33333333); + testing.expect((try a.to(u64)) == 0xffffffff33333333); } test "big.int bitwise or multi-limb" { @@ -2091,15 +2084,15 @@ test "big.int bitwise or multi-limb" { try a.bitOr(a, b); // TODO: big.int.cpp or is wrong on multi-limb. - debug.assert((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); + testing.expect((try a.to(DoubleLimb)) == (maxInt(Limb) + 1) + maxInt(Limb)); } test "big.int var args" { var a = try Int.initSet(al, 5); try a.add(a, try Int.initSet(al, 6)); - debug.assert((try a.to(u64)) == 11); + testing.expect((try a.to(u64)) == 11); - debug.assert(a.cmp(try Int.initSet(al, 11)) == 0); - debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0); + testing.expect(a.cmp(try Int.initSet(al, 11)) == 0); + testing.expect(a.cmp(try Int.initSet(al, 14)) <= 0); } diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig index c067c5155a..957e026af4 100644 --- a/std/math/cbrt.zig +++ b/std/math/cbrt.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn cbrt(x: var) @typeOf(x) { const T = @typeOf(x); @@ -114,44 +114,44 @@ fn cbrt64(x: f64) f64 { } test "math.cbrt" { - assert(cbrt(f32(0.0)) == cbrt32(0.0)); - assert(cbrt(f64(0.0)) == cbrt64(0.0)); + expect(cbrt(f32(0.0)) == cbrt32(0.0)); + expect(cbrt(f64(0.0)) == cbrt64(0.0)); } test "math.cbrt32" { const epsilon = 0.000001; - assert(cbrt32(0.0) == 0.0); - assert(math.approxEq(f32, cbrt32(0.2), 0.584804, epsilon)); - assert(math.approxEq(f32, cbrt32(0.8923), 0.962728, epsilon)); - assert(math.approxEq(f32, cbrt32(1.5), 1.144714, epsilon)); - assert(math.approxEq(f32, cbrt32(37.45), 3.345676, epsilon)); - assert(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon)); + expect(cbrt32(0.0) == 0.0); + expect(math.approxEq(f32, cbrt32(0.2), 0.584804, epsilon)); + expect(math.approxEq(f32, cbrt32(0.8923), 0.962728, epsilon)); + expect(math.approxEq(f32, cbrt32(1.5), 1.144714, epsilon)); + expect(math.approxEq(f32, cbrt32(37.45), 3.345676, epsilon)); + expect(math.approxEq(f32, cbrt32(123123.234375), 49.748501, epsilon)); } test "math.cbrt64" { const epsilon = 0.000001; - assert(cbrt64(0.0) == 0.0); - assert(math.approxEq(f64, cbrt64(0.2), 0.584804, epsilon)); - assert(math.approxEq(f64, cbrt64(0.8923), 0.962728, epsilon)); - assert(math.approxEq(f64, cbrt64(1.5), 1.144714, epsilon)); - assert(math.approxEq(f64, cbrt64(37.45), 3.345676, epsilon)); - assert(math.approxEq(f64, cbrt64(123123.234375), 49.748501, epsilon)); + expect(cbrt64(0.0) == 0.0); + expect(math.approxEq(f64, cbrt64(0.2), 0.584804, epsilon)); + expect(math.approxEq(f64, cbrt64(0.8923), 0.962728, epsilon)); + expect(math.approxEq(f64, cbrt64(1.5), 1.144714, epsilon)); + expect(math.approxEq(f64, cbrt64(37.45), 3.345676, epsilon)); + expect(math.approxEq(f64, cbrt64(123123.234375), 49.748501, epsilon)); } test "math.cbrt.special" { - assert(cbrt32(0.0) == 0.0); - assert(cbrt32(-0.0) == -0.0); - assert(math.isPositiveInf(cbrt32(math.inf(f32)))); - assert(math.isNegativeInf(cbrt32(-math.inf(f32)))); - assert(math.isNan(cbrt32(math.nan(f32)))); + expect(cbrt32(0.0) == 0.0); + expect(cbrt32(-0.0) == -0.0); + expect(math.isPositiveInf(cbrt32(math.inf(f32)))); + expect(math.isNegativeInf(cbrt32(-math.inf(f32)))); + expect(math.isNan(cbrt32(math.nan(f32)))); } test "math.cbrt64.special" { - assert(cbrt64(0.0) == 0.0); - assert(cbrt64(-0.0) == -0.0); - assert(math.isPositiveInf(cbrt64(math.inf(f64)))); - assert(math.isNegativeInf(cbrt64(-math.inf(f64)))); - assert(math.isNan(cbrt64(math.nan(f64)))); + expect(cbrt64(0.0) == 0.0); + expect(cbrt64(-0.0) == -0.0); + expect(math.isPositiveInf(cbrt64(math.inf(f64)))); + expect(math.isNegativeInf(cbrt64(-math.inf(f64)))); + expect(math.isNan(cbrt64(math.nan(f64)))); } diff --git a/std/math/ceil.zig b/std/math/ceil.zig index 8a5221d862..5c6b98b2ca 100644 --- a/std/math/ceil.zig +++ b/std/math/ceil.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn ceil(x: var) @typeOf(x) { const T = @typeOf(x); @@ -81,34 +81,34 @@ fn ceil64(x: f64) f64 { } test "math.ceil" { - assert(ceil(f32(0.0)) == ceil32(0.0)); - assert(ceil(f64(0.0)) == ceil64(0.0)); + expect(ceil(f32(0.0)) == ceil32(0.0)); + expect(ceil(f64(0.0)) == ceil64(0.0)); } test "math.ceil32" { - assert(ceil32(1.3) == 2.0); - assert(ceil32(-1.3) == -1.0); - assert(ceil32(0.2) == 1.0); + expect(ceil32(1.3) == 2.0); + expect(ceil32(-1.3) == -1.0); + expect(ceil32(0.2) == 1.0); } test "math.ceil64" { - assert(ceil64(1.3) == 2.0); - assert(ceil64(-1.3) == -1.0); - assert(ceil64(0.2) == 1.0); + expect(ceil64(1.3) == 2.0); + expect(ceil64(-1.3) == -1.0); + expect(ceil64(0.2) == 1.0); } test "math.ceil32.special" { - assert(ceil32(0.0) == 0.0); - assert(ceil32(-0.0) == -0.0); - assert(math.isPositiveInf(ceil32(math.inf(f32)))); - assert(math.isNegativeInf(ceil32(-math.inf(f32)))); - assert(math.isNan(ceil32(math.nan(f32)))); + expect(ceil32(0.0) == 0.0); + expect(ceil32(-0.0) == -0.0); + expect(math.isPositiveInf(ceil32(math.inf(f32)))); + expect(math.isNegativeInf(ceil32(-math.inf(f32)))); + expect(math.isNan(ceil32(math.nan(f32)))); } test "math.ceil64.special" { - assert(ceil64(0.0) == 0.0); - assert(ceil64(-0.0) == -0.0); - assert(math.isPositiveInf(ceil64(math.inf(f64)))); - assert(math.isNegativeInf(ceil64(-math.inf(f64)))); - assert(math.isNan(ceil64(math.nan(f64)))); + expect(ceil64(0.0) == 0.0); + expect(ceil64(-0.0) == -0.0); + expect(math.isPositiveInf(ceil64(math.inf(f64)))); + expect(math.isNegativeInf(ceil64(-math.inf(f64)))); + expect(math.isNan(ceil64(math.nan(f64)))); } diff --git a/std/math/complex/abs.zig b/std/math/complex/abs.zig index 4cd095c46b..245d67d4c5 100644 --- a/std/math/complex/abs.zig +++ b/std/math/complex/abs.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -14,5 +14,5 @@ const epsilon = 0.0001; test "complex.cabs" { const a = Complex(f32).new(5, 3); const c = abs(a); - debug.assert(math.approxEq(f32, c, 5.83095, epsilon)); + testing.expect(math.approxEq(f32, c, 5.83095, epsilon)); } diff --git a/std/math/complex/acos.zig b/std/math/complex/acos.zig index a5760b4ace..1b314bc31a 100644 --- a/std/math/complex/acos.zig +++ b/std/math/complex/acos.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.cacos" { const a = Complex(f32).new(5, 3); const c = acos(a); - debug.assert(math.approxEq(f32, c.re, 0.546975, epsilon)); - debug.assert(math.approxEq(f32, c.im, -2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.546975, epsilon)); + testing.expect(math.approxEq(f32, c.im, -2.452914, epsilon)); } diff --git a/std/math/complex/acosh.zig b/std/math/complex/acosh.zig index 8dd91b2836..0e4c0121f4 100644 --- a/std/math/complex/acosh.zig +++ b/std/math/complex/acosh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.cacosh" { const a = Complex(f32).new(5, 3); const c = acosh(a); - debug.assert(math.approxEq(f32, c.re, 2.452914, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.546975, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.546975, epsilon)); } diff --git a/std/math/complex/arg.zig b/std/math/complex/arg.zig index f24512ac73..be117a5940 100644 --- a/std/math/complex/arg.zig +++ b/std/math/complex/arg.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -14,5 +14,5 @@ const epsilon = 0.0001; test "complex.carg" { const a = Complex(f32).new(5, 3); const c = arg(a); - debug.assert(math.approxEq(f32, c, 0.540420, epsilon)); + testing.expect(math.approxEq(f32, c, 0.540420, epsilon)); } diff --git a/std/math/complex/asin.zig b/std/math/complex/asin.zig index 584a3a1a9b..cf802ea206 100644 --- a/std/math/complex/asin.zig +++ b/std/math/complex/asin.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -22,6 +22,6 @@ test "complex.casin" { const a = Complex(f32).new(5, 3); const c = asin(a); - debug.assert(math.approxEq(f32, c.re, 1.023822, epsilon)); - debug.assert(math.approxEq(f32, c.im, 2.452914, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.023822, epsilon)); + testing.expect(math.approxEq(f32, c.im, 2.452914, epsilon)); } diff --git a/std/math/complex/asinh.zig b/std/math/complex/asinh.zig index 0c4dc2b6e4..0386a636b0 100644 --- a/std/math/complex/asinh.zig +++ b/std/math/complex/asinh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.casinh" { const a = Complex(f32).new(5, 3); const c = asinh(a); - debug.assert(math.approxEq(f32, c.re, 2.459831, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.533999, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.459831, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.533999, epsilon)); } diff --git a/std/math/complex/atan.zig b/std/math/complex/atan.zig index de60f2546d..8e60e58e43 100644 --- a/std/math/complex/atan.zig +++ b/std/math/complex/atan.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -117,14 +117,14 @@ test "complex.catan32" { const a = Complex(f32).new(5, 3); const c = atan(a); - debug.assert(math.approxEq(f32, c.re, 1.423679, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.086569, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.423679, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.086569, epsilon)); } test "complex.catan64" { const a = Complex(f64).new(5, 3); const c = atan(a); - debug.assert(math.approxEq(f64, c.re, 1.423679, epsilon)); - debug.assert(math.approxEq(f64, c.im, 0.086569, epsilon)); + testing.expect(math.approxEq(f64, c.re, 1.423679, epsilon)); + testing.expect(math.approxEq(f64, c.im, 0.086569, epsilon)); } diff --git a/std/math/complex/atanh.zig b/std/math/complex/atanh.zig index f70c741765..5b18fe1992 100644 --- a/std/math/complex/atanh.zig +++ b/std/math/complex/atanh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.catanh" { const a = Complex(f32).new(5, 3); const c = atanh(a); - debug.assert(math.approxEq(f32, c.re, 0.146947, epsilon)); - debug.assert(math.approxEq(f32, c.im, 1.480870, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.146947, epsilon)); + testing.expect(math.approxEq(f32, c.im, 1.480870, epsilon)); } diff --git a/std/math/complex/conj.zig b/std/math/complex/conj.zig index ad3e8b5036..143543f9e7 100644 --- a/std/math/complex/conj.zig +++ b/std/math/complex/conj.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -13,5 +13,5 @@ test "complex.conj" { const a = Complex(f32).new(5, 3); const c = a.conjugate(); - debug.assert(c.re == 5 and c.im == -3); + testing.expect(c.re == 5 and c.im == -3); } diff --git a/std/math/complex/cos.zig b/std/math/complex/cos.zig index 96e4ffcdb0..658d19c3b6 100644 --- a/std/math/complex/cos.zig +++ b/std/math/complex/cos.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -16,6 +16,6 @@ test "complex.ccos" { const a = Complex(f32).new(5, 3); const c = cos(a); - debug.assert(math.approxEq(f32, c.re, 2.855815, epsilon)); - debug.assert(math.approxEq(f32, c.im, 9.606383, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.855815, epsilon)); + testing.expect(math.approxEq(f32, c.im, 9.606383, epsilon)); } diff --git a/std/math/complex/cosh.zig b/std/math/complex/cosh.zig index 91875a0c47..5ce10b03f8 100644 --- a/std/math/complex/cosh.zig +++ b/std/math/complex/cosh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -152,14 +152,14 @@ test "complex.ccosh32" { const a = Complex(f32).new(5, 3); const c = cosh(a); - debug.assert(math.approxEq(f32, c.re, -73.467300, epsilon)); - debug.assert(math.approxEq(f32, c.im, 10.471557, epsilon)); + testing.expect(math.approxEq(f32, c.re, -73.467300, epsilon)); + testing.expect(math.approxEq(f32, c.im, 10.471557, epsilon)); } test "complex.ccosh64" { const a = Complex(f64).new(5, 3); const c = cosh(a); - debug.assert(math.approxEq(f64, c.re, -73.467300, epsilon)); - debug.assert(math.approxEq(f64, c.im, 10.471557, epsilon)); + testing.expect(math.approxEq(f64, c.re, -73.467300, epsilon)); + testing.expect(math.approxEq(f64, c.im, 10.471557, epsilon)); } diff --git a/std/math/complex/exp.zig b/std/math/complex/exp.zig index 0473f653b6..9ded698d08 100644 --- a/std/math/complex/exp.zig +++ b/std/math/complex/exp.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -118,14 +118,14 @@ test "complex.cexp32" { const a = Complex(f32).new(5, 3); const c = exp(a); - debug.assert(math.approxEq(f32, c.re, -146.927917, epsilon)); - debug.assert(math.approxEq(f32, c.im, 20.944065, epsilon)); + testing.expect(math.approxEq(f32, c.re, -146.927917, epsilon)); + testing.expect(math.approxEq(f32, c.im, 20.944065, epsilon)); } test "complex.cexp64" { const a = Complex(f64).new(5, 3); const c = exp(a); - debug.assert(math.approxEq(f64, c.re, -146.927917, epsilon)); - debug.assert(math.approxEq(f64, c.im, 20.944065, epsilon)); + testing.expect(math.approxEq(f64, c.re, -146.927917, epsilon)); + testing.expect(math.approxEq(f64, c.im, 20.944065, epsilon)); } diff --git a/std/math/complex/index.zig b/std/math/complex/index.zig index 171c4c5829..ffbf14d83e 100644 --- a/std/math/complex/index.zig +++ b/std/math/complex/index.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; pub const abs = @import("abs.zig").abs; @@ -97,7 +97,7 @@ test "complex.add" { const b = Complex(f32).new(2, 7); const c = a.add(b); - debug.assert(c.re == 7 and c.im == 10); + testing.expect(c.re == 7 and c.im == 10); } test "complex.sub" { @@ -105,7 +105,7 @@ test "complex.sub" { const b = Complex(f32).new(2, 7); const c = a.sub(b); - debug.assert(c.re == 3 and c.im == -4); + testing.expect(c.re == 3 and c.im == -4); } test "complex.mul" { @@ -113,7 +113,7 @@ test "complex.mul" { const b = Complex(f32).new(2, 7); const c = a.mul(b); - debug.assert(c.re == -11 and c.im == 41); + testing.expect(c.re == -11 and c.im == 41); } test "complex.div" { @@ -121,7 +121,7 @@ test "complex.div" { const b = Complex(f32).new(2, 7); const c = a.div(b); - debug.assert(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and + testing.expect(math.approxEq(f32, c.re, f32(31) / 53, epsilon) and math.approxEq(f32, c.im, f32(-29) / 53, epsilon)); } @@ -129,14 +129,14 @@ test "complex.conjugate" { const a = Complex(f32).new(5, 3); const c = a.conjugate(); - debug.assert(c.re == 5 and c.im == -3); + testing.expect(c.re == 5 and c.im == -3); } test "complex.reciprocal" { const a = Complex(f32).new(5, 3); const c = a.reciprocal(); - debug.assert(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and + testing.expect(math.approxEq(f32, c.re, f32(5) / 34, epsilon) and math.approxEq(f32, c.im, f32(-3) / 34, epsilon)); } @@ -144,7 +144,7 @@ test "complex.magnitude" { const a = Complex(f32).new(5, 3); const c = a.magnitude(); - debug.assert(math.approxEq(f32, c, 5.83095, epsilon)); + testing.expect(math.approxEq(f32, c, 5.83095, epsilon)); } test "complex.cmath" { diff --git a/std/math/complex/log.zig b/std/math/complex/log.zig index a4a1d1664f..360bb7d21e 100644 --- a/std/math/complex/log.zig +++ b/std/math/complex/log.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -18,6 +18,6 @@ test "complex.clog" { const a = Complex(f32).new(5, 3); const c = log(a); - debug.assert(math.approxEq(f32, c.re, 1.763180, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.540419, epsilon)); + testing.expect(math.approxEq(f32, c.re, 1.763180, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.540419, epsilon)); } diff --git a/std/math/complex/pow.zig b/std/math/complex/pow.zig index edf68653b6..bd625626c8 100644 --- a/std/math/complex/pow.zig +++ b/std/math/complex/pow.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.cpow" { const b = Complex(f32).new(2.3, -1.3); const c = pow(Complex(f32), a, b); - debug.assert(math.approxEq(f32, c.re, 58.049110, epsilon)); - debug.assert(math.approxEq(f32, c.im, -101.003433, epsilon)); + testing.expect(math.approxEq(f32, c.re, 58.049110, epsilon)); + testing.expect(math.approxEq(f32, c.im, -101.003433, epsilon)); } diff --git a/std/math/complex/proj.zig b/std/math/complex/proj.zig index b6c4cc046e..d31006129e 100644 --- a/std/math/complex/proj.zig +++ b/std/math/complex/proj.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -20,5 +20,5 @@ test "complex.cproj" { const a = Complex(f32).new(5, 3); const c = proj(a); - debug.assert(c.re == 5 and c.im == 3); + testing.expect(c.re == 5 and c.im == 3); } diff --git a/std/math/complex/sin.zig b/std/math/complex/sin.zig index d32b771d3b..9d54ab0969 100644 --- a/std/math/complex/sin.zig +++ b/std/math/complex/sin.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.csin" { const a = Complex(f32).new(5, 3); const c = sin(a); - debug.assert(math.approxEq(f32, c.re, -9.654126, epsilon)); - debug.assert(math.approxEq(f32, c.im, 2.841692, epsilon)); + testing.expect(math.approxEq(f32, c.re, -9.654126, epsilon)); + testing.expect(math.approxEq(f32, c.im, 2.841692, epsilon)); } diff --git a/std/math/complex/sinh.zig b/std/math/complex/sinh.zig index dc19a0ba1b..469ea6067a 100644 --- a/std/math/complex/sinh.zig +++ b/std/math/complex/sinh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -151,14 +151,14 @@ test "complex.csinh32" { const a = Complex(f32).new(5, 3); const c = sinh(a); - debug.assert(math.approxEq(f32, c.re, -73.460617, epsilon)); - debug.assert(math.approxEq(f32, c.im, 10.472508, epsilon)); + testing.expect(math.approxEq(f32, c.re, -73.460617, epsilon)); + testing.expect(math.approxEq(f32, c.im, 10.472508, epsilon)); } test "complex.csinh64" { const a = Complex(f64).new(5, 3); const c = sinh(a); - debug.assert(math.approxEq(f64, c.re, -73.460617, epsilon)); - debug.assert(math.approxEq(f64, c.im, 10.472508, epsilon)); + testing.expect(math.approxEq(f64, c.re, -73.460617, epsilon)); + testing.expect(math.approxEq(f64, c.im, 10.472508, epsilon)); } diff --git a/std/math/complex/sqrt.zig b/std/math/complex/sqrt.zig index 47367816f7..60f6061baa 100644 --- a/std/math/complex/sqrt.zig +++ b/std/math/complex/sqrt.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -125,14 +125,14 @@ test "complex.csqrt32" { const a = Complex(f32).new(5, 3); const c = sqrt(a); - debug.assert(math.approxEq(f32, c.re, 2.327117, epsilon)); - debug.assert(math.approxEq(f32, c.im, 0.644574, epsilon)); + testing.expect(math.approxEq(f32, c.re, 2.327117, epsilon)); + testing.expect(math.approxEq(f32, c.im, 0.644574, epsilon)); } test "complex.csqrt64" { const a = Complex(f64).new(5, 3); const c = sqrt(a); - debug.assert(math.approxEq(f64, c.re, 2.3271175190399496, epsilon)); - debug.assert(math.approxEq(f64, c.im, 0.6445742373246469, epsilon)); + testing.expect(math.approxEq(f64, c.re, 2.3271175190399496, epsilon)); + testing.expect(math.approxEq(f64, c.im, 0.6445742373246469, epsilon)); } diff --git a/std/math/complex/tan.zig b/std/math/complex/tan.zig index 4ea5182fa7..db34580598 100644 --- a/std/math/complex/tan.zig +++ b/std/math/complex/tan.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -17,6 +17,6 @@ test "complex.ctan" { const a = Complex(f32).new(5, 3); const c = tan(a); - debug.assert(math.approxEq(f32, c.re, -0.002708233, epsilon)); - debug.assert(math.approxEq(f32, c.im, 1.004165, epsilon)); + testing.expect(math.approxEq(f32, c.re, -0.002708233, epsilon)); + testing.expect(math.approxEq(f32, c.im, 1.004165, epsilon)); } diff --git a/std/math/complex/tanh.zig b/std/math/complex/tanh.zig index e48d438783..03ab431312 100644 --- a/std/math/complex/tanh.zig +++ b/std/math/complex/tanh.zig @@ -1,5 +1,5 @@ const std = @import("../../index.zig"); -const debug = std.debug; +const testing = std.testing; const math = std.math; const cmath = math.complex; const Complex = cmath.Complex; @@ -100,14 +100,14 @@ test "complex.ctanh32" { const a = Complex(f32).new(5, 3); const c = tanh(a); - debug.assert(math.approxEq(f32, c.re, 0.999913, epsilon)); - debug.assert(math.approxEq(f32, c.im, -0.000025, epsilon)); + testing.expect(math.approxEq(f32, c.re, 0.999913, epsilon)); + testing.expect(math.approxEq(f32, c.im, -0.000025, epsilon)); } test "complex.ctanh64" { const a = Complex(f64).new(5, 3); const c = tanh(a); - debug.assert(math.approxEq(f64, c.re, 0.999913, epsilon)); - debug.assert(math.approxEq(f64, c.im, -0.000025, epsilon)); + testing.expect(math.approxEq(f64, c.re, 0.999913, epsilon)); + testing.expect(math.approxEq(f64, c.im, -0.000025, epsilon)); } diff --git a/std/math/copysign.zig b/std/math/copysign.zig index 4c6e333d6c..dbf8f6e1ef 100644 --- a/std/math/copysign.zig +++ b/std/math/copysign.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn copysign(comptime T: type, x: T, y: T) T { @@ -40,28 +40,28 @@ fn copysign64(x: f64, y: f64) f64 { } test "math.copysign" { - assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0)); - assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); - assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); + expect(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0)); + expect(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0)); + expect(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0)); } test "math.copysign16" { - assert(copysign16(5.0, 1.0) == 5.0); - assert(copysign16(5.0, -1.0) == -5.0); - assert(copysign16(-5.0, -1.0) == -5.0); - assert(copysign16(-5.0, 1.0) == 5.0); + expect(copysign16(5.0, 1.0) == 5.0); + expect(copysign16(5.0, -1.0) == -5.0); + expect(copysign16(-5.0, -1.0) == -5.0); + expect(copysign16(-5.0, 1.0) == 5.0); } test "math.copysign32" { - assert(copysign32(5.0, 1.0) == 5.0); - assert(copysign32(5.0, -1.0) == -5.0); - assert(copysign32(-5.0, -1.0) == -5.0); - assert(copysign32(-5.0, 1.0) == 5.0); + expect(copysign32(5.0, 1.0) == 5.0); + expect(copysign32(5.0, -1.0) == -5.0); + expect(copysign32(-5.0, -1.0) == -5.0); + expect(copysign32(-5.0, 1.0) == 5.0); } test "math.copysign64" { - assert(copysign64(5.0, 1.0) == 5.0); - assert(copysign64(5.0, -1.0) == -5.0); - assert(copysign64(-5.0, -1.0) == -5.0); - assert(copysign64(-5.0, 1.0) == 5.0); + expect(copysign64(5.0, 1.0) == 5.0); + expect(copysign64(5.0, -1.0) == -5.0); + expect(copysign64(-5.0, -1.0) == -5.0); + expect(copysign64(-5.0, 1.0) == 5.0); } diff --git a/std/math/cos.zig b/std/math/cos.zig index b6a2fbffe6..7783ddc09b 100644 --- a/std/math/cos.zig +++ b/std/math/cos.zig @@ -6,7 +6,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn cos(x: var) @typeOf(x) { const T = @typeOf(x); @@ -139,40 +139,40 @@ fn cos64(x_: f64) f64 { } test "math.cos" { - assert(cos(f32(0.0)) == cos32(0.0)); - assert(cos(f64(0.0)) == cos64(0.0)); + expect(cos(f32(0.0)) == cos32(0.0)); + expect(cos(f64(0.0)) == cos64(0.0)); } test "math.cos32" { const epsilon = 0.000001; - assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); - assert(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); - assert(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); - assert(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); - assert(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); - assert(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); + expect(math.approxEq(f32, cos32(0.0), 1.0, epsilon)); + expect(math.approxEq(f32, cos32(0.2), 0.980067, epsilon)); + expect(math.approxEq(f32, cos32(0.8923), 0.627623, epsilon)); + expect(math.approxEq(f32, cos32(1.5), 0.070737, epsilon)); + expect(math.approxEq(f32, cos32(37.45), 0.969132, epsilon)); + expect(math.approxEq(f32, cos32(89.123), 0.400798, epsilon)); } test "math.cos64" { const epsilon = 0.000001; - assert(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); - assert(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); - assert(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); - assert(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); - assert(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); - assert(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); + expect(math.approxEq(f64, cos64(0.0), 1.0, epsilon)); + expect(math.approxEq(f64, cos64(0.2), 0.980067, epsilon)); + expect(math.approxEq(f64, cos64(0.8923), 0.627623, epsilon)); + expect(math.approxEq(f64, cos64(1.5), 0.070737, epsilon)); + expect(math.approxEq(f64, cos64(37.45), 0.969132, epsilon)); + expect(math.approxEq(f64, cos64(89.123), 0.40080, epsilon)); } test "math.cos32.special" { - assert(math.isNan(cos32(math.inf(f32)))); - assert(math.isNan(cos32(-math.inf(f32)))); - assert(math.isNan(cos32(math.nan(f32)))); + expect(math.isNan(cos32(math.inf(f32)))); + expect(math.isNan(cos32(-math.inf(f32)))); + expect(math.isNan(cos32(math.nan(f32)))); } test "math.cos64.special" { - assert(math.isNan(cos64(math.inf(f64)))); - assert(math.isNan(cos64(-math.inf(f64)))); - assert(math.isNan(cos64(math.nan(f64)))); + expect(math.isNan(cos64(math.inf(f64)))); + expect(math.isNan(cos64(-math.inf(f64)))); + expect(math.isNan(cos64(math.nan(f64)))); } diff --git a/std/math/cosh.zig b/std/math/cosh.zig index 77e02855fd..57c5eef828 100644 --- a/std/math/cosh.zig +++ b/std/math/cosh.zig @@ -8,7 +8,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; const expo2 = @import("expo2.zig").expo2; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn cosh(x: var) @typeOf(x) { @@ -82,40 +82,40 @@ fn cosh64(x: f64) f64 { } test "math.cosh" { - assert(cosh(f32(1.5)) == cosh32(1.5)); - assert(cosh(f64(1.5)) == cosh64(1.5)); + expect(cosh(f32(1.5)) == cosh32(1.5)); + expect(cosh(f64(1.5)) == cosh64(1.5)); } test "math.cosh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, cosh32(0.0), 1.0, epsilon)); - assert(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon)); - assert(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon)); + expect(math.approxEq(f32, cosh32(0.0), 1.0, epsilon)); + expect(math.approxEq(f32, cosh32(0.2), 1.020067, epsilon)); + expect(math.approxEq(f32, cosh32(0.8923), 1.425225, epsilon)); + expect(math.approxEq(f32, cosh32(1.5), 2.352410, epsilon)); } test "math.cosh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, cosh64(0.0), 1.0, epsilon)); - assert(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon)); - assert(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon)); - assert(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon)); + expect(math.approxEq(f64, cosh64(0.0), 1.0, epsilon)); + expect(math.approxEq(f64, cosh64(0.2), 1.020067, epsilon)); + expect(math.approxEq(f64, cosh64(0.8923), 1.425225, epsilon)); + expect(math.approxEq(f64, cosh64(1.5), 2.352410, epsilon)); } test "math.cosh32.special" { - assert(cosh32(0.0) == 1.0); - assert(cosh32(-0.0) == 1.0); - assert(math.isPositiveInf(cosh32(math.inf(f32)))); - assert(math.isPositiveInf(cosh32(-math.inf(f32)))); - assert(math.isNan(cosh32(math.nan(f32)))); + expect(cosh32(0.0) == 1.0); + expect(cosh32(-0.0) == 1.0); + expect(math.isPositiveInf(cosh32(math.inf(f32)))); + expect(math.isPositiveInf(cosh32(-math.inf(f32)))); + expect(math.isNan(cosh32(math.nan(f32)))); } test "math.cosh64.special" { - assert(cosh64(0.0) == 1.0); - assert(cosh64(-0.0) == 1.0); - assert(math.isPositiveInf(cosh64(math.inf(f64)))); - assert(math.isPositiveInf(cosh64(-math.inf(f64)))); - assert(math.isNan(cosh64(math.nan(f64)))); + expect(cosh64(0.0) == 1.0); + expect(cosh64(-0.0) == 1.0); + expect(math.isPositiveInf(cosh64(math.inf(f64)))); + expect(math.isPositiveInf(cosh64(-math.inf(f64)))); + expect(math.isNan(cosh64(math.nan(f64)))); } diff --git a/std/math/exp2.zig b/std/math/exp2.zig index 3d8e5d692e..ba0001a09a 100644 --- a/std/math/exp2.zig +++ b/std/math/exp2.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn exp2(x: var) @typeOf(x) { const T = @typeOf(x); @@ -415,35 +415,35 @@ fn exp2_64(x: f64) f64 { } test "math.exp2" { - assert(exp2(f32(0.8923)) == exp2_32(0.8923)); - assert(exp2(f64(0.8923)) == exp2_64(0.8923)); + expect(exp2(f32(0.8923)) == exp2_32(0.8923)); + expect(exp2(f64(0.8923)) == exp2_64(0.8923)); } test "math.exp2_32" { const epsilon = 0.000001; - assert(exp2_32(0.0) == 1.0); - assert(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon)); - assert(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon)); - assert(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon)); + expect(exp2_32(0.0) == 1.0); + expect(math.approxEq(f32, exp2_32(0.2), 1.148698, epsilon)); + expect(math.approxEq(f32, exp2_32(0.8923), 1.856133, epsilon)); + expect(math.approxEq(f32, exp2_32(1.5), 2.828427, epsilon)); + expect(math.approxEq(f32, exp2_32(37.45), 187747237888, epsilon)); } test "math.exp2_64" { const epsilon = 0.000001; - assert(exp2_64(0.0) == 1.0); - assert(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon)); - assert(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon)); - assert(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon)); + expect(exp2_64(0.0) == 1.0); + expect(math.approxEq(f64, exp2_64(0.2), 1.148698, epsilon)); + expect(math.approxEq(f64, exp2_64(0.8923), 1.856133, epsilon)); + expect(math.approxEq(f64, exp2_64(1.5), 2.828427, epsilon)); } test "math.exp2_32.special" { - assert(math.isPositiveInf(exp2_32(math.inf(f32)))); - assert(math.isNan(exp2_32(math.nan(f32)))); + expect(math.isPositiveInf(exp2_32(math.inf(f32)))); + expect(math.isNan(exp2_32(math.nan(f32)))); } test "math.exp2_64.special" { - assert(math.isPositiveInf(exp2_64(math.inf(f64)))); - assert(math.isNan(exp2_64(math.nan(f64)))); + expect(math.isPositiveInf(exp2_64(math.inf(f64)))); + expect(math.isNan(exp2_64(math.nan(f64)))); } diff --git a/std/math/expm1.zig b/std/math/expm1.zig index 6729417f60..ba00ec2561 100644 --- a/std/math/expm1.zig +++ b/std/math/expm1.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn expm1(x: var) @typeOf(x) { const T = @typeOf(x); @@ -278,42 +278,42 @@ fn expm1_64(x_: f64) f64 { } test "math.exp1m" { - assert(expm1(f32(0.0)) == expm1_32(0.0)); - assert(expm1(f64(0.0)) == expm1_64(0.0)); + expect(expm1(f32(0.0)) == expm1_32(0.0)); + expect(expm1(f64(0.0)) == expm1_64(0.0)); } test "math.expm1_32" { const epsilon = 0.000001; - assert(expm1_32(0.0) == 0.0); - assert(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon)); - assert(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon)); + expect(expm1_32(0.0) == 0.0); + expect(math.approxEq(f32, expm1_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, expm1_32(0.2), 0.221403, epsilon)); + expect(math.approxEq(f32, expm1_32(0.8923), 1.440737, epsilon)); + expect(math.approxEq(f32, expm1_32(1.5), 3.481689, epsilon)); } test "math.expm1_64" { const epsilon = 0.000001; - assert(expm1_64(0.0) == 0.0); - assert(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon)); - assert(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon)); - assert(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon)); + expect(expm1_64(0.0) == 0.0); + expect(math.approxEq(f64, expm1_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, expm1_64(0.2), 0.221403, epsilon)); + expect(math.approxEq(f64, expm1_64(0.8923), 1.440737, epsilon)); + expect(math.approxEq(f64, expm1_64(1.5), 3.481689, epsilon)); } test "math.expm1_32.special" { const epsilon = 0.000001; - assert(math.isPositiveInf(expm1_32(math.inf(f32)))); - assert(expm1_32(-math.inf(f32)) == -1.0); - assert(math.isNan(expm1_32(math.nan(f32)))); + expect(math.isPositiveInf(expm1_32(math.inf(f32)))); + expect(expm1_32(-math.inf(f32)) == -1.0); + expect(math.isNan(expm1_32(math.nan(f32)))); } test "math.expm1_64.special" { const epsilon = 0.000001; - assert(math.isPositiveInf(expm1_64(math.inf(f64)))); - assert(expm1_64(-math.inf(f64)) == -1.0); - assert(math.isNan(expm1_64(math.nan(f64)))); + expect(math.isPositiveInf(expm1_64(math.inf(f64)))); + expect(expm1_64(-math.inf(f64)) == -1.0); + expect(math.isNan(expm1_64(math.nan(f64)))); } diff --git a/std/math/fabs.zig b/std/math/fabs.zig index 443010ac7f..9fad5644c3 100644 --- a/std/math/fabs.zig +++ b/std/math/fabs.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn fabs(x: var) @typeOf(x) { @@ -37,40 +37,40 @@ fn fabs64(x: f64) f64 { } test "math.fabs" { - assert(fabs(f16(1.0)) == fabs16(1.0)); - assert(fabs(f32(1.0)) == fabs32(1.0)); - assert(fabs(f64(1.0)) == fabs64(1.0)); + expect(fabs(f16(1.0)) == fabs16(1.0)); + expect(fabs(f32(1.0)) == fabs32(1.0)); + expect(fabs(f64(1.0)) == fabs64(1.0)); } test "math.fabs16" { - assert(fabs16(1.0) == 1.0); - assert(fabs16(-1.0) == 1.0); + expect(fabs16(1.0) == 1.0); + expect(fabs16(-1.0) == 1.0); } test "math.fabs32" { - assert(fabs32(1.0) == 1.0); - assert(fabs32(-1.0) == 1.0); + expect(fabs32(1.0) == 1.0); + expect(fabs32(-1.0) == 1.0); } test "math.fabs64" { - assert(fabs64(1.0) == 1.0); - assert(fabs64(-1.0) == 1.0); + expect(fabs64(1.0) == 1.0); + expect(fabs64(-1.0) == 1.0); } test "math.fabs16.special" { - assert(math.isPositiveInf(fabs(math.inf(f16)))); - assert(math.isPositiveInf(fabs(-math.inf(f16)))); - assert(math.isNan(fabs(math.nan(f16)))); + expect(math.isPositiveInf(fabs(math.inf(f16)))); + expect(math.isPositiveInf(fabs(-math.inf(f16)))); + expect(math.isNan(fabs(math.nan(f16)))); } test "math.fabs32.special" { - assert(math.isPositiveInf(fabs(math.inf(f32)))); - assert(math.isPositiveInf(fabs(-math.inf(f32)))); - assert(math.isNan(fabs(math.nan(f32)))); + expect(math.isPositiveInf(fabs(math.inf(f32)))); + expect(math.isPositiveInf(fabs(-math.inf(f32)))); + expect(math.isNan(fabs(math.nan(f32)))); } test "math.fabs64.special" { - assert(math.isPositiveInf(fabs(math.inf(f64)))); - assert(math.isPositiveInf(fabs(-math.inf(f64)))); - assert(math.isNan(fabs(math.nan(f64)))); + expect(math.isPositiveInf(fabs(math.inf(f64)))); + expect(math.isPositiveInf(fabs(-math.inf(f64)))); + expect(math.isNan(fabs(math.nan(f64)))); } diff --git a/std/math/floor.zig b/std/math/floor.zig index 6ce462b10f..c7c12e37ba 100644 --- a/std/math/floor.zig +++ b/std/math/floor.zig @@ -5,7 +5,7 @@ // - floor(nan) = nan const builtin = @import("builtin"); -const assert = std.debug.assert; +const expect = std.testing.expect; const std = @import("../index.zig"); const math = std.math; @@ -117,49 +117,49 @@ fn floor64(x: f64) f64 { } test "math.floor" { - assert(floor(f16(1.3)) == floor16(1.3)); - assert(floor(f32(1.3)) == floor32(1.3)); - assert(floor(f64(1.3)) == floor64(1.3)); + expect(floor(f16(1.3)) == floor16(1.3)); + expect(floor(f32(1.3)) == floor32(1.3)); + expect(floor(f64(1.3)) == floor64(1.3)); } test "math.floor16" { - assert(floor16(1.3) == 1.0); - assert(floor16(-1.3) == -2.0); - assert(floor16(0.2) == 0.0); + expect(floor16(1.3) == 1.0); + expect(floor16(-1.3) == -2.0); + expect(floor16(0.2) == 0.0); } test "math.floor32" { - assert(floor32(1.3) == 1.0); - assert(floor32(-1.3) == -2.0); - assert(floor32(0.2) == 0.0); + expect(floor32(1.3) == 1.0); + expect(floor32(-1.3) == -2.0); + expect(floor32(0.2) == 0.0); } test "math.floor64" { - assert(floor64(1.3) == 1.0); - assert(floor64(-1.3) == -2.0); - assert(floor64(0.2) == 0.0); + expect(floor64(1.3) == 1.0); + expect(floor64(-1.3) == -2.0); + expect(floor64(0.2) == 0.0); } test "math.floor16.special" { - assert(floor16(0.0) == 0.0); - assert(floor16(-0.0) == -0.0); - assert(math.isPositiveInf(floor16(math.inf(f16)))); - assert(math.isNegativeInf(floor16(-math.inf(f16)))); - assert(math.isNan(floor16(math.nan(f16)))); + expect(floor16(0.0) == 0.0); + expect(floor16(-0.0) == -0.0); + expect(math.isPositiveInf(floor16(math.inf(f16)))); + expect(math.isNegativeInf(floor16(-math.inf(f16)))); + expect(math.isNan(floor16(math.nan(f16)))); } test "math.floor32.special" { - assert(floor32(0.0) == 0.0); - assert(floor32(-0.0) == -0.0); - assert(math.isPositiveInf(floor32(math.inf(f32)))); - assert(math.isNegativeInf(floor32(-math.inf(f32)))); - assert(math.isNan(floor32(math.nan(f32)))); + expect(floor32(0.0) == 0.0); + expect(floor32(-0.0) == -0.0); + expect(math.isPositiveInf(floor32(math.inf(f32)))); + expect(math.isNegativeInf(floor32(-math.inf(f32)))); + expect(math.isNan(floor32(math.nan(f32)))); } test "math.floor64.special" { - assert(floor64(0.0) == 0.0); - assert(floor64(-0.0) == -0.0); - assert(math.isPositiveInf(floor64(math.inf(f64)))); - assert(math.isNegativeInf(floor64(-math.inf(f64)))); - assert(math.isNan(floor64(math.nan(f64)))); + expect(floor64(0.0) == 0.0); + expect(floor64(-0.0) == -0.0); + expect(math.isPositiveInf(floor64(math.inf(f64)))); + expect(math.isNegativeInf(floor64(-math.inf(f64)))); + expect(math.isNan(floor64(math.nan(f64)))); } diff --git a/std/math/fma.zig b/std/math/fma.zig index 21faf4118d..b084cf3cbd 100644 --- a/std/math/fma.zig +++ b/std/math/fma.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn fma(comptime T: type, x: T, y: T, z: T) T { return switch (T) { @@ -135,30 +135,30 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { } test "math.fma" { - assert(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); - assert(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); + expect(fma(f32, 0.0, 1.0, 1.0) == fma32(0.0, 1.0, 1.0)); + expect(fma(f64, 0.0, 1.0, 1.0) == fma64(0.0, 1.0, 1.0)); } test "math.fma32" { const epsilon = 0.000001; - assert(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); - assert(math.approxEq(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon)); - assert(math.approxEq(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon)); - assert(math.approxEq(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon)); - assert(math.approxEq(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon)); - assert(math.approxEq(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon)); - assert(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + expect(math.approxEq(f32, fma32(0.0, 5.0, 9.124), 9.124, epsilon)); + expect(math.approxEq(f32, fma32(0.2, 5.0, 9.124), 10.124, epsilon)); + expect(math.approxEq(f32, fma32(0.8923, 5.0, 9.124), 13.5855, epsilon)); + expect(math.approxEq(f32, fma32(1.5, 5.0, 9.124), 16.624, epsilon)); + expect(math.approxEq(f32, fma32(37.45, 5.0, 9.124), 196.374004, epsilon)); + expect(math.approxEq(f32, fma32(89.123, 5.0, 9.124), 454.739005, epsilon)); + expect(math.approxEq(f32, fma32(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } test "math.fma64" { const epsilon = 0.000001; - assert(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); - assert(math.approxEq(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon)); - assert(math.approxEq(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon)); - assert(math.approxEq(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon)); - assert(math.approxEq(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon)); - assert(math.approxEq(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon)); - assert(math.approxEq(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); + expect(math.approxEq(f64, fma64(0.0, 5.0, 9.124), 9.124, epsilon)); + expect(math.approxEq(f64, fma64(0.2, 5.0, 9.124), 10.124, epsilon)); + expect(math.approxEq(f64, fma64(0.8923, 5.0, 9.124), 13.5855, epsilon)); + expect(math.approxEq(f64, fma64(1.5, 5.0, 9.124), 16.624, epsilon)); + expect(math.approxEq(f64, fma64(37.45, 5.0, 9.124), 196.374, epsilon)); + expect(math.approxEq(f64, fma64(89.123, 5.0, 9.124), 454.739, epsilon)); + expect(math.approxEq(f64, fma64(123123.234375, 5.0, 9.124), 615625.295875, epsilon)); } diff --git a/std/math/frexp.zig b/std/math/frexp.zig index dfc790fdd9..35f3e081a9 100644 --- a/std/math/frexp.zig +++ b/std/math/frexp.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; fn frexp_result(comptime T: type) type { return struct { @@ -103,11 +103,11 @@ fn frexp64(x: f64) frexp64_result { test "math.frexp" { const a = frexp(f32(1.3)); const b = frexp32(1.3); - assert(a.significand == b.significand and a.exponent == b.exponent); + expect(a.significand == b.significand and a.exponent == b.exponent); const c = frexp(f64(1.3)); const d = frexp64(1.3); - assert(c.significand == d.significand and c.exponent == d.exponent); + expect(c.significand == d.significand and c.exponent == d.exponent); } test "math.frexp32" { @@ -115,10 +115,10 @@ test "math.frexp32" { var r: frexp32_result = undefined; r = frexp32(1.3); - assert(math.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1); + expect(math.approxEq(f32, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp32(78.0234); - assert(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); + expect(math.approxEq(f32, r.significand, 0.609558, epsilon) and r.exponent == 7); } test "math.frexp64" { @@ -126,46 +126,46 @@ test "math.frexp64" { var r: frexp64_result = undefined; r = frexp64(1.3); - assert(math.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1); + expect(math.approxEq(f64, r.significand, 0.65, epsilon) and r.exponent == 1); r = frexp64(78.0234); - assert(math.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7); + expect(math.approxEq(f64, r.significand, 0.609558, epsilon) and r.exponent == 7); } test "math.frexp32.special" { var r: frexp32_result = undefined; r = frexp32(0.0); - assert(r.significand == 0.0 and r.exponent == 0); + expect(r.significand == 0.0 and r.exponent == 0); r = frexp32(-0.0); - assert(r.significand == -0.0 and r.exponent == 0); + expect(r.significand == -0.0 and r.exponent == 0); r = frexp32(math.inf(f32)); - assert(math.isPositiveInf(r.significand) and r.exponent == 0); + expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp32(-math.inf(f32)); - assert(math.isNegativeInf(r.significand) and r.exponent == 0); + expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp32(math.nan(f32)); - assert(math.isNan(r.significand)); + expect(math.isNan(r.significand)); } test "math.frexp64.special" { var r: frexp64_result = undefined; r = frexp64(0.0); - assert(r.significand == 0.0 and r.exponent == 0); + expect(r.significand == 0.0 and r.exponent == 0); r = frexp64(-0.0); - assert(r.significand == -0.0 and r.exponent == 0); + expect(r.significand == -0.0 and r.exponent == 0); r = frexp64(math.inf(f64)); - assert(math.isPositiveInf(r.significand) and r.exponent == 0); + expect(math.isPositiveInf(r.significand) and r.exponent == 0); r = frexp64(-math.inf(f64)); - assert(math.isNegativeInf(r.significand) and r.exponent == 0); + expect(math.isNegativeInf(r.significand) and r.exponent == 0); r = frexp64(math.nan(f64)); - assert(math.isNan(r.significand)); + expect(math.isNan(r.significand)); } diff --git a/std/math/hypot.zig b/std/math/hypot.zig index a63657a621..dea11e0a61 100644 --- a/std/math/hypot.zig +++ b/std/math/hypot.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn hypot(comptime T: type, x: T, y: T) T { @@ -115,48 +115,48 @@ fn hypot64(x: f64, y: f64) f64 { } test "math.hypot" { - assert(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2)); - assert(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2)); + expect(hypot(f32, 0.0, -1.2) == hypot32(0.0, -1.2)); + expect(hypot(f64, 0.0, -1.2) == hypot64(0.0, -1.2)); } test "math.hypot32" { const epsilon = 0.000001; - assert(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon)); - assert(math.approxEq(f32, hypot32(0.2, -0.34), 0.394462, epsilon)); - assert(math.approxEq(f32, hypot32(0.8923, 2.636890), 2.783772, epsilon)); - assert(math.approxEq(f32, hypot32(1.5, 5.25), 5.460083, epsilon)); - assert(math.approxEq(f32, hypot32(37.45, 159.835), 164.163742, epsilon)); - assert(math.approxEq(f32, hypot32(89.123, 382.028905), 392.286865, epsilon)); - assert(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon)); + expect(math.approxEq(f32, hypot32(0.0, -1.2), 1.2, epsilon)); + expect(math.approxEq(f32, hypot32(0.2, -0.34), 0.394462, epsilon)); + expect(math.approxEq(f32, hypot32(0.8923, 2.636890), 2.783772, epsilon)); + expect(math.approxEq(f32, hypot32(1.5, 5.25), 5.460083, epsilon)); + expect(math.approxEq(f32, hypot32(37.45, 159.835), 164.163742, epsilon)); + expect(math.approxEq(f32, hypot32(89.123, 382.028905), 392.286865, epsilon)); + expect(math.approxEq(f32, hypot32(123123.234375, 529428.707813), 543556.875, epsilon)); } test "math.hypot64" { const epsilon = 0.000001; - assert(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon)); - assert(math.approxEq(f64, hypot64(0.2, -0.34), 0.394462, epsilon)); - assert(math.approxEq(f64, hypot64(0.8923, 2.636890), 2.783772, epsilon)); - assert(math.approxEq(f64, hypot64(1.5, 5.25), 5.460082, epsilon)); - assert(math.approxEq(f64, hypot64(37.45, 159.835), 164.163728, epsilon)); - assert(math.approxEq(f64, hypot64(89.123, 382.028905), 392.286876, epsilon)); - assert(math.approxEq(f64, hypot64(123123.234375, 529428.707813), 543556.885247, epsilon)); + expect(math.approxEq(f64, hypot64(0.0, -1.2), 1.2, epsilon)); + expect(math.approxEq(f64, hypot64(0.2, -0.34), 0.394462, epsilon)); + expect(math.approxEq(f64, hypot64(0.8923, 2.636890), 2.783772, epsilon)); + expect(math.approxEq(f64, hypot64(1.5, 5.25), 5.460082, epsilon)); + expect(math.approxEq(f64, hypot64(37.45, 159.835), 164.163728, epsilon)); + expect(math.approxEq(f64, hypot64(89.123, 382.028905), 392.286876, epsilon)); + expect(math.approxEq(f64, hypot64(123123.234375, 529428.707813), 543556.885247, epsilon)); } test "math.hypot32.special" { - assert(math.isPositiveInf(hypot32(math.inf(f32), 0.0))); - assert(math.isPositiveInf(hypot32(-math.inf(f32), 0.0))); - assert(math.isPositiveInf(hypot32(0.0, math.inf(f32)))); - assert(math.isPositiveInf(hypot32(0.0, -math.inf(f32)))); - assert(math.isNan(hypot32(math.nan(f32), 0.0))); - assert(math.isNan(hypot32(0.0, math.nan(f32)))); + expect(math.isPositiveInf(hypot32(math.inf(f32), 0.0))); + expect(math.isPositiveInf(hypot32(-math.inf(f32), 0.0))); + expect(math.isPositiveInf(hypot32(0.0, math.inf(f32)))); + expect(math.isPositiveInf(hypot32(0.0, -math.inf(f32)))); + expect(math.isNan(hypot32(math.nan(f32), 0.0))); + expect(math.isNan(hypot32(0.0, math.nan(f32)))); } test "math.hypot64.special" { - assert(math.isPositiveInf(hypot64(math.inf(f64), 0.0))); - assert(math.isPositiveInf(hypot64(-math.inf(f64), 0.0))); - assert(math.isPositiveInf(hypot64(0.0, math.inf(f64)))); - assert(math.isPositiveInf(hypot64(0.0, -math.inf(f64)))); - assert(math.isNan(hypot64(math.nan(f64), 0.0))); - assert(math.isNan(hypot64(0.0, math.nan(f64)))); + expect(math.isPositiveInf(hypot64(math.inf(f64), 0.0))); + expect(math.isPositiveInf(hypot64(-math.inf(f64), 0.0))); + expect(math.isPositiveInf(hypot64(0.0, math.inf(f64)))); + expect(math.isPositiveInf(hypot64(0.0, -math.inf(f64)))); + expect(math.isNan(hypot64(math.nan(f64), 0.0))); + expect(math.isNan(hypot64(0.0, math.nan(f64)))); } diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig index e6bdb14012..e7b6485357 100644 --- a/std/math/ilogb.zig +++ b/std/math/ilogb.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -95,38 +95,38 @@ fn ilogb64(x: f64) i32 { } test "math.ilogb" { - assert(ilogb(f32(0.2)) == ilogb32(0.2)); - assert(ilogb(f64(0.2)) == ilogb64(0.2)); + expect(ilogb(f32(0.2)) == ilogb32(0.2)); + expect(ilogb(f64(0.2)) == ilogb64(0.2)); } test "math.ilogb32" { - assert(ilogb32(0.0) == fp_ilogb0); - assert(ilogb32(0.5) == -1); - assert(ilogb32(0.8923) == -1); - assert(ilogb32(10.0) == 3); - assert(ilogb32(-123984) == 16); - assert(ilogb32(2398.23) == 11); + expect(ilogb32(0.0) == fp_ilogb0); + expect(ilogb32(0.5) == -1); + expect(ilogb32(0.8923) == -1); + expect(ilogb32(10.0) == 3); + expect(ilogb32(-123984) == 16); + expect(ilogb32(2398.23) == 11); } test "math.ilogb64" { - assert(ilogb64(0.0) == fp_ilogb0); - assert(ilogb64(0.5) == -1); - assert(ilogb64(0.8923) == -1); - assert(ilogb64(10.0) == 3); - assert(ilogb64(-123984) == 16); - assert(ilogb64(2398.23) == 11); + expect(ilogb64(0.0) == fp_ilogb0); + expect(ilogb64(0.5) == -1); + expect(ilogb64(0.8923) == -1); + expect(ilogb64(10.0) == 3); + expect(ilogb64(-123984) == 16); + expect(ilogb64(2398.23) == 11); } test "math.ilogb32.special" { - assert(ilogb32(math.inf(f32)) == maxInt(i32)); - assert(ilogb32(-math.inf(f32)) == maxInt(i32)); - assert(ilogb32(0.0) == minInt(i32)); - assert(ilogb32(math.nan(f32)) == maxInt(i32)); + expect(ilogb32(math.inf(f32)) == maxInt(i32)); + expect(ilogb32(-math.inf(f32)) == maxInt(i32)); + expect(ilogb32(0.0) == minInt(i32)); + expect(ilogb32(math.nan(f32)) == maxInt(i32)); } test "math.ilogb64.special" { - assert(ilogb64(math.inf(f64)) == maxInt(i32)); - assert(ilogb64(-math.inf(f64)) == maxInt(i32)); - assert(ilogb64(0.0) == minInt(i32)); - assert(ilogb64(math.nan(f64)) == maxInt(i32)); + expect(ilogb64(math.inf(f64)) == maxInt(i32)); + expect(ilogb64(-math.inf(f64)) == maxInt(i32)); + expect(ilogb64(0.0) == minInt(i32)); + expect(ilogb64(math.nan(f64)) == maxInt(i32)); } diff --git a/std/math/index.zig b/std/math/index.zig index f37de2505b..ccfac03038 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -2,6 +2,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const TypeId = builtin.TypeId; const assert = std.debug.assert; +const testing = std.testing; pub const e = 2.71828182845904523536028747135266249775724709369995; pub const pi = 3.14159265358979323846264338327950288419716939937510; @@ -240,7 +241,7 @@ pub fn min(x: var, y: var) @typeOf(x + y) { } test "math.min" { - assert(min(i32(-1), i32(2)) == -1); + testing.expect(min(i32(-1), i32(2)) == -1); } pub fn max(x: var, y: var) @typeOf(x + y) { @@ -248,7 +249,7 @@ pub fn max(x: var, y: var) @typeOf(x + y) { } test "math.max" { - assert(max(i32(-1), i32(2)) == 2); + testing.expect(max(i32(-1), i32(2)) == 2); } pub fn mul(comptime T: type, a: T, b: T) (error{Overflow}!T) { @@ -293,10 +294,10 @@ pub fn shl(comptime T: type, a: T, shift_amt: var) T { } test "math.shl" { - assert(shl(u8, 0b11111111, usize(3)) == 0b11111000); - assert(shl(u8, 0b11111111, usize(8)) == 0); - assert(shl(u8, 0b11111111, usize(9)) == 0); - assert(shl(u8, 0b11111111, isize(-2)) == 0b00111111); + testing.expect(shl(u8, 0b11111111, usize(3)) == 0b11111000); + testing.expect(shl(u8, 0b11111111, usize(8)) == 0); + testing.expect(shl(u8, 0b11111111, usize(9)) == 0); + testing.expect(shl(u8, 0b11111111, isize(-2)) == 0b00111111); } /// Shifts right. Overflowed bits are truncated. @@ -317,10 +318,10 @@ pub fn shr(comptime T: type, a: T, shift_amt: var) T { } test "math.shr" { - assert(shr(u8, 0b11111111, usize(3)) == 0b00011111); - assert(shr(u8, 0b11111111, usize(8)) == 0); - assert(shr(u8, 0b11111111, usize(9)) == 0); - assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100); + testing.expect(shr(u8, 0b11111111, usize(3)) == 0b00011111); + testing.expect(shr(u8, 0b11111111, usize(8)) == 0); + testing.expect(shr(u8, 0b11111111, usize(9)) == 0); + testing.expect(shr(u8, 0b11111111, isize(-2)) == 0b11111100); } /// Rotates right. Only unsigned values can be rotated. @@ -335,11 +336,11 @@ pub fn rotr(comptime T: type, x: T, r: var) T { } test "math.rotr" { - assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001); - assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000); - assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001); - assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000); - assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010); + testing.expect(rotr(u8, 0b00000001, usize(0)) == 0b00000001); + testing.expect(rotr(u8, 0b00000001, usize(9)) == 0b10000000); + testing.expect(rotr(u8, 0b00000001, usize(8)) == 0b00000001); + testing.expect(rotr(u8, 0b00000001, usize(4)) == 0b00010000); + testing.expect(rotr(u8, 0b00000001, isize(-1)) == 0b00000010); } /// Rotates left. Only unsigned values can be rotated. @@ -354,11 +355,11 @@ pub fn rotl(comptime T: type, x: T, r: var) T { } test "math.rotl" { - assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001); - assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010); - assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001); - assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000); - assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000); + testing.expect(rotl(u8, 0b00000001, usize(0)) == 0b00000001); + testing.expect(rotl(u8, 0b00000001, usize(9)) == 0b00000010); + testing.expect(rotl(u8, 0b00000001, usize(8)) == 0b00000001); + testing.expect(rotl(u8, 0b00000001, usize(4)) == 0b00010000); + testing.expect(rotl(u8, 0b00000001, isize(-1)) == 0b10000000); } pub fn Log2Int(comptime T: type) type { @@ -389,50 +390,50 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t } test "math.IntFittingRange" { - assert(IntFittingRange(0, 0) == u0); - assert(IntFittingRange(0, 1) == u1); - assert(IntFittingRange(0, 2) == u2); - assert(IntFittingRange(0, 3) == u2); - assert(IntFittingRange(0, 4) == u3); - assert(IntFittingRange(0, 7) == u3); - assert(IntFittingRange(0, 8) == u4); - assert(IntFittingRange(0, 9) == u4); - assert(IntFittingRange(0, 15) == u4); - assert(IntFittingRange(0, 16) == u5); - assert(IntFittingRange(0, 17) == u5); - assert(IntFittingRange(0, 4095) == u12); - assert(IntFittingRange(2000, 4095) == u12); - assert(IntFittingRange(0, 4096) == u13); - assert(IntFittingRange(2000, 4096) == u13); - assert(IntFittingRange(0, 4097) == u13); - assert(IntFittingRange(2000, 4097) == u13); - assert(IntFittingRange(0, 123456789123456798123456789) == u87); - assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177); - - assert(IntFittingRange(-1, -1) == i1); - assert(IntFittingRange(-1, 0) == i1); - assert(IntFittingRange(-1, 1) == i2); - assert(IntFittingRange(-2, -2) == i2); - assert(IntFittingRange(-2, -1) == i2); - assert(IntFittingRange(-2, 0) == i2); - assert(IntFittingRange(-2, 1) == i2); - assert(IntFittingRange(-2, 2) == i3); - assert(IntFittingRange(-1, 2) == i3); - assert(IntFittingRange(-1, 3) == i3); - assert(IntFittingRange(-1, 4) == i4); - assert(IntFittingRange(-1, 7) == i4); - assert(IntFittingRange(-1, 8) == i5); - assert(IntFittingRange(-1, 9) == i5); - assert(IntFittingRange(-1, 15) == i5); - assert(IntFittingRange(-1, 16) == i6); - assert(IntFittingRange(-1, 17) == i6); - assert(IntFittingRange(-1, 4095) == i13); - assert(IntFittingRange(-4096, 4095) == i13); - assert(IntFittingRange(-1, 4096) == i14); - assert(IntFittingRange(-4097, 4095) == i14); - assert(IntFittingRange(-1, 4097) == i14); - assert(IntFittingRange(-1, 123456789123456798123456789) == i88); - assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178); + testing.expect(IntFittingRange(0, 0) == u0); + testing.expect(IntFittingRange(0, 1) == u1); + testing.expect(IntFittingRange(0, 2) == u2); + testing.expect(IntFittingRange(0, 3) == u2); + testing.expect(IntFittingRange(0, 4) == u3); + testing.expect(IntFittingRange(0, 7) == u3); + testing.expect(IntFittingRange(0, 8) == u4); + testing.expect(IntFittingRange(0, 9) == u4); + testing.expect(IntFittingRange(0, 15) == u4); + testing.expect(IntFittingRange(0, 16) == u5); + testing.expect(IntFittingRange(0, 17) == u5); + testing.expect(IntFittingRange(0, 4095) == u12); + testing.expect(IntFittingRange(2000, 4095) == u12); + testing.expect(IntFittingRange(0, 4096) == u13); + testing.expect(IntFittingRange(2000, 4096) == u13); + testing.expect(IntFittingRange(0, 4097) == u13); + testing.expect(IntFittingRange(2000, 4097) == u13); + testing.expect(IntFittingRange(0, 123456789123456798123456789) == u87); + testing.expect(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177); + + testing.expect(IntFittingRange(-1, -1) == i1); + testing.expect(IntFittingRange(-1, 0) == i1); + testing.expect(IntFittingRange(-1, 1) == i2); + testing.expect(IntFittingRange(-2, -2) == i2); + testing.expect(IntFittingRange(-2, -1) == i2); + testing.expect(IntFittingRange(-2, 0) == i2); + testing.expect(IntFittingRange(-2, 1) == i2); + testing.expect(IntFittingRange(-2, 2) == i3); + testing.expect(IntFittingRange(-1, 2) == i3); + testing.expect(IntFittingRange(-1, 3) == i3); + testing.expect(IntFittingRange(-1, 4) == i4); + testing.expect(IntFittingRange(-1, 7) == i4); + testing.expect(IntFittingRange(-1, 8) == i5); + testing.expect(IntFittingRange(-1, 9) == i5); + testing.expect(IntFittingRange(-1, 15) == i5); + testing.expect(IntFittingRange(-1, 16) == i6); + testing.expect(IntFittingRange(-1, 17) == i6); + testing.expect(IntFittingRange(-1, 4095) == i13); + testing.expect(IntFittingRange(-4096, 4095) == i13); + testing.expect(IntFittingRange(-1, 4096) == i14); + testing.expect(IntFittingRange(-4097, 4095) == i14); + testing.expect(IntFittingRange(-1, 4097) == i14); + testing.expect(IntFittingRange(-1, 123456789123456798123456789) == i88); + testing.expect(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178); } test "math overflow functions" { @@ -441,10 +442,10 @@ test "math overflow functions" { } fn testOverflow() void { - assert((mul(i32, 3, 4) catch unreachable) == 12); - assert((add(i32, 3, 4) catch unreachable) == 7); - assert((sub(i32, 3, 4) catch unreachable) == -1); - assert((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); + testing.expect((mul(i32, 3, 4) catch unreachable) == 12); + testing.expect((add(i32, 3, 4) catch unreachable) == 7); + testing.expect((sub(i32, 3, 4) catch unreachable) == -1); + testing.expect((shlExact(i32, 0b11, 4) catch unreachable) == 0b110000); } pub fn absInt(x: var) !@typeOf(x) { @@ -465,8 +466,8 @@ test "math.absInt" { comptime testAbsInt(); } fn testAbsInt() void { - assert((absInt(i32(-10)) catch unreachable) == 10); - assert((absInt(i32(10)) catch unreachable) == 10); + testing.expect((absInt(i32(-10)) catch unreachable) == 10); + testing.expect((absInt(i32(10)) catch unreachable) == 10); } pub const absFloat = @import("fabs.zig").fabs; @@ -483,13 +484,13 @@ test "math.divTrunc" { comptime testDivTrunc(); } fn testDivTrunc() void { - assert((divTrunc(i32, 5, 3) catch unreachable) == 1); - assert((divTrunc(i32, -5, 3) catch unreachable) == -1); - if (divTrunc(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divTrunc(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); + testing.expect((divTrunc(i32, 5, 3) catch unreachable) == 1); + testing.expect((divTrunc(i32, -5, 3) catch unreachable) == -1); + testing.expectError(error.DivisionByZero, divTrunc(i8, -5, 0)); + testing.expectError(error.Overflow, divTrunc(i8, -128, -1)); - assert((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0); - assert((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); + testing.expect((divTrunc(f32, 5.0, 3.0) catch unreachable) == 1.0); + testing.expect((divTrunc(f32, -5.0, 3.0) catch unreachable) == -1.0); } pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { @@ -504,13 +505,13 @@ test "math.divFloor" { comptime testDivFloor(); } fn testDivFloor() void { - assert((divFloor(i32, 5, 3) catch unreachable) == 1); - assert((divFloor(i32, -5, 3) catch unreachable) == -2); - if (divFloor(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divFloor(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); + testing.expect((divFloor(i32, 5, 3) catch unreachable) == 1); + testing.expect((divFloor(i32, -5, 3) catch unreachable) == -2); + testing.expectError(error.DivisionByZero, divFloor(i8, -5, 0)); + testing.expectError(error.Overflow, divFloor(i8, -128, -1)); - assert((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0); - assert((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); + testing.expect((divFloor(f32, 5.0, 3.0) catch unreachable) == 1.0); + testing.expect((divFloor(f32, -5.0, 3.0) catch unreachable) == -2.0); } pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { @@ -527,15 +528,15 @@ test "math.divExact" { comptime testDivExact(); } fn testDivExact() void { - assert((divExact(i32, 10, 5) catch unreachable) == 2); - assert((divExact(i32, -10, 5) catch unreachable) == -2); - if (divExact(i8, -5, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); - if (divExact(i8, -128, -1)) |_| unreachable else |err| assert(err == error.Overflow); - if (divExact(i32, 5, 2)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); + testing.expect((divExact(i32, 10, 5) catch unreachable) == 2); + testing.expect((divExact(i32, -10, 5) catch unreachable) == -2); + testing.expectError(error.DivisionByZero, divExact(i8, -5, 0)); + testing.expectError(error.Overflow, divExact(i8, -128, -1)); + testing.expectError(error.UnexpectedRemainder, divExact(i32, 5, 2)); - assert((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0); - assert((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0); - if (divExact(f32, 5.0, 2.0)) |_| unreachable else |err| assert(err == error.UnexpectedRemainder); + testing.expect((divExact(f32, 10.0, 5.0) catch unreachable) == 2.0); + testing.expect((divExact(f32, -10.0, 5.0) catch unreachable) == -2.0); + testing.expectError(error.UnexpectedRemainder, divExact(f32, 5.0, 2.0)); } pub fn mod(comptime T: type, numerator: T, denominator: T) !T { @@ -550,15 +551,15 @@ test "math.mod" { comptime testMod(); } fn testMod() void { - assert((mod(i32, -5, 3) catch unreachable) == 1); - assert((mod(i32, 5, 3) catch unreachable) == 2); - if (mod(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + testing.expect((mod(i32, -5, 3) catch unreachable) == 1); + testing.expect((mod(i32, 5, 3) catch unreachable) == 2); + testing.expectError(error.NegativeDenominator, mod(i32, 10, -1)); + testing.expectError(error.DivisionByZero, mod(i32, 10, 0)); - assert((mod(f32, -5, 3) catch unreachable) == 1); - assert((mod(f32, 5, 3) catch unreachable) == 2); - if (mod(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (mod(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + testing.expect((mod(f32, -5, 3) catch unreachable) == 1); + testing.expect((mod(f32, 5, 3) catch unreachable) == 2); + testing.expectError(error.NegativeDenominator, mod(f32, 10, -1)); + testing.expectError(error.DivisionByZero, mod(f32, 10, 0)); } pub fn rem(comptime T: type, numerator: T, denominator: T) !T { @@ -573,15 +574,15 @@ test "math.rem" { comptime testRem(); } fn testRem() void { - assert((rem(i32, -5, 3) catch unreachable) == -2); - assert((rem(i32, 5, 3) catch unreachable) == 2); - if (rem(i32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(i32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + testing.expect((rem(i32, -5, 3) catch unreachable) == -2); + testing.expect((rem(i32, 5, 3) catch unreachable) == 2); + testing.expectError(error.NegativeDenominator, rem(i32, 10, -1)); + testing.expectError(error.DivisionByZero, rem(i32, 10, 0)); - assert((rem(f32, -5, 3) catch unreachable) == -2); - assert((rem(f32, 5, 3) catch unreachable) == 2); - if (rem(f32, 10, -1)) |_| unreachable else |err| assert(err == error.NegativeDenominator); - if (rem(f32, 10, 0)) |_| unreachable else |err| assert(err == error.DivisionByZero); + testing.expect((rem(f32, -5, 3) catch unreachable) == -2); + testing.expect((rem(f32, 5, 3) catch unreachable) == 2); + testing.expectError(error.NegativeDenominator, rem(f32, 10, -1)); + testing.expectError(error.DivisionByZero, rem(f32, 10, 0)); } /// Returns the absolute value of the integer parameter. @@ -594,14 +595,14 @@ pub fn absCast(x: var) @IntType(false, @typeOf(x).bit_count) { } test "math.absCast" { - assert(absCast(i32(-999)) == 999); - assert(@typeOf(absCast(i32(-999))) == u32); + testing.expect(absCast(i32(-999)) == 999); + testing.expect(@typeOf(absCast(i32(-999))) == u32); - assert(absCast(i32(999)) == 999); - assert(@typeOf(absCast(i32(999))) == u32); + testing.expect(absCast(i32(999)) == 999); + testing.expect(@typeOf(absCast(i32(999))) == u32); - assert(absCast(i32(minInt(i32))) == -minInt(i32)); - assert(@typeOf(absCast(i32(minInt(i32)))) == u32); + testing.expect(absCast(i32(minInt(i32))) == -minInt(i32)); + testing.expect(@typeOf(absCast(i32(minInt(i32)))) == u32); } /// Returns the negation of the integer parameter. @@ -618,13 +619,13 @@ pub fn negateCast(x: var) !@IntType(true, @typeOf(x).bit_count) { } test "math.negateCast" { - assert((negateCast(u32(999)) catch unreachable) == -999); - assert(@typeOf(negateCast(u32(999)) catch unreachable) == i32); + testing.expect((negateCast(u32(999)) catch unreachable) == -999); + testing.expect(@typeOf(negateCast(u32(999)) catch unreachable) == i32); - assert((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32)); - assert(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32); + testing.expect((negateCast(u32(-minInt(i32))) catch unreachable) == minInt(i32)); + testing.expect(@typeOf(negateCast(u32(-minInt(i32))) catch unreachable) == i32); - if (negateCast(u32(maxInt(i32) + 10))) |_| unreachable else |err| assert(err == error.Overflow); + testing.expectError(error.Overflow, negateCast(u32(maxInt(i32) + 10))); } /// Cast an integer to a different integer type. If the value doesn't fit, @@ -642,13 +643,13 @@ pub fn cast(comptime T: type, x: var) (error{Overflow}!T) { } test "math.cast" { - if (cast(u8, u32(300))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(i8, i32(-200))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(u8, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); - if (cast(u64, i8(-1))) |_| @panic("fail") else |err| assert(err == error.Overflow); + testing.expectError(error.Overflow, cast(u8, u32(300))); + testing.expectError(error.Overflow, cast(i8, i32(-200))); + testing.expectError(error.Overflow, cast(u8, i8(-1))); + testing.expectError(error.Overflow, cast(u64, i8(-1))); - assert((try cast(u8, u32(255))) == u8(255)); - assert(@typeOf(try cast(u8, u32(255))) == u8); + testing.expect((try cast(u8, u32(255))) == u8(255)); + testing.expect(@typeOf(try cast(u8, u32(255))) == u8); } pub const AlignCastError = error{UnalignedMemory}; @@ -692,25 +693,25 @@ pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) { } test "std.math.log2_int_ceil" { - assert(log2_int_ceil(u32, 1) == 0); - assert(log2_int_ceil(u32, 2) == 1); - assert(log2_int_ceil(u32, 3) == 2); - assert(log2_int_ceil(u32, 4) == 2); - assert(log2_int_ceil(u32, 5) == 3); - assert(log2_int_ceil(u32, 6) == 3); - assert(log2_int_ceil(u32, 7) == 3); - assert(log2_int_ceil(u32, 8) == 3); - assert(log2_int_ceil(u32, 9) == 4); - assert(log2_int_ceil(u32, 10) == 4); + testing.expect(log2_int_ceil(u32, 1) == 0); + testing.expect(log2_int_ceil(u32, 2) == 1); + testing.expect(log2_int_ceil(u32, 3) == 2); + testing.expect(log2_int_ceil(u32, 4) == 2); + testing.expect(log2_int_ceil(u32, 5) == 3); + testing.expect(log2_int_ceil(u32, 6) == 3); + testing.expect(log2_int_ceil(u32, 7) == 3); + testing.expect(log2_int_ceil(u32, 8) == 3); + testing.expect(log2_int_ceil(u32, 9) == 4); + testing.expect(log2_int_ceil(u32, 10) == 4); } fn testFloorPowerOfTwo() void { - assert(floorPowerOfTwo(u32, 63) == 32); - assert(floorPowerOfTwo(u32, 64) == 64); - assert(floorPowerOfTwo(u32, 65) == 64); - assert(floorPowerOfTwo(u4, 7) == 4); - assert(floorPowerOfTwo(u4, 8) == 8); - assert(floorPowerOfTwo(u4, 9) == 8); + testing.expect(floorPowerOfTwo(u32, 63) == 32); + testing.expect(floorPowerOfTwo(u32, 64) == 64); + testing.expect(floorPowerOfTwo(u32, 65) == 64); + testing.expect(floorPowerOfTwo(u4, 7) == 4); + testing.expect(floorPowerOfTwo(u4, 8) == 8); + testing.expect(floorPowerOfTwo(u4, 9) == 8); } pub fn lossyCast(comptime T: type, value: var) T { @@ -726,7 +727,7 @@ pub fn lossyCast(comptime T: type, value: var) T { test "math.f64_min" { const f64_min_u64 = 0x0010000000000000; const fmin: f64 = f64_min; - assert(@bitCast(u64, fmin) == f64_min_u64); + testing.expect(@bitCast(u64, fmin) == f64_min_u64); } pub fn maxInt(comptime T: type) comptime_int { @@ -745,36 +746,36 @@ pub fn minInt(comptime T: type) comptime_int { } test "minInt and maxInt" { - assert(maxInt(u0) == 0); - assert(maxInt(u1) == 1); - assert(maxInt(u8) == 255); - assert(maxInt(u16) == 65535); - assert(maxInt(u32) == 4294967295); - assert(maxInt(u64) == 18446744073709551615); - - assert(maxInt(i0) == 0); - assert(maxInt(i1) == 0); - assert(maxInt(i8) == 127); - assert(maxInt(i16) == 32767); - assert(maxInt(i32) == 2147483647); - assert(maxInt(i63) == 4611686018427387903); - assert(maxInt(i64) == 9223372036854775807); - - assert(minInt(u0) == 0); - assert(minInt(u1) == 0); - assert(minInt(u8) == 0); - assert(minInt(u16) == 0); - assert(minInt(u32) == 0); - assert(minInt(u63) == 0); - assert(minInt(u64) == 0); - - assert(minInt(i0) == 0); - assert(minInt(i1) == -1); - assert(minInt(i8) == -128); - assert(minInt(i16) == -32768); - assert(minInt(i32) == -2147483648); - assert(minInt(i63) == -4611686018427387904); - assert(minInt(i64) == -9223372036854775808); + testing.expect(maxInt(u0) == 0); + testing.expect(maxInt(u1) == 1); + testing.expect(maxInt(u8) == 255); + testing.expect(maxInt(u16) == 65535); + testing.expect(maxInt(u32) == 4294967295); + testing.expect(maxInt(u64) == 18446744073709551615); + + testing.expect(maxInt(i0) == 0); + testing.expect(maxInt(i1) == 0); + testing.expect(maxInt(i8) == 127); + testing.expect(maxInt(i16) == 32767); + testing.expect(maxInt(i32) == 2147483647); + testing.expect(maxInt(i63) == 4611686018427387903); + testing.expect(maxInt(i64) == 9223372036854775807); + + testing.expect(minInt(u0) == 0); + testing.expect(minInt(u1) == 0); + testing.expect(minInt(u8) == 0); + testing.expect(minInt(u16) == 0); + testing.expect(minInt(u32) == 0); + testing.expect(minInt(u63) == 0); + testing.expect(minInt(u64) == 0); + + testing.expect(minInt(i0) == 0); + testing.expect(minInt(i1) == -1); + testing.expect(minInt(i8) == -128); + testing.expect(minInt(i16) == -32768); + testing.expect(minInt(i32) == -2147483648); + testing.expect(minInt(i63) == -4611686018427387904); + testing.expect(minInt(i64) == -9223372036854775808); } test "max value type" { @@ -782,5 +783,5 @@ test "max value type" { // u32 would not work. But since the value is a number literal, // it works fine. const x: u32 = maxInt(i32); - assert(x == 2147483647); + testing.expect(x == 2147483647); } diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig index bdfdff8f9f..bf1c9ac63c 100644 --- a/std/math/isfinite.zig +++ b/std/math/isfinite.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isFinite(x: var) bool { @@ -25,16 +25,16 @@ pub fn isFinite(x: var) bool { } test "math.isFinite" { - assert(isFinite(f16(0.0))); - assert(isFinite(f16(-0.0))); - assert(isFinite(f32(0.0))); - assert(isFinite(f32(-0.0))); - assert(isFinite(f64(0.0))); - assert(isFinite(f64(-0.0))); - assert(!isFinite(math.inf(f16))); - assert(!isFinite(-math.inf(f16))); - assert(!isFinite(math.inf(f32))); - assert(!isFinite(-math.inf(f32))); - assert(!isFinite(math.inf(f64))); - assert(!isFinite(-math.inf(f64))); + expect(isFinite(f16(0.0))); + expect(isFinite(f16(-0.0))); + expect(isFinite(f32(0.0))); + expect(isFinite(f32(-0.0))); + expect(isFinite(f64(0.0))); + expect(isFinite(f64(-0.0))); + expect(!isFinite(math.inf(f16))); + expect(!isFinite(-math.inf(f16))); + expect(!isFinite(math.inf(f32))); + expect(!isFinite(-math.inf(f32))); + expect(!isFinite(math.inf(f64))); + expect(!isFinite(-math.inf(f64))); } diff --git a/std/math/isinf.zig b/std/math/isinf.zig index 93f66cc870..e34e9c5971 100644 --- a/std/math/isinf.zig +++ b/std/math/isinf.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isInf(x: var) bool { @@ -61,46 +61,46 @@ pub fn isNegativeInf(x: var) bool { } test "math.isInf" { - assert(!isInf(f16(0.0))); - assert(!isInf(f16(-0.0))); - assert(!isInf(f32(0.0))); - assert(!isInf(f32(-0.0))); - assert(!isInf(f64(0.0))); - assert(!isInf(f64(-0.0))); - assert(isInf(math.inf(f16))); - assert(isInf(-math.inf(f16))); - assert(isInf(math.inf(f32))); - assert(isInf(-math.inf(f32))); - assert(isInf(math.inf(f64))); - assert(isInf(-math.inf(f64))); + expect(!isInf(f16(0.0))); + expect(!isInf(f16(-0.0))); + expect(!isInf(f32(0.0))); + expect(!isInf(f32(-0.0))); + expect(!isInf(f64(0.0))); + expect(!isInf(f64(-0.0))); + expect(isInf(math.inf(f16))); + expect(isInf(-math.inf(f16))); + expect(isInf(math.inf(f32))); + expect(isInf(-math.inf(f32))); + expect(isInf(math.inf(f64))); + expect(isInf(-math.inf(f64))); } test "math.isPositiveInf" { - assert(!isPositiveInf(f16(0.0))); - assert(!isPositiveInf(f16(-0.0))); - assert(!isPositiveInf(f32(0.0))); - assert(!isPositiveInf(f32(-0.0))); - assert(!isPositiveInf(f64(0.0))); - assert(!isPositiveInf(f64(-0.0))); - assert(isPositiveInf(math.inf(f16))); - assert(!isPositiveInf(-math.inf(f16))); - assert(isPositiveInf(math.inf(f32))); - assert(!isPositiveInf(-math.inf(f32))); - assert(isPositiveInf(math.inf(f64))); - assert(!isPositiveInf(-math.inf(f64))); + expect(!isPositiveInf(f16(0.0))); + expect(!isPositiveInf(f16(-0.0))); + expect(!isPositiveInf(f32(0.0))); + expect(!isPositiveInf(f32(-0.0))); + expect(!isPositiveInf(f64(0.0))); + expect(!isPositiveInf(f64(-0.0))); + expect(isPositiveInf(math.inf(f16))); + expect(!isPositiveInf(-math.inf(f16))); + expect(isPositiveInf(math.inf(f32))); + expect(!isPositiveInf(-math.inf(f32))); + expect(isPositiveInf(math.inf(f64))); + expect(!isPositiveInf(-math.inf(f64))); } test "math.isNegativeInf" { - assert(!isNegativeInf(f16(0.0))); - assert(!isNegativeInf(f16(-0.0))); - assert(!isNegativeInf(f32(0.0))); - assert(!isNegativeInf(f32(-0.0))); - assert(!isNegativeInf(f64(0.0))); - assert(!isNegativeInf(f64(-0.0))); - assert(!isNegativeInf(math.inf(f16))); - assert(isNegativeInf(-math.inf(f16))); - assert(!isNegativeInf(math.inf(f32))); - assert(isNegativeInf(-math.inf(f32))); - assert(!isNegativeInf(math.inf(f64))); - assert(isNegativeInf(-math.inf(f64))); + expect(!isNegativeInf(f16(0.0))); + expect(!isNegativeInf(f16(-0.0))); + expect(!isNegativeInf(f32(0.0))); + expect(!isNegativeInf(f32(-0.0))); + expect(!isNegativeInf(f64(0.0))); + expect(!isNegativeInf(f64(-0.0))); + expect(!isNegativeInf(math.inf(f16))); + expect(isNegativeInf(-math.inf(f16))); + expect(!isNegativeInf(math.inf(f32))); + expect(isNegativeInf(-math.inf(f32))); + expect(!isNegativeInf(math.inf(f64))); + expect(isNegativeInf(-math.inf(f64))); } diff --git a/std/math/isnan.zig b/std/math/isnan.zig index a2cb85b4f7..641da9e620 100644 --- a/std/math/isnan.zig +++ b/std/math/isnan.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isNan(x: var) bool { @@ -31,10 +31,10 @@ pub fn isSignalNan(x: var) bool { } test "math.isNan" { - assert(isNan(math.nan(f16))); - assert(isNan(math.nan(f32))); - assert(isNan(math.nan(f64))); - assert(!isNan(f16(1.0))); - assert(!isNan(f32(1.0))); - assert(!isNan(f64(1.0))); + expect(isNan(math.nan(f16))); + expect(isNan(math.nan(f32))); + expect(isNan(math.nan(f64))); + expect(!isNan(f16(1.0))); + expect(!isNan(f32(1.0))); + expect(!isNan(f64(1.0))); } diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig index cc088e46a0..2c57aea7a9 100644 --- a/std/math/isnormal.zig +++ b/std/math/isnormal.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn isNormal(x: var) bool { @@ -25,13 +25,13 @@ pub fn isNormal(x: var) bool { } test "math.isNormal" { - assert(!isNormal(math.nan(f16))); - assert(!isNormal(math.nan(f32))); - assert(!isNormal(math.nan(f64))); - assert(!isNormal(f16(0))); - assert(!isNormal(f32(0))); - assert(!isNormal(f64(0))); - assert(isNormal(f16(1.0))); - assert(isNormal(f32(1.0))); - assert(isNormal(f64(1.0))); + expect(!isNormal(math.nan(f16))); + expect(!isNormal(math.nan(f32))); + expect(!isNormal(math.nan(f64))); + expect(!isNormal(f16(0))); + expect(!isNormal(f32(0))); + expect(!isNormal(f64(0))); + expect(isNormal(f16(1.0))); + expect(isNormal(f32(1.0))); + expect(isNormal(f64(1.0))); } diff --git a/std/math/ln.zig b/std/math/ln.zig index a560fee8ec..257ce8054f 100644 --- a/std/math/ln.zig +++ b/std/math/ln.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; @@ -143,42 +143,42 @@ pub fn ln_64(x_: f64) f64 { } test "math.ln" { - assert(ln(f32(0.2)) == ln_32(0.2)); - assert(ln(f64(0.2)) == ln_64(0.2)); + expect(ln(f32(0.2)) == ln_32(0.2)); + expect(ln(f64(0.2)) == ln_64(0.2)); } test "math.ln32" { const epsilon = 0.000001; - assert(math.approxEq(f32, ln_32(0.2), -1.609438, epsilon)); - assert(math.approxEq(f32, ln_32(0.8923), -0.113953, epsilon)); - assert(math.approxEq(f32, ln_32(1.5), 0.405465, epsilon)); - assert(math.approxEq(f32, ln_32(37.45), 3.623007, epsilon)); - assert(math.approxEq(f32, ln_32(89.123), 4.490017, epsilon)); - assert(math.approxEq(f32, ln_32(123123.234375), 11.720941, epsilon)); + expect(math.approxEq(f32, ln_32(0.2), -1.609438, epsilon)); + expect(math.approxEq(f32, ln_32(0.8923), -0.113953, epsilon)); + expect(math.approxEq(f32, ln_32(1.5), 0.405465, epsilon)); + expect(math.approxEq(f32, ln_32(37.45), 3.623007, epsilon)); + expect(math.approxEq(f32, ln_32(89.123), 4.490017, epsilon)); + expect(math.approxEq(f32, ln_32(123123.234375), 11.720941, epsilon)); } test "math.ln64" { const epsilon = 0.000001; - assert(math.approxEq(f64, ln_64(0.2), -1.609438, epsilon)); - assert(math.approxEq(f64, ln_64(0.8923), -0.113953, epsilon)); - assert(math.approxEq(f64, ln_64(1.5), 0.405465, epsilon)); - assert(math.approxEq(f64, ln_64(37.45), 3.623007, epsilon)); - assert(math.approxEq(f64, ln_64(89.123), 4.490017, epsilon)); - assert(math.approxEq(f64, ln_64(123123.234375), 11.720941, epsilon)); + expect(math.approxEq(f64, ln_64(0.2), -1.609438, epsilon)); + expect(math.approxEq(f64, ln_64(0.8923), -0.113953, epsilon)); + expect(math.approxEq(f64, ln_64(1.5), 0.405465, epsilon)); + expect(math.approxEq(f64, ln_64(37.45), 3.623007, epsilon)); + expect(math.approxEq(f64, ln_64(89.123), 4.490017, epsilon)); + expect(math.approxEq(f64, ln_64(123123.234375), 11.720941, epsilon)); } test "math.ln32.special" { - assert(math.isPositiveInf(ln_32(math.inf(f32)))); - assert(math.isNegativeInf(ln_32(0.0))); - assert(math.isNan(ln_32(-1.0))); - assert(math.isNan(ln_32(math.nan(f32)))); + expect(math.isPositiveInf(ln_32(math.inf(f32)))); + expect(math.isNegativeInf(ln_32(0.0))); + expect(math.isNan(ln_32(-1.0))); + expect(math.isNan(ln_32(math.nan(f32)))); } test "math.ln64.special" { - assert(math.isPositiveInf(ln_64(math.inf(f64)))); - assert(math.isNegativeInf(ln_64(0.0))); - assert(math.isNan(ln_64(-1.0))); - assert(math.isNan(ln_64(math.nan(f64)))); + expect(math.isPositiveInf(ln_64(math.inf(f64)))); + expect(math.isNegativeInf(ln_64(0.0))); + expect(math.isNan(ln_64(-1.0))); + expect(math.isNan(ln_64(math.nan(f64)))); } diff --git a/std/math/log.zig b/std/math/log.zig index 20b6d055e8..21cffcc078 100644 --- a/std/math/log.zig +++ b/std/math/log.zig @@ -2,7 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const builtin = @import("builtin"); const TypeId = builtin.TypeId; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn log(comptime T: type, base: T, x: T) T { if (base == 2) { @@ -41,25 +41,25 @@ pub fn log(comptime T: type, base: T, x: T) T { } test "math.log integer" { - assert(log(u8, 2, 0x1) == 0); - assert(log(u8, 2, 0x2) == 1); - assert(log(i16, 2, 0x72) == 6); - assert(log(u32, 2, 0xFFFFFF) == 23); - assert(log(u64, 2, 0x7FF0123456789ABC) == 62); + expect(log(u8, 2, 0x1) == 0); + expect(log(u8, 2, 0x2) == 1); + expect(log(i16, 2, 0x72) == 6); + expect(log(u32, 2, 0xFFFFFF) == 23); + expect(log(u64, 2, 0x7FF0123456789ABC) == 62); } test "math.log float" { const epsilon = 0.000001; - assert(math.approxEq(f32, log(f32, 6, 0.23947), -0.797723, epsilon)); - assert(math.approxEq(f32, log(f32, 89, 0.23947), -0.318432, epsilon)); - assert(math.approxEq(f64, log(f64, 123897, 12389216414), 1.981724596, epsilon)); + expect(math.approxEq(f32, log(f32, 6, 0.23947), -0.797723, epsilon)); + expect(math.approxEq(f32, log(f32, 89, 0.23947), -0.318432, epsilon)); + expect(math.approxEq(f64, log(f64, 123897, 12389216414), 1.981724596, epsilon)); } test "math.log float_special" { - assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974))); - assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974))); + expect(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974))); + expect(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974))); - assert(log(f64, 2, 213.23019799993) == math.log2(f64(213.23019799993))); - assert(log(f64, 10, 213.23019799993) == math.log10(f64(213.23019799993))); + expect(log(f64, 2, 213.23019799993) == math.log2(f64(213.23019799993))); + expect(log(f64, 10, 213.23019799993) == math.log10(f64(213.23019799993))); } diff --git a/std/math/log10.zig b/std/math/log10.zig index 2b53d8a6ae..8055f71280 100644 --- a/std/math/log10.zig +++ b/std/math/log10.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -171,42 +171,42 @@ pub fn log10_64(x_: f64) f64 { } test "math.log10" { - assert(log10(f32(0.2)) == log10_32(0.2)); - assert(log10(f64(0.2)) == log10_64(0.2)); + testing.expect(log10(f32(0.2)) == log10_32(0.2)); + testing.expect(log10(f64(0.2)) == log10_64(0.2)); } test "math.log10_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon)); - assert(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon)); - assert(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon)); - assert(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon)); - assert(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon)); + testing.expect(math.approxEq(f32, log10_32(0.2), -0.698970, epsilon)); + testing.expect(math.approxEq(f32, log10_32(0.8923), -0.049489, epsilon)); + testing.expect(math.approxEq(f32, log10_32(1.5), 0.176091, epsilon)); + testing.expect(math.approxEq(f32, log10_32(37.45), 1.573452, epsilon)); + testing.expect(math.approxEq(f32, log10_32(89.123), 1.94999, epsilon)); + testing.expect(math.approxEq(f32, log10_32(123123.234375), 5.09034, epsilon)); } test "math.log10_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon)); - assert(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon)); - assert(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon)); - assert(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon)); - assert(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon)); - assert(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon)); + testing.expect(math.approxEq(f64, log10_64(0.2), -0.698970, epsilon)); + testing.expect(math.approxEq(f64, log10_64(0.8923), -0.049489, epsilon)); + testing.expect(math.approxEq(f64, log10_64(1.5), 0.176091, epsilon)); + testing.expect(math.approxEq(f64, log10_64(37.45), 1.573452, epsilon)); + testing.expect(math.approxEq(f64, log10_64(89.123), 1.94999, epsilon)); + testing.expect(math.approxEq(f64, log10_64(123123.234375), 5.09034, epsilon)); } test "math.log10_32.special" { - assert(math.isPositiveInf(log10_32(math.inf(f32)))); - assert(math.isNegativeInf(log10_32(0.0))); - assert(math.isNan(log10_32(-1.0))); - assert(math.isNan(log10_32(math.nan(f32)))); + testing.expect(math.isPositiveInf(log10_32(math.inf(f32)))); + testing.expect(math.isNegativeInf(log10_32(0.0))); + testing.expect(math.isNan(log10_32(-1.0))); + testing.expect(math.isNan(log10_32(math.nan(f32)))); } test "math.log10_64.special" { - assert(math.isPositiveInf(log10_64(math.inf(f64)))); - assert(math.isNegativeInf(log10_64(0.0))); - assert(math.isNan(log10_64(-1.0))); - assert(math.isNan(log10_64(math.nan(f64)))); + testing.expect(math.isPositiveInf(log10_64(math.inf(f64)))); + testing.expect(math.isNegativeInf(log10_64(0.0))); + testing.expect(math.isNan(log10_64(-1.0))); + testing.expect(math.isNan(log10_64(math.nan(f64)))); } diff --git a/std/math/log1p.zig b/std/math/log1p.zig index 903fceac05..257e7b90d4 100644 --- a/std/math/log1p.zig +++ b/std/math/log1p.zig @@ -9,7 +9,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn log1p(x: var) @typeOf(x) { const T = @typeOf(x); @@ -177,48 +177,48 @@ fn log1p_64(x: f64) f64 { } test "math.log1p" { - assert(log1p(f32(0.0)) == log1p_32(0.0)); - assert(log1p(f64(0.0)) == log1p_64(0.0)); + expect(log1p(f32(0.0)) == log1p_32(0.0)); + expect(log1p(f64(0.0)) == log1p_64(0.0)); } test "math.log1p_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon)); - assert(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon)); - assert(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon)); - assert(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon)); - assert(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon)); + expect(math.approxEq(f32, log1p_32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, log1p_32(0.2), 0.182322, epsilon)); + expect(math.approxEq(f32, log1p_32(0.8923), 0.637793, epsilon)); + expect(math.approxEq(f32, log1p_32(1.5), 0.916291, epsilon)); + expect(math.approxEq(f32, log1p_32(37.45), 3.649359, epsilon)); + expect(math.approxEq(f32, log1p_32(89.123), 4.501175, epsilon)); + expect(math.approxEq(f32, log1p_32(123123.234375), 11.720949, epsilon)); } test "math.log1p_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon)); - assert(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon)); - assert(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon)); - assert(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon)); - assert(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon)); - assert(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon)); + expect(math.approxEq(f64, log1p_64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, log1p_64(0.2), 0.182322, epsilon)); + expect(math.approxEq(f64, log1p_64(0.8923), 0.637793, epsilon)); + expect(math.approxEq(f64, log1p_64(1.5), 0.916291, epsilon)); + expect(math.approxEq(f64, log1p_64(37.45), 3.649359, epsilon)); + expect(math.approxEq(f64, log1p_64(89.123), 4.501175, epsilon)); + expect(math.approxEq(f64, log1p_64(123123.234375), 11.720949, epsilon)); } test "math.log1p_32.special" { - assert(math.isPositiveInf(log1p_32(math.inf(f32)))); - assert(log1p_32(0.0) == 0.0); - assert(log1p_32(-0.0) == -0.0); - assert(math.isNegativeInf(log1p_32(-1.0))); - assert(math.isNan(log1p_32(-2.0))); - assert(math.isNan(log1p_32(math.nan(f32)))); + expect(math.isPositiveInf(log1p_32(math.inf(f32)))); + expect(log1p_32(0.0) == 0.0); + expect(log1p_32(-0.0) == -0.0); + expect(math.isNegativeInf(log1p_32(-1.0))); + expect(math.isNan(log1p_32(-2.0))); + expect(math.isNan(log1p_32(math.nan(f32)))); } test "math.log1p_64.special" { - assert(math.isPositiveInf(log1p_64(math.inf(f64)))); - assert(log1p_64(0.0) == 0.0); - assert(log1p_64(-0.0) == -0.0); - assert(math.isNegativeInf(log1p_64(-1.0))); - assert(math.isNan(log1p_64(-2.0))); - assert(math.isNan(log1p_64(math.nan(f64)))); + expect(math.isPositiveInf(log1p_64(math.inf(f64)))); + expect(log1p_64(0.0) == 0.0); + expect(log1p_64(-0.0) == -0.0); + expect(math.isNegativeInf(log1p_64(-1.0))); + expect(math.isNan(log1p_64(-2.0))); + expect(math.isNan(log1p_64(math.nan(f64)))); } diff --git a/std/math/log2.zig b/std/math/log2.zig index 555c0bdf18..1bb51bf9f9 100644 --- a/std/math/log2.zig +++ b/std/math/log2.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -169,40 +169,40 @@ pub fn log2_64(x_: f64) f64 { } test "math.log2" { - assert(log2(f32(0.2)) == log2_32(0.2)); - assert(log2(f64(0.2)) == log2_64(0.2)); + expect(log2(f32(0.2)) == log2_32(0.2)); + expect(log2(f64(0.2)) == log2_64(0.2)); } test "math.log2_32" { const epsilon = 0.000001; - assert(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon)); - assert(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon)); - assert(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon)); - assert(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon)); + expect(math.approxEq(f32, log2_32(0.2), -2.321928, epsilon)); + expect(math.approxEq(f32, log2_32(0.8923), -0.164399, epsilon)); + expect(math.approxEq(f32, log2_32(1.5), 0.584962, epsilon)); + expect(math.approxEq(f32, log2_32(37.45), 5.226894, epsilon)); + expect(math.approxEq(f32, log2_32(123123.234375), 16.909744, epsilon)); } test "math.log2_64" { const epsilon = 0.000001; - assert(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon)); - assert(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon)); - assert(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon)); - assert(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon)); - assert(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon)); + expect(math.approxEq(f64, log2_64(0.2), -2.321928, epsilon)); + expect(math.approxEq(f64, log2_64(0.8923), -0.164399, epsilon)); + expect(math.approxEq(f64, log2_64(1.5), 0.584962, epsilon)); + expect(math.approxEq(f64, log2_64(37.45), 5.226894, epsilon)); + expect(math.approxEq(f64, log2_64(123123.234375), 16.909744, epsilon)); } test "math.log2_32.special" { - assert(math.isPositiveInf(log2_32(math.inf(f32)))); - assert(math.isNegativeInf(log2_32(0.0))); - assert(math.isNan(log2_32(-1.0))); - assert(math.isNan(log2_32(math.nan(f32)))); + expect(math.isPositiveInf(log2_32(math.inf(f32)))); + expect(math.isNegativeInf(log2_32(0.0))); + expect(math.isNan(log2_32(-1.0))); + expect(math.isNan(log2_32(math.nan(f32)))); } test "math.log2_64.special" { - assert(math.isPositiveInf(log2_64(math.inf(f64)))); - assert(math.isNegativeInf(log2_64(0.0))); - assert(math.isNan(log2_64(-1.0))); - assert(math.isNan(log2_64(math.nan(f64)))); + expect(math.isPositiveInf(log2_64(math.inf(f64)))); + expect(math.isNegativeInf(log2_64(0.0))); + expect(math.isNan(log2_64(-1.0))); + expect(math.isNan(log2_64(math.nan(f64)))); } diff --git a/std/math/modf.zig b/std/math/modf.zig index 0f619f25bc..2dadda76a9 100644 --- a/std/math/modf.zig +++ b/std/math/modf.zig @@ -5,7 +5,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; fn modf_result(comptime T: type) type { @@ -119,11 +119,11 @@ test "math.modf" { const a = modf(f32(1.0)); const b = modf32(1.0); // NOTE: No struct comparison on generic return type function? non-named, makes sense, but still. - assert(a.ipart == b.ipart and a.fpart == b.fpart); + expect(a.ipart == b.ipart and a.fpart == b.fpart); const c = modf(f64(1.0)); const d = modf64(1.0); - assert(a.ipart == b.ipart and a.fpart == b.fpart); + expect(a.ipart == b.ipart and a.fpart == b.fpart); } test "math.modf32" { @@ -131,24 +131,24 @@ test "math.modf32" { var r: modf32_result = undefined; r = modf32(1.0); - assert(math.approxEq(f32, r.ipart, 1.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.0, epsilon)); + expect(math.approxEq(f32, r.ipart, 1.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.0, epsilon)); r = modf32(2.545); - assert(math.approxEq(f32, r.ipart, 2.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.545, epsilon)); + expect(math.approxEq(f32, r.ipart, 2.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.545, epsilon)); r = modf32(3.978123); - assert(math.approxEq(f32, r.ipart, 3.0, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.978123, epsilon)); + expect(math.approxEq(f32, r.ipart, 3.0, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.978123, epsilon)); r = modf32(43874.3); - assert(math.approxEq(f32, r.ipart, 43874, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.300781, epsilon)); + expect(math.approxEq(f32, r.ipart, 43874, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.300781, epsilon)); r = modf32(1234.340780); - assert(math.approxEq(f32, r.ipart, 1234, epsilon)); - assert(math.approxEq(f32, r.fpart, 0.340820, epsilon)); + expect(math.approxEq(f32, r.ipart, 1234, epsilon)); + expect(math.approxEq(f32, r.fpart, 0.340820, epsilon)); } test "math.modf64" { @@ -156,48 +156,48 @@ test "math.modf64" { var r: modf64_result = undefined; r = modf64(1.0); - assert(math.approxEq(f64, r.ipart, 1.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.0, epsilon)); + expect(math.approxEq(f64, r.ipart, 1.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.0, epsilon)); r = modf64(2.545); - assert(math.approxEq(f64, r.ipart, 2.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.545, epsilon)); + expect(math.approxEq(f64, r.ipart, 2.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.545, epsilon)); r = modf64(3.978123); - assert(math.approxEq(f64, r.ipart, 3.0, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.978123, epsilon)); + expect(math.approxEq(f64, r.ipart, 3.0, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.978123, epsilon)); r = modf64(43874.3); - assert(math.approxEq(f64, r.ipart, 43874, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.3, epsilon)); + expect(math.approxEq(f64, r.ipart, 43874, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.3, epsilon)); r = modf64(1234.340780); - assert(math.approxEq(f64, r.ipart, 1234, epsilon)); - assert(math.approxEq(f64, r.fpart, 0.340780, epsilon)); + expect(math.approxEq(f64, r.ipart, 1234, epsilon)); + expect(math.approxEq(f64, r.fpart, 0.340780, epsilon)); } test "math.modf32.special" { var r: modf32_result = undefined; r = modf32(math.inf(f32)); - assert(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); r = modf32(-math.inf(f32)); - assert(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); r = modf32(math.nan(f32)); - assert(math.isNan(r.ipart) and math.isNan(r.fpart)); + expect(math.isNan(r.ipart) and math.isNan(r.fpart)); } test "math.modf64.special" { var r: modf64_result = undefined; r = modf64(math.inf(f64)); - assert(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isPositiveInf(r.ipart) and math.isNan(r.fpart)); r = modf64(-math.inf(f64)); - assert(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); + expect(math.isNegativeInf(r.ipart) and math.isNan(r.fpart)); r = modf64(math.nan(f64)); - assert(math.isNan(r.ipart) and math.isNan(r.fpart)); + expect(math.isNan(r.ipart) and math.isNan(r.fpart)); } diff --git a/std/math/pow.zig b/std/math/pow.zig index 39a2bfa9f7..f037f66d7e 100644 --- a/std/math/pow.zig +++ b/std/math/pow.zig @@ -24,7 +24,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; // This implementation is taken from the go stlib, musl is a bit more complex. pub fn pow(comptime T: type, x: T, y: T) T { @@ -179,56 +179,56 @@ fn isOddInteger(x: f64) bool { test "math.pow" { const epsilon = 0.000001; - assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon)); - assert(math.approxEq(f32, pow(f32, 0.8923, 3.3), 0.686572, epsilon)); - assert(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon)); - assert(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon)); - assert(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon)); - assert(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); - - assert(math.approxEq(f64, pow(f64, 0.0, 3.3), 0.0, epsilon)); - assert(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon)); - assert(math.approxEq(f64, pow(f64, 0.2, 3.3), 0.004936, epsilon)); - assert(math.approxEq(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon)); - assert(math.approxEq(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon)); - assert(math.approxEq(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.8923, 3.3), 0.686572, epsilon)); + expect(math.approxEq(f32, pow(f32, 0.2, 3.3), 0.004936, epsilon)); + expect(math.approxEq(f32, pow(f32, 1.5, 3.3), 3.811546, epsilon)); + expect(math.approxEq(f32, pow(f32, 37.45, 3.3), 155736.703125, epsilon)); + expect(math.approxEq(f32, pow(f32, 89.123, 3.3), 2722489.5, epsilon)); + + expect(math.approxEq(f64, pow(f64, 0.0, 3.3), 0.0, epsilon)); + expect(math.approxEq(f64, pow(f64, 0.8923, 3.3), 0.686572, epsilon)); + expect(math.approxEq(f64, pow(f64, 0.2, 3.3), 0.004936, epsilon)); + expect(math.approxEq(f64, pow(f64, 1.5, 3.3), 3.811546, epsilon)); + expect(math.approxEq(f64, pow(f64, 37.45, 3.3), 155736.7160616, epsilon)); + expect(math.approxEq(f64, pow(f64, 89.123, 3.3), 2722490.231436, epsilon)); } test "math.pow.special" { const epsilon = 0.000001; - assert(pow(f32, 4, 0.0) == 1.0); - assert(pow(f32, 7, -0.0) == 1.0); - assert(pow(f32, 45, 1.0) == 45); - assert(pow(f32, -45, 1.0) == -45); - assert(math.isNan(pow(f32, math.nan(f32), 5.0))); - assert(math.isNan(pow(f32, 5.0, math.nan(f32)))); - assert(math.isPositiveInf(pow(f32, 0.0, -1.0))); - //assert(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? - assert(math.isPositiveInf(pow(f32, 0.0, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -0.0, -math.inf(f32)))); - assert(pow(f32, 0.0, math.inf(f32)) == 0.0); - assert(pow(f32, -0.0, math.inf(f32)) == 0.0); - assert(math.isPositiveInf(pow(f32, 0.0, -2.0))); - assert(math.isPositiveInf(pow(f32, -0.0, -2.0))); - assert(pow(f32, 0.0, 1.0) == 0.0); - assert(pow(f32, -0.0, 1.0) == -0.0); - assert(pow(f32, 0.0, 2.0) == 0.0); - assert(pow(f32, -0.0, 2.0) == 0.0); - assert(math.approxEq(f32, pow(f32, -1.0, math.inf(f32)), 1.0, epsilon)); - assert(math.approxEq(f32, pow(f32, -1.0, -math.inf(f32)), 1.0, epsilon)); - assert(math.isPositiveInf(pow(f32, 1.2, math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -1.2, math.inf(f32)))); - assert(pow(f32, 1.2, -math.inf(f32)) == 0.0); - assert(pow(f32, -1.2, -math.inf(f32)) == 0.0); - assert(pow(f32, 0.2, math.inf(f32)) == 0.0); - assert(pow(f32, -0.2, math.inf(f32)) == 0.0); - assert(math.isPositiveInf(pow(f32, 0.2, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, -0.2, -math.inf(f32)))); - assert(math.isPositiveInf(pow(f32, math.inf(f32), 1.0))); - assert(pow(f32, math.inf(f32), -1.0) == 0.0); - //assert(pow(f32, -math.inf(f32), 5.0) == pow(f32, -0.0, -5.0)); TODO support negative 0? - assert(pow(f32, -math.inf(f32), -5.2) == pow(f32, -0.0, 5.2)); - assert(math.isNan(pow(f32, -1.0, 1.2))); - assert(math.isNan(pow(f32, -12.4, 78.5))); + expect(pow(f32, 4, 0.0) == 1.0); + expect(pow(f32, 7, -0.0) == 1.0); + expect(pow(f32, 45, 1.0) == 45); + expect(pow(f32, -45, 1.0) == -45); + expect(math.isNan(pow(f32, math.nan(f32), 5.0))); + expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); + expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); + //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? + expect(math.isPositiveInf(pow(f32, 0.0, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -0.0, -math.inf(f32)))); + expect(pow(f32, 0.0, math.inf(f32)) == 0.0); + expect(pow(f32, -0.0, math.inf(f32)) == 0.0); + expect(math.isPositiveInf(pow(f32, 0.0, -2.0))); + expect(math.isPositiveInf(pow(f32, -0.0, -2.0))); + expect(pow(f32, 0.0, 1.0) == 0.0); + expect(pow(f32, -0.0, 1.0) == -0.0); + expect(pow(f32, 0.0, 2.0) == 0.0); + expect(pow(f32, -0.0, 2.0) == 0.0); + expect(math.approxEq(f32, pow(f32, -1.0, math.inf(f32)), 1.0, epsilon)); + expect(math.approxEq(f32, pow(f32, -1.0, -math.inf(f32)), 1.0, epsilon)); + expect(math.isPositiveInf(pow(f32, 1.2, math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -1.2, math.inf(f32)))); + expect(pow(f32, 1.2, -math.inf(f32)) == 0.0); + expect(pow(f32, -1.2, -math.inf(f32)) == 0.0); + expect(pow(f32, 0.2, math.inf(f32)) == 0.0); + expect(pow(f32, -0.2, math.inf(f32)) == 0.0); + expect(math.isPositiveInf(pow(f32, 0.2, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, -0.2, -math.inf(f32)))); + expect(math.isPositiveInf(pow(f32, math.inf(f32), 1.0))); + expect(pow(f32, math.inf(f32), -1.0) == 0.0); + //expect(pow(f32, -math.inf(f32), 5.0) == pow(f32, -0.0, -5.0)); TODO support negative 0? + expect(pow(f32, -math.inf(f32), -5.2) == pow(f32, -0.0, 5.2)); + expect(math.isNan(pow(f32, -1.0, 1.2))); + expect(math.isNan(pow(f32, -12.4, 78.5))); } diff --git a/std/math/powi.zig b/std/math/powi.zig index 13c09b192e..9c2a4a4965 100644 --- a/std/math/powi.zig +++ b/std/math/powi.zig @@ -12,7 +12,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; const assert = std.debug.assert; -const assertError = std.debug.assertError; +const testing = std.testing; // This implementation is based on that from the rust stlib pub fn powi(comptime T: type, x: T, y: T) (error{ @@ -103,75 +103,75 @@ pub fn powi(comptime T: type, x: T, y: T) (error{ } test "math.powi" { - assertError(powi(i8, -66, 6), error.Underflow); - assertError(powi(i16, -13, 13), error.Underflow); - assertError(powi(i32, -32, 21), error.Underflow); - assertError(powi(i64, -24, 61), error.Underflow); - assertError(powi(i17, -15, 15), error.Underflow); - assertError(powi(i42, -6, 40), error.Underflow); - - assert((try powi(i8, -5, 3)) == -125); - assert((try powi(i16, -16, 3)) == -4096); - assert((try powi(i32, -91, 3)) == -753571); - assert((try powi(i64, -36, 6)) == 2176782336); - assert((try powi(i17, -2, 15)) == -32768); - assert((try powi(i42, -5, 7)) == -78125); - - assert((try powi(u8, 6, 2)) == 36); - assert((try powi(u16, 5, 4)) == 625); - assert((try powi(u32, 12, 6)) == 2985984); - assert((try powi(u64, 34, 2)) == 1156); - assert((try powi(u17, 16, 3)) == 4096); - assert((try powi(u42, 34, 6)) == 1544804416); - - assertError(powi(i8, 120, 7), error.Overflow); - assertError(powi(i16, 73, 15), error.Overflow); - assertError(powi(i32, 23, 31), error.Overflow); - assertError(powi(i64, 68, 61), error.Overflow); - assertError(powi(i17, 15, 15), error.Overflow); - assertError(powi(i42, 121312, 41), error.Overflow); - - assertError(powi(u8, 123, 7), error.Overflow); - assertError(powi(u16, 2313, 15), error.Overflow); - assertError(powi(u32, 8968, 31), error.Overflow); - assertError(powi(u64, 2342, 63), error.Overflow); - assertError(powi(u17, 2723, 16), error.Overflow); - assertError(powi(u42, 8234, 41), error.Overflow); + testing.expectError(error.Underflow, powi(i8, -66, 6)); + testing.expectError(error.Underflow, powi(i16, -13, 13)); + testing.expectError(error.Underflow, powi(i32, -32, 21)); + testing.expectError(error.Underflow, powi(i64, -24, 61)); + testing.expectError(error.Underflow, powi(i17, -15, 15)); + testing.expectError(error.Underflow, powi(i42, -6, 40)); + + testing.expect((try powi(i8, -5, 3)) == -125); + testing.expect((try powi(i16, -16, 3)) == -4096); + testing.expect((try powi(i32, -91, 3)) == -753571); + testing.expect((try powi(i64, -36, 6)) == 2176782336); + testing.expect((try powi(i17, -2, 15)) == -32768); + testing.expect((try powi(i42, -5, 7)) == -78125); + + testing.expect((try powi(u8, 6, 2)) == 36); + testing.expect((try powi(u16, 5, 4)) == 625); + testing.expect((try powi(u32, 12, 6)) == 2985984); + testing.expect((try powi(u64, 34, 2)) == 1156); + testing.expect((try powi(u17, 16, 3)) == 4096); + testing.expect((try powi(u42, 34, 6)) == 1544804416); + + testing.expectError(error.Overflow, powi(i8, 120, 7)); + testing.expectError(error.Overflow, powi(i16, 73, 15)); + testing.expectError(error.Overflow, powi(i32, 23, 31)); + testing.expectError(error.Overflow, powi(i64, 68, 61)); + testing.expectError(error.Overflow, powi(i17, 15, 15)); + testing.expectError(error.Overflow, powi(i42, 121312, 41)); + + testing.expectError(error.Overflow, powi(u8, 123, 7)); + testing.expectError(error.Overflow, powi(u16, 2313, 15)); + testing.expectError(error.Overflow, powi(u32, 8968, 31)); + testing.expectError(error.Overflow, powi(u64, 2342, 63)); + testing.expectError(error.Overflow, powi(u17, 2723, 16)); + testing.expectError(error.Overflow, powi(u42, 8234, 41)); } test "math.powi.special" { - assertError(powi(i8, -2, 8), error.Underflow); - assertError(powi(i16, -2, 16), error.Underflow); - assertError(powi(i32, -2, 32), error.Underflow); - assertError(powi(i64, -2, 64), error.Underflow); - assertError(powi(i17, -2, 17), error.Underflow); - assertError(powi(i42, -2, 42), error.Underflow); - - assert((try powi(i8, -1, 3)) == -1); - assert((try powi(i16, -1, 2)) == 1); - assert((try powi(i32, -1, 16)) == 1); - assert((try powi(i64, -1, 6)) == 1); - assert((try powi(i17, -1, 15)) == -1); - assert((try powi(i42, -1, 7)) == -1); - - assert((try powi(u8, 1, 2)) == 1); - assert((try powi(u16, 1, 4)) == 1); - assert((try powi(u32, 1, 6)) == 1); - assert((try powi(u64, 1, 2)) == 1); - assert((try powi(u17, 1, 3)) == 1); - assert((try powi(u42, 1, 6)) == 1); - - assertError(powi(i8, 2, 7), error.Overflow); - assertError(powi(i16, 2, 15), error.Overflow); - assertError(powi(i32, 2, 31), error.Overflow); - assertError(powi(i64, 2, 63), error.Overflow); - assertError(powi(i17, 2, 16), error.Overflow); - assertError(powi(i42, 2, 41), error.Overflow); - - assertError(powi(u8, 2, 8), error.Overflow); - assertError(powi(u16, 2, 16), error.Overflow); - assertError(powi(u32, 2, 32), error.Overflow); - assertError(powi(u64, 2, 64), error.Overflow); - assertError(powi(u17, 2, 17), error.Overflow); - assertError(powi(u42, 2, 42), error.Overflow); + testing.expectError(error.Underflow, powi(i8, -2, 8)); + testing.expectError(error.Underflow, powi(i16, -2, 16)); + testing.expectError(error.Underflow, powi(i32, -2, 32)); + testing.expectError(error.Underflow, powi(i64, -2, 64)); + testing.expectError(error.Underflow, powi(i17, -2, 17)); + testing.expectError(error.Underflow, powi(i42, -2, 42)); + + testing.expect((try powi(i8, -1, 3)) == -1); + testing.expect((try powi(i16, -1, 2)) == 1); + testing.expect((try powi(i32, -1, 16)) == 1); + testing.expect((try powi(i64, -1, 6)) == 1); + testing.expect((try powi(i17, -1, 15)) == -1); + testing.expect((try powi(i42, -1, 7)) == -1); + + testing.expect((try powi(u8, 1, 2)) == 1); + testing.expect((try powi(u16, 1, 4)) == 1); + testing.expect((try powi(u32, 1, 6)) == 1); + testing.expect((try powi(u64, 1, 2)) == 1); + testing.expect((try powi(u17, 1, 3)) == 1); + testing.expect((try powi(u42, 1, 6)) == 1); + + testing.expectError(error.Overflow, powi(i8, 2, 7)); + testing.expectError(error.Overflow, powi(i16, 2, 15)); + testing.expectError(error.Overflow, powi(i32, 2, 31)); + testing.expectError(error.Overflow, powi(i64, 2, 63)); + testing.expectError(error.Overflow, powi(i17, 2, 16)); + testing.expectError(error.Overflow, powi(i42, 2, 41)); + + testing.expectError(error.Overflow, powi(u8, 2, 8)); + testing.expectError(error.Overflow, powi(u16, 2, 16)); + testing.expectError(error.Overflow, powi(u32, 2, 32)); + testing.expectError(error.Overflow, powi(u64, 2, 64)); + testing.expectError(error.Overflow, powi(u17, 2, 17)); + testing.expectError(error.Overflow, powi(u42, 2, 42)); } diff --git a/std/math/round.zig b/std/math/round.zig index 4fe35365c8..7346b703c9 100644 --- a/std/math/round.zig +++ b/std/math/round.zig @@ -5,7 +5,7 @@ // - round(nan) = nan const builtin = @import("builtin"); -const assert = std.debug.assert; +const expect = std.testing.expect; const std = @import("../index.zig"); const math = std.math; @@ -85,36 +85,36 @@ fn round64(x_: f64) f64 { } test "math.round" { - assert(round(f32(1.3)) == round32(1.3)); - assert(round(f64(1.3)) == round64(1.3)); + expect(round(f32(1.3)) == round32(1.3)); + expect(round(f64(1.3)) == round64(1.3)); } test "math.round32" { - assert(round32(1.3) == 1.0); - assert(round32(-1.3) == -1.0); - assert(round32(0.2) == 0.0); - assert(round32(1.8) == 2.0); + expect(round32(1.3) == 1.0); + expect(round32(-1.3) == -1.0); + expect(round32(0.2) == 0.0); + expect(round32(1.8) == 2.0); } test "math.round64" { - assert(round64(1.3) == 1.0); - assert(round64(-1.3) == -1.0); - assert(round64(0.2) == 0.0); - assert(round64(1.8) == 2.0); + expect(round64(1.3) == 1.0); + expect(round64(-1.3) == -1.0); + expect(round64(0.2) == 0.0); + expect(round64(1.8) == 2.0); } test "math.round32.special" { - assert(round32(0.0) == 0.0); - assert(round32(-0.0) == -0.0); - assert(math.isPositiveInf(round32(math.inf(f32)))); - assert(math.isNegativeInf(round32(-math.inf(f32)))); - assert(math.isNan(round32(math.nan(f32)))); + expect(round32(0.0) == 0.0); + expect(round32(-0.0) == -0.0); + expect(math.isPositiveInf(round32(math.inf(f32)))); + expect(math.isNegativeInf(round32(-math.inf(f32)))); + expect(math.isNan(round32(math.nan(f32)))); } test "math.round64.special" { - assert(round64(0.0) == 0.0); - assert(round64(-0.0) == -0.0); - assert(math.isPositiveInf(round64(math.inf(f64)))); - assert(math.isNegativeInf(round64(-math.inf(f64)))); - assert(math.isNan(round64(math.nan(f64)))); + expect(round64(0.0) == 0.0); + expect(round64(-0.0) == -0.0); + expect(math.isPositiveInf(round64(math.inf(f64)))); + expect(math.isNegativeInf(round64(-math.inf(f64)))); + expect(math.isNan(round64(math.nan(f64)))); } diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig index f72c7e866f..d37a8659a9 100644 --- a/std/math/scalbn.zig +++ b/std/math/scalbn.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn scalbn(x: var, n: i32) @typeOf(x) { const T = @typeOf(x); @@ -72,14 +72,14 @@ fn scalbn64(x: f64, n_: i32) f64 { } test "math.scalbn" { - assert(scalbn(f32(1.5), 4) == scalbn32(1.5, 4)); - assert(scalbn(f64(1.5), 4) == scalbn64(1.5, 4)); + expect(scalbn(f32(1.5), 4) == scalbn32(1.5, 4)); + expect(scalbn(f64(1.5), 4) == scalbn64(1.5, 4)); } test "math.scalbn32" { - assert(scalbn32(1.5, 4) == 24.0); + expect(scalbn32(1.5, 4) == 24.0); } test "math.scalbn64" { - assert(scalbn64(1.5, 4) == 24.0); + expect(scalbn64(1.5, 4) == 24.0); } diff --git a/std/math/signbit.zig b/std/math/signbit.zig index 8c6829dfcd..728f651aec 100644 --- a/std/math/signbit.zig +++ b/std/math/signbit.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn signbit(x: var) bool { const T = @typeOf(x); @@ -28,22 +28,22 @@ fn signbit64(x: f64) bool { } test "math.signbit" { - assert(signbit(f16(4.0)) == signbit16(4.0)); - assert(signbit(f32(4.0)) == signbit32(4.0)); - assert(signbit(f64(4.0)) == signbit64(4.0)); + expect(signbit(f16(4.0)) == signbit16(4.0)); + expect(signbit(f32(4.0)) == signbit32(4.0)); + expect(signbit(f64(4.0)) == signbit64(4.0)); } test "math.signbit16" { - assert(!signbit16(4.0)); - assert(signbit16(-3.0)); + expect(!signbit16(4.0)); + expect(signbit16(-3.0)); } test "math.signbit32" { - assert(!signbit32(4.0)); - assert(signbit32(-3.0)); + expect(!signbit32(4.0)); + expect(signbit32(-3.0)); } test "math.signbit64" { - assert(!signbit64(4.0)); - assert(signbit64(-3.0)); + expect(!signbit64(4.0)); + expect(signbit64(-3.0)); } diff --git a/std/math/sin.zig b/std/math/sin.zig index 15b2f9f17a..5ade6636c7 100644 --- a/std/math/sin.zig +++ b/std/math/sin.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn sin(x: var) @typeOf(x) { const T = @typeOf(x); @@ -142,45 +142,45 @@ fn sin64(x_: f64) f64 { } test "math.sin" { - assert(sin(f32(0.0)) == sin32(0.0)); - assert(sin(f64(0.0)) == sin64(0.0)); - assert(comptime (math.sin(f64(2))) == math.sin(f64(2))); + expect(sin(f32(0.0)) == sin32(0.0)); + expect(sin(f64(0.0)) == sin64(0.0)); + expect(comptime (math.sin(f64(2))) == math.sin(f64(2))); } test "math.sin32" { const epsilon = 0.000001; - assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); - assert(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); - assert(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); - assert(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); - assert(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); + expect(math.approxEq(f32, sin32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, sin32(0.2), 0.198669, epsilon)); + expect(math.approxEq(f32, sin32(0.8923), 0.778517, epsilon)); + expect(math.approxEq(f32, sin32(1.5), 0.997495, epsilon)); + expect(math.approxEq(f32, sin32(37.45), -0.246544, epsilon)); + expect(math.approxEq(f32, sin32(89.123), 0.916166, epsilon)); } test "math.sin64" { const epsilon = 0.000001; - assert(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); - assert(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); - assert(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); - assert(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); - assert(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); + expect(math.approxEq(f64, sin64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, sin64(0.2), 0.198669, epsilon)); + expect(math.approxEq(f64, sin64(0.8923), 0.778517, epsilon)); + expect(math.approxEq(f64, sin64(1.5), 0.997495, epsilon)); + expect(math.approxEq(f64, sin64(37.45), -0.246543, epsilon)); + expect(math.approxEq(f64, sin64(89.123), 0.916166, epsilon)); } test "math.sin32.special" { - assert(sin32(0.0) == 0.0); - assert(sin32(-0.0) == -0.0); - assert(math.isNan(sin32(math.inf(f32)))); - assert(math.isNan(sin32(-math.inf(f32)))); - assert(math.isNan(sin32(math.nan(f32)))); + expect(sin32(0.0) == 0.0); + expect(sin32(-0.0) == -0.0); + expect(math.isNan(sin32(math.inf(f32)))); + expect(math.isNan(sin32(-math.inf(f32)))); + expect(math.isNan(sin32(math.nan(f32)))); } test "math.sin64.special" { - assert(sin64(0.0) == 0.0); - assert(sin64(-0.0) == -0.0); - assert(math.isNan(sin64(math.inf(f64)))); - assert(math.isNan(sin64(-math.inf(f64)))); - assert(math.isNan(sin64(math.nan(f64)))); + expect(sin64(0.0) == 0.0); + expect(sin64(-0.0) == -0.0); + expect(math.isNan(sin64(math.inf(f64)))); + expect(math.isNan(sin64(-math.inf(f64)))); + expect(math.isNan(sin64(math.nan(f64)))); } diff --git a/std/math/sinh.zig b/std/math/sinh.zig index 733b89754a..95924ba55a 100644 --- a/std/math/sinh.zig +++ b/std/math/sinh.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; @@ -87,40 +87,40 @@ fn sinh64(x: f64) f64 { } test "math.sinh" { - assert(sinh(f32(1.5)) == sinh32(1.5)); - assert(sinh(f64(1.5)) == sinh64(1.5)); + expect(sinh(f32(1.5)) == sinh32(1.5)); + expect(sinh(f64(1.5)) == sinh64(1.5)); } test "math.sinh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, sinh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon)); - assert(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon)); + expect(math.approxEq(f32, sinh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, sinh32(0.2), 0.201336, epsilon)); + expect(math.approxEq(f32, sinh32(0.8923), 1.015512, epsilon)); + expect(math.approxEq(f32, sinh32(1.5), 2.129279, epsilon)); } test "math.sinh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, sinh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon)); - assert(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon)); - assert(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon)); + expect(math.approxEq(f64, sinh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, sinh64(0.2), 0.201336, epsilon)); + expect(math.approxEq(f64, sinh64(0.8923), 1.015512, epsilon)); + expect(math.approxEq(f64, sinh64(1.5), 2.129279, epsilon)); } test "math.sinh32.special" { - assert(sinh32(0.0) == 0.0); - assert(sinh32(-0.0) == -0.0); - assert(math.isPositiveInf(sinh32(math.inf(f32)))); - assert(math.isNegativeInf(sinh32(-math.inf(f32)))); - assert(math.isNan(sinh32(math.nan(f32)))); + expect(sinh32(0.0) == 0.0); + expect(sinh32(-0.0) == -0.0); + expect(math.isPositiveInf(sinh32(math.inf(f32)))); + expect(math.isNegativeInf(sinh32(-math.inf(f32)))); + expect(math.isNan(sinh32(math.nan(f32)))); } test "math.sinh64.special" { - assert(sinh64(0.0) == 0.0); - assert(sinh64(-0.0) == -0.0); - assert(math.isPositiveInf(sinh64(math.inf(f64)))); - assert(math.isNegativeInf(sinh64(-math.inf(f64)))); - assert(math.isNan(sinh64(math.nan(f64)))); + expect(sinh64(0.0) == 0.0); + expect(sinh64(-0.0) == -0.0); + expect(math.isPositiveInf(sinh64(math.inf(f64)))); + expect(math.isNegativeInf(sinh64(-math.inf(f64)))); + expect(math.isNan(sinh64(math.nan(f64)))); } diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig index 4300f20f5a..9996b44b20 100644 --- a/std/math/sqrt.zig +++ b/std/math/sqrt.zig @@ -7,7 +7,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const builtin = @import("builtin"); const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; @@ -32,75 +32,75 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ } test "math.sqrt" { - assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0)); - assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); - assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); + expect(sqrt(f16(0.0)) == @sqrt(f16, 0.0)); + expect(sqrt(f32(0.0)) == @sqrt(f32, 0.0)); + expect(sqrt(f64(0.0)) == @sqrt(f64, 0.0)); } test "math.sqrt16" { const epsilon = 0.000001; - assert(@sqrt(f16, 0.0) == 0.0); - assert(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon)); - assert(@sqrt(f16, 4.0) == 2.0); - assert(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f16, 64.0) == 8.0); - assert(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon)); + expect(@sqrt(f16, 0.0) == 0.0); + expect(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon)); + expect(@sqrt(f16, 4.0) == 2.0); + expect(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f16, 64.0) == 8.0); + expect(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon)); } test "math.sqrt32" { const epsilon = 0.000001; - assert(@sqrt(f32, 0.0) == 0.0); - assert(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon)); - assert(@sqrt(f32, 4.0) == 2.0); - assert(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f32, 64.0) == 8.0); - assert(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon)); + expect(@sqrt(f32, 0.0) == 0.0); + expect(math.approxEq(f32, @sqrt(f32, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 3.6), 1.897367, epsilon)); + expect(@sqrt(f32, 4.0) == 2.0); + expect(math.approxEq(f32, @sqrt(f32, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f32, 64.0) == 8.0); + expect(math.approxEq(f32, @sqrt(f32, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f32, @sqrt(f32, 8942.230469), 94.563370, epsilon)); } test "math.sqrt64" { const epsilon = 0.000001; - assert(@sqrt(f64, 0.0) == 0.0); - assert(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon)); - assert(@sqrt(f64, 4.0) == 2.0); - assert(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon)); - assert(@sqrt(f64, 64.0) == 8.0); - assert(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon)); - assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); + expect(@sqrt(f64, 0.0) == 0.0); + expect(math.approxEq(f64, @sqrt(f64, 2.0), 1.414214, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 3.6), 1.897367, epsilon)); + expect(@sqrt(f64, 4.0) == 2.0); + expect(math.approxEq(f64, @sqrt(f64, 7.539840), 2.745877, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 19.230934), 4.385309, epsilon)); + expect(@sqrt(f64, 64.0) == 8.0); + expect(math.approxEq(f64, @sqrt(f64, 64.1), 8.006248, epsilon)); + expect(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon)); } test "math.sqrt16.special" { - assert(math.isPositiveInf(@sqrt(f16, math.inf(f16)))); - assert(@sqrt(f16, 0.0) == 0.0); - assert(@sqrt(f16, -0.0) == -0.0); - assert(math.isNan(@sqrt(f16, -1.0))); - assert(math.isNan(@sqrt(f16, math.nan(f16)))); + expect(math.isPositiveInf(@sqrt(f16, math.inf(f16)))); + expect(@sqrt(f16, 0.0) == 0.0); + expect(@sqrt(f16, -0.0) == -0.0); + expect(math.isNan(@sqrt(f16, -1.0))); + expect(math.isNan(@sqrt(f16, math.nan(f16)))); } test "math.sqrt32.special" { - assert(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); - assert(@sqrt(f32, 0.0) == 0.0); - assert(@sqrt(f32, -0.0) == -0.0); - assert(math.isNan(@sqrt(f32, -1.0))); - assert(math.isNan(@sqrt(f32, math.nan(f32)))); + expect(math.isPositiveInf(@sqrt(f32, math.inf(f32)))); + expect(@sqrt(f32, 0.0) == 0.0); + expect(@sqrt(f32, -0.0) == -0.0); + expect(math.isNan(@sqrt(f32, -1.0))); + expect(math.isNan(@sqrt(f32, math.nan(f32)))); } test "math.sqrt64.special" { - assert(math.isPositiveInf(@sqrt(f64, math.inf(f64)))); - assert(@sqrt(f64, 0.0) == 0.0); - assert(@sqrt(f64, -0.0) == -0.0); - assert(math.isNan(@sqrt(f64, -1.0))); - assert(math.isNan(@sqrt(f64, math.nan(f64)))); + expect(math.isPositiveInf(@sqrt(f64, math.inf(f64)))); + expect(@sqrt(f64, 0.0) == 0.0); + expect(@sqrt(f64, -0.0) == -0.0); + expect(math.isNan(@sqrt(f64, -1.0))); + expect(math.isNan(@sqrt(f64, math.nan(f64)))); } fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { @@ -127,10 +127,10 @@ fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { } test "math.sqrt_int" { - assert(sqrt_int(u32, 3) == 1); - assert(sqrt_int(u32, 4) == 2); - assert(sqrt_int(u32, 5) == 2); - assert(sqrt_int(u32, 8) == 2); - assert(sqrt_int(u32, 9) == 3); - assert(sqrt_int(u32, 10) == 3); + expect(sqrt_int(u32, 3) == 1); + expect(sqrt_int(u32, 4) == 2); + expect(sqrt_int(u32, 5) == 2); + expect(sqrt_int(u32, 8) == 2); + expect(sqrt_int(u32, 9) == 3); + expect(sqrt_int(u32, 10) == 3); } diff --git a/std/math/tan.zig b/std/math/tan.zig index a71a17e625..ec43092320 100644 --- a/std/math/tan.zig +++ b/std/math/tan.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; pub fn tan(x: var) @typeOf(x) { const T = @typeOf(x); @@ -129,44 +129,44 @@ fn tan64(x_: f64) f64 { } test "math.tan" { - assert(tan(f32(0.0)) == tan32(0.0)); - assert(tan(f64(0.0)) == tan64(0.0)); + expect(tan(f32(0.0)) == tan32(0.0)); + expect(tan(f64(0.0)) == tan64(0.0)); } test "math.tan32" { const epsilon = 0.000001; - assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); - assert(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); - assert(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); - assert(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); - assert(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); + expect(math.approxEq(f32, tan32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, tan32(0.2), 0.202710, epsilon)); + expect(math.approxEq(f32, tan32(0.8923), 1.240422, epsilon)); + expect(math.approxEq(f32, tan32(1.5), 14.101420, epsilon)); + expect(math.approxEq(f32, tan32(37.45), -0.254397, epsilon)); + expect(math.approxEq(f32, tan32(89.123), 2.285852, epsilon)); } test "math.tan64" { const epsilon = 0.000001; - assert(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); - assert(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); - assert(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); - assert(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); - assert(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); + expect(math.approxEq(f64, tan64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, tan64(0.2), 0.202710, epsilon)); + expect(math.approxEq(f64, tan64(0.8923), 1.240422, epsilon)); + expect(math.approxEq(f64, tan64(1.5), 14.101420, epsilon)); + expect(math.approxEq(f64, tan64(37.45), -0.254397, epsilon)); + expect(math.approxEq(f64, tan64(89.123), 2.2858376, epsilon)); } test "math.tan32.special" { - assert(tan32(0.0) == 0.0); - assert(tan32(-0.0) == -0.0); - assert(math.isNan(tan32(math.inf(f32)))); - assert(math.isNan(tan32(-math.inf(f32)))); - assert(math.isNan(tan32(math.nan(f32)))); + expect(tan32(0.0) == 0.0); + expect(tan32(-0.0) == -0.0); + expect(math.isNan(tan32(math.inf(f32)))); + expect(math.isNan(tan32(-math.inf(f32)))); + expect(math.isNan(tan32(math.nan(f32)))); } test "math.tan64.special" { - assert(tan64(0.0) == 0.0); - assert(tan64(-0.0) == -0.0); - assert(math.isNan(tan64(math.inf(f64)))); - assert(math.isNan(tan64(-math.inf(f64)))); - assert(math.isNan(tan64(math.nan(f64)))); + expect(tan64(0.0) == 0.0); + expect(tan64(-0.0) == -0.0); + expect(math.isNan(tan64(math.inf(f64)))); + expect(math.isNan(tan64(-math.inf(f64)))); + expect(math.isNan(tan64(math.nan(f64)))); } diff --git a/std/math/tanh.zig b/std/math/tanh.zig index faeb2641cc..a35449a053 100644 --- a/std/math/tanh.zig +++ b/std/math/tanh.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const expo2 = @import("expo2.zig").expo2; const maxInt = std.math.maxInt; @@ -113,42 +113,42 @@ fn tanh64(x: f64) f64 { } test "math.tanh" { - assert(tanh(f32(1.5)) == tanh32(1.5)); - assert(tanh(f64(1.5)) == tanh64(1.5)); + expect(tanh(f32(1.5)) == tanh32(1.5)); + expect(tanh(f64(1.5)) == tanh64(1.5)); } test "math.tanh32" { const epsilon = 0.000001; - assert(math.approxEq(f32, tanh32(0.0), 0.0, epsilon)); - assert(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon)); - assert(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon)); - assert(math.approxEq(f32, tanh32(37.45), 1.0, epsilon)); + expect(math.approxEq(f32, tanh32(0.0), 0.0, epsilon)); + expect(math.approxEq(f32, tanh32(0.2), 0.197375, epsilon)); + expect(math.approxEq(f32, tanh32(0.8923), 0.712528, epsilon)); + expect(math.approxEq(f32, tanh32(1.5), 0.905148, epsilon)); + expect(math.approxEq(f32, tanh32(37.45), 1.0, epsilon)); } test "math.tanh64" { const epsilon = 0.000001; - assert(math.approxEq(f64, tanh64(0.0), 0.0, epsilon)); - assert(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon)); - assert(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon)); - assert(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon)); - assert(math.approxEq(f64, tanh64(37.45), 1.0, epsilon)); + expect(math.approxEq(f64, tanh64(0.0), 0.0, epsilon)); + expect(math.approxEq(f64, tanh64(0.2), 0.197375, epsilon)); + expect(math.approxEq(f64, tanh64(0.8923), 0.712528, epsilon)); + expect(math.approxEq(f64, tanh64(1.5), 0.905148, epsilon)); + expect(math.approxEq(f64, tanh64(37.45), 1.0, epsilon)); } test "math.tanh32.special" { - assert(tanh32(0.0) == 0.0); - assert(tanh32(-0.0) == -0.0); - assert(tanh32(math.inf(f32)) == 1.0); - assert(tanh32(-math.inf(f32)) == -1.0); - assert(math.isNan(tanh32(math.nan(f32)))); + expect(tanh32(0.0) == 0.0); + expect(tanh32(-0.0) == -0.0); + expect(tanh32(math.inf(f32)) == 1.0); + expect(tanh32(-math.inf(f32)) == -1.0); + expect(math.isNan(tanh32(math.nan(f32)))); } test "math.tanh64.special" { - assert(tanh64(0.0) == 0.0); - assert(tanh64(-0.0) == -0.0); - assert(tanh64(math.inf(f64)) == 1.0); - assert(tanh64(-math.inf(f64)) == -1.0); - assert(math.isNan(tanh64(math.nan(f64)))); + expect(tanh64(0.0) == 0.0); + expect(tanh64(-0.0) == -0.0); + expect(tanh64(math.inf(f64)) == 1.0); + expect(tanh64(-math.inf(f64)) == -1.0); + expect(math.isNan(tanh64(math.nan(f64)))); } diff --git a/std/math/trunc.zig b/std/math/trunc.zig index bb309a1e24..8c91ccc568 100644 --- a/std/math/trunc.zig +++ b/std/math/trunc.zig @@ -6,7 +6,7 @@ const std = @import("../index.zig"); const math = std.math; -const assert = std.debug.assert; +const expect = std.testing.expect; const maxInt = std.math.maxInt; pub fn trunc(x: var) @typeOf(x) { @@ -61,34 +61,34 @@ fn trunc64(x: f64) f64 { } test "math.trunc" { - assert(trunc(f32(1.3)) == trunc32(1.3)); - assert(trunc(f64(1.3)) == trunc64(1.3)); + expect(trunc(f32(1.3)) == trunc32(1.3)); + expect(trunc(f64(1.3)) == trunc64(1.3)); } test "math.trunc32" { - assert(trunc32(1.3) == 1.0); - assert(trunc32(-1.3) == -1.0); - assert(trunc32(0.2) == 0.0); + expect(trunc32(1.3) == 1.0); + expect(trunc32(-1.3) == -1.0); + expect(trunc32(0.2) == 0.0); } test "math.trunc64" { - assert(trunc64(1.3) == 1.0); - assert(trunc64(-1.3) == -1.0); - assert(trunc64(0.2) == 0.0); + expect(trunc64(1.3) == 1.0); + expect(trunc64(-1.3) == -1.0); + expect(trunc64(0.2) == 0.0); } test "math.trunc32.special" { - assert(trunc32(0.0) == 0.0); // 0x3F800000 - assert(trunc32(-0.0) == -0.0); - assert(math.isPositiveInf(trunc32(math.inf(f32)))); - assert(math.isNegativeInf(trunc32(-math.inf(f32)))); - assert(math.isNan(trunc32(math.nan(f32)))); + expect(trunc32(0.0) == 0.0); // 0x3F800000 + expect(trunc32(-0.0) == -0.0); + expect(math.isPositiveInf(trunc32(math.inf(f32)))); + expect(math.isNegativeInf(trunc32(-math.inf(f32)))); + expect(math.isNan(trunc32(math.nan(f32)))); } test "math.trunc64.special" { - assert(trunc64(0.0) == 0.0); - assert(trunc64(-0.0) == -0.0); - assert(math.isPositiveInf(trunc64(math.inf(f64)))); - assert(math.isNegativeInf(trunc64(-math.inf(f64)))); - assert(math.isNan(trunc64(math.nan(f64)))); + expect(trunc64(0.0) == 0.0); + expect(trunc64(-0.0) == -0.0); + expect(math.isPositiveInf(trunc64(math.inf(f64)))); + expect(math.isNegativeInf(trunc64(-math.inf(f64)))); + expect(math.isNan(trunc64(math.nan(f64)))); } diff --git a/std/mem.zig b/std/mem.zig index a6cbae744f..1c7523bf13 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -6,6 +6,7 @@ const builtin = @import("builtin"); const mem = @This(); const meta = std.meta; const trait = meta.trait; +const testing = std.testing; pub const Allocator = struct { pub const Error = error{OutOfMemory}; @@ -181,7 +182,7 @@ test "mem.secureZero" { set(u8, a[0..], 0); secureZero(u8, b[0..]); - assert(eql(u8, a[0..], b[0..])); + testing.expectEqualSlices(u8, a[0..], b[0..]); } pub fn compare(comptime T: type, lhs: []const T, rhs: []const T) Compare { @@ -210,11 +211,11 @@ pub fn compare(comptime T: type, lhs: []const T, rhs: []const T) Compare { } test "mem.compare" { - assert(compare(u8, "abcd", "bee") == Compare.LessThan); - assert(compare(u8, "abc", "abc") == Compare.Equal); - assert(compare(u8, "abc", "abc0") == Compare.LessThan); - assert(compare(u8, "", "") == Compare.Equal); - assert(compare(u8, "", "a") == Compare.LessThan); + testing.expect(compare(u8, "abcd", "bee") == Compare.LessThan); + testing.expect(compare(u8, "abc", "abc") == Compare.Equal); + testing.expect(compare(u8, "abc", "abc0") == Compare.LessThan); + testing.expect(compare(u8, "", "") == Compare.Equal); + testing.expect(compare(u8, "", "a") == Compare.LessThan); } /// Returns true if lhs < rhs, false otherwise @@ -227,11 +228,11 @@ pub fn lessThan(comptime T: type, lhs: []const T, rhs: []const T) bool { } test "mem.lessThan" { - assert(lessThan(u8, "abcd", "bee")); - assert(!lessThan(u8, "abc", "abc")); - assert(lessThan(u8, "abc", "abc0")); - assert(!lessThan(u8, "", "")); - assert(lessThan(u8, "", "a")); + testing.expect(lessThan(u8, "abcd", "bee")); + testing.expect(!lessThan(u8, "abc", "abc")); + testing.expect(lessThan(u8, "abc", "abc0")); + testing.expect(!lessThan(u8, "", "")); + testing.expect(lessThan(u8, "", "a")); } /// Compares two slices and returns whether they are equal. @@ -296,10 +297,10 @@ pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []co } test "mem.trim" { - assert(eql(u8, trimLeft(u8, " foo\n ", " \n"), "foo\n ")); - assert(eql(u8, trimRight(u8, " foo\n ", " \n"), " foo")); - assert(eql(u8, trim(u8, " foo\n ", " \n"), "foo")); - assert(eql(u8, trim(u8, "foo", " \n"), "foo")); + testing.expectEqualSlices(u8, "foo\n ", trimLeft(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, " foo", trimRight(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, "foo", trim(u8, " foo\n ", " \n")); + testing.expectEqualSlices(u8, "foo", trim(u8, "foo", " \n")); } /// Linear search for the index of a scalar value inside a slice. @@ -380,20 +381,20 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee } test "mem.indexOf" { - assert(indexOf(u8, "one two three four", "four").? == 14); - assert(lastIndexOf(u8, "one two three two four", "two").? == 14); - assert(indexOf(u8, "one two three four", "gour") == null); - assert(lastIndexOf(u8, "one two three four", "gour") == null); - assert(indexOf(u8, "foo", "foo").? == 0); - assert(lastIndexOf(u8, "foo", "foo").? == 0); - assert(indexOf(u8, "foo", "fool") == null); - assert(lastIndexOf(u8, "foo", "lfoo") == null); - assert(lastIndexOf(u8, "foo", "fool") == null); - - assert(indexOf(u8, "foo foo", "foo").? == 0); - assert(lastIndexOf(u8, "foo foo", "foo").? == 4); - assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); - assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); + testing.expect(indexOf(u8, "one two three four", "four").? == 14); + testing.expect(lastIndexOf(u8, "one two three two four", "two").? == 14); + testing.expect(indexOf(u8, "one two three four", "gour") == null); + testing.expect(lastIndexOf(u8, "one two three four", "gour") == null); + testing.expect(indexOf(u8, "foo", "foo").? == 0); + testing.expect(lastIndexOf(u8, "foo", "foo").? == 0); + testing.expect(indexOf(u8, "foo", "fool") == null); + testing.expect(lastIndexOf(u8, "foo", "lfoo") == null); + testing.expect(lastIndexOf(u8, "foo", "fool") == null); + + testing.expect(indexOf(u8, "foo foo", "foo").? == 0); + testing.expect(lastIndexOf(u8, "foo foo", "foo").? == 4); + testing.expect(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); + testing.expect(lastIndexOfScalar(u8, "boo", 'o').? == 2); } /// Reads an integer from memory with size equal to bytes.len. @@ -504,34 +505,34 @@ test "comptime read/write int" { var bytes: [2]u8 = undefined; std.mem.writeIntLittle(u16, &bytes, 0x1234); const result = std.mem.readIntBig(u16, &bytes); - std.debug.assert(result == 0x3412); + testing.expect(result == 0x3412); } comptime { var bytes: [2]u8 = undefined; std.mem.writeIntBig(u16, &bytes, 0x1234); const result = std.mem.readIntLittle(u16, &bytes); - std.debug.assert(result == 0x3412); + testing.expect(result == 0x3412); } } test "readIntBig and readIntLittle" { - assert(readIntSliceBig(u0, []u8{}) == 0x0); - assert(readIntSliceLittle(u0, []u8{}) == 0x0); + testing.expect(readIntSliceBig(u0, []u8{}) == 0x0); + testing.expect(readIntSliceLittle(u0, []u8{}) == 0x0); - assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); - assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); + testing.expect(readIntSliceBig(u8, []u8{0x32}) == 0x32); + testing.expect(readIntSliceLittle(u8, []u8{0x12}) == 0x12); - assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); - assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); + testing.expect(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + testing.expect(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); - assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + testing.expect(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + testing.expect(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - assert(readIntSliceBig(i8, []u8{0xff}) == -1); - assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); + testing.expect(readIntSliceBig(i8, []u8{0xff}) == -1); + testing.expect(readIntSliceLittle(i8, []u8{0xfe}) == -2); - assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); - assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); + testing.expect(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + testing.expect(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); } /// Writes an integer to memory, storing it in twos-complement. @@ -645,34 +646,34 @@ test "writeIntBig and writeIntLittle" { var buf9: [9]u8 = undefined; writeIntBig(u0, &buf0, 0x0); - assert(eql_slice_u8(buf0[0..], []u8{})); + testing.expect(eql_slice_u8(buf0[0..], []u8{})); writeIntLittle(u0, &buf0, 0x0); - assert(eql_slice_u8(buf0[0..], []u8{})); + testing.expect(eql_slice_u8(buf0[0..], []u8{})); writeIntBig(u8, &buf1, 0x12); - assert(eql_slice_u8(buf1[0..], []u8{0x12})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0x12})); writeIntLittle(u8, &buf1, 0x34); - assert(eql_slice_u8(buf1[0..], []u8{0x34})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0x34})); writeIntBig(u16, &buf2, 0x1234); - assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); writeIntLittle(u16, &buf2, 0x5678); - assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); writeIntBig(u72, &buf9, 0x123456789abcdef024); - assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); + testing.expect(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); - assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); + testing.expect(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); writeIntBig(i8, &buf1, -1); - assert(eql_slice_u8(buf1[0..], []u8{0xff})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0xff})); writeIntLittle(i8, &buf1, -2); - assert(eql_slice_u8(buf1[0..], []u8{0xfe})); + testing.expect(eql_slice_u8(buf1[0..], []u8{0xfe})); writeIntBig(i16, &buf2, -3); - assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); writeIntLittle(i16, &buf2, -4); - assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); + testing.expect(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } pub fn hash_slice_u8(k: []const u8) u32 { @@ -706,46 +707,46 @@ pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator { test "mem.tokenize" { var it = tokenize(" abc def ghi ", " "); - assert(eql(u8, it.next().?, "abc")); - assert(eql(u8, it.next().?, "def")); - assert(eql(u8, it.next().?, "ghi")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "abc")); + testing.expect(eql(u8, it.next().?, "def")); + testing.expect(eql(u8, it.next().?, "ghi")); + testing.expect(it.next() == null); it = tokenize("..\\bob", "\\"); - assert(eql(u8, it.next().?, "..")); - assert(eql(u8, "..", "..\\bob"[0..it.index])); - assert(eql(u8, it.next().?, "bob")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "..")); + testing.expect(eql(u8, "..", "..\\bob"[0..it.index])); + testing.expect(eql(u8, it.next().?, "bob")); + testing.expect(it.next() == null); it = tokenize("//a/b", "/"); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b")); - assert(eql(u8, "//a/b", "//a/b"[0..it.index])); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b")); + testing.expect(eql(u8, "//a/b", "//a/b"[0..it.index])); + testing.expect(it.next() == null); it = tokenize("|", "|"); - assert(it.next() == null); + testing.expect(it.next() == null); it = tokenize("", "|"); - assert(it.next() == null); + testing.expect(it.next() == null); it = tokenize("hello", ""); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); it = tokenize("hello", " "); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); } test "mem.tokenize (multibyte)" { var it = tokenize("a|b,c/d e", " /,|"); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b")); - assert(eql(u8, it.next().?, "c")); - assert(eql(u8, it.next().?, "d")); - assert(eql(u8, it.next().?, "e")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b")); + testing.expect(eql(u8, it.next().?, "c")); + testing.expect(eql(u8, it.next().?, "d")); + testing.expect(eql(u8, it.next().?, "e")); + testing.expect(it.next() == null); } /// Returns an iterator that iterates over the slices of `buffer` that @@ -769,34 +770,34 @@ pub fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator { test "mem.separate" { var it = separate("abc|def||ghi", "|"); - assert(eql(u8, it.next().?, "abc")); - assert(eql(u8, it.next().?, "def")); - assert(eql(u8, it.next().?, "")); - assert(eql(u8, it.next().?, "ghi")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "abc")); + testing.expect(eql(u8, it.next().?, "def")); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(eql(u8, it.next().?, "ghi")); + testing.expect(it.next() == null); it = separate("", "|"); - assert(eql(u8, it.next().?, "")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(it.next() == null); it = separate("|", "|"); - assert(eql(u8, it.next().?, "")); - assert(eql(u8, it.next().?, "")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(eql(u8, it.next().?, "")); + testing.expect(it.next() == null); it = separate("hello", " "); - assert(eql(u8, it.next().?, "hello")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "hello")); + testing.expect(it.next() == null); } test "mem.separate (multibyte)" { var it = separate("a, b ,, c, d, e", ", "); - assert(eql(u8, it.next().?, "a")); - assert(eql(u8, it.next().?, "b ,")); - assert(eql(u8, it.next().?, "c")); - assert(eql(u8, it.next().?, "d")); - assert(eql(u8, it.next().?, "e")); - assert(it.next() == null); + testing.expect(eql(u8, it.next().?, "a")); + testing.expect(eql(u8, it.next().?, "b ,")); + testing.expect(eql(u8, it.next().?, "c")); + testing.expect(eql(u8, it.next().?, "d")); + testing.expect(eql(u8, it.next().?, "e")); + testing.expect(it.next() == null); } pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool { @@ -804,8 +805,8 @@ pub fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool } test "mem.startsWith" { - assert(startsWith(u8, "Bob", "Bo")); - assert(!startsWith(u8, "Needle in haystack", "haystack")); + testing.expect(startsWith(u8, "Bob", "Bo")); + testing.expect(!startsWith(u8, "Needle in haystack", "haystack")); } pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool { @@ -813,8 +814,8 @@ pub fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool { } test "mem.endsWith" { - assert(endsWith(u8, "Needle in haystack", "haystack")); - assert(!endsWith(u8, "Bob", "Bo")); + testing.expect(endsWith(u8, "Needle in haystack", "haystack")); + testing.expect(!endsWith(u8, "Bob", "Bo")); } pub const TokenIterator = struct { @@ -913,15 +914,15 @@ pub fn join(allocator: *Allocator, separator: []const u8, slices: []const []cons test "mem.join" { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; - assert(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); - assert(eql(u8, try join(a, ",", [][]const u8{"a"}), "a")); - assert(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{ "a", "b", "c" }), "a,b,c")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{"a"}), "a")); + testing.expect(eql(u8, try join(a, ",", [][]const u8{ "a", "", "b", "", "c" }), "a,,b,,c")); } test "testStringEquality" { - assert(eql(u8, "abcd", "abcd")); - assert(!eql(u8, "abcdef", "abZdef")); - assert(!eql(u8, "abcdefg", "abcdef")); + testing.expect(eql(u8, "abcd", "abcd")); + testing.expect(!eql(u8, "abcdef", "abZdef")); + testing.expect(!eql(u8, "abcdefg", "abcdef")); } test "testReadInt" { @@ -936,12 +937,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); - assert(readIntBig(u32, &bytes) == 0x12345678); - assert(readIntBig(i32, &bytes) == 0x12345678); - assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); - assert(readIntLittle(u32, &bytes) == 0x78563412); - assert(readIntLittle(i32, &bytes) == 0x78563412); + testing.expect(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + testing.expect(readIntBig(u32, &bytes) == 0x12345678); + testing.expect(readIntBig(i32, &bytes) == 0x12345678); + testing.expect(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + testing.expect(readIntLittle(u32, &bytes) == 0x78563412); + testing.expect(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -951,7 +952,7 @@ fn testReadIntImpl() void { 0x34, }; const answer = readInt(u32, &buf, builtin.Endian.Big); - assert(answer == 0x00001234); + testing.expect(answer == 0x00001234); } { const buf = []u8{ @@ -961,17 +962,17 @@ fn testReadIntImpl() void { 0x00, }; const answer = readInt(u32, &buf, builtin.Endian.Little); - assert(answer == 0x00003412); + testing.expect(answer == 0x00003412); } { const bytes = []u8{ 0xff, 0xfe, }; - assert(readIntBig(u16, &bytes) == 0xfffe); - assert(readIntBig(i16, &bytes) == -0x0002); - assert(readIntLittle(u16, &bytes) == 0xfeff); - assert(readIntLittle(i16, &bytes) == -0x0101); + testing.expect(readIntBig(u16, &bytes) == 0xfffe); + testing.expect(readIntBig(i16, &bytes) == -0x0002); + testing.expect(readIntLittle(u16, &bytes) == 0xfeff); + testing.expect(readIntLittle(i16, &bytes) == -0x0101); } } @@ -983,19 +984,19 @@ fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })); writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, })); writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1007,7 +1008,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1019,7 +1020,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, @@ -1031,7 +1032,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, @@ -1043,7 +1044,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x00, 0x00, 0x00, @@ -1055,7 +1056,7 @@ fn testWriteIntImpl() void { })); writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); - assert(eql(u8, bytes, []u8{ + testing.expect(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, @@ -1076,7 +1077,7 @@ pub fn min(comptime T: type, slice: []const T) T { } test "mem.min" { - assert(min(u8, "abcdefg") == 'a'); + testing.expect(min(u8, "abcdefg") == 'a'); } pub fn max(comptime T: type, slice: []const T) T { @@ -1088,7 +1089,7 @@ pub fn max(comptime T: type, slice: []const T) T { } test "mem.max" { - assert(max(u8, "abcdefg") == 'g'); + testing.expect(max(u8, "abcdefg") == 'g'); } pub fn swap(comptime T: type, a: *T, b: *T) void { @@ -1116,7 +1117,7 @@ test "std.mem.reverse" { }; reverse(i32, arr[0..]); - assert(eql(i32, arr, []i32{ + testing.expect(eql(i32, arr, []i32{ 4, 2, 1, @@ -1143,7 +1144,7 @@ test "std.mem.rotate" { }; rotate(i32, arr[0..], 2); - assert(eql(i32, arr, []i32{ + testing.expect(eql(i32, arr, []i32{ 1, 2, 4, @@ -1225,12 +1226,12 @@ test "std.mem.asBytes" { builtin.Endian.Little => "\xEF\xBE\xAD\xDE", }; - debug.assert(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); + testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); var codeface = u32(0xC0DEFACE); for (asBytes(&codeface).*) |*b| b.* = 0; - debug.assert(codeface == 0); + testing.expect(codeface == 0); const S = packed struct { a: u8, @@ -1245,7 +1246,7 @@ test "std.mem.asBytes" { .c = 0xDE, .d = 0xA1, }; - debug.assert(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); + testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1")); } ///Given any value, returns a copy of its bytes in an array. @@ -1256,14 +1257,14 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 { test "std.mem.toBytes" { var my_bytes = toBytes(u32(0x12345678)); switch (builtin.endian) { - builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")), - builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")), + builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")), + builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")), } my_bytes[0] = '\x99'; switch (builtin.endian) { - builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")), - builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")), + builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")), + builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")), } } @@ -1292,17 +1293,17 @@ test "std.mem.bytesAsValue" { builtin.Endian.Little => "\xEF\xBE\xAD\xDE", }; - debug.assert(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*); + testing.expect(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*); var codeface_bytes = switch (builtin.endian) { builtin.Endian.Big => "\xC0\xDE\xFA\xCE", builtin.Endian.Little => "\xCE\xFA\xDE\xC0", }; var codeface = bytesAsValue(u32, &codeface_bytes); - debug.assert(codeface.* == 0xC0DEFACE); + testing.expect(codeface.* == 0xC0DEFACE); codeface.* = 0; for (codeface_bytes) |b| - debug.assert(b == 0); + testing.expect(b == 0); const S = packed struct { a: u8, @@ -1319,7 +1320,7 @@ test "std.mem.bytesAsValue" { }; const inst_bytes = "\xBE\xEF\xDE\xA1"; const inst2 = bytesAsValue(S, &inst_bytes); - debug.assert(meta.eql(inst, inst2.*)); + testing.expect(meta.eql(inst, inst2.*)); } ///Given a pointer to an array of bytes, returns a value of the specified type backed by a @@ -1334,7 +1335,7 @@ test "std.mem.bytesToValue" { }; const deadbeef = bytesToValue(u32, deadbeef_bytes); - debug.assert(deadbeef == u32(0xDEADBEEF)); + testing.expect(deadbeef == u32(0xDEADBEEF)); } fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { @@ -1345,7 +1346,7 @@ fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { ///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubArrayPtrReturnType(@typeOf(ptr), length) { - debug.assert(start + length <= ptr.*.len); + assert(start + length <= ptr.*.len); const ReturnType = SubArrayPtrReturnType(@typeOf(ptr), length); const T = meta.Child(meta.Child(@typeOf(ptr))); @@ -1355,14 +1356,14 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA test "std.mem.subArrayPtr" { const a1 = "abcdef"; const sub1 = subArrayPtr(&a1, 2, 3); - debug.assert(std.mem.eql(u8, sub1.*, "cde")); + testing.expect(std.mem.eql(u8, sub1.*, "cde")); var a2 = "abcdef"; var sub2 = subArrayPtr(&a2, 2, 3); - debug.assert(std.mem.eql(u8, sub2, "cde")); + testing.expect(std.mem.eql(u8, sub2, "cde")); sub2[1] = 'X'; - debug.assert(std.mem.eql(u8, a2, "abcXef")); + testing.expect(std.mem.eql(u8, a2, "abcXef")); } /// Round an address up to the nearest aligned address @@ -1371,16 +1372,16 @@ pub fn alignForward(addr: usize, alignment: usize) usize { } test "std.mem.alignForward" { - debug.assertOrPanic(alignForward(1, 1) == 1); - debug.assertOrPanic(alignForward(2, 1) == 2); - debug.assertOrPanic(alignForward(1, 2) == 2); - debug.assertOrPanic(alignForward(2, 2) == 2); - debug.assertOrPanic(alignForward(3, 2) == 4); - debug.assertOrPanic(alignForward(4, 2) == 4); - debug.assertOrPanic(alignForward(7, 8) == 8); - debug.assertOrPanic(alignForward(8, 8) == 8); - debug.assertOrPanic(alignForward(9, 8) == 16); - debug.assertOrPanic(alignForward(15, 8) == 16); - debug.assertOrPanic(alignForward(16, 8) == 16); - debug.assertOrPanic(alignForward(17, 8) == 24); + testing.expect(alignForward(1, 1) == 1); + testing.expect(alignForward(2, 1) == 2); + testing.expect(alignForward(1, 2) == 2); + testing.expect(alignForward(2, 2) == 2); + testing.expect(alignForward(3, 2) == 4); + testing.expect(alignForward(4, 2) == 4); + testing.expect(alignForward(7, 8) == 8); + testing.expect(alignForward(8, 8) == 8); + testing.expect(alignForward(9, 8) == 16); + testing.expect(alignForward(15, 8) == 16); + testing.expect(alignForward(16, 8) == 16); + testing.expect(alignForward(17, 8) == 24); } diff --git a/std/meta/index.zig b/std/meta/index.zig index 4d195a6a12..3f8ea762a6 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const debug = std.debug; const mem = std.mem; const math = std.math; +const testing = std.testing; pub const trait = @import("trait.zig"); @@ -64,16 +65,16 @@ test "std.meta.tagName" { var u2a = U2{ .C = 0 }; var u2b = U2{ .D = 0 }; - debug.assert(mem.eql(u8, tagName(E1.A), "A")); - debug.assert(mem.eql(u8, tagName(E1.B), "B")); - debug.assert(mem.eql(u8, tagName(E2.C), "C")); - debug.assert(mem.eql(u8, tagName(E2.D), "D")); - debug.assert(mem.eql(u8, tagName(error.E), "E")); - debug.assert(mem.eql(u8, tagName(error.F), "F")); - debug.assert(mem.eql(u8, tagName(u1g), "G")); - debug.assert(mem.eql(u8, tagName(u1h), "H")); - debug.assert(mem.eql(u8, tagName(u2a), "C")); - debug.assert(mem.eql(u8, tagName(u2b), "D")); + testing.expect(mem.eql(u8, tagName(E1.A), "A")); + testing.expect(mem.eql(u8, tagName(E1.B), "B")); + testing.expect(mem.eql(u8, tagName(E2.C), "C")); + testing.expect(mem.eql(u8, tagName(E2.D), "D")); + testing.expect(mem.eql(u8, tagName(error.E), "E")); + testing.expect(mem.eql(u8, tagName(error.F), "F")); + testing.expect(mem.eql(u8, tagName(u1g), "G")); + testing.expect(mem.eql(u8, tagName(u1h), "H")); + testing.expect(mem.eql(u8, tagName(u2a), "C")); + testing.expect(mem.eql(u8, tagName(u2b), "D")); } pub fn stringToEnum(comptime T: type, str: []const u8) ?T { @@ -90,9 +91,9 @@ test "std.meta.stringToEnum" { A, B, }; - debug.assert(E1.A == stringToEnum(E1, "A").?); - debug.assert(E1.B == stringToEnum(E1, "B").?); - debug.assert(null == stringToEnum(E1, "C")); + testing.expect(E1.A == stringToEnum(E1, "A").?); + testing.expect(E1.B == stringToEnum(E1, "B").?); + testing.expect(null == stringToEnum(E1, "C")); } pub fn bitCount(comptime T: type) comptime_int { @@ -104,8 +105,8 @@ pub fn bitCount(comptime T: type) comptime_int { } test "std.meta.bitCount" { - debug.assert(bitCount(u8) == 8); - debug.assert(bitCount(f32) == 32); + testing.expect(bitCount(u8) == 8); + testing.expect(bitCount(f32) == 32); } pub fn alignment(comptime T: type) comptime_int { @@ -115,11 +116,11 @@ pub fn alignment(comptime T: type) comptime_int { } test "std.meta.alignment" { - debug.assert(alignment(u8) == 1); - debug.assert(alignment(*align(1) u8) == 1); - debug.assert(alignment(*align(2) u8) == 2); - debug.assert(alignment([]align(1) u8) == 1); - debug.assert(alignment([]align(2) u8) == 2); + testing.expect(alignment(u8) == 1); + testing.expect(alignment(*align(1) u8) == 1); + testing.expect(alignment(*align(2) u8) == 2); + testing.expect(alignment([]align(1) u8) == 1); + testing.expect(alignment([]align(2) u8) == 2); } pub fn Child(comptime T: type) type { @@ -133,11 +134,11 @@ pub fn Child(comptime T: type) type { } test "std.meta.Child" { - debug.assert(Child([1]u8) == u8); - debug.assert(Child(*u8) == u8); - debug.assert(Child([]u8) == u8); - debug.assert(Child(?u8) == u8); - debug.assert(Child(promise->u8) == u8); + testing.expect(Child([1]u8) == u8); + testing.expect(Child(*u8) == u8); + testing.expect(Child([]u8) == u8); + testing.expect(Child(?u8) == u8); + testing.expect(Child(promise->u8) == u8); } pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { @@ -172,15 +173,15 @@ test "std.meta.containerLayout" { a: u8, }; - debug.assert(containerLayout(E1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(E2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(E3) == TypeInfo.ContainerLayout.Extern); - debug.assert(containerLayout(S1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(S2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(S3) == TypeInfo.ContainerLayout.Extern); - debug.assert(containerLayout(U1) == TypeInfo.ContainerLayout.Auto); - debug.assert(containerLayout(U2) == TypeInfo.ContainerLayout.Packed); - debug.assert(containerLayout(U3) == TypeInfo.ContainerLayout.Extern); + testing.expect(containerLayout(E1) == TypeInfo.ContainerLayout.Auto); + testing.expect(containerLayout(E2) == TypeInfo.ContainerLayout.Packed); + testing.expect(containerLayout(E3) == TypeInfo.ContainerLayout.Extern); + testing.expect(containerLayout(S1) == TypeInfo.ContainerLayout.Auto); + testing.expect(containerLayout(S2) == TypeInfo.ContainerLayout.Packed); + testing.expect(containerLayout(S3) == TypeInfo.ContainerLayout.Extern); + testing.expect(containerLayout(U1) == TypeInfo.ContainerLayout.Auto); + testing.expect(containerLayout(U2) == TypeInfo.ContainerLayout.Packed); + testing.expect(containerLayout(U3) == TypeInfo.ContainerLayout.Extern); } pub fn definitions(comptime T: type) []TypeInfo.Definition { @@ -214,8 +215,8 @@ test "std.meta.definitions" { }; inline for (defs) |def| { - debug.assert(def.len == 1); - debug.assert(comptime mem.eql(u8, def[0].name, "a")); + testing.expect(def.len == 1); + testing.expect(comptime mem.eql(u8, def[0].name, "a")); } } @@ -250,8 +251,8 @@ test "std.meta.definitionInfo" { }; inline for (infos) |info| { - debug.assert(comptime mem.eql(u8, info.name, "a")); - debug.assert(!info.is_pub); + testing.expect(comptime mem.eql(u8, info.name, "a")); + testing.expect(!info.is_pub); } } @@ -288,16 +289,16 @@ test "std.meta.fields" { const sf = comptime fields(S1); const uf = comptime fields(U1); - debug.assert(e1f.len == 1); - debug.assert(e2f.len == 1); - debug.assert(sf.len == 1); - debug.assert(uf.len == 1); - debug.assert(mem.eql(u8, e1f[0].name, "A")); - debug.assert(mem.eql(u8, e2f[0].name, "A")); - debug.assert(mem.eql(u8, sf[0].name, "a")); - debug.assert(mem.eql(u8, uf[0].name, "a")); - debug.assert(comptime sf[0].field_type == u8); - debug.assert(comptime uf[0].field_type == u8); + testing.expect(e1f.len == 1); + testing.expect(e2f.len == 1); + testing.expect(sf.len == 1); + testing.expect(uf.len == 1); + testing.expect(mem.eql(u8, e1f[0].name, "A")); + testing.expect(mem.eql(u8, e2f[0].name, "A")); + testing.expect(mem.eql(u8, sf[0].name, "a")); + testing.expect(mem.eql(u8, uf[0].name, "a")); + testing.expect(comptime sf[0].field_type == u8); + testing.expect(comptime uf[0].field_type == u8); } pub fn fieldInfo(comptime T: type, comptime field_name: []const u8) switch (@typeInfo(T)) { @@ -332,12 +333,12 @@ test "std.meta.fieldInfo" { const sf = comptime fieldInfo(S1, "a"); const uf = comptime fieldInfo(U1, "a"); - debug.assert(mem.eql(u8, e1f.name, "A")); - debug.assert(mem.eql(u8, e2f.name, "A")); - debug.assert(mem.eql(u8, sf.name, "a")); - debug.assert(mem.eql(u8, uf.name, "a")); - debug.assert(comptime sf.field_type == u8); - debug.assert(comptime uf.field_type == u8); + testing.expect(mem.eql(u8, e1f.name, "A")); + testing.expect(mem.eql(u8, e2f.name, "A")); + testing.expect(mem.eql(u8, sf.name, "a")); + testing.expect(mem.eql(u8, uf.name, "a")); + testing.expect(comptime sf.field_type == u8); + testing.expect(comptime uf.field_type == u8); } pub fn TagType(comptime T: type) type { @@ -358,8 +359,8 @@ test "std.meta.TagType" { D: u16, }; - debug.assert(TagType(E) == u8); - debug.assert(TagType(U) == E); + testing.expect(TagType(E) == u8); + testing.expect(TagType(U) == E); } ///Returns the active tag of a tagged union @@ -380,18 +381,18 @@ test "std.meta.activeTag" { }; var u = U{ .Int = 32 }; - debug.assert(activeTag(u) == UE.Int); + testing.expect(activeTag(u) == UE.Int); u = U{ .Float = 112.9876 }; - debug.assert(activeTag(u) == UE.Float); + testing.expect(activeTag(u) == UE.Float); } ///Given a tagged union type, and an enum, return the type of the union /// field corresponding to the enum tag. pub fn TagPayloadType(comptime U: type, tag: var) type { const Tag = @typeOf(tag); - debug.assert(trait.is(builtin.TypeId.Union)(U)); - debug.assert(trait.is(builtin.TypeId.Enum)(Tag)); + testing.expect(trait.is(builtin.TypeId.Union)(U)); + testing.expect(trait.is(builtin.TypeId.Enum)(Tag)); const info = @typeInfo(U).Union; @@ -410,7 +411,7 @@ test "std.meta.TagPayloadType" { }; const MovedEvent = TagPayloadType(Event, Event.Moved); var e: Event = undefined; - debug.assert(MovedEvent == @typeOf(e.Moved)); + testing.expect(MovedEvent == @typeOf(e.Moved)); } ///Compares two of any type for equality. Containers are compared on a field-by-field basis, @@ -509,19 +510,19 @@ test "std.meta.eql" { const u_2 = U{ .s = s_1 }; const u_3 = U{ .f = 24 }; - debug.assert(eql(s_1, s_3)); - debug.assert(eql(&s_1, &s_1)); - debug.assert(!eql(&s_1, &s_3)); - debug.assert(eql(u_1, u_3)); - debug.assert(!eql(u_1, u_2)); + testing.expect(eql(s_1, s_3)); + testing.expect(eql(&s_1, &s_1)); + testing.expect(!eql(&s_1, &s_3)); + testing.expect(eql(u_1, u_3)); + testing.expect(!eql(u_1, u_2)); var a1 = "abcdef"; var a2 = "abcdef"; var a3 = "ghijkl"; - debug.assert(eql(a1, a2)); - debug.assert(!eql(a1, a3)); - debug.assert(!eql(a1[0..], a2[0..])); + testing.expect(eql(a1, a2)); + testing.expect(!eql(a1, a3)); + testing.expect(!eql(a1[0..], a2[0..])); const EU = struct { fn tst(err: bool) !u8 { @@ -530,9 +531,9 @@ test "std.meta.eql" { } }; - debug.assert(eql(EU.tst(true), EU.tst(true))); - debug.assert(eql(EU.tst(false), EU.tst(false))); - debug.assert(!eql(EU.tst(false), EU.tst(true))); + testing.expect(eql(EU.tst(true), EU.tst(true))); + testing.expect(eql(EU.tst(false), EU.tst(false))); + testing.expect(!eql(EU.tst(false), EU.tst(true))); } test "intToEnum with error return" { @@ -546,9 +547,9 @@ test "intToEnum with error return" { var zero: u8 = 0; var one: u16 = 1; - debug.assert(intToEnum(E1, zero) catch unreachable == E1.A); - debug.assert(intToEnum(E2, one) catch unreachable == E2.B); - debug.assertError(intToEnum(E1, one), error.InvalidEnumTag); + testing.expect(intToEnum(E1, zero) catch unreachable == E1.A); + testing.expect(intToEnum(E2, one) catch unreachable == E2.B); + testing.expectError(error.InvalidEnumTag, intToEnum(E1, one)); } pub const IntToEnumError = error{InvalidEnumTag}; diff --git a/std/meta/trait.zig b/std/meta/trait.zig index c9d9e971c9..7fca5f4dcd 100644 --- a/std/meta/trait.zig +++ b/std/meta/trait.zig @@ -2,6 +2,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const mem = std.mem; const debug = std.debug; +const testing = std.testing; const warn = debug.warn; const meta = @import("index.zig"); @@ -50,8 +51,8 @@ test "std.meta.trait.multiTrait" { hasField("x"), hasField("y"), }); - debug.assert(isVector(Vector2)); - debug.assert(!isVector(u8)); + testing.expect(isVector(Vector2)); + testing.expect(!isVector(u8)); } /// @@ -85,12 +86,12 @@ test "std.meta.trait.hasDef" { const value = u8(16); }; - debug.assert(hasDef("value")(TestStruct)); - debug.assert(!hasDef("value")(TestStructFail)); - debug.assert(!hasDef("value")(*TestStruct)); - debug.assert(!hasDef("value")(**TestStructFail)); - debug.assert(!hasDef("x")(TestStruct)); - debug.assert(!hasDef("value")(u8)); + testing.expect(hasDef("value")(TestStruct)); + testing.expect(!hasDef("value")(TestStructFail)); + testing.expect(!hasDef("value")(*TestStruct)); + testing.expect(!hasDef("value")(**TestStructFail)); + testing.expect(!hasDef("x")(TestStruct)); + testing.expect(!hasDef("value")(u8)); } /// @@ -111,9 +112,9 @@ test "std.meta.trait.hasFn" { pub fn useless() void {} }; - debug.assert(hasFn("useless")(TestStruct)); - debug.assert(!hasFn("append")(TestStruct)); - debug.assert(!hasFn("useless")(u8)); + testing.expect(hasFn("useless")(TestStruct)); + testing.expect(!hasFn("append")(TestStruct)); + testing.expect(!hasFn("useless")(u8)); } /// @@ -143,11 +144,11 @@ test "std.meta.trait.hasField" { value: u32, }; - debug.assert(hasField("value")(TestStruct)); - debug.assert(!hasField("value")(*TestStruct)); - debug.assert(!hasField("x")(TestStruct)); - debug.assert(!hasField("x")(**TestStruct)); - debug.assert(!hasField("value")(u8)); + testing.expect(hasField("value")(TestStruct)); + testing.expect(!hasField("value")(*TestStruct)); + testing.expect(!hasField("x")(TestStruct)); + testing.expect(!hasField("x")(**TestStruct)); + testing.expect(!hasField("value")(u8)); } /// @@ -161,11 +162,11 @@ pub fn is(comptime id: builtin.TypeId) TraitFn { } test "std.meta.trait.is" { - debug.assert(is(builtin.TypeId.Int)(u8)); - debug.assert(!is(builtin.TypeId.Int)(f32)); - debug.assert(is(builtin.TypeId.Pointer)(*u8)); - debug.assert(is(builtin.TypeId.Void)(void)); - debug.assert(!is(builtin.TypeId.Optional)(anyerror)); + testing.expect(is(builtin.TypeId.Int)(u8)); + testing.expect(!is(builtin.TypeId.Int)(f32)); + testing.expect(is(builtin.TypeId.Pointer)(*u8)); + testing.expect(is(builtin.TypeId.Void)(void)); + testing.expect(!is(builtin.TypeId.Optional)(anyerror)); } /// @@ -180,9 +181,9 @@ pub fn isPtrTo(comptime id: builtin.TypeId) TraitFn { } test "std.meta.trait.isPtrTo" { - debug.assert(!isPtrTo(builtin.TypeId.Struct)(struct {})); - debug.assert(isPtrTo(builtin.TypeId.Struct)(*struct {})); - debug.assert(!isPtrTo(builtin.TypeId.Struct)(**struct {})); + testing.expect(!isPtrTo(builtin.TypeId.Struct)(struct {})); + testing.expect(isPtrTo(builtin.TypeId.Struct)(*struct {})); + testing.expect(!isPtrTo(builtin.TypeId.Struct)(**struct {})); } ///////////Strait trait Fns @@ -205,9 +206,9 @@ test "std.meta.trait.isExtern" { const TestExStruct = extern struct {}; const TestStruct = struct {}; - debug.assert(isExtern(TestExStruct)); - debug.assert(!isExtern(TestStruct)); - debug.assert(!isExtern(u8)); + testing.expect(isExtern(TestExStruct)); + testing.expect(!isExtern(TestStruct)); + testing.expect(!isExtern(u8)); } /// @@ -226,9 +227,9 @@ test "std.meta.trait.isPacked" { const TestPStruct = packed struct {}; const TestStruct = struct {}; - debug.assert(isPacked(TestPStruct)); - debug.assert(!isPacked(TestStruct)); - debug.assert(!isPacked(u8)); + testing.expect(isPacked(TestPStruct)); + testing.expect(!isPacked(TestStruct)); + testing.expect(!isPacked(u8)); } /// @@ -240,10 +241,10 @@ pub fn isUnsignedInt(comptime T: type) bool { } test "isUnsignedInt" { - debug.assert(isUnsignedInt(u32) == true); - debug.assert(isUnsignedInt(comptime_int) == false); - debug.assert(isUnsignedInt(i64) == false); - debug.assert(isUnsignedInt(f64) == false); + testing.expect(isUnsignedInt(u32) == true); + testing.expect(isUnsignedInt(comptime_int) == false); + testing.expect(isUnsignedInt(i64) == false); + testing.expect(isUnsignedInt(f64) == false); } /// @@ -256,10 +257,10 @@ pub fn isSignedInt(comptime T: type) bool { } test "isSignedInt" { - debug.assert(isSignedInt(u32) == false); - debug.assert(isSignedInt(comptime_int) == true); - debug.assert(isSignedInt(i64) == true); - debug.assert(isSignedInt(f64) == false); + testing.expect(isSignedInt(u32) == false); + testing.expect(isSignedInt(comptime_int) == true); + testing.expect(isSignedInt(i64) == true); + testing.expect(isSignedInt(f64) == false); } /// @@ -273,9 +274,9 @@ pub fn isSingleItemPtr(comptime T: type) bool { test "std.meta.trait.isSingleItemPtr" { const array = []u8{0} ** 10; - debug.assert(isSingleItemPtr(@typeOf(&array[0]))); - debug.assert(!isSingleItemPtr(@typeOf(array))); - debug.assert(!isSingleItemPtr(@typeOf(array[0..1]))); + testing.expect(isSingleItemPtr(@typeOf(&array[0]))); + testing.expect(!isSingleItemPtr(@typeOf(array))); + testing.expect(!isSingleItemPtr(@typeOf(array[0..1]))); } /// @@ -290,9 +291,9 @@ pub fn isManyItemPtr(comptime T: type) bool { test "std.meta.trait.isManyItemPtr" { const array = []u8{0} ** 10; const mip = @ptrCast([*]const u8, &array[0]); - debug.assert(isManyItemPtr(@typeOf(mip))); - debug.assert(!isManyItemPtr(@typeOf(array))); - debug.assert(!isManyItemPtr(@typeOf(array[0..1]))); + testing.expect(isManyItemPtr(@typeOf(mip))); + testing.expect(!isManyItemPtr(@typeOf(array))); + testing.expect(!isManyItemPtr(@typeOf(array[0..1]))); } /// @@ -306,9 +307,9 @@ pub fn isSlice(comptime T: type) bool { test "std.meta.trait.isSlice" { const array = []u8{0} ** 10; - debug.assert(isSlice(@typeOf(array[0..]))); - debug.assert(!isSlice(@typeOf(array))); - debug.assert(!isSlice(@typeOf(&array[0]))); + testing.expect(isSlice(@typeOf(array[0..]))); + testing.expect(!isSlice(@typeOf(array))); + testing.expect(!isSlice(@typeOf(&array[0]))); } /// @@ -328,10 +329,10 @@ test "std.meta.trait.isIndexable" { const array = []u8{0} ** 10; const slice = array[0..]; - debug.assert(isIndexable(@typeOf(array))); - debug.assert(isIndexable(@typeOf(&array))); - debug.assert(isIndexable(@typeOf(slice))); - debug.assert(!isIndexable(meta.Child(@typeOf(slice)))); + testing.expect(isIndexable(@typeOf(array))); + testing.expect(isIndexable(@typeOf(&array))); + testing.expect(isIndexable(@typeOf(slice))); + testing.expect(!isIndexable(meta.Child(@typeOf(slice)))); } /// @@ -347,13 +348,13 @@ test "std.meta.trait.isNumber" { number: u8, }; - debug.assert(isNumber(u32)); - debug.assert(isNumber(f32)); - debug.assert(isNumber(u64)); - debug.assert(isNumber(@typeOf(102))); - debug.assert(isNumber(@typeOf(102.123))); - debug.assert(!isNumber([]u8)); - debug.assert(!isNumber(NotANumber)); + testing.expect(isNumber(u32)); + testing.expect(isNumber(f32)); + testing.expect(isNumber(u64)); + testing.expect(isNumber(@typeOf(102))); + testing.expect(isNumber(@typeOf(102.123))); + testing.expect(!isNumber([]u8)); + testing.expect(!isNumber(NotANumber)); } /// @@ -366,10 +367,10 @@ pub fn isConstPtr(comptime T: type) bool { test "std.meta.trait.isConstPtr" { var t = u8(0); const c = u8(0); - debug.assert(isConstPtr(*const @typeOf(t))); - debug.assert(isConstPtr(@typeOf(&c))); - debug.assert(!isConstPtr(*@typeOf(t))); - debug.assert(!isConstPtr(@typeOf(6))); + testing.expect(isConstPtr(*const @typeOf(t))); + testing.expect(isConstPtr(@typeOf(&c))); + testing.expect(!isConstPtr(*@typeOf(t))); + testing.expect(!isConstPtr(@typeOf(6))); } /// @@ -393,8 +394,8 @@ test "std.meta.trait.isContainer" { B, }; - debug.assert(isContainer(TestStruct)); - debug.assert(isContainer(TestUnion)); - debug.assert(isContainer(TestEnum)); - debug.assert(!isContainer(u8)); + testing.expect(isContainer(TestStruct)); + testing.expect(isContainer(TestUnion)); + testing.expect(isContainer(TestEnum)); + testing.expect(!isContainer(u8)); } diff --git a/std/mutex.zig b/std/mutex.zig index 54173fa38a..a13b1c06c7 100644 --- a/std/mutex.zig +++ b/std/mutex.zig @@ -2,7 +2,7 @@ const std = @import("index.zig"); const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; -const assert = std.debug.assert; +const testing = std.testing; const SpinLock = std.SpinLock; const linux = std.os.linux; const windows = std.os.windows; @@ -149,7 +149,7 @@ test "std.Mutex" { if (builtin.single_threaded) { worker(&context); - std.debug.assertOrPanic(context.data == TestContext.incr_count); + testing.expect(context.data == TestContext.incr_count); } else { const thread_count = 10; var threads: [thread_count]*std.os.Thread = undefined; @@ -159,7 +159,7 @@ test "std.Mutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + testing.expect(context.data == thread_count * TestContext.incr_count); } } diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 6635b76976..1da0b3492b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -7,7 +7,6 @@ const posix = os.posix; const windows = os.windows; const mem = std.mem; const debug = std.debug; -const assert = debug.assert; const BufMap = std.BufMap; const Buffer = std.Buffer; const builtin = @import("builtin"); diff --git a/std/os/index.zig b/std/os/index.zig index 8e9876c36b..f52c12c2b6 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -91,6 +91,7 @@ pub const GetAppDataDirError = @import("get_app_data_dir.zig").GetAppDataDirErro const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const c = std.c; @@ -172,7 +173,7 @@ test "os.getRandomBytes" { try getRandomBytes(buf_b[0..]); // Check if random (not 100% conclusive) - assert(!mem.eql(u8, buf_a, buf_b)); + testing.expect(!mem.eql(u8, buf_a, buf_b)); } /// Raises a signal in the current kernel thread, ending its execution. @@ -828,7 +829,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned test "os.getEnvVarOwned" { var ga = debug.global_allocator; - debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); + testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); } /// Caller must free the returned memory. @@ -2219,9 +2220,9 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { const arg = it.next(debug.global_allocator).? catch unreachable; - assert(mem.eql(u8, arg, expected_arg)); + testing.expectEqualSlices(u8, expected_arg, arg); } - assert(it.next(debug.global_allocator) == null); + testing.expect(it.next(debug.global_allocator) == null); } // TODO make this a build variable that you can set diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig index 4de26012c7..40fb7823d2 100644 --- a/std/os/linux/test.zig +++ b/std/os/linux/test.zig @@ -1,19 +1,19 @@ const std = @import("../../index.zig"); const builtin = @import("builtin"); const linux = std.os.linux; -const assert = std.debug.assert; +const expect = std.testing.expect; test "getpid" { - assert(linux.getpid() != 0); + expect(linux.getpid() != 0); } test "timer" { const epoll_fd = linux.epoll_create(); var err = linux.getErrno(epoll_fd); - assert(err == 0); + expect(err == 0); const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0); - assert(linux.getErrno(timer_fd) == 0); + expect(linux.getErrno(timer_fd) == 0); const time_interval = linux.timespec{ .tv_sec = 0, @@ -26,7 +26,7 @@ test "timer" { }; err = linux.timerfd_settime(@intCast(i32, timer_fd), 0, &new_time, null); - assert(err == 0); + expect(err == 0); var event = linux.epoll_event{ .events = linux.EPOLLIN | linux.EPOLLOUT | linux.EPOLLET, @@ -34,7 +34,7 @@ test "timer" { }; err = linux.epoll_ctl(@intCast(i32, epoll_fd), linux.EPOLL_CTL_ADD, @intCast(i32, timer_fd), &event); - assert(err == 0); + expect(err == 0); const events_one: linux.epoll_event = undefined; var events = []linux.epoll_event{events_one} ** 8; diff --git a/std/os/path.zig b/std/os/path.zig index 266a77b97c..5ba345fceb 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const mem = std.mem; const fmt = std.fmt; const Allocator = mem.Allocator; @@ -94,14 +95,14 @@ fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; const actual = joinWindows(a, paths) catch @panic("fail"); - debug.assertOrPanic(mem.eql(u8, actual, expected)); + testing.expectEqualSlices(u8, expected, actual); } fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { var buf: [1024]u8 = undefined; const a = &std.heap.FixedBufferAllocator.init(&buf).allocator; const actual = joinPosix(a, paths) catch @panic("fail"); - debug.assertOrPanic(mem.eql(u8, actual, expected)); + testing.expectEqualSlices(u8, expected, actual); } test "os.path.join" { @@ -193,11 +194,11 @@ test "os.path.isAbsolutePosix" { } fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void { - assert(isAbsoluteWindows(path) == expected_result); + testing.expectEqual(expected_result, isAbsoluteWindows(path)); } fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void { - assert(isAbsolutePosix(path) == expected_result); + testing.expectEqual(expected_result, isAbsolutePosix(path)); } pub const WindowsPath = struct { @@ -281,33 +282,33 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { test "os.path.windowsParsePath" { { const parsed = windowsParsePath("//a/b"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.NetworkShare); - assert(mem.eql(u8, parsed.disk_designator, "//a/b")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare); + testing.expect(mem.eql(u8, parsed.disk_designator, "//a/b")); } { const parsed = windowsParsePath("\\\\a\\b"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.NetworkShare); - assert(mem.eql(u8, parsed.disk_designator, "\\\\a\\b")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare); + testing.expect(mem.eql(u8, parsed.disk_designator, "\\\\a\\b")); } { const parsed = windowsParsePath("\\\\a\\"); - assert(!parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.None); - assert(mem.eql(u8, parsed.disk_designator, "")); + testing.expect(!parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.None); + testing.expect(mem.eql(u8, parsed.disk_designator, "")); } { const parsed = windowsParsePath("/usr/local"); - assert(parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.None); - assert(mem.eql(u8, parsed.disk_designator, "")); + testing.expect(parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.None); + testing.expect(mem.eql(u8, parsed.disk_designator, "")); } { const parsed = windowsParsePath("c:../"); - assert(!parsed.is_abs); - assert(parsed.kind == WindowsPath.Kind.Drive); - assert(mem.eql(u8, parsed.disk_designator, "c:")); + testing.expect(!parsed.is_abs); + testing.expect(parsed.kind == WindowsPath.Kind.Drive); + testing.expect(mem.eql(u8, parsed.disk_designator, "c:")); } } @@ -642,10 +643,10 @@ test "os.path.resolve" { if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { cwd[0] = asciiUpper(cwd[0]); } - assert(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd)); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd)); } else { - assert(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd)); - assert(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd)); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd)); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd)); } } @@ -662,7 +663,7 @@ test "os.path.resolveWindows" { if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - assert(mem.eql(u8, result, expected)); + testing.expect(mem.eql(u8, result, expected)); } { const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" }); @@ -673,36 +674,36 @@ test "os.path.resolveWindows" { if (parsed_cwd.kind == WindowsPath.Kind.Drive) { expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); } - assert(mem.eql(u8, result, expected)); + testing.expect(mem.eql(u8, result, expected)); } } - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir")); - assert(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir")); + testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js")); } test "os.path.resolvePosix" { - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/")); - assert(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c")); - - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute")); - assert(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c")); + + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute")); + testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js")); } fn testResolveWindows(paths: []const []const u8) []u8 { @@ -833,17 +834,17 @@ test "os.path.dirnameWindows" { fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void { if (dirnamePosix(input)) |output| { - assert(mem.eql(u8, output, expected_output.?)); + testing.expect(mem.eql(u8, output, expected_output.?)); } else { - assert(expected_output == null); + testing.expect(expected_output == null); } } fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void { if (dirnameWindows(input)) |output| { - assert(mem.eql(u8, output, expected_output.?)); + testing.expect(mem.eql(u8, output, expected_output.?)); } else { - assert(expected_output == null); + testing.expect(expected_output == null); } } @@ -948,15 +949,15 @@ test "os.path.basename" { } fn testBasename(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basename(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basename(input)); } fn testBasenamePosix(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basenamePosix(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basenamePosix(input)); } fn testBasenameWindows(input: []const u8, expected_output: []const u8) void { - assert(mem.eql(u8, basenameWindows(input), expected_output)); + testing.expectEqualSlices(u8, expected_output, basenameWindows(input)); } /// Returns the relative path from `from` to `to`. If `from` and `to` each @@ -1131,12 +1132,12 @@ test "os.path.relative" { fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void { const result = relativePosix(debug.global_allocator, from, to) catch unreachable; - assert(mem.eql(u8, result, expected_output)); + testing.expectEqualSlices(u8, expected_output, result); } fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void { const result = relativeWindows(debug.global_allocator, from, to) catch unreachable; - assert(mem.eql(u8, result, expected_output)); + testing.expectEqualSlices(u8, expected_output, result); } pub const RealError = error{ @@ -1283,5 +1284,5 @@ pub fn realAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { test "os.path.real" { // at least call it so it gets compiled var buf: [os.MAX_PATH_BYTES]u8 = undefined; - std.debug.assertError(real(&buf, "definitely_bogus_does_not_exist1234"), error.FileNotFound); + testing.expectError(error.FileNotFound, real(&buf, "definitely_bogus_does_not_exist1234")); } diff --git a/std/os/test.zig b/std/os/test.zig index bd9148d1b1..b2a4d96651 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -1,6 +1,6 @@ const std = @import("../index.zig"); const os = std.os; -const assert = std.debug.assert; +const expect = std.testing.expect; const io = std.io; const mem = std.mem; @@ -18,7 +18,7 @@ test "makePath, put some files in it, deleteTree" { if (os.Dir.open(a, "os_test_tmp")) |dir| { @panic("expected error"); } else |err| { - assert(err == error.FileNotFound); + expect(err == error.FileNotFound); } } @@ -27,7 +27,7 @@ test "access file" { if (os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt")) |ok| { @panic("expected error"); } else |err| { - assert(err == error.FileNotFound); + expect(err == error.FileNotFound); } try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "file.txt", ""); @@ -47,9 +47,9 @@ test "std.os.Thread.getCurrentId" { const thread_id = thread.handle(); thread.wait(); switch (builtin.os) { - builtin.Os.windows => assert(os.Thread.getCurrentId() != thread_current_id), + builtin.Os.windows => expect(os.Thread.getCurrentId() != thread_current_id), else => { - assert(thread_current_id == thread_id); + expect(thread_current_id == thread_id); }, } } @@ -69,7 +69,7 @@ test "spawn threads" { thread3.wait(); thread4.wait(); - assert(shared_ctx == 4); + expect(shared_ctx == 4); } fn start1(ctx: void) u8 { @@ -83,7 +83,7 @@ fn start2(ctx: *i32) u8 { test "cpu count" { const cpu_count = try std.os.cpuCount(a); - assert(cpu_count >= 1); + expect(cpu_count >= 1); } test "AtomicFile" { @@ -101,7 +101,7 @@ test "AtomicFile" { try af.finish(); } const content = try io.readFileAlloc(allocator, test_out_file); - assert(mem.eql(u8, content, test_content)); + expect(mem.eql(u8, content, test_content)); try os.deleteFile(test_out_file); } diff --git a/std/os/time.zig b/std/os/time.zig index 4b11a69376..638fb41ff1 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -2,6 +2,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; +const testing = std.testing; const windows = std.os.windows; const linux = std.os.linux; @@ -270,7 +271,7 @@ test "os.time.timestamp" { sleep(ns_per_ms); const time_1 = milliTimestamp(); const interval = time_1 - time_0; - debug.assert(interval > 0 and interval < margin); + testing.expect(interval > 0 and interval < margin); } test "os.time.Timer" { @@ -280,11 +281,11 @@ test "os.time.Timer" { var timer = try Timer.start(); sleep(10 * ns_per_ms); const time_0 = timer.read(); - debug.assert(time_0 > 0 and time_0 < margin); + testing.expect(time_0 > 0 and time_0 < margin); const time_1 = timer.lap(); - debug.assert(time_1 >= time_0); + testing.expect(time_1 >= time_0); timer.reset(); - debug.assert(timer.read() < time_1); + testing.expect(timer.read() < time_1); } diff --git a/std/rand/index.zig b/std/rand/index.zig index c335063e64..12dd763aee 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -17,6 +17,7 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; +const expect = std.testing.expect; const mem = std.mem; const math = std.math; const ziggurat = @import("ziggurat.zig"); @@ -316,43 +317,43 @@ test "Random int" { fn testRandomInt() void { var r = SequentialPrng.init(); - assert(r.random.int(u0) == 0); + expect(r.random.int(u0) == 0); r.next_value = 0; - assert(r.random.int(u1) == 0); - assert(r.random.int(u1) == 1); - assert(r.random.int(u2) == 2); - assert(r.random.int(u2) == 3); - assert(r.random.int(u2) == 0); + expect(r.random.int(u1) == 0); + expect(r.random.int(u1) == 1); + expect(r.random.int(u2) == 2); + expect(r.random.int(u2) == 3); + expect(r.random.int(u2) == 0); r.next_value = 0xff; - assert(r.random.int(u8) == 0xff); + expect(r.random.int(u8) == 0xff); r.next_value = 0x11; - assert(r.random.int(u8) == 0x11); + expect(r.random.int(u8) == 0x11); r.next_value = 0xff; - assert(r.random.int(u32) == 0xffffffff); + expect(r.random.int(u32) == 0xffffffff); r.next_value = 0x11; - assert(r.random.int(u32) == 0x11111111); + expect(r.random.int(u32) == 0x11111111); r.next_value = 0xff; - assert(r.random.int(i32) == -1); + expect(r.random.int(i32) == -1); r.next_value = 0x11; - assert(r.random.int(i32) == 0x11111111); + expect(r.random.int(i32) == 0x11111111); r.next_value = 0xff; - assert(r.random.int(i8) == -1); + expect(r.random.int(i8) == -1); r.next_value = 0x11; - assert(r.random.int(i8) == 0x11); + expect(r.random.int(i8) == 0x11); r.next_value = 0xff; - assert(r.random.int(u33) == 0x1ffffffff); + expect(r.random.int(u33) == 0x1ffffffff); r.next_value = 0xff; - assert(r.random.int(i1) == -1); + expect(r.random.int(i1) == -1); r.next_value = 0xff; - assert(r.random.int(i2) == -1); + expect(r.random.int(i2) == -1); r.next_value = 0xff; - assert(r.random.int(i33) == -1); + expect(r.random.int(i33) == -1); } test "Random boolean" { @@ -361,10 +362,10 @@ test "Random boolean" { } fn testRandomBoolean() void { var r = SequentialPrng.init(); - assert(r.random.boolean() == false); - assert(r.random.boolean() == true); - assert(r.random.boolean() == false); - assert(r.random.boolean() == true); + expect(r.random.boolean() == false); + expect(r.random.boolean() == true); + expect(r.random.boolean() == false); + expect(r.random.boolean() == true); } test "Random intLessThan" { @@ -375,36 +376,36 @@ test "Random intLessThan" { fn testRandomIntLessThan() void { var r = SequentialPrng.init(); r.next_value = 0xff; - assert(r.random.uintLessThan(u8, 4) == 3); - assert(r.next_value == 0); - assert(r.random.uintLessThan(u8, 4) == 0); - assert(r.next_value == 1); + expect(r.random.uintLessThan(u8, 4) == 3); + expect(r.next_value == 0); + expect(r.random.uintLessThan(u8, 4) == 0); + expect(r.next_value == 1); r.next_value = 0; - assert(r.random.uintLessThan(u64, 32) == 0); + expect(r.random.uintLessThan(u64, 32) == 0); // trigger the bias rejection code path r.next_value = 0; - assert(r.random.uintLessThan(u8, 3) == 0); + expect(r.random.uintLessThan(u8, 3) == 0); // verify we incremented twice - assert(r.next_value == 2); + expect(r.next_value == 2); r.next_value = 0xff; - assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); + expect(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe); + expect(r.random.intRangeLessThan(u8, 0x7f, 0xff) == 0xfe); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f); + expect(r.random.intRangeLessThan(i8, 0, 0x40) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f); + expect(r.random.intRangeLessThan(i8, -0x40, 0x40) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1); + expect(r.random.intRangeLessThan(i8, -0x80, 0) == -1); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i3, -4, 0) == -1); + expect(r.random.intRangeLessThan(i3, -4, 0) == -1); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i3, -2, 2) == 1); + expect(r.random.intRangeLessThan(i3, -2, 2) == 1); } test "Random intAtMost" { @@ -415,34 +416,34 @@ test "Random intAtMost" { fn testRandomIntAtMost() void { var r = SequentialPrng.init(); r.next_value = 0xff; - assert(r.random.uintAtMost(u8, 3) == 3); - assert(r.next_value == 0); - assert(r.random.uintAtMost(u8, 3) == 0); + expect(r.random.uintAtMost(u8, 3) == 3); + expect(r.next_value == 0); + expect(r.random.uintAtMost(u8, 3) == 0); // trigger the bias rejection code path r.next_value = 0; - assert(r.random.uintAtMost(u8, 2) == 0); + expect(r.random.uintAtMost(u8, 2) == 0); // verify we incremented twice - assert(r.next_value == 2); + expect(r.next_value == 2); r.next_value = 0xff; - assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); + expect(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe); + expect(r.random.intRangeAtMost(u8, 0x7f, 0xfe) == 0xfe); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f); + expect(r.random.intRangeAtMost(i8, 0, 0x3f) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f); + expect(r.random.intRangeAtMost(i8, -0x40, 0x3f) == 0x3f); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1); + expect(r.random.intRangeAtMost(i8, -0x80, -1) == -1); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i3, -4, -1) == -1); + expect(r.random.intRangeAtMost(i3, -4, -1) == -1); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i3, -2, 1) == 1); + expect(r.random.intRangeAtMost(i3, -2, 1) == 1); - assert(r.random.uintAtMost(u0, 0) == 0); + expect(r.random.uintAtMost(u0, 0) == 0); } test "Random Biased" { @@ -450,30 +451,30 @@ test "Random Biased" { // Not thoroughly checking the logic here. // Just want to execute all the paths with different types. - assert(r.random.uintLessThanBiased(u1, 1) == 0); - assert(r.random.uintLessThanBiased(u32, 10) < 10); - assert(r.random.uintLessThanBiased(u64, 20) < 20); + expect(r.random.uintLessThanBiased(u1, 1) == 0); + expect(r.random.uintLessThanBiased(u32, 10) < 10); + expect(r.random.uintLessThanBiased(u64, 20) < 20); - assert(r.random.uintAtMostBiased(u0, 0) == 0); - assert(r.random.uintAtMostBiased(u1, 0) <= 0); - assert(r.random.uintAtMostBiased(u32, 10) <= 10); - assert(r.random.uintAtMostBiased(u64, 20) <= 20); + expect(r.random.uintAtMostBiased(u0, 0) == 0); + expect(r.random.uintAtMostBiased(u1, 0) <= 0); + expect(r.random.uintAtMostBiased(u32, 10) <= 10); + expect(r.random.uintAtMostBiased(u64, 20) <= 20); - assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0); - assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1); - assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10); - assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10); - assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20); - assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20); + expect(r.random.intRangeLessThanBiased(u1, 0, 1) == 0); + expect(r.random.intRangeLessThanBiased(i1, -1, 0) == -1); + expect(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10); + expect(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10); + expect(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20); + expect(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20); // uncomment for broken module error: - //assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0); - assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0); - assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1); - assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10); - assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10); - assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20); - assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20); + //expect(r.random.intRangeAtMostBiased(u0, 0, 0) == 0); + expect(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0); + expect(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1); + expect(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10); + expect(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10); + expect(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20); + expect(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20); } // Generator to extend 64-bit seed values into longer sequences. @@ -510,7 +511,7 @@ test "splitmix64 sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -603,7 +604,7 @@ test "pcg sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -712,7 +713,7 @@ test "xoroshiro sequence" { }; for (seq1) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } r.jump(); @@ -727,7 +728,7 @@ test "xoroshiro sequence" { }; for (seq2) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -930,7 +931,7 @@ test "isaac64 sequence" { }; for (seq) |s| { - std.debug.assert(s == r.next()); + expect(s == r.next()); } } @@ -941,12 +942,12 @@ test "Random float" { var i: usize = 0; while (i < 1000) : (i += 1) { const val1 = prng.random.float(f32); - std.debug.assert(val1 >= 0.0); - std.debug.assert(val1 < 1.0); + expect(val1 >= 0.0); + expect(val1 < 1.0); const val2 = prng.random.float(f64); - std.debug.assert(val2 >= 0.0); - std.debug.assert(val2 < 1.0); + expect(val2 >= 0.0); + expect(val2 < 1.0); } } @@ -960,12 +961,12 @@ test "Random shuffle" { while (i < 1000) : (i += 1) { prng.random.shuffle(u8, seq[0..]); seen[seq[0]] = true; - std.debug.assert(sumArray(seq[0..]) == 10); + expect(sumArray(seq[0..]) == 10); } // we should see every entry at the head at least once for (seen) |e| { - std.debug.assert(e == true); + expect(e == true); } } diff --git a/std/rb.zig b/std/rb.zig index beb7f3aae9..27e60dca6a 100644 --- a/std/rb.zig +++ b/std/rb.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; // For mem.Compare const Color = enum(u1) { @@ -533,13 +534,13 @@ test "rb" { _ = tree.insert(&ns[8].node); _ = tree.insert(&ns[9].node); tree.remove(&ns[3].node); - assert(tree.insert(&dup.node) == &ns[7].node); + testing.expect(tree.insert(&dup.node) == &ns[7].node); try tree.replace(&ns[7].node, &dup.node); var num: *testNumber = undefined; num = testGetNumber(tree.first().?); while (num.node.next() != null) { - assert(testGetNumber(num.node.next().?).value > num.value); + testing.expect(testGetNumber(num.node.next().?).value > num.value); num = testGetNumber(num.node.next().?); } } diff --git a/std/segmented_list.zig b/std/segmented_list.zig index d786e0becd..26b7fa48f5 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const Allocator = std.mem.Allocator; // Imagine that `fn at(self: *Self, index: usize) &T` is a customer asking for a box @@ -352,14 +353,14 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { var i: usize = 0; while (i < 100) : (i += 1) { try list.push(@intCast(i32, i + 1)); - assert(list.len == i + 1); + testing.expect(list.len == i + 1); } } { var i: usize = 0; while (i < 100) : (i += 1) { - assert(list.at(i).* == @intCast(i32, i + 1)); + testing.expect(list.at(i).* == @intCast(i32, i + 1)); } } @@ -368,35 +369,35 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { var x: i32 = 0; while (it.next()) |item| { x += 1; - assert(item.* == x); + testing.expect(item.* == x); } - assert(x == 100); + testing.expect(x == 100); while (it.prev()) |item| : (x -= 1) { - assert(item.* == x); + testing.expect(item.* == x); } - assert(x == 0); + testing.expect(x == 0); } - assert(list.pop().? == 100); - assert(list.len == 99); + testing.expect(list.pop().? == 100); + testing.expect(list.len == 99); try list.pushMany([]i32{ 1, 2, 3, }); - assert(list.len == 102); - assert(list.pop().? == 3); - assert(list.pop().? == 2); - assert(list.pop().? == 1); - assert(list.len == 99); + testing.expect(list.len == 102); + testing.expect(list.pop().? == 3); + testing.expect(list.pop().? == 2); + testing.expect(list.pop().? == 1); + testing.expect(list.len == 99); try list.pushMany([]const i32{}); - assert(list.len == 99); + testing.expect(list.len == 99); var i: i32 = 99; while (list.pop()) |item| : (i -= 1) { - assert(item == i); + testing.expect(item == i); list.shrinkCapacity(list.len); } } diff --git a/std/sort.zig b/std/sort.zig index f29f51b7cf..86a6724fee 100644 --- a/std/sort.zig +++ b/std/sort.zig @@ -1,5 +1,6 @@ const std = @import("index.zig"); const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; const math = std.math; const builtin = @import("builtin"); @@ -1031,8 +1032,8 @@ fn testStableSort() void { for (cases) |*case| { insertionSort(IdAndValue, (case.*)[0..], cmpByValue); for (case.*) |item, i| { - assert(item.id == expected[i].id); - assert(item.value == expected[i].value); + testing.expect(item.id == expected[i].id); + testing.expect(item.value == expected[i].value); } } } @@ -1077,7 +1078,7 @@ test "std.sort" { const slice = buf[0..case[0].len]; mem.copy(u8, slice, case[0]); sort(u8, slice, asc(u8)); - assert(mem.eql(u8, slice, case[1])); + testing.expect(mem.eql(u8, slice, case[1])); } const i32cases = [][]const []const i32{ @@ -1112,7 +1113,7 @@ test "std.sort" { const slice = buf[0..case[0].len]; mem.copy(i32, slice, case[0]); sort(i32, slice, asc(i32)); - assert(mem.eql(i32, slice, case[1])); + testing.expect(mem.eql(i32, slice, case[1])); } } @@ -1149,7 +1150,7 @@ test "std.sort descending" { const slice = buf[0..case[0].len]; mem.copy(i32, slice, case[0]); sort(i32, slice, desc(i32)); - assert(mem.eql(i32, slice, case[1])); + testing.expect(mem.eql(i32, slice, case[1])); } } @@ -1157,7 +1158,7 @@ test "another sort case" { var arr = []i32{ 5, 3, 1, 2, 4 }; sort(i32, arr[0..], asc(i32)); - assert(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 })); + testing.expect(mem.eql(i32, arr, []i32{ 1, 2, 3, 4, 5 })); } test "sort fuzz testing" { @@ -1185,9 +1186,9 @@ fn fuzzTest(rng: *std.rand.Random) void { var index: usize = 1; while (index < array.len) : (index += 1) { if (array[index].value == array[index - 1].value) { - assert(array[index].id > array[index - 1].id); + testing.expect(array[index].id > array[index - 1].id); } else { - assert(array[index].value > array[index - 1].value); + testing.expect(array[index].value > array[index - 1].value); } } } diff --git a/std/special/compiler_rt/divti3_test.zig b/std/special/compiler_rt/divti3_test.zig index eef5a9b812..e1c1babae7 100644 --- a/std/special/compiler_rt/divti3_test.zig +++ b/std/special/compiler_rt/divti3_test.zig @@ -1,9 +1,9 @@ const __divti3 = @import("divti3.zig").__divti3; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__divti3(a: i128, b: i128, expected: i128) void { const x = __divti3(a, b); - assert(x == expected); + testing.expect(x == expected); } test "divti3" { diff --git a/std/special/compiler_rt/extendXfYf2_test.zig b/std/special/compiler_rt/extendXfYf2_test.zig index 9969607011..050a799823 100644 --- a/std/special/compiler_rt/extendXfYf2_test.zig +++ b/std/special/compiler_rt/extendXfYf2_test.zig @@ -1,7 +1,6 @@ const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; -const assert = @import("std").debug.assert; fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void { const x = __extenddftf2(a); diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/std/special/compiler_rt/fixdfdi_test.zig index 72bcf452d2..a55245210b 100644 --- a/std/special/compiler_rt/fixdfdi_test.zig +++ b/std/special/compiler_rt/fixdfdi_test.zig @@ -1,13 +1,13 @@ const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfdi(a: f64, expected: i64) void { const x = __fixdfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfdi" { diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/std/special/compiler_rt/fixdfsi_test.zig index 147f46534a..5cb9bef1d9 100644 --- a/std/special/compiler_rt/fixdfsi_test.zig +++ b/std/special/compiler_rt/fixdfsi_test.zig @@ -1,13 +1,13 @@ const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfsi(a: f64, expected: i32) void { const x = __fixdfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfsi" { diff --git a/std/special/compiler_rt/fixdfti_test.zig b/std/special/compiler_rt/fixdfti_test.zig index 5bb3a31a3f..5fbcd206ed 100644 --- a/std/special/compiler_rt/fixdfti_test.zig +++ b/std/special/compiler_rt/fixdfti_test.zig @@ -1,13 +1,13 @@ const __fixdfti = @import("fixdfti.zig").__fixdfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixdfti(a: f64, expected: i128) void { const x = __fixdfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixdfti" { diff --git a/std/special/compiler_rt/fixint_test.zig b/std/special/compiler_rt/fixint_test.zig index 6676bddbee..0b0936d1e2 100644 --- a/std/special/compiler_rt/fixint_test.zig +++ b/std/special/compiler_rt/fixint_test.zig @@ -1,7 +1,7 @@ const is_test = @import("builtin").is_test; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; const fixint = @import("fixint.zig").fixint; @@ -9,7 +9,7 @@ const fixint = @import("fixint.zig").fixint; fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void { const x = fixint(fp_t, fixint_t, a); //warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected); - assert(x == expected); + testing.expect(x == expected); } test "fixint.i1" { diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/std/special/compiler_rt/fixsfdi_test.zig index ef8e50e38e..276670421b 100644 --- a/std/special/compiler_rt/fixsfdi_test.zig +++ b/std/special/compiler_rt/fixsfdi_test.zig @@ -1,13 +1,13 @@ const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfdi(a: f32, expected: i64) void { const x = __fixsfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfdi" { diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/std/special/compiler_rt/fixsfsi_test.zig index d5c0ba5c2a..a05c15e536 100644 --- a/std/special/compiler_rt/fixsfsi_test.zig +++ b/std/special/compiler_rt/fixsfsi_test.zig @@ -1,13 +1,13 @@ const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfsi(a: f32, expected: i32) void { const x = __fixsfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfsi" { diff --git a/std/special/compiler_rt/fixsfti_test.zig b/std/special/compiler_rt/fixsfti_test.zig index d693143b18..32410e2dee 100644 --- a/std/special/compiler_rt/fixsfti_test.zig +++ b/std/special/compiler_rt/fixsfti_test.zig @@ -1,13 +1,13 @@ const __fixsfti = @import("fixsfti.zig").__fixsfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixsfti(a: f32, expected: i128) void { const x = __fixsfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixsfti" { diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/std/special/compiler_rt/fixtfdi_test.zig index 58ccbc5832..a31bcb7d6f 100644 --- a/std/special/compiler_rt/fixtfdi_test.zig +++ b/std/special/compiler_rt/fixtfdi_test.zig @@ -1,13 +1,13 @@ const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfdi(a: f128, expected: i64) void { const x = __fixtfdi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u64, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfdi" { diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/std/special/compiler_rt/fixtfsi_test.zig index 7a3cc7f46c..7b37e4e09f 100644 --- a/std/special/compiler_rt/fixtfsi_test.zig +++ b/std/special/compiler_rt/fixtfsi_test.zig @@ -1,13 +1,13 @@ const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfsi(a: f128, expected: i32) void { const x = __fixtfsi(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u32, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfsi" { diff --git a/std/special/compiler_rt/fixtfti_test.zig b/std/special/compiler_rt/fixtfti_test.zig index 520009486a..be461a1c91 100644 --- a/std/special/compiler_rt/fixtfti_test.zig +++ b/std/special/compiler_rt/fixtfti_test.zig @@ -1,13 +1,13 @@ const __fixtfti = @import("fixtfti.zig").__fixtfti; const std = @import("std"); const math = std.math; -const assert = std.debug.assert; +const testing = std.testing; const warn = std.debug.warn; fn test__fixtfti(a: f128, expected: i128) void { const x = __fixtfti(a); //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u128, expected)); - assert(x == expected); + testing.expect(x == expected); } test "fixtfti" { diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/std/special/compiler_rt/fixunsdfdi_test.zig index e59d09f8de..67eeb70520 100644 --- a/std/special/compiler_rt/fixunsdfdi_test.zig +++ b/std/special/compiler_rt/fixunsdfdi_test.zig @@ -1,9 +1,9 @@ const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfdi(a: f64, expected: u64) void { const x = __fixunsdfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfdi" { diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/std/special/compiler_rt/fixunsdfsi_test.zig index db6e32e23d..c006473fb9 100644 --- a/std/special/compiler_rt/fixunsdfsi_test.zig +++ b/std/special/compiler_rt/fixunsdfsi_test.zig @@ -1,9 +1,9 @@ const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfsi(a: f64, expected: u32) void { const x = __fixunsdfsi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfsi" { diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/std/special/compiler_rt/fixunsdfti_test.zig index 7f7b083d19..8241900692 100644 --- a/std/special/compiler_rt/fixunsdfti_test.zig +++ b/std/special/compiler_rt/fixunsdfti_test.zig @@ -1,9 +1,9 @@ const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunsdfti(a: f64, expected: u128) void { const x = __fixunsdfti(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunsdfti" { diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/std/special/compiler_rt/fixunssfdi_test.zig index e4e6c1736d..e2089822d2 100644 --- a/std/special/compiler_rt/fixunssfdi_test.zig +++ b/std/special/compiler_rt/fixunssfdi_test.zig @@ -1,9 +1,9 @@ const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfdi(a: f32, expected: u64) void { const x = __fixunssfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfdi" { diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/std/special/compiler_rt/fixunssfsi_test.zig index 614c648dfe..4aee84d2d2 100644 --- a/std/special/compiler_rt/fixunssfsi_test.zig +++ b/std/special/compiler_rt/fixunssfsi_test.zig @@ -1,9 +1,9 @@ const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfsi(a: f32, expected: u32) void { const x = __fixunssfsi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfsi" { diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/std/special/compiler_rt/fixunssfti_test.zig index 43ad527f53..4cb27cbb8a 100644 --- a/std/special/compiler_rt/fixunssfti_test.zig +++ b/std/special/compiler_rt/fixunssfti_test.zig @@ -1,9 +1,9 @@ const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunssfti(a: f32, expected: u128) void { const x = __fixunssfti(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunssfti" { diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig index 6b1b9b7bd2..0d47641c09 100644 --- a/std/special/compiler_rt/fixunstfdi_test.zig +++ b/std/special/compiler_rt/fixunstfdi_test.zig @@ -1,9 +1,9 @@ const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfdi(a: f128, expected: u64) void { const x = __fixunstfdi(a); - assert(x == expected); + testing.expect(x == expected); } test "fixunstfdi" { diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig index f47fcb3c86..e709636912 100644 --- a/std/special/compiler_rt/fixunstfsi_test.zig +++ b/std/special/compiler_rt/fixunstfsi_test.zig @@ -1,9 +1,9 @@ const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfsi(a: f128, expected: u32) void { const x = __fixunstfsi(a); - assert(x == expected); + testing.expect(x == expected); } const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); diff --git a/std/special/compiler_rt/fixunstfti_test.zig b/std/special/compiler_rt/fixunstfti_test.zig index 9128ac6c08..833e4779dd 100644 --- a/std/special/compiler_rt/fixunstfti_test.zig +++ b/std/special/compiler_rt/fixunstfti_test.zig @@ -1,9 +1,9 @@ const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__fixunstfti(a: f128, expected: u128) void { const x = __fixunstfti(a); - assert(x == expected); + testing.expect(x == expected); } const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); diff --git a/std/special/compiler_rt/floattidf_test.zig b/std/special/compiler_rt/floattidf_test.zig index 25dc595052..4914342c31 100644 --- a/std/special/compiler_rt/floattidf_test.zig +++ b/std/special/compiler_rt/floattidf_test.zig @@ -1,9 +1,9 @@ const __floattidf = @import("floattidf.zig").__floattidf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattidf(a: i128, expected: f64) void { const x = __floattidf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattidf" { diff --git a/std/special/compiler_rt/floattisf_test.zig b/std/special/compiler_rt/floattisf_test.zig index ecb8eac60a..a6aa115307 100644 --- a/std/special/compiler_rt/floattisf_test.zig +++ b/std/special/compiler_rt/floattisf_test.zig @@ -1,9 +1,9 @@ const __floattisf = @import("floattisf.zig").__floattisf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattisf(a: i128, expected: f32) void { const x = __floattisf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattisf" { diff --git a/std/special/compiler_rt/floattitf_test.zig b/std/special/compiler_rt/floattitf_test.zig index da2ccc8b35..53e3e48bdb 100644 --- a/std/special/compiler_rt/floattitf_test.zig +++ b/std/special/compiler_rt/floattitf_test.zig @@ -1,9 +1,9 @@ const __floattitf = @import("floattitf.zig").__floattitf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floattitf(a: i128, expected: f128) void { const x = __floattitf(a); - assert(x == expected); + testing.expect(x == expected); } test "floattitf" { diff --git a/std/special/compiler_rt/floatunditf_test.zig b/std/special/compiler_rt/floatunditf_test.zig index 8533c75070..5b4e195870 100644 --- a/std/special/compiler_rt/floatunditf_test.zig +++ b/std/special/compiler_rt/floatunditf_test.zig @@ -1,5 +1,4 @@ const __floatunditf = @import("floatunditf.zig").__floatunditf; -const assert = @import("std").debug.assert; fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void { const x = __floatunditf(a); diff --git a/std/special/compiler_rt/floatunsitf_test.zig b/std/special/compiler_rt/floatunsitf_test.zig index 06f54cde03..52e4786903 100644 --- a/std/special/compiler_rt/floatunsitf_test.zig +++ b/std/special/compiler_rt/floatunsitf_test.zig @@ -1,5 +1,4 @@ const __floatunsitf = @import("floatunsitf.zig").__floatunsitf; -const assert = @import("std").debug.assert; fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void { const x = __floatunsitf(a); diff --git a/std/special/compiler_rt/floatuntidf_test.zig b/std/special/compiler_rt/floatuntidf_test.zig index e2c79378e2..974f3e4be3 100644 --- a/std/special/compiler_rt/floatuntidf_test.zig +++ b/std/special/compiler_rt/floatuntidf_test.zig @@ -1,9 +1,9 @@ const __floatuntidf = @import("floatuntidf.zig").__floatuntidf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntidf(a: u128, expected: f64) void { const x = __floatuntidf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntidf" { diff --git a/std/special/compiler_rt/floatuntisf_test.zig b/std/special/compiler_rt/floatuntisf_test.zig index 7f84c1f963..3a97807066 100644 --- a/std/special/compiler_rt/floatuntisf_test.zig +++ b/std/special/compiler_rt/floatuntisf_test.zig @@ -1,9 +1,9 @@ const __floatuntisf = @import("floatuntisf.zig").__floatuntisf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntisf(a: u128, expected: f32) void { const x = __floatuntisf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntisf" { diff --git a/std/special/compiler_rt/floatuntitf_test.zig b/std/special/compiler_rt/floatuntitf_test.zig index 8e67fee108..09f3eabb3e 100644 --- a/std/special/compiler_rt/floatuntitf_test.zig +++ b/std/special/compiler_rt/floatuntitf_test.zig @@ -1,9 +1,9 @@ const __floatuntitf = @import("floatuntitf.zig").__floatuntitf; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__floatuntitf(a: u128, expected: f128) void { const x = __floatuntitf(a); - assert(x == expected); + testing.expect(x == expected); } test "floatuntitf" { diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 4bbfc2b290..3df94db589 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -110,6 +110,7 @@ comptime { const std = @import("std"); const assert = std.debug.assert; +const testing = std.testing; const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; @@ -417,7 +418,7 @@ test "test_umoddi3" { fn test_one_umoddi3(a: u64, b: u64, expected_r: u64) void { const r = __umoddi3(a, b); - assert(r == expected_r); + testing.expect(r == expected_r); } test "test_udivsi3" { @@ -1091,5 +1092,5 @@ test "test_udivsi3" { fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void { const q: u32 = __udivsi3(a, b); - assert(q == expected_q); + testing.expect(q == expected_q); } diff --git a/std/special/compiler_rt/muloti4_test.zig b/std/special/compiler_rt/muloti4_test.zig index 6b3671323f..00144a8839 100644 --- a/std/special/compiler_rt/muloti4_test.zig +++ b/std/special/compiler_rt/muloti4_test.zig @@ -1,10 +1,10 @@ const __muloti4 = @import("muloti4.zig").__muloti4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) void { var overflow: c_int = undefined; const x = __muloti4(a, b, &overflow); - assert(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); + testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); } test "muloti4" { diff --git a/std/special/compiler_rt/multi3_test.zig b/std/special/compiler_rt/multi3_test.zig index 413ff20a79..92c580e20f 100644 --- a/std/special/compiler_rt/multi3_test.zig +++ b/std/special/compiler_rt/multi3_test.zig @@ -1,9 +1,9 @@ const __multi3 = @import("multi3.zig").__multi3; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__multi3(a: i128, b: i128, expected: i128) void { const x = __multi3(a, b); - assert(x == expected); + testing.expect(x == expected); } test "multi3" { diff --git a/std/special/compiler_rt/udivmoddi4_test.zig b/std/special/compiler_rt/udivmoddi4_test.zig index 34b9dda1ea..5e6924f290 100644 --- a/std/special/compiler_rt/udivmoddi4_test.zig +++ b/std/special/compiler_rt/udivmoddi4_test.zig @@ -1,13 +1,13 @@ // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__udivmoddi4(a: u64, b: u64, expected_q: u64, expected_r: u64) void { var r: u64 = undefined; const q = __udivmoddi4(a, b, &r); - assert(q == expected_q); - assert(r == expected_r); + testing.expect(q == expected_q); + testing.expect(r == expected_r); } test "udivmoddi4" { diff --git a/std/special/compiler_rt/udivmodti4_test.zig b/std/special/compiler_rt/udivmodti4_test.zig index f6b370c26e..0c7880f346 100644 --- a/std/special/compiler_rt/udivmodti4_test.zig +++ b/std/special/compiler_rt/udivmodti4_test.zig @@ -1,13 +1,13 @@ // Disable formatting to avoid unnecessary source repository bloat. // zig fmt: off const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; -const assert = @import("std").debug.assert; +const testing = @import("std").testing; fn test__udivmodti4(a: u128, b: u128, expected_q: u128, expected_r: u128) void { var r: u128 = undefined; const q = __udivmodti4(a, b, &r); - assert(q == expected_q); - assert(r == expected_r); + testing.expect(q == expected_q); + testing.expect(r == expected_r); } test "udivmodti4" { diff --git a/std/special/init-lib/src/main.zig b/std/special/init-lib/src/main.zig index 27fdeb2030..747bb08573 100644 --- a/std/special/init-lib/src/main.zig +++ b/std/special/init-lib/src/main.zig @@ -1,10 +1,10 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; export fn add(a: i32, b: i32) i32 { return a + b; } test "basic add functionality" { - assertOrPanic(add(3, 7) == 10); + testing.expect(add(3, 7) == 10); } diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig index 37582d49c1..16bcd7adaf 100644 --- a/std/statically_initialized_mutex.zig +++ b/std/statically_initialized_mutex.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const AtomicOrder = builtin.AtomicOrder; const AtomicRmwOp = builtin.AtomicRmwOp; const assert = std.debug.assert; +const expect = std.testing.expect; const windows = std.os.windows; /// Lock may be held only once. If the same thread @@ -95,7 +96,7 @@ test "std.StaticallyInitializedMutex" { if (builtin.single_threaded) { TestContext.worker(&context); - std.debug.assertOrPanic(context.data == TestContext.incr_count); + expect(context.data == TestContext.incr_count); } else { const thread_count = 10; var threads: [thread_count]*std.os.Thread = undefined; @@ -105,6 +106,6 @@ test "std.StaticallyInitializedMutex" { for (threads) |t| t.wait(); - std.debug.assertOrPanic(context.data == thread_count * TestContext.incr_count); + expect(context.data == thread_count * TestContext.incr_count); } } diff --git a/std/testing.zig b/std/testing.zig new file mode 100644 index 0000000000..ade6e8b0dd --- /dev/null +++ b/std/testing.zig @@ -0,0 +1,152 @@ +const builtin = @import("builtin"); +const TypeId = builtin.TypeId; +const std = @import("index.zig"); + +/// This function is intended to be used only in tests. It prints diagnostics to stderr +/// and then aborts when actual_error_union is not expected_error. +pub fn expectError(expected_error: anyerror, actual_error_union: var) void { + // TODO remove the workaround here for https://github.com/ziglang/zig/issues/1936 + if (actual_error_union) |actual_payload| { + // TODO remove workaround here for https://github.com/ziglang/zig/issues/557 + if (@sizeOf(@typeOf(actual_payload)) == 0) { + std.debug.panic("expected error.{}, found {} value", @errorName(expected_error), @typeName(@typeOf(actual_payload))); + } else { + std.debug.panic("expected error.{}, found {}", @errorName(expected_error), actual_payload); + } + } else |actual_error| { + if (expected_error != actual_error) { + std.debug.panic("expected error.{}, found error.{}", @errorName(expected_error), @errorName(actual_error)); + } + } +} + +/// This function is intended to be used only in tests. When the two values are not +/// equal, prints diagnostics to stderr to show exactly how they are not equal, +/// then aborts. +/// The types must match exactly. +pub fn expectEqual(expected: var, actual: var) void { + if (@typeOf(actual) != @typeOf(expected)) { + @compileError("type mismatch. expected " ++ @typeName(@typeOf(expected)) ++ ", found " ++ @typeName(@typeOf(actual))); + } + + switch (@typeInfo(@typeOf(actual))) { + TypeId.NoReturn, + TypeId.BoundFn, + TypeId.ArgTuple, + TypeId.Opaque, + => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"), + + TypeId.Undefined, + TypeId.Null, + TypeId.Void, + => return, + + TypeId.Type, + TypeId.Bool, + TypeId.Int, + TypeId.Float, + TypeId.ComptimeFloat, + TypeId.ComptimeInt, + TypeId.Enum, + TypeId.Namespace, + TypeId.Fn, + TypeId.Promise, + TypeId.Vector, + TypeId.ErrorSet, + => { + if (actual != expected) { + std.debug.panic("expected {}, found {}", expected, actual); + } + }, + + TypeId.Pointer => |pointer| { + switch (pointer.size) { + builtin.TypeInfo.Pointer.Size.One, + builtin.TypeInfo.Pointer.Size.Many, + => { + if (actual != expected) { + std.debug.panic("expected {}, found {}", expected, actual); + } + }, + + builtin.TypeInfo.Pointer.Size.Slice => { + if (actual.ptr != expected.ptr) { + std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr); + } + if (actual.len != expected.len) { + std.debug.panic("expected slice len {}, found {}", expected.len, actual.len); + } + }, + } + }, + + TypeId.Array => |array| expectEqualSlices(array.child, &expected, &actual), + + TypeId.Struct => { + @compileError("TODO implement testing.expectEqual for structs"); + }, + + TypeId.Union => |union_info| { + if (union_info.tag_type == null) { + @compileError("Unable to compare untagged union values"); + } + @compileError("TODO implement testing.expectEqual for tagged unions"); + }, + + TypeId.Optional => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + expectEqual(expected_payload, actual_payload); + } else { + std.debug.panic("expected {}, found null", expected_payload); + } + } else { + if (actual) |actual_payload| { + std.debug.panic("expected null, found {}", actual_payload); + } + } + }, + + TypeId.ErrorUnion => { + if (expected) |expected_payload| { + if (actual) |actual_payload| { + expectEqual(expected_payload, actual_payload); + } else |actual_err| { + std.debug.panic("expected {}, found {}", expected_payload, actual_err); + } + } else |expected_err| { + if (actual) |actual_payload| { + std.debug.panic("expected {}, found {}", expected_err, actual_payload); + } else |actual_err| { + expectEqual(expected_err, actual_err); + } + } + }, + + } +} + +/// This function is intended to be used only in tests. When the two slices are not +/// equal, prints diagnostics to stderr to show exactly how they are not equal, +/// then aborts. +pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) void { + // TODO better printing of the difference + // If the arrays are small enough we could print the whole thing + // If the child type is u8 and no weird bytes, we could print it as strings + // Even for the length difference, it would be useful to see the values of the slices probably. + if (expected.len != actual.len) { + std.debug.panic("slice lengths differ. expected {}, found {}", expected.len, actual.len); + } + var i: usize = 0; + while (i < expected.len) : (i += 1) { + if (expected[i] != actual[i]) { + std.debug.panic("index {} incorrect. expected {}, found {}", i, expected[i], actual[i]); + } + } +} + +/// This function is intended to be used only in tests. When `ok` is false, the test fails. +/// A message is printed to stderr and then abort is called. +pub fn expect(ok: bool) void { + if (!ok) @panic("test failure"); +} diff --git a/std/unicode.zig b/std/unicode.zig index 2e542bcb19..fccdf513b9 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -1,7 +1,7 @@ const std = @import("./index.zig"); const builtin = @import("builtin"); -const debug = std.debug; const assert = std.debug.assert; +const testing = std.testing; const mem = std.mem; /// Returns how many bytes the UTF-8 representation would require @@ -32,7 +32,7 @@ pub fn utf8ByteSequenceLength(first_byte: u8) !u3 { /// Returns: the number of bytes written to out. pub fn utf8Encode(c: u32, out: []u8) !u3 { const length = try utf8CodepointSequenceLength(c); - debug.assert(out.len >= length); + assert(out.len >= length); switch (length) { // The pattern for each is the same // - Increasing the initial shift by 6 each time @@ -81,8 +81,8 @@ const Utf8Decode2Error = error{ Utf8OverlongEncoding, }; pub fn utf8Decode2(bytes: []const u8) Utf8Decode2Error!u32 { - debug.assert(bytes.len == 2); - debug.assert(bytes[0] & 0b11100000 == 0b11000000); + assert(bytes.len == 2); + assert(bytes[0] & 0b11100000 == 0b11000000); var value: u32 = bytes[0] & 0b00011111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -100,8 +100,8 @@ const Utf8Decode3Error = error{ Utf8EncodesSurrogateHalf, }; pub fn utf8Decode3(bytes: []const u8) Utf8Decode3Error!u32 { - debug.assert(bytes.len == 3); - debug.assert(bytes[0] & 0b11110000 == 0b11100000); + assert(bytes.len == 3); + assert(bytes[0] & 0b11110000 == 0b11100000); var value: u32 = bytes[0] & 0b00001111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -124,8 +124,8 @@ const Utf8Decode4Error = error{ Utf8CodepointTooLarge, }; pub fn utf8Decode4(bytes: []const u8) Utf8Decode4Error!u32 { - debug.assert(bytes.len == 4); - debug.assert(bytes[0] & 0b11111000 == 0b11110000); + assert(bytes.len == 4); + assert(bytes[0] & 0b11111000 == 0b11110000); var value: u32 = bytes[0] & 0b00000111; if (bytes[1] & 0b11000000 != 0b10000000) return error.Utf8ExpectedContinuation; @@ -274,23 +274,23 @@ test "utf8 encode" { fn testUtf8Encode() !void { // A few taken from wikipedia a few taken elsewhere var array: [4]u8 = undefined; - debug.assert((try utf8Encode(try utf8Decode("€"), array[0..])) == 3); - debug.assert(array[0] == 0b11100010); - debug.assert(array[1] == 0b10000010); - debug.assert(array[2] == 0b10101100); + testing.expect((try utf8Encode(try utf8Decode("€"), array[0..])) == 3); + testing.expect(array[0] == 0b11100010); + testing.expect(array[1] == 0b10000010); + testing.expect(array[2] == 0b10101100); - debug.assert((try utf8Encode(try utf8Decode("$"), array[0..])) == 1); - debug.assert(array[0] == 0b00100100); + testing.expect((try utf8Encode(try utf8Decode("$"), array[0..])) == 1); + testing.expect(array[0] == 0b00100100); - debug.assert((try utf8Encode(try utf8Decode("¢"), array[0..])) == 2); - debug.assert(array[0] == 0b11000010); - debug.assert(array[1] == 0b10100010); + testing.expect((try utf8Encode(try utf8Decode("¢"), array[0..])) == 2); + testing.expect(array[0] == 0b11000010); + testing.expect(array[1] == 0b10100010); - debug.assert((try utf8Encode(try utf8Decode("𐍈"), array[0..])) == 4); - debug.assert(array[0] == 0b11110000); - debug.assert(array[1] == 0b10010000); - debug.assert(array[2] == 0b10001101); - debug.assert(array[3] == 0b10001000); + testing.expect((try utf8Encode(try utf8Decode("𐍈"), array[0..])) == 4); + testing.expect(array[0] == 0b11110000); + testing.expect(array[1] == 0b10010000); + testing.expect(array[2] == 0b10001101); + testing.expect(array[3] == 0b10001000); } test "utf8 encode error" { @@ -306,11 +306,7 @@ fn testUtf8EncodeError() void { } fn testErrorEncode(codePoint: u32, array: []u8, expectedErr: anyerror) void { - if (utf8Encode(codePoint, array)) |_| { - unreachable; - } else |err| { - debug.assert(err == expectedErr); - } + testing.expectError(expectedErr, utf8Encode(codePoint, array)); } test "utf8 iterator on ascii" { @@ -321,16 +317,16 @@ fn testUtf8IteratorOnAscii() void { const s = Utf8View.initComptime("abc"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?)); - debug.assert(it1.nextCodepointSlice() == null); + testing.expect(std.mem.eql(u8, "a", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "b", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "c", it1.nextCodepointSlice().?)); + testing.expect(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(it2.nextCodepoint().? == 'a'); - debug.assert(it2.nextCodepoint().? == 'b'); - debug.assert(it2.nextCodepoint().? == 'c'); - debug.assert(it2.nextCodepoint() == null); + testing.expect(it2.nextCodepoint().? == 'a'); + testing.expect(it2.nextCodepoint().? == 'b'); + testing.expect(it2.nextCodepoint().? == 'c'); + testing.expect(it2.nextCodepoint() == null); } test "utf8 view bad" { @@ -340,12 +336,7 @@ test "utf8 view bad" { fn testUtf8ViewBad() void { // Compile-time error. // const s3 = Utf8View.initComptime("\xfe\xf2"); - const s = Utf8View.init("hel\xadlo"); - if (s) |_| { - unreachable; - } else |err| { - debug.assert(err == error.InvalidUtf8); - } + testing.expectError(error.InvalidUtf8, Utf8View.init("hel\xadlo")); } test "utf8 view ok" { @@ -356,16 +347,16 @@ fn testUtf8ViewOk() void { const s = Utf8View.initComptime("東京市"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?)); - debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?)); - debug.assert(it1.nextCodepointSlice() == null); + testing.expect(std.mem.eql(u8, "東", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "京", it1.nextCodepointSlice().?)); + testing.expect(std.mem.eql(u8, "市", it1.nextCodepointSlice().?)); + testing.expect(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(it2.nextCodepoint().? == 0x6771); - debug.assert(it2.nextCodepoint().? == 0x4eac); - debug.assert(it2.nextCodepoint().? == 0x5e02); - debug.assert(it2.nextCodepoint() == null); + testing.expect(it2.nextCodepoint().? == 0x6771); + testing.expect(it2.nextCodepoint().? == 0x4eac); + testing.expect(it2.nextCodepoint().? == 0x5e02); + testing.expect(it2.nextCodepoint() == null); } test "bad utf8 slice" { @@ -373,10 +364,10 @@ test "bad utf8 slice" { testBadUtf8Slice(); } fn testBadUtf8Slice() void { - debug.assert(utf8ValidateSlice("abc")); - debug.assert(!utf8ValidateSlice("abc\xc0")); - debug.assert(!utf8ValidateSlice("abc\xc0abc")); - debug.assert(utf8ValidateSlice("abc\xdf\xbf")); + testing.expect(utf8ValidateSlice("abc")); + testing.expect(!utf8ValidateSlice("abc\xc0")); + testing.expect(!utf8ValidateSlice("abc\xc0abc")); + testing.expect(utf8ValidateSlice("abc\xdf\xbf")); } test "valid utf8" { @@ -459,21 +450,17 @@ fn testMiscInvalidUtf8() void { } fn testError(bytes: []const u8, expected_err: anyerror) void { - if (testDecode(bytes)) |_| { - unreachable; - } else |err| { - debug.assert(err == expected_err); - } + testing.expectError(expected_err, testDecode(bytes)); } fn testValid(bytes: []const u8, expected_codepoint: u32) void { - debug.assert((testDecode(bytes) catch unreachable) == expected_codepoint); + testing.expect((testDecode(bytes) catch unreachable) == expected_codepoint); } fn testDecode(bytes: []const u8) !u32 { const length = try utf8ByteSequenceLength(bytes[0]); if (bytes.len < length) return error.UnexpectedEof; - debug.assert(bytes.len == length); + testing.expect(bytes.len == length); return utf8Decode(bytes); } @@ -513,14 +500,14 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "Aa")); + testing.expect(mem.eql(u8, utf8, "Aa")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); + testing.expect(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { @@ -528,7 +515,7 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); + testing.expect(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { @@ -536,7 +523,7 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); + testing.expect(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { @@ -544,14 +531,14 @@ test "utf16leToUtf8" { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); + testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); - assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); + testing.expect(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } } diff --git a/std/zig/ast.zig b/std/zig/ast.zig index bb2099fb75..f6ac4ed98c 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -1,5 +1,6 @@ const std = @import("../index.zig"); const assert = std.debug.assert; +const testing = std.testing; const SegmentedList = std.SegmentedList; const mem = std.mem; const Token = std.zig.Token; @@ -2224,5 +2225,5 @@ test "iterate" { .shebang = null, }; var base = &root.base; - assert(base.iterate(0) == null); + testing.expect(base.iterate(0) == null); } diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 2b60fb9b00..7ad842e4b6 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1940,7 +1940,7 @@ fn testTransform(source: []const u8, expected_source: []const u8) !void { warn("std.zig.render returned {} instead of {}\n", anything_changed, changes_expected); return error.TestFailed; } - std.debug.assert(anything_changed == changes_expected); + std.testing.expect(anything_changed == changes_expected); failing_allocator.allocator.free(result_source); break :x failing_allocator.index; }; diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 4941fe2cc2..e71babe4e8 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -1345,5 +1345,5 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { } } const last_token = tokenizer.next(); - std.debug.assert(last_token.id == Token.Id.Eof); + std.testing.expect(last_token.id == Token.Id.Eof); } diff --git a/test/cli.zig b/test/cli.zig index 745da4dd80..1520b3bde0 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -1,7 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const os = std.os; -const assertOrPanic = std.debug.assertOrPanic; +const testing = std.testing; var a: *std.mem.Allocator = undefined; @@ -87,13 +87,13 @@ fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult { fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void { _ = try exec(dir_path, [][]const u8{ zig_exe, "init-lib" }); const test_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "test" }); - assertOrPanic(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); + testing.expect(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); } fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { _ = try exec(dir_path, [][]const u8{ zig_exe, "init-exe" }); const run_result = try exec(dir_path, [][]const u8{ zig_exe, "build", "run" }); - assertOrPanic(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); + testing.expect(std.mem.eql(u8, run_result.stderr, "All your base are belong to us.\n")); } fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { @@ -126,6 +126,6 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { _ = try exec(dir_path, args); const out_asm = try std.io.readFileAlloc(a, example_s_path); - assertOrPanic(std.mem.indexOf(u8, out_asm, "square:") != null); - assertOrPanic(std.mem.indexOf(u8, out_asm, "imul\tedi, edi") != null); + testing.expect(std.mem.indexOf(u8, out_asm, "square:") != null); + testing.expect(std.mem.indexOf(u8, out_asm, "imul\tedi, edi") != null); } diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index aa7a93ad84..dbd705ddc4 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -1,13 +1,13 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const builtin = @import("builtin"); var foo: u8 align(4) = 100; test "global variable alignment" { - assertOrPanic(@typeOf(&foo).alignment == 4); - assertOrPanic(@typeOf(&foo) == *align(4) u8); + expect(@typeOf(&foo).alignment == 4); + expect(@typeOf(&foo) == *align(4) u8); const slice = (*[1]u8)(&foo)[0..]; - assertOrPanic(@typeOf(slice) == []align(4) u8); + expect(@typeOf(slice) == []align(4) u8); } fn derp() align(@sizeOf(usize) * 2) i32 { @@ -17,9 +17,9 @@ fn noop1() align(1) void {} fn noop4() align(4) void {} test "function alignment" { - assertOrPanic(derp() == 1234); - assertOrPanic(@typeOf(noop1) == fn () align(1) void); - assertOrPanic(@typeOf(noop4) == fn () align(4) void); + expect(derp() == 1234); + expect(@typeOf(noop1) == fn () align(1) void); + expect(@typeOf(noop4) == fn () align(4) void); noop1(); noop4(); } @@ -30,7 +30,7 @@ var baz: packed struct { } = undefined; test "packed struct alignment" { - assertOrPanic(@typeOf(&baz.b) == *align(1) u32); + expect(@typeOf(&baz.b) == *align(1) u32); } const blah: packed struct { @@ -40,17 +40,17 @@ const blah: packed struct { } = undefined; test "bit field alignment" { - assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3); + expect(@typeOf(&blah.b) == *align(1:3:1) const u3); } test "default alignment allows unspecified in type syntax" { - assertOrPanic(*u32 == *align(@alignOf(u32)) u32); + expect(*u32 == *align(@alignOf(u32)) u32); } test "implicitly decreasing pointer alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assertOrPanic(addUnaligned(&a, &b) == 7); + expect(addUnaligned(&a, &b) == 7); } fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { @@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { test "implicitly decreasing slice alignment" { const a: u32 align(4) = 3; const b: u32 align(8) = 4; - assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); + expect(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7); } fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { return a[0] + b[0]; @@ -77,7 +77,7 @@ fn testBytesAlign(b: u8) void { b, }; const ptr = @ptrCast(*u32, &bytes[0]); - assertOrPanic(ptr.* == 0x33333333); + expect(ptr.* == 0x33333333); } test "specifying alignment allows slice cast" { @@ -91,13 +91,13 @@ fn testBytesAlignSlice(b: u8) void { b, }; const slice: []u32 = @bytesToSlice(u32, bytes[0..]); - assertOrPanic(slice[0] == 0x33333333); + expect(slice[0] == 0x33333333); } test "@alignCast pointers" { var x: u32 align(4) = 1; expectsOnly1(&x); - assertOrPanic(x == 2); + expect(x == 2); } fn expectsOnly1(x: *align(1) u32) void { expects4(@alignCast(4, x)); @@ -113,7 +113,7 @@ test "@alignCast slices" { }; const slice = array[0..]; sliceExpectsOnly1(slice); - assertOrPanic(slice[0] == 2); + expect(slice[0] == 2); } fn sliceExpectsOnly1(slice: []align(1) u32) void { sliceExpects4(@alignCast(4, slice)); @@ -128,7 +128,7 @@ test "implicitly decreasing fn alignment" { } fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void { - assertOrPanic(ptr() == answer); + expect(ptr() == answer); } fn alignedSmall() align(8) i32 { @@ -139,7 +139,7 @@ fn alignedBig() align(16) i32 { } test "@alignCast functions" { - assertOrPanic(fnExpectsOnly1(simple4) == 0x19); + expect(fnExpectsOnly1(simple4) == 0x19); } fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 { return fnExpects4(@alignCast(4, ptr)); @@ -152,9 +152,9 @@ fn simple4() align(4) i32 { } test "generic function with align param" { - assertOrPanic(whyWouldYouEverDoThis(1) == 0x1); - assertOrPanic(whyWouldYouEverDoThis(4) == 0x1); - assertOrPanic(whyWouldYouEverDoThis(8) == 0x1); + expect(whyWouldYouEverDoThis(1) == 0x1); + expect(whyWouldYouEverDoThis(4) == 0x1); + expect(whyWouldYouEverDoThis(8) == 0x1); } fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { @@ -164,28 +164,28 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 { test "@ptrCast preserves alignment of bigger source" { var x: u32 align(16) = 1234; const ptr = @ptrCast(*u8, &x); - assertOrPanic(@typeOf(ptr) == *align(16) u8); + expect(@typeOf(ptr) == *align(16) u8); } test "runtime known array index has best alignment possible" { // take full advantage of over-alignment var array align(4) = []u8{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(&array[0]) == *align(4) u8); - assertOrPanic(@typeOf(&array[1]) == *u8); - assertOrPanic(@typeOf(&array[2]) == *align(2) u8); - assertOrPanic(@typeOf(&array[3]) == *u8); + expect(@typeOf(&array[0]) == *align(4) u8); + expect(@typeOf(&array[1]) == *u8); + expect(@typeOf(&array[2]) == *align(2) u8); + expect(@typeOf(&array[3]) == *u8); // because align is too small but we still figure out to use 2 var bigger align(2) = []u64{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64); - assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64); + expect(@typeOf(&bigger[0]) == *align(2) u64); + expect(@typeOf(&bigger[1]) == *align(2) u64); + expect(@typeOf(&bigger[2]) == *align(2) u64); + expect(@typeOf(&bigger[3]) == *align(2) u64); // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 var smaller align(2) = []u32{ 1, 2, 3, 4 }; - comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32); - comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32); + comptime expect(@typeOf(smaller[0..]) == []align(2) u32); + comptime expect(@typeOf(smaller[0..].ptr) == [*]align(2) u32); testIndex(smaller[0..].ptr, 0, *align(2) u32); testIndex(smaller[0..].ptr, 1, *align(2) u32); testIndex(smaller[0..].ptr, 2, *align(2) u32); @@ -198,14 +198,14 @@ test "runtime known array index has best alignment possible" { testIndex2(array[0..].ptr, 3, *u8); } fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { - comptime assertOrPanic(@typeOf(&smaller[index]) == T); + comptime expect(@typeOf(&smaller[index]) == T); } fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void { - comptime assertOrPanic(@typeOf(&ptr[index]) == T); + comptime expect(@typeOf(&ptr[index]) == T); } test "alignstack" { - assertOrPanic(fnWithAlignedStack() == 1234); + expect(fnWithAlignedStack() == 1234); } fn fnWithAlignedStack() i32 { @@ -214,7 +214,7 @@ fn fnWithAlignedStack() i32 { } test "alignment of structs" { - assertOrPanic(@alignOf(struct { + expect(@alignOf(struct { a: i32, b: *i32, }) == @alignOf(usize)); diff --git a/test/stage1/behavior/alignof.zig b/test/stage1/behavior/alignof.zig index 98c805908b..d4d9661ead 100644 --- a/test/stage1/behavior/alignof.zig +++ b/test/stage1/behavior/alignof.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -10,9 +10,9 @@ const Foo = struct { }; test "@alignOf(T) before referencing T" { - comptime assertOrPanic(@alignOf(Foo) != maxInt(usize)); + comptime expect(@alignOf(Foo) != maxInt(usize)); if (builtin.arch == builtin.Arch.x86_64) { - comptime assertOrPanic(@alignOf(Foo) == 4); + comptime expect(@alignOf(Foo) == 4); } } diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 1183305209..99b828e53c 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; test "arrays" { @@ -18,8 +18,8 @@ test "arrays" { i += 1; } - assertOrPanic(accumulator == 15); - assertOrPanic(getArrayLen(array) == 5); + expect(accumulator == 15); + expect(getArrayLen(array) == 5); } fn getArrayLen(a: []const u32) usize { return a.len; @@ -29,8 +29,8 @@ test "void arrays" { var array: [4]void = undefined; array[0] = void{}; array[1] = array[2]; - assertOrPanic(@sizeOf(@typeOf(array)) == 0); - assertOrPanic(array.len == 4); + expect(@sizeOf(@typeOf(array)) == 0); + expect(array.len == 4); } test "array literal" { @@ -41,12 +41,12 @@ test "array literal" { 1, }; - assertOrPanic(hex_mult.len == 4); - assertOrPanic(hex_mult[1] == 256); + expect(hex_mult.len == 4); + expect(hex_mult[1] == 256); } test "array dot len const expr" { - assertOrPanic(comptime x: { + expect(comptime x: { break :x some_array.len == 4; }); } @@ -70,11 +70,11 @@ test "nested arrays" { "thing", }; for (array_of_strings) |s, i| { - if (i == 0) assertOrPanic(mem.eql(u8, s, "hello")); - if (i == 1) assertOrPanic(mem.eql(u8, s, "this")); - if (i == 2) assertOrPanic(mem.eql(u8, s, "is")); - if (i == 3) assertOrPanic(mem.eql(u8, s, "my")); - if (i == 4) assertOrPanic(mem.eql(u8, s, "thing")); + if (i == 0) expect(mem.eql(u8, s, "hello")); + if (i == 1) expect(mem.eql(u8, s, "this")); + if (i == 2) expect(mem.eql(u8, s, "is")); + if (i == 3) expect(mem.eql(u8, s, "my")); + if (i == 4) expect(mem.eql(u8, s, "thing")); } } @@ -92,9 +92,9 @@ test "set global var array via slice embedded in struct" { s.a[1].b = 2; s.a[2].b = 3; - assertOrPanic(s_array[0].b == 1); - assertOrPanic(s_array[1].b == 2); - assertOrPanic(s_array[2].b == 3); + expect(s_array[0].b == 1); + expect(s_array[1].b == 2); + expect(s_array[2].b == 3); } test "array literal with specified size" { @@ -102,27 +102,27 @@ test "array literal with specified size" { 1, 2, }; - assertOrPanic(array[0] == 1); - assertOrPanic(array[1] == 2); + expect(array[0] == 1); + expect(array[1] == 2); } test "array child property" { var x: [5]i32 = undefined; - assertOrPanic(@typeOf(x).Child == i32); + expect(@typeOf(x).Child == i32); } test "array len property" { var x: [5]i32 = undefined; - assertOrPanic(@typeOf(x).len == 5); + expect(@typeOf(x).len == 5); } test "array len field" { var arr = [4]u8{ 0, 0, 0, 0 }; var ptr = &arr; - assertOrPanic(arr.len == 4); - comptime assertOrPanic(arr.len == 4); - assertOrPanic(ptr.len == 4); - comptime assertOrPanic(ptr.len == 4); + expect(arr.len == 4); + comptime expect(arr.len == 4); + expect(ptr.len == 4); + comptime expect(ptr.len == 4); } test "single-item pointer to array indexing and slicing" { @@ -133,7 +133,7 @@ test "single-item pointer to array indexing and slicing" { fn testSingleItemPtrArrayIndexSlice() void { var array = "aaaa"; doSomeMangling(&array); - assertOrPanic(mem.eql(u8, "azya", array)); + expect(mem.eql(u8, "azya", array)); } fn doSomeMangling(array: *[4]u8) void { @@ -150,7 +150,7 @@ fn testImplicitCastSingleItemPtr() void { var byte: u8 = 100; const slice = (*[1]u8)(&byte)[0..]; slice[0] += 1; - assertOrPanic(byte == 101); + expect(byte == 101); } fn testArrayByValAtComptime(b: [2]u8) u8 { @@ -165,7 +165,7 @@ test "comptime evalutating function that takes array by value" { test "implicit comptime in array type size" { var arr: [plusOne(10)]bool = undefined; - assertOrPanic(arr.len == 11); + expect(arr.len == 11); } fn plusOne(x: u32) u32 { @@ -197,15 +197,15 @@ test "array literal as argument to function" { }); } fn foo(x: []const i32) void { - assertOrPanic(x[0] == 1); - assertOrPanic(x[1] == 2); - assertOrPanic(x[2] == 3); + expect(x[0] == 1); + expect(x[1] == 2); + expect(x[2] == 3); } fn foo2(trash: bool, x: []const i32) void { - assertOrPanic(trash); - assertOrPanic(x[0] == 1); - assertOrPanic(x[1] == 2); - assertOrPanic(x[2] == 3); + expect(trash); + expect(x[0] == 1); + expect(x[1] == 2); + expect(x[2] == 3); } }; S.entry(2); @@ -229,12 +229,12 @@ test "double nested array to const slice cast in array literal" { []i32{1}, []i32{ two, 3 }, }; - assertOrPanic(cases2.len == 2); - assertOrPanic(cases2[0].len == 1); - assertOrPanic(cases2[0][0] == 1); - assertOrPanic(cases2[1].len == 2); - assertOrPanic(cases2[1][0] == 2); - assertOrPanic(cases2[1][1] == 3); + expect(cases2.len == 2); + expect(cases2[0].len == 1); + expect(cases2[0][0] == 1); + expect(cases2[1].len == 2); + expect(cases2[1][0] == 2); + expect(cases2[1][1] == 3); const cases3 = [][]const []const i32{ [][]const i32{[]i32{1}}, @@ -248,21 +248,21 @@ test "double nested array to const slice cast in array literal" { } fn check(cases: []const []const []const i32) void { - assertOrPanic(cases.len == 3); - assertOrPanic(cases[0].len == 1); - assertOrPanic(cases[0][0].len == 1); - assertOrPanic(cases[0][0][0] == 1); - assertOrPanic(cases[1].len == 1); - assertOrPanic(cases[1][0].len == 2); - assertOrPanic(cases[1][0][0] == 2); - assertOrPanic(cases[1][0][1] == 3); - assertOrPanic(cases[2].len == 2); - assertOrPanic(cases[2][0].len == 1); - assertOrPanic(cases[2][0][0] == 4); - assertOrPanic(cases[2][1].len == 3); - assertOrPanic(cases[2][1][0] == 5); - assertOrPanic(cases[2][1][1] == 6); - assertOrPanic(cases[2][1][2] == 7); + expect(cases.len == 3); + expect(cases[0].len == 1); + expect(cases[0][0].len == 1); + expect(cases[0][0][0] == 1); + expect(cases[1].len == 1); + expect(cases[1][0].len == 2); + expect(cases[1][0][0] == 2); + expect(cases[1][0][1] == 3); + expect(cases[2].len == 2); + expect(cases[2][0].len == 1); + expect(cases[2][0][0] == 4); + expect(cases[2][1].len == 3); + expect(cases[2][1][0] == 5); + expect(cases[2][1][1] == 6); + expect(cases[2][1][2] == 7); } }; S.entry(2); diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig index 48701c5836..845d80777a 100644 --- a/test/stage1/behavior/asm.zig +++ b/test/stage1/behavior/asm.zig @@ -1,5 +1,5 @@ const config = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; comptime { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { @@ -13,7 +13,7 @@ comptime { test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assertOrPanic(aoeu() == 1234); + expect(aoeu() == 1234); } } diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig index fa3c5f29a6..daa463fd45 100644 --- a/test/stage1/behavior/atomics.zig +++ b/test/stage1/behavior/atomics.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const AtomicRmwOp = builtin.AtomicRmwOp; const AtomicOrder = builtin.AtomicOrder; @@ -7,18 +7,18 @@ const AtomicOrder = builtin.AtomicOrder; test "cmpxchg" { var x: i32 = 1234; if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == 1234); + expect(x1 == 1234); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == 1234); + expect(x1 == 1234); } - assertOrPanic(x == 5678); + expect(x == 5678); - assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assertOrPanic(x == 42); + expect(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + expect(x == 42); } test "fence" { @@ -30,24 +30,24 @@ test "fence" { test "atomicrmw and atomicload" { var data: u8 = 200; testAtomicRmw(&data); - assertOrPanic(data == 42); + expect(data == 42); testAtomicLoad(&data); } fn testAtomicRmw(ptr: *u8) void { const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst); - assertOrPanic(prev_value == 200); + expect(prev_value == 200); comptime { var x: i32 = 1234; const y: i32 = 12345; - assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); - assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); + expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234); + expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345); } } fn testAtomicLoad(ptr: *u8) void { const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst); - assertOrPanic(x == 42); + expect(x == 42); } test "cmpxchg with ptr" { @@ -56,16 +56,16 @@ test "cmpxchg with ptr" { var data3: i32 = 9101; var x: *i32 = &data1; if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == &data1); + expect(x1 == &data1); } else { @panic("cmpxchg should have failed"); } while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| { - assertOrPanic(x1 == &data1); + expect(x1 == &data1); } - assertOrPanic(x == &data3); + expect(x == &data3); - assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); - assertOrPanic(x == &data2); + expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null); + expect(x == &data2); } diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig index 3290688358..610acc06c2 100644 --- a/test/stage1/behavior/bit_shifting.zig +++ b/test/stage1/behavior/bit_shifting.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { - assertOrPanic(Key == @IntType(false, Key.bit_count)); - assertOrPanic(Key.bit_count >= mask_bit_count); + expect(Key == @IntType(false, Key.bit_count)); + expect(Key.bit_count >= mask_bit_count); const ShardKey = @IntType(false, mask_bit_count); const shift_amount = Key.bit_count - ShardKey.bit_count; return struct { @@ -77,12 +77,12 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c var node_buffer: [node_count]Table.Node = undefined; for (node_buffer) |*node, i| { const key = @intCast(Key, i); - assertOrPanic(table.get(key) == null); + expect(table.get(key) == null); node.init(key, {}); table.put(node); } for (node_buffer) |*node, i| { - assertOrPanic(table.get(@intCast(Key, i)) == node); + expect(table.get(@intCast(Key, i)) == node); } } diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index 19030255e4..9607d2e3ef 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const maxInt = std.math.maxInt; test "@bitCast i32 -> u32" { @@ -8,8 +8,8 @@ test "@bitCast i32 -> u32" { } fn testBitCast_i32_u32() void { - assertOrPanic(conv(-1) == maxInt(u32)); - assertOrPanic(conv2(maxInt(u32)) == -1); + expect(conv(-1) == maxInt(u32)); + expect(conv2(maxInt(u32)) == -1); } fn conv(x: i32) u32 { @@ -27,7 +27,7 @@ test "@bitCast extern enum to its integer type" { fn testBitCastExternEnum() void { var SOCK_DGRAM = @This().B; var sock_dgram = @bitCast(c_int, SOCK_DGRAM); - assertOrPanic(sock_dgram == 1); + expect(sock_dgram == 1); } }; diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig index 97787ace84..3897a3eab7 100644 --- a/test/stage1/behavior/bitreverse.zig +++ b/test/stage1/behavior/bitreverse.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const minInt = std.math.minInt; test "@bitreverse" { @@ -9,73 +9,73 @@ test "@bitreverse" { fn testBitReverse() void { // using comptime_ints, unsigned - assertOrPanic(@bitreverse(u0, 0) == 0); - assertOrPanic(@bitreverse(u5, 0x12) == 0x9); - assertOrPanic(@bitreverse(u8, 0x12) == 0x48); - assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48); - assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48); - assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); - assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); - assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); - assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); - assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); - assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); + expect(@bitreverse(u0, 0) == 0); + expect(@bitreverse(u5, 0x12) == 0x9); + expect(@bitreverse(u8, 0x12) == 0x48); + expect(@bitreverse(u16, 0x1234) == 0x2c48); + expect(@bitreverse(u24, 0x123456) == 0x6a2c48); + expect(@bitreverse(u32, 0x12345678) == 0x1e6a2c48); + expect(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48); + expect(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48); + expect(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48); + expect(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48); + expect(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48); // using runtime uints, unsigned var num0: u0 = 0; - assertOrPanic(@bitreverse(u0, num0) == 0); + expect(@bitreverse(u0, num0) == 0); var num5: u5 = 0x12; - assertOrPanic(@bitreverse(u5, num5) == 0x9); + expect(@bitreverse(u5, num5) == 0x9); var num8: u8 = 0x12; - assertOrPanic(@bitreverse(u8, num8) == 0x48); + expect(@bitreverse(u8, num8) == 0x48); var num16: u16 = 0x1234; - assertOrPanic(@bitreverse(u16, num16) == 0x2c48); + expect(@bitreverse(u16, num16) == 0x2c48); var num24: u24 = 0x123456; - assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48); + expect(@bitreverse(u24, num24) == 0x6a2c48); var num32: u32 = 0x12345678; - assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48); + expect(@bitreverse(u32, num32) == 0x1e6a2c48); var num40: u40 = 0x123456789a; - assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48); + expect(@bitreverse(u40, num40) == 0x591e6a2c48); var num48: u48 = 0x123456789abc; - assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48); + expect(@bitreverse(u48, num48) == 0x3d591e6a2c48); var num56: u56 = 0x123456789abcde; - assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); + expect(@bitreverse(u56, num56) == 0x7b3d591e6a2c48); var num64: u64 = 0x123456789abcdef1; - assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); + expect(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48); var num128: u128 = 0x123456789abcdef11121314151617181; - assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); + expect(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48); // using comptime_ints, signed, positive - assertOrPanic(@bitreverse(i0, 0) == 0); - assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); - assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); - assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); - assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); - assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); - assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); - assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); - assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); - assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); + expect(@bitreverse(i0, 0) == 0); + expect(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49))); + expect(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48))); + expect(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48))); + expect(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48))); + expect(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48))); + expect(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48))); + expect(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48))); + expect(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48))); + expect(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48))); // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm. var neg5: i5 = minInt(i5) + 1; - assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); + expect(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5)); var neg8: i8 = -18; - assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); + expect(@bitreverse(i8, -18) == @bitreverse(i8, neg8)); var neg16: i16 = -32694; - assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); + expect(@bitreverse(i16, -32694) == @bitreverse(i16, neg16)); var neg24: i24 = -6773785; - assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); + expect(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24)); var neg32: i32 = -16773785; - assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); + expect(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32)); var neg40: i40 = minInt(i40) + 12345; - assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); + expect(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40)); var neg48: i48 = minInt(i48) + 12345; - assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); + expect(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48)); var neg56: i56 = minInt(i56) + 12345; - assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); + expect(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56)); var neg64: i64 = minInt(i64) + 12345; - assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); + expect(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64)); var neg128: i128 = minInt(i128) + 12345; - assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); + expect(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128)); } diff --git a/test/stage1/behavior/bool.zig b/test/stage1/behavior/bool.zig index 2d7241526f..dfc2279005 100644 --- a/test/stage1/behavior/bool.zig +++ b/test/stage1/behavior/bool.zig @@ -1,25 +1,25 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "bool literals" { - assertOrPanic(true); - assertOrPanic(!false); + expect(true); + expect(!false); } test "cast bool to int" { const t = true; const f = false; - assertOrPanic(@boolToInt(t) == u32(1)); - assertOrPanic(@boolToInt(f) == u32(0)); + expect(@boolToInt(t) == u32(1)); + expect(@boolToInt(f) == u32(0)); nonConstCastBoolToInt(t, f); } fn nonConstCastBoolToInt(t: bool, f: bool) void { - assertOrPanic(@boolToInt(t) == u32(1)); - assertOrPanic(@boolToInt(f) == u32(0)); + expect(@boolToInt(t) == u32(1)); + expect(@boolToInt(f) == u32(0)); } test "bool cmp" { - assertOrPanic(testBoolCmp(true, false) == false); + expect(testBoolCmp(true, false) == false); } fn testBoolCmp(a: bool, b: bool) bool { return a == b; @@ -30,6 +30,6 @@ const global_t = true; const not_global_f = !global_f; const not_global_t = !global_t; test "compile time bool not" { - assertOrPanic(not_global_f); - assertOrPanic(!not_global_t); + expect(not_global_f); + expect(!not_global_t); } diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig index 8084538e03..beffa0f73a 100644 --- a/test/stage1/behavior/bswap.zig +++ b/test/stage1/behavior/bswap.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "@bswap" { comptime testByteSwap(); @@ -7,26 +7,26 @@ test "@bswap" { } fn testByteSwap() void { - assertOrPanic(@bswap(u0, 0) == 0); - assertOrPanic(@bswap(u8, 0x12) == 0x12); - assertOrPanic(@bswap(u16, 0x1234) == 0x3412); - assertOrPanic(@bswap(u24, 0x123456) == 0x563412); - assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412); - assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412); - assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); - assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); - assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); - assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); + expect(@bswap(u0, 0) == 0); + expect(@bswap(u8, 0x12) == 0x12); + expect(@bswap(u16, 0x1234) == 0x3412); + expect(@bswap(u24, 0x123456) == 0x563412); + expect(@bswap(u32, 0x12345678) == 0x78563412); + expect(@bswap(u40, 0x123456789a) == 0x9a78563412); + expect(@bswap(u48, 0x123456789abc) == 0xbc9a78563412); + expect(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412); + expect(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); + expect(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); - assertOrPanic(@bswap(i0, 0) == 0); - assertOrPanic(@bswap(i8, -50) == -50); - assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); - assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); - assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); - assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); - assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); - assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); - assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); - assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == + expect(@bswap(i0, 0) == 0); + expect(@bswap(i8, -50) == -50); + expect(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); + expect(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); + expect(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); + expect(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412))); + expect(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); + expect(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); + expect(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); + expect(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); } diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig index 69a7e70f7d..9dc1d111ea 100644 --- a/test/stage1/behavior/bugs/1076.zig +++ b/test/stage1/behavior/bugs/1076.zig @@ -1,6 +1,6 @@ const std = @import("std"); const mem = std.mem; -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "comptime code should not modify constant data" { testCastPtrOfArrayToSliceAndPtr(); @@ -11,6 +11,6 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "boeu")); + expect(mem.eql(u8, array[0..], "boeu")); } diff --git a/test/stage1/behavior/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig index a83e7653e2..3aa1db2ea0 100644 --- a/test/stage1/behavior/bugs/1277.zig +++ b/test/stage1/behavior/bugs/1277.zig @@ -11,5 +11,5 @@ fn f() i32 { } test "don't emit an LLVM global for a const function when it's in an optional in a struct" { - std.debug.assertOrPanic(s.f.?() == 1234); + std.testing.expect(s.f.?() == 1234); } diff --git a/test/stage1/behavior/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig index 2e67f4473f..f1d61baa3a 100644 --- a/test/stage1/behavior/bugs/1322.zig +++ b/test/stage1/behavior/bugs/1322.zig @@ -13,7 +13,7 @@ const C = struct {}; test "tagged union with all void fields but a meaningful tag" { var a: A = A{ .b = B{ .c = C{} } }; - std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c); + std.testing.expect(@TagType(B)(a.b) == @TagType(B).c); a = A{ .b = B.None }; - std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None); + std.testing.expect(@TagType(B)(a.b) == @TagType(B).None); } diff --git a/test/stage1/behavior/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig index 2d452da156..91c994d7c0 100644 --- a/test/stage1/behavior/bugs/1381.zig +++ b/test/stage1/behavior/bugs/1381.zig @@ -17,5 +17,5 @@ test "union that needs padding bytes inside an array" { }; const a = as[0].B; - std.debug.assertOrPanic(a.D == 1); + std.testing.expect(a.D == 1); } diff --git a/test/stage1/behavior/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig index fbc932781a..48cf1ae2a6 100644 --- a/test/stage1/behavior/bugs/1421.zig +++ b/test/stage1/behavior/bugs/1421.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const S = struct { fn method() builtin.TypeInfo { @@ -10,5 +10,5 @@ const S = struct { test "functions with return type required to be comptime are generic" { const ti = S.method(); - assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct); + expect(builtin.TypeId(ti) == builtin.TypeId.Struct); } diff --git a/test/stage1/behavior/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig index e9dfd5d2ce..d5ea3f66fe 100644 --- a/test/stage1/behavior/bugs/1442.zig +++ b/test/stage1/behavior/bugs/1442.zig @@ -7,5 +7,5 @@ const Union = union(enum) { test "const error union field alignment" { var union_or_err: anyerror!Union = Union{ .Color = 1234 }; - std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234); + std.testing.expect((union_or_err catch unreachable).Color == 1234); } diff --git a/test/stage1/behavior/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig index 0483e3828c..d1bb8d7053 100644 --- a/test/stage1/behavior/bugs/1486.zig +++ b/test/stage1/behavior/bugs/1486.zig @@ -1,11 +1,11 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const ptr = &global; var global: u64 = 123; test "constant pointer to global variable causes runtime load" { global = 1234; - assertOrPanic(&global == ptr); - assertOrPanic(ptr.* == 1234); + expect(&global == ptr); + expect(ptr.* == 1234); } diff --git a/test/stage1/behavior/bugs/394.zig b/test/stage1/behavior/bugs/394.zig index 766ad9e157..b1f0b6b605 100644 --- a/test/stage1/behavior/bugs/394.zig +++ b/test/stage1/behavior/bugs/394.zig @@ -7,12 +7,12 @@ const S = struct { y: E, }; -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "bug 394 fixed" { const x = S{ .x = 3, .y = E{ .B = 1 }, }; - assertOrPanic(x.x == 3); + expect(x.x == 3); } diff --git a/test/stage1/behavior/bugs/655.zig b/test/stage1/behavior/bugs/655.zig index 67ba6a231f..d4491bfc27 100644 --- a/test/stage1/behavior/bugs/655.zig +++ b/test/stage1/behavior/bugs/655.zig @@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig"); test "function with *const parameter with type dereferenced by namespace" { const x: other_file.Integer = 1234; - comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer); + comptime std.testing.expect(@typeOf(&x) == *const other_file.Integer); foo(&x); } fn foo(x: *const other_file.Integer) void { - std.debug.assertOrPanic(x.* == 1234); + std.testing.expect(x.* == 1234); } diff --git a/test/stage1/behavior/bugs/656.zig b/test/stage1/behavior/bugs/656.zig index cb37fe67fe..159ec52d43 100644 --- a/test/stage1/behavior/bugs/656.zig +++ b/test/stage1/behavior/bugs/656.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const PrefixOp = union(enum) { Return, @@ -22,7 +22,7 @@ fn foo(a: bool, b: bool) void { PrefixOp.AddrOf => |addr_of_info| { if (b) {} if (addr_of_info.align_expr) |align_expr| { - assertOrPanic(align_expr == 1234); + expect(align_expr == 1234); } }, PrefixOp.Return => {}, diff --git a/test/stage1/behavior/bugs/726.zig b/test/stage1/behavior/bugs/726.zig index ce20480c63..dd2a135b56 100644 --- a/test/stage1/behavior/bugs/726.zig +++ b/test/stage1/behavior/bugs/726.zig @@ -1,9 +1,9 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@ptrCast from const to nullable" { const c: u8 = 4; var x: ?*const u8 = @ptrCast(?*const u8, &c); - assertOrPanic(x.?.* == 4); + expect(x.?.* == 4); } test "@ptrCast from var in empty struct to nullable" { @@ -11,6 +11,6 @@ test "@ptrCast from var in empty struct to nullable" { var c: u8 = 4; }; var x: ?*const u8 = @ptrCast(?*const u8, &container.c); - assertOrPanic(x.?.* == 4); + expect(x.?.* == 4); } diff --git a/test/stage1/behavior/bugs/920.zig b/test/stage1/behavior/bugs/920.zig index e29c5c4acf..10c002f6ba 100644 --- a/test/stage1/behavior/bugs/920.zig +++ b/test/stage1/behavior/bugs/920.zig @@ -60,6 +60,6 @@ test "bug 920 fixed" { }; for (NormalDist1.f) |_, i| { - std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]); + std.testing.expect(NormalDist1.f[i] == NormalDist.f[i]); } } diff --git a/test/stage1/behavior/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig index 14ee212ce0..3794a965c6 100644 --- a/test/stage1/behavior/byval_arg_var.zig +++ b/test/stage1/behavior/byval_arg_var.zig @@ -6,7 +6,7 @@ test "pass string literal byvalue to a generic var param" { start(); blowUpStack(10); - std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal")); + std.testing.expect(std.mem.eql(u8, result, "string literal")); } fn start() void { diff --git a/test/stage1/behavior/cancel.zig b/test/stage1/behavior/cancel.zig index 863da4bdb8..7fadf7f230 100644 --- a/test/stage1/behavior/cancel.zig +++ b/test/stage1/behavior/cancel.zig @@ -10,9 +10,9 @@ test "cancel forwards" { const p = async<&da.allocator> f1() catch unreachable; cancel p; - std.debug.assertOrPanic(defer_f1); - std.debug.assertOrPanic(defer_f2); - std.debug.assertOrPanic(defer_f3); + std.testing.expect(defer_f1); + std.testing.expect(defer_f2); + std.testing.expect(defer_f3); } async fn f1() void { @@ -47,10 +47,10 @@ test "cancel backwards" { const p = async<&da.allocator> b1() catch unreachable; cancel p; - std.debug.assertOrPanic(defer_b1); - std.debug.assertOrPanic(defer_b2); - std.debug.assertOrPanic(defer_b3); - std.debug.assertOrPanic(defer_b4); + std.testing.expect(defer_b1); + std.testing.expect(defer_b2); + std.testing.expect(defer_b3); + std.testing.expect(defer_b4); } async fn b1() void { diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 27f685a96e..8ed03f4936 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; const maxInt = std.math.maxInt; @@ -7,12 +7,12 @@ test "int to ptr cast" { const x = usize(13); const y = @intToPtr(*u8, x); const z = @ptrToInt(y); - assertOrPanic(z == 13); + expect(z == 13); } test "integer literal to pointer cast" { const vga_mem = @intToPtr(*u16, 0xB8000); - assertOrPanic(@ptrToInt(vga_mem) == 0xB8000); + expect(@ptrToInt(vga_mem) == 0xB8000); } test "pointer reinterpret const float to int" { @@ -20,7 +20,7 @@ test "pointer reinterpret const float to int" { const float_ptr = &float; const int_ptr = @ptrCast(*const i32, float_ptr); const int_val = int_ptr.*; - assertOrPanic(int_val == 858993411); + expect(int_val == 858993411); } test "implicitly cast indirect pointer to maybe-indirect pointer" { @@ -44,10 +44,10 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" { const p = &s; const q = &p; const r = &q; - assertOrPanic(42 == S.constConst(q)); - assertOrPanic(42 == S.maybeConstConst(q)); - assertOrPanic(42 == S.constConstConst(r)); - assertOrPanic(42 == S.maybeConstConstConst(r)); + expect(42 == S.constConst(q)); + expect(42 == S.maybeConstConst(q)); + expect(42 == S.constConstConst(r)); + expect(42 == S.maybeConstConstConst(r)); } test "explicit cast from integer to error type" { @@ -57,14 +57,14 @@ test "explicit cast from integer to error type" { fn testCastIntToErr(err: anyerror) void { const x = @errorToInt(err); const y = @intToError(x); - assertOrPanic(error.ItBroke == y); + expect(error.ItBroke == y); } test "peer resolve arrays of different size to const slice" { - assertOrPanic(mem.eql(u8, boolToStr(true), "true")); - assertOrPanic(mem.eql(u8, boolToStr(false), "false")); - comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true")); - comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false")); + expect(mem.eql(u8, boolToStr(true), "true")); + expect(mem.eql(u8, boolToStr(false), "false")); + comptime expect(mem.eql(u8, boolToStr(true), "true")); + comptime expect(mem.eql(u8, boolToStr(false), "false")); } fn boolToStr(b: bool) []const u8 { return if (b) "true" else "false"; @@ -77,8 +77,8 @@ test "peer resolve array and const slice" { fn testPeerResolveArrayConstSlice(b: bool) void { const value1 = if (b) "aoeu" else ([]const u8)("zz"); const value2 = if (b) ([]const u8)("zz") else "aoeu"; - assertOrPanic(mem.eql(u8, value1, "aoeu")); - assertOrPanic(mem.eql(u8, value2, "zz")); + expect(mem.eql(u8, value1, "aoeu")); + expect(mem.eql(u8, value2, "zz")); } test "implicitly cast from T to anyerror!?T" { @@ -92,14 +92,14 @@ const A = struct { fn castToOptionalTypeError(z: i32) void { const x = i32(1); const y: anyerror!?i32 = x; - assertOrPanic((try y).? == 1); + expect((try y).? == 1); const f = z; const g: anyerror!?i32 = f; const a = A{ .a = z }; const b: anyerror!?A = a; - assertOrPanic((b catch unreachable).?.a == 1); + expect((b catch unreachable).?.a == 1); } test "implicitly cast from int to anyerror!?T" { @@ -114,7 +114,7 @@ fn implicitIntLitToOptional() void { test "return null from fn() anyerror!?&T" { const a = returnNullFromOptionalTypeErrorRef(); const b = returnNullLitFromOptionalTypeErrorRef(); - assertOrPanic((try a) == null and (try b) == null); + expect((try a) == null and (try b) == null); } fn returnNullFromOptionalTypeErrorRef() anyerror!?*A { const a: ?*A = null; @@ -125,11 +125,11 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { } test "peer type resolution: ?T and T" { - assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); - assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); comptime { - assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0); - assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3); + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); } } fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { @@ -141,11 +141,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { } test "peer type resolution: [0]u8 and []const u8" { - assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); comptime { - assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); - assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); + expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); + expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); } } fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { @@ -157,8 +157,8 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { } test "implicitly cast from [N]T to ?[]const T" { - assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); - comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi")); + expect(mem.eql(u8, castToOptionalSlice().?, "hi")); + comptime expect(mem.eql(u8, castToOptionalSlice().?, "hi")); } fn castToOptionalSlice() ?[]const u8 { @@ -171,7 +171,7 @@ test "implicitly cast from [0]T to anyerror![]T" { } fn testCastZeroArrayToErrSliceMut() void { - assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0); + expect((gimmeErrOrSlice() catch unreachable).len == 0); } fn gimmeErrOrSlice() anyerror![]u8 { @@ -182,14 +182,14 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { { var data = "hi"; const slice = data[0..]; - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } comptime { var data = "hi"; const slice = data[0..]; - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); } } fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { @@ -207,7 +207,7 @@ test "resolve undefined with integer" { fn testResolveUndefWithInt(b: bool, x: i32) void { const value = if (b) x else undefined; if (b) { - assertOrPanic(value == x); + expect(value == x); } } @@ -219,17 +219,17 @@ test "implicit cast from &const [N]T to []const T" { fn testCastConstArrayRefToConstSlice() void { const blah = "aoeu"; const const_array_ref = &blah; - assertOrPanic(@typeOf(const_array_ref) == *const [4]u8); + expect(@typeOf(const_array_ref) == *const [4]u8); const slice: []const u8 = const_array_ref; - assertOrPanic(mem.eql(u8, slice, "aoeu")); + expect(mem.eql(u8, slice, "aoeu")); } test "peer type resolution: error and [N]T" { // TODO: implicit error!T to error!U where T can implicitly cast to U - //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); - assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); - comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + //expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + //comptime expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); + expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); + comptime expect(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK")); } //fn testPeerErrorAndArray(x: u8) error![]const u8 { @@ -253,9 +253,9 @@ test "@floatToInt" { fn testFloatToInts() void { const x = i32(1e4); - assertOrPanic(x == 10000); + expect(x == 10000); const y = @floatToInt(i32, f32(1e4)); - assertOrPanic(y == 10000); + expect(y == 10000); expectFloatToInt(f16, 255.1, u8, 255); expectFloatToInt(f16, 127.2, i8, 127); expectFloatToInt(f16, -128.2, i8, -128); @@ -266,7 +266,7 @@ fn testFloatToInts() void { } fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void { - assertOrPanic(@floatToInt(I, f) == i); + expect(@floatToInt(I, f) == i); } test "cast u128 to f128 and back" { @@ -275,7 +275,7 @@ test "cast u128 to f128 and back" { } fn testCast128() void { - assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); + expect(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); } fn cast128Int(x: f128) u128 { @@ -295,9 +295,9 @@ test "const slice widen cast" { }; const u32_value = @bytesToSlice(u32, bytes[0..])[0]; - assertOrPanic(u32_value == 0x12121212); + expect(u32_value == 0x12121212); - assertOrPanic(@bitCast(u32, bytes) == 0x12121212); + expect(@bitCast(u32, bytes) == 0x12121212); } test "single-item pointer of array to slice and to unknown length pointer" { @@ -309,76 +309,76 @@ fn testCastPtrOfArrayToSliceAndPtr() void { var array = "aoeu"; const x: [*]u8 = &array; x[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "boeu")); + expect(mem.eql(u8, array[0..], "boeu")); const y: []u8 = &array; y[0] += 1; - assertOrPanic(mem.eql(u8, array[0..], "coeu")); + expect(mem.eql(u8, array[0..], "coeu")); } test "cast *[1][*]const u8 to [*]const ?[*]const u8" { const window_name = [1][*]const u8{c"window name"}; const x: [*]const ?[*]const u8 = &window_name; - assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); + expect(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); } test "@intCast comptime_int" { const result = @intCast(i32, 1234); - assertOrPanic(@typeOf(result) == i32); - assertOrPanic(result == 1234); + expect(@typeOf(result) == i32); + expect(result == 1234); } test "@floatCast comptime_int and comptime_float" { { const result = @floatCast(f16, 1234); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @floatCast(f16, 1234.0); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @floatCast(f32, 1234); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } { const result = @floatCast(f32, 1234.0); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } } test "comptime_int @intToFloat" { { const result = @intToFloat(f16, 1234); - assertOrPanic(@typeOf(result) == f16); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f16); + expect(result == 1234.0); } { const result = @intToFloat(f32, 1234); - assertOrPanic(@typeOf(result) == f32); - assertOrPanic(result == 1234.0); + expect(@typeOf(result) == f32); + expect(result == 1234.0); } } test "@bytesToSlice keeps pointer alignment" { var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 }; const numbers = @bytesToSlice(u32, bytes[0..]); - comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); + comptime expect(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32); } test "@intCast i32 to u7" { var x: u128 = maxInt(u128); var y: i32 = 120; var z = x >> @intCast(u7, y); - assertOrPanic(z == 0xff); + expect(z == 0xff); } test "implicit cast undefined to optional" { - assertOrPanic(MakeType(void).getNull() == null); - assertOrPanic(MakeType(void).getNonNull() != null); + expect(MakeType(void).getNull() == null); + expect(MakeType(void).getNonNull() != null); } fn MakeType(comptime T: type) type { @@ -398,16 +398,16 @@ test "implicit cast from *[N]T to ?[*]T" { var y: [4]u16 = [4]u16{ 0, 1, 2, 3 }; x = &y; - assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); + expect(std.mem.eql(u16, x.?[0..4], y[0..4])); x.?[0] = 8; y[3] = 6; - assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4])); + expect(std.mem.eql(u16, x.?[0..4], y[0..4])); } test "implicit cast from *T to ?*c_void" { var a: u8 = 1; incrementVoidPtrValue(&a); - std.debug.assertOrPanic(a == 2); + std.testing.expect(a == 2); } fn incrementVoidPtrValue(value: ?*c_void) void { @@ -417,7 +417,7 @@ fn incrementVoidPtrValue(value: ?*c_void) void { test "implicit cast from [*]T to ?*c_void" { var a = []u8{ 3, 2, 1 }; incrementVoidPtrArray(a[0..].ptr, 3); - assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); + expect(std.mem.eql(u8, a, []u8{ 4, 3, 2 })); } fn incrementVoidPtrArray(array: ?*c_void, len: usize) void { @@ -441,27 +441,27 @@ pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize)); pub const PFN_void = extern fn (*c_void) void; fn foobar(func: PFN_void) void { - std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize)); + std.testing.expect(@ptrToInt(func) == maxInt(usize)); } test "implicit ptr to *c_void" { var a: u32 = 1; var ptr: *c_void = &a; var b: *u32 = @ptrCast(*u32, ptr); - assertOrPanic(b.* == 1); + expect(b.* == 1); var ptr2: ?*c_void = &a; var c: *u32 = @ptrCast(*u32, ptr2.?); - assertOrPanic(c.* == 1); + expect(c.* == 1); } test "@intCast to comptime_int" { - assertOrPanic(@intCast(comptime_int, 0) == 0); + expect(@intCast(comptime_int, 0) == 0); } test "implicit cast comptime numbers to any type when the value fits" { const a: u64 = 255; var b: u8 = a; - assertOrPanic(b == 255); + expect(b == 255); } test "@intToEnum passed a comptime_int to an enum with one item" { @@ -469,14 +469,14 @@ test "@intToEnum passed a comptime_int to an enum with one item" { A, }; const x = @intToEnum(E, 0); - assertOrPanic(x == E.A); + expect(x == E.A); } test "@intCast to u0 and use the result" { const S = struct { fn doTheTest(zero: u1, one: u1, bigzero: i32) void { - assertOrPanic((one << @intCast(u0, bigzero)) == 1); - assertOrPanic((zero << @intCast(u0, bigzero)) == 0); + expect((one << @intCast(u0, bigzero)) == 1); + expect((zero << @intCast(u0, bigzero)) == 0); } }; S.doTheTest(0, 1, 0); diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index 5b9b70a558..57044d8aae 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -1,5 +1,6 @@ -const debug = @import("std").debug; -const assertOrPanic = debug.assertOrPanic; +const std = @import("std"); +const debug = std.debug; +const expect = std.testing.expect; var argv: [*]const [*]const u8 = undefined; @@ -15,10 +16,10 @@ test "const slice child" { } fn foo(args: [][]const u8) void { - assertOrPanic(args.len == 3); - assertOrPanic(streql(args[0], "one")); - assertOrPanic(streql(args[1], "two")); - assertOrPanic(streql(args[2], "three")); + expect(args.len == 3); + expect(streql(args[0], "one")); + expect(streql(args[1], "two")); + expect(streql(args[2], "three")); } fn bar(argc: usize) void { diff --git a/test/stage1/behavior/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig index 6ca2a301ec..29f77bf67c 100644 --- a/test/stage1/behavior/coroutine_await_struct.zig +++ b/test/stage1/behavior/coroutine_await_struct.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const Foo = struct { x: i32, @@ -18,8 +18,8 @@ test "coroutine await struct" { await_seq('f'); resume await_a_promise; await_seq('i'); - assertOrPanic(await_final_result.x == 1234); - assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); + expect(await_final_result.x == 1234); + expect(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig index a2327c5060..be977bbfce 100644 --- a/test/stage1/behavior/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; var x: i32 = 1; @@ -9,9 +9,9 @@ test "create a coroutine and cancel it" { defer da.deinit(); const p = try async<&da.allocator> simpleAsyncFn(); - comptime assertOrPanic(@typeOf(p) == promise->void); + comptime expect(@typeOf(p) == promise->void); cancel p; - assertOrPanic(x == 2); + expect(x == 2); } async fn simpleAsyncFn() void { x += 1; @@ -31,7 +31,7 @@ test "coroutine suspend, resume, cancel" { cancel p; seq('g'); - assertOrPanic(std.mem.eql(u8, points, "abcdefg")); + expect(std.mem.eql(u8, points, "abcdefg")); } async fn testAsyncSeq() void { defer seq('e'); @@ -53,9 +53,9 @@ test "coroutine suspend with block" { defer da.deinit(); const p = try async<&da.allocator> testSuspendBlock(); - std.debug.assertOrPanic(!result); + std.testing.expect(!result); resume a_promise; - std.debug.assertOrPanic(result); + std.testing.expect(result); cancel p; } @@ -63,13 +63,13 @@ var a_promise: promise = undefined; var result = false; async fn testSuspendBlock() void { suspend { - comptime assertOrPanic(@typeOf(@handle()) == promise->void); + comptime expect(@typeOf(@handle()) == promise->void); a_promise = @handle(); } //Test to make sure that @handle() works as advertised (issue #1296) //var our_handle: promise = @handle(); - assertOrPanic(a_promise == @handle()); + expect(a_promise == @handle()); result = true; } @@ -86,8 +86,8 @@ test "coroutine await" { await_seq('f'); resume await_a_promise; await_seq('i'); - assertOrPanic(await_final_result == 1234); - assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi")); + expect(await_final_result == 1234); + expect(std.mem.eql(u8, await_points, "abcdefghi")); } async fn await_amain() void { await_seq('b'); @@ -123,8 +123,8 @@ test "coroutine await early return" { early_seq('a'); const p = async<&da.allocator> early_amain() catch @panic("out of memory"); early_seq('f'); - assertOrPanic(early_final_result == 1234); - assertOrPanic(std.mem.eql(u8, early_points, "abcdef")); + expect(early_final_result == 1234); + expect(std.mem.eql(u8, early_points, "abcdef")); } async fn early_amain() void { early_seq('b'); @@ -170,7 +170,7 @@ test "async function with dot syntax" { defer da.deinit(); const p = try async<&da.allocator> S.foo(); cancel p; - assertOrPanic(S.y == 2); + expect(S.y == 2); } test "async fn pointer in a struct field" { @@ -182,9 +182,9 @@ test "async fn pointer in a struct field" { var da = std.heap.DirectAllocator.init(); defer da.deinit(); const p = (async<&da.allocator> foo.bar(&data)) catch unreachable; - assertOrPanic(data == 2); + expect(data == 2); cancel p; - assertOrPanic(data == 4); + expect(data == 4); } async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void { defer y.* += 2; @@ -230,9 +230,9 @@ async fn suspendThenFail() anyerror!void { } async fn printTrace(p: promise->(anyerror!void)) void { (await p) catch |e| { - std.debug.assertOrPanic(e == error.Fail); + std.testing.expect(e == error.Fail); if (@errorReturnTrace()) |trace| { - assertOrPanic(trace.index == 1); + expect(trace.index == 1); } else switch (builtin.mode) { builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"), builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {}, @@ -246,7 +246,7 @@ test "break from suspend" { var my_result: i32 = 1; const p = try async
testBreakFromSuspend(&my_result); cancel p; - std.debug.assertOrPanic(my_result == 2); + std.testing.expect(my_result == 2); } async fn testBreakFromSuspend(my_result: *i32) void { suspend { diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig index 6c6c60311e..0bb9125e7c 100644 --- a/test/stage1/behavior/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; var result: [3]u8 = undefined; var index: usize = undefined; @@ -21,18 +21,18 @@ fn runSomeErrorDefers(x: bool) !bool { } test "mixing normal and error defers" { - assertOrPanic(runSomeErrorDefers(true) catch unreachable); - assertOrPanic(result[0] == 'c'); - assertOrPanic(result[1] == 'a'); + expect(runSomeErrorDefers(true) catch unreachable); + expect(result[0] == 'c'); + expect(result[1] == 'a'); const ok = runSomeErrorDefers(false) catch |err| x: { - assertOrPanic(err == error.FalseNotAllowed); + expect(err == error.FalseNotAllowed); break :x true; }; - assertOrPanic(ok); - assertOrPanic(result[0] == 'c'); - assertOrPanic(result[1] == 'b'); - assertOrPanic(result[2] == 'a'); + expect(ok); + expect(result[0] == 'c'); + expect(result[1] == 'b'); + expect(result[2] == 'a'); } test "break and continue inside loop inside defer expression" { @@ -47,7 +47,7 @@ fn testBreakContInDefer(x: usize) void { if (i < 5) continue; if (i == 5) break; } - assertOrPanic(i == 5); + expect(i == 5); } } @@ -59,11 +59,11 @@ test "defer and labeled break" { break :blk; } - assertOrPanic(i == 1); + expect(i == 1); } test "errdefer does not apply to fn inside fn" { - if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad); + if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| expect(e == error.Bad); } fn testNestedFnErrDefer() anyerror!void { diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 9de138ef78..899aeea67d 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; test "enum type" { @@ -11,16 +11,16 @@ test "enum type" { }; const bar = Bar.B; - assertOrPanic(bar == Bar.B); - assertOrPanic(@memberCount(Foo) == 3); - assertOrPanic(@memberCount(Bar) == 4); - assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - assertOrPanic(@sizeOf(Bar) == 1); + expect(bar == Bar.B); + expect(@memberCount(Foo) == 3); + expect(@memberCount(Bar) == 4); + expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + expect(@sizeOf(Bar) == 1); } test "enum as return value" { switch (returnAnInt(13)) { - Foo.One => |value| assertOrPanic(value == 13), + Foo.One => |value| expect(value == 13), else => unreachable, } } @@ -92,14 +92,14 @@ test "enum to int" { } fn shouldEqual(n: Number, expected: u3) void { - assertOrPanic(@enumToInt(n) == expected); + expect(@enumToInt(n) == expected); } test "int to enum" { testIntToEnumEval(3); } fn testIntToEnumEval(x: i32) void { - assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); + expect(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); } const IntToEnumNumber = enum { Zero, @@ -110,8 +110,8 @@ const IntToEnumNumber = enum { }; test "@tagName" { - assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); - comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); + comptime expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); } fn testEnumTagNameBare(n: BareNumber) []const u8 { @@ -126,8 +126,8 @@ const BareNumber = enum { test "enum alignment" { comptime { - assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); - assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64)); + expect(@alignOf(AlignTestEnum) >= @alignOf([9]u8)); + expect(@alignOf(AlignTestEnum) >= @alignOf(u64)); } } @@ -663,10 +663,10 @@ const ValueCount257 = enum { test "enum sizes" { comptime { - assertOrPanic(@sizeOf(ValueCount1) == 0); - assertOrPanic(@sizeOf(ValueCount2) == 1); - assertOrPanic(@sizeOf(ValueCount256) == 1); - assertOrPanic(@sizeOf(ValueCount257) == 2); + expect(@sizeOf(ValueCount1) == 0); + expect(@sizeOf(ValueCount2) == 1); + expect(@sizeOf(ValueCount256) == 1); + expect(@sizeOf(ValueCount257) == 2); } } @@ -685,12 +685,12 @@ test "set enum tag type" { { var x = Small.One; x = Small.Two; - comptime assertOrPanic(@TagType(Small) == u2); + comptime expect(@TagType(Small) == u2); } { var x = Small2.One; x = Small2.Two; - comptime assertOrPanic(@TagType(Small2) == u2); + comptime expect(@TagType(Small2) == u2); } } @@ -737,17 +737,17 @@ const bit_field_1 = BitFieldOfEnums{ test "bit field access with enum fields" { var data = bit_field_1; - assertOrPanic(getA(&data) == A.Two); - assertOrPanic(getB(&data) == B.Three3); - assertOrPanic(getC(&data) == C.Four4); - comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1); + expect(getA(&data) == A.Two); + expect(getB(&data) == B.Three3); + expect(getC(&data) == C.Four4); + comptime expect(@sizeOf(BitFieldOfEnums) == 1); data.b = B.Four3; - assertOrPanic(data.b == B.Four3); + expect(data.b == B.Four3); data.a = A.Three; - assertOrPanic(data.a == A.Three); - assertOrPanic(data.b == B.Four3); + expect(data.a == A.Three); + expect(data.b == B.Four3); } fn getA(data: *const BitFieldOfEnums) A { @@ -768,7 +768,7 @@ test "casting enum to its tag type" { } fn testCastEnumToTagType(value: Small2) void { - assertOrPanic(@enumToInt(value) == 1); + expect(@enumToInt(value) == 1); } const MultipleChoice = enum(u32) { @@ -784,8 +784,8 @@ test "enum with specified tag values" { } fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { - assertOrPanic(@enumToInt(x) == 60); - assertOrPanic(1234 == switch (x) { + expect(@enumToInt(x) == 60); + expect(1234 == switch (x) { MultipleChoice.A => 1, MultipleChoice.B => 2, MultipleChoice.C => u32(1234), @@ -811,8 +811,8 @@ test "enum with specified and unspecified tag values" { } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assertOrPanic(@enumToInt(x) == 1000); - assertOrPanic(1234 == switch (x) { + expect(@enumToInt(x) == 1000); + expect(1234 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => 3, @@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { } test "cast integer literal to enum" { - assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); - assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); + expect(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); + expect(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); } const EnumWithOneMember = enum { @@ -865,14 +865,14 @@ const EnumWithTagValues = enum(u4) { D = 1 << 3, }; test "enum with tag values don't require parens" { - assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100); + expect(@enumToInt(EnumWithTagValues.C) == 0b0100); } test "enum with 1 field but explicit tag type should still have the tag type" { const Enum = enum(u8) { B = 2, }; - comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8)); + comptime @import("std").testing.expect(@sizeOf(Enum) == @sizeOf(u8)); } test "empty extern enum with members" { @@ -881,7 +881,7 @@ test "empty extern enum with members" { B, C, }; - assertOrPanic(@sizeOf(E) == @sizeOf(c_int)); + expect(@sizeOf(E) == @sizeOf(c_int)); } test "tag name with assigned enum values" { @@ -890,5 +890,5 @@ test "tag name with assigned enum values" { B = 0, }; var b = LocalFoo.B; - assertOrPanic(mem.eql(u8, @tagName(b), "B")); + expect(mem.eql(u8, @tagName(b), "B")); } diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig index 49af1ceae7..2e022a3427 100644 --- a/test/stage1/behavior/enum_with_members.zig +++ b/test/stage1/behavior/enum_with_members.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const fmt = @import("std").fmt; @@ -19,9 +19,9 @@ test "enum with members" { const b = ET{ .UINT = 42 }; var buf: [20]u8 = undefined; - assertOrPanic((a.print(buf[0..]) catch unreachable) == 3); - assertOrPanic(mem.eql(u8, buf[0..3], "-42")); + expect((a.print(buf[0..]) catch unreachable) == 3); + expect(mem.eql(u8, buf[0..3], "-42")); - assertOrPanic((b.print(buf[0..]) catch unreachable) == 2); - assertOrPanic(mem.eql(u8, buf[0..2], "42")); + expect((b.print(buf[0..]) catch unreachable) == 2); + expect(mem.eql(u8, buf[0..2], "42")); } diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index c7e38712bc..265ddd9d6c 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; -const assertError = std.debug.assertError; +const expect = std.testing.expect; +const expectError = std.testing.expectError; const mem = std.mem; const builtin = @import("builtin"); @@ -19,7 +19,7 @@ pub fn baz() anyerror!i32 { } test "error wrapping" { - assertOrPanic((baz() catch unreachable) == 15); + expect((baz() catch unreachable) == 15); } fn gimmeItBroke() []const u8 { @@ -27,14 +27,14 @@ fn gimmeItBroke() []const u8 { } test "@errorName" { - assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError")); - assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); + expect(mem.eql(u8, @errorName(error.AnError), "AnError")); + expect(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName")); } test "error values" { const a = @errorToInt(error.err1); const b = @errorToInt(error.err2); - assertOrPanic(a != b); + expect(a != b); } test "redefinition of error values allowed" { @@ -47,8 +47,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { test "error binary operator" { const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; - assertOrPanic(a == 3); - assertOrPanic(b == 10); + expect(a == 3); + expect(b == 10); } fn errBinaryOperatorG(x: bool) anyerror!isize { return if (x) error.ItBroke else isize(10); @@ -56,7 +56,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize { test "unwrap simple value from error" { const i = unwrapSimpleValueFromErrorDo() catch unreachable; - assertOrPanic(i == 13); + expect(i == 13); } fn unwrapSimpleValueFromErrorDo() anyerror!isize { return 13; @@ -82,10 +82,10 @@ test "error union type " { fn testErrorUnionType() void { const x: anyerror!i32 = 1234; - if (x) |value| assertOrPanic(value == 1234) else |_| unreachable; - assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); - assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); - assertOrPanic(@typeOf(x).ErrorSet == anyerror); + if (x) |value| expect(value == 1234) else |_| unreachable; + expect(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion); + expect(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); + expect(@typeOf(x).ErrorSet == anyerror); } test "error set type" { @@ -99,12 +99,12 @@ const MyErrSet = error{ }; fn testErrorSetType() void { - assertOrPanic(@memberCount(MyErrSet) == 2); + expect(@memberCount(MyErrSet) == 2); const a: MyErrSet!i32 = 5678; const b: MyErrSet!i32 = MyErrSet.OutOfMemory; - if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) { + if (a) |value| expect(value == 5678) else |err| switch (err) { error.OutOfMemory => unreachable, error.FileNotFound => unreachable, } @@ -127,7 +127,7 @@ const Set2 = error{ fn testExplicitErrorSetCast(set1: Set1) void { var x = @errSetCast(Set2, set1); var y = @errSetCast(Set1, x); - assertOrPanic(y == error.A); + expect(y == error.A); } test "comptime test error for empty error set" { @@ -138,12 +138,12 @@ test "comptime test error for empty error set" { const EmptyErrorSet = error{}; fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { - if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad"); + if (x) |v| expect(v == 1234) else |err| @compileError("bad"); } test "syntax: optional operator in front of error union operator" { comptime { - assertOrPanic(?(anyerror!i32) == ?(anyerror!i32)); + expect(?(anyerror!i32) == ?(anyerror!i32)); } } @@ -173,7 +173,7 @@ fn testErrorUnionPeerTypeResolution(x: i32) void { if (y) |_| { @panic("expected error"); } else |e| { - assertOrPanic(e == error.A); + expect(e == error.A); } } @@ -282,13 +282,13 @@ test "nested error union function call in optional unwrap" { return null; } }; - assertOrPanic((try S.errorable()) == 1234); - assertError(S.errorable2(), error.Failure); - assertError(S.errorable3(), error.Other); + expect((try S.errorable()) == 1234); + expectError(error.Failure, S.errorable2()); + expectError(error.Other, S.errorable3()); comptime { - assertOrPanic((try S.errorable()) == 1234); - assertError(S.errorable2(), error.Failure); - assertError(S.errorable3(), error.Other); + expect((try S.errorable()) == 1234); + expectError(error.Failure, S.errorable2()); + expectError(error.Other, S.errorable3()); } } @@ -303,7 +303,7 @@ test "widen cast integer payload of error union function call" { return 1234; } }; - assertOrPanic((try S.errorable()) == 1234); + expect((try S.errorable()) == 1234); } test "return function call to error set from error union function" { @@ -316,17 +316,17 @@ test "return function call to error set from error union function" { return error.Failure; } }; - assertError(S.errorable(), error.Failure); - comptime assertError(S.errorable(), error.Failure); + expectError(error.Failure, S.errorable()); + comptime expectError(error.Failure, S.errorable()); } test "optional error set is the same size as error set" { - comptime assertOrPanic(@sizeOf(?anyerror) == @sizeOf(anyerror)); + comptime expect(@sizeOf(?anyerror) == @sizeOf(anyerror)); const S = struct { fn returnsOptErrSet() ?anyerror { return null; } }; - assertOrPanic(S.returnsOptErrSet() == null); - comptime assertOrPanic(S.returnsOptErrSet() == null); + expect(S.returnsOptErrSet() == null); + comptime expect(S.returnsOptErrSet() == null); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 0d1ecfab5b..5976761f77 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); test "compile time recursion" { - assertOrPanic(some_data.len == 21); + expect(some_data.len == 21); } var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined; fn fibonacci(x: i32) i32 { @@ -16,7 +16,7 @@ fn unwrapAndAddOne(blah: ?i32) i32 { } const should_be_1235 = unwrapAndAddOne(1234); test "static add one" { - assertOrPanic(should_be_1235 == 1235); + expect(should_be_1235 == 1235); } test "inlined loop" { @@ -24,7 +24,7 @@ test "inlined loop" { comptime var sum = 0; inline while (i <= 5) : (i += 1) sum += i; - assertOrPanic(sum == 15); + expect(sum == 15); } fn gimme1or2(comptime a: bool) i32 { @@ -34,12 +34,12 @@ fn gimme1or2(comptime a: bool) i32 { return z; } test "inline variable gets result of const if" { - assertOrPanic(gimme1or2(true) == 1); - assertOrPanic(gimme1or2(false) == 2); + expect(gimme1or2(true) == 1); + expect(gimme1or2(false) == 2); } test "static function evaluation" { - assertOrPanic(statically_added_number == 3); + expect(statically_added_number == 3); } const statically_added_number = staticAdd(1, 2); fn staticAdd(a: i32, b: i32) i32 { @@ -47,8 +47,8 @@ fn staticAdd(a: i32, b: i32) i32 { } test "const expr eval on single expr blocks" { - assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); - comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); + comptime expect(constExprEvalOnSingleExprBlocksFn(1, true) == 3); } fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { @@ -64,10 +64,10 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { } test "statically initialized list" { - assertOrPanic(static_point_list[0].x == 1); - assertOrPanic(static_point_list[0].y == 2); - assertOrPanic(static_point_list[1].x == 3); - assertOrPanic(static_point_list[1].y == 4); + expect(static_point_list[0].x == 1); + expect(static_point_list[0].y == 2); + expect(static_point_list[1].x == 3); + expect(static_point_list[1].y == 4); } const Point = struct { x: i32, @@ -85,8 +85,8 @@ fn makePoint(x: i32, y: i32) Point { } test "static eval list init" { - assertOrPanic(static_vec3.data[2] == 1.0); - assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0); + expect(static_vec3.data[2] == 1.0); + expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); } const static_vec3 = vec3(0.0, 0.0, 1.0); pub const Vec3 = struct { @@ -102,12 +102,12 @@ pub fn vec3(x: f32, y: f32, z: f32) Vec3 { test "constant expressions" { var array: [array_size]u8 = undefined; - assertOrPanic(@sizeOf(@typeOf(array)) == 20); + expect(@sizeOf(@typeOf(array)) == 20); } const array_size: u8 = 20; test "constant struct with negation" { - assertOrPanic(vertices[0].x == -0.6); + expect(vertices[0].x == -0.6); } const Vertex = struct { x: f32, @@ -142,7 +142,7 @@ const vertices = []Vertex{ test "statically initialized struct" { st_init_str_foo.x += 1; - assertOrPanic(st_init_str_foo.x == 14); + expect(st_init_str_foo.x == 14); } const StInitStrFoo = struct { x: i32, @@ -155,7 +155,7 @@ var st_init_str_foo = StInitStrFoo{ test "statically initalized array literal" { const y: [4]u8 = st_init_arr_lit_x; - assertOrPanic(y[3] == 4); + expect(y[3] == 4); } const st_init_arr_lit_x = []u8{ 1, @@ -167,15 +167,15 @@ const st_init_arr_lit_x = []u8{ test "const slice" { comptime { const a = "1234567890"; - assertOrPanic(a.len == 10); + expect(a.len == 10); const b = a[1..2]; - assertOrPanic(b.len == 1); - assertOrPanic(b[0] == '2'); + expect(b.len == 1); + expect(b[0] == '2'); } } test "try to trick eval with runtime if" { - assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10); + expect(testTryToTrickEvalWithRuntimeIf(true) == 10); } fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { @@ -201,16 +201,16 @@ fn letsTryToCompareBools(a: bool, b: bool) bool { return max(bool, a, b); } test "inlined block and runtime block phi" { - assertOrPanic(letsTryToCompareBools(true, true)); - assertOrPanic(letsTryToCompareBools(true, false)); - assertOrPanic(letsTryToCompareBools(false, true)); - assertOrPanic(!letsTryToCompareBools(false, false)); + expect(letsTryToCompareBools(true, true)); + expect(letsTryToCompareBools(true, false)); + expect(letsTryToCompareBools(false, true)); + expect(!letsTryToCompareBools(false, false)); comptime { - assertOrPanic(letsTryToCompareBools(true, true)); - assertOrPanic(letsTryToCompareBools(true, false)); - assertOrPanic(letsTryToCompareBools(false, true)); - assertOrPanic(!letsTryToCompareBools(false, false)); + expect(letsTryToCompareBools(true, true)); + expect(letsTryToCompareBools(true, false)); + expect(letsTryToCompareBools(false, true)); + expect(!letsTryToCompareBools(false, false)); } } @@ -255,14 +255,14 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 { } test "comptime iterate over fn ptr list" { - assertOrPanic(performFn('t', 1) == 6); - assertOrPanic(performFn('o', 0) == 1); - assertOrPanic(performFn('w', 99) == 99); + expect(performFn('t', 1) == 6); + expect(performFn('o', 0) == 1); + expect(performFn('w', 99) == 99); } test "eval @setRuntimeSafety at compile-time" { const result = comptime fnWithSetRuntimeSafety(); - assertOrPanic(result == 1234); + expect(result == 1234); } fn fnWithSetRuntimeSafety() i32 { @@ -272,7 +272,7 @@ fn fnWithSetRuntimeSafety() i32 { test "eval @setFloatMode at compile-time" { const result = comptime fnWithFloatMode(); - assertOrPanic(result == 1234.0); + expect(result == 1234.0); } fn fnWithFloatMode() f32 { @@ -293,15 +293,15 @@ var simple_struct = SimpleStruct{ .field = 1234 }; const bound_fn = simple_struct.method; test "call method on bound fn referring to var instance" { - assertOrPanic(bound_fn() == 1237); + expect(bound_fn() == 1237); } test "ptr to local array argument at comptime" { comptime { var bytes: [10]u8 = undefined; modifySomeBytes(bytes[0..]); - assertOrPanic(bytes[0] == 'a'); - assertOrPanic(bytes[9] == 'b'); + expect(bytes[0] == 'a'); + expect(bytes[9] == 'b'); } } @@ -329,9 +329,9 @@ fn testCompTimeUIntComparisons(x: u32) void { } test "const ptr to variable data changes at runtime" { - assertOrPanic(foo_ref.name[0] == 'a'); + expect(foo_ref.name[0] == 'a'); foo_ref.name = "b"; - assertOrPanic(foo_ref.name[0] == 'b'); + expect(foo_ref.name[0] == 'b'); } const Foo = struct { @@ -342,8 +342,8 @@ var foo_contents = Foo{ .name = "a" }; const foo_ref = &foo_contents; test "create global array with for loop" { - assertOrPanic(global_array[5] == 5 * 5); - assertOrPanic(global_array[9] == 9 * 9); + expect(global_array[5] == 5 * 5); + expect(global_array[9] == 9 * 9); } const global_array = x: { @@ -358,7 +358,7 @@ test "compile-time downcast when the bits fit" { comptime { const spartan_count: u16 = 255; const byte = @intCast(u8, spartan_count); - assertOrPanic(byte == 255); + expect(byte == 255); } } @@ -366,44 +366,44 @@ const hi1 = "hi"; const hi2 = hi1; test "const global shares pointer with other same one" { assertEqualPtrs(&hi1[0], &hi2[0]); - comptime assertOrPanic(&hi1[0] == &hi2[0]); + comptime expect(&hi1[0] == &hi2[0]); } fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void { - assertOrPanic(ptr1 == ptr2); + expect(ptr1 == ptr2); } test "@setEvalBranchQuota" { comptime { - // 1001 for the loop and then 1 more for the assertOrPanic fn call + // 1001 for the loop and then 1 more for the expect fn call @setEvalBranchQuota(1002); var i = 0; var sum = 0; while (i < 1001) : (i += 1) { sum += i; } - assertOrPanic(sum == 500500); + expect(sum == 500500); } } // TODO test "float literal at compile time not lossy" { -// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0); -// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0); +// TODO expect(16777216.0 + 1.0 == 16777217.0); +// TODO expect(9007199254740992.0 + 1.0 == 9007199254740993.0); // TODO } test "f32 at compile time is lossy" { - assertOrPanic(f32(1 << 24) + 1 == 1 << 24); + expect(f32(1 << 24) + 1 == 1 << 24); } test "f64 at compile time is lossy" { - assertOrPanic(f64(1 << 53) + 1 == 1 << 53); + expect(f64(1 << 53) + 1 == 1 << 53); } test "f128 at compile time is lossy" { - assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); + expect(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0); } comptime { - assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192); + expect(f128(1 << 113) == 10384593717069655257060992658440192); } pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { @@ -415,15 +415,15 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { test "string literal used as comptime slice is memoized" { const a = "link"; const b = "link"; - comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); - comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); + comptime expect(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); + comptime expect(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); } test "comptime slice of undefined pointer of length 0" { const slice1 = ([*]i32)(undefined)[0..0]; - assertOrPanic(slice1.len == 0); + expect(slice1.len == 0); const slice2 = ([*]i32)(undefined)[100..100]; - assertOrPanic(slice2.len == 0); + expect(slice2.len == 0); } fn copyWithPartialInline(s: []u32, b: []u8) void { @@ -445,16 +445,16 @@ test "binary math operator in partially inlined function" { r.* = @intCast(u8, i + 1); copyWithPartialInline(s[0..], b[0..]); - assertOrPanic(s[0] == 0x1020304); - assertOrPanic(s[1] == 0x5060708); - assertOrPanic(s[2] == 0x90a0b0c); - assertOrPanic(s[3] == 0xd0e0f10); + expect(s[0] == 0x1020304); + expect(s[1] == 0x5060708); + expect(s[2] == 0x90a0b0c); + expect(s[3] == 0xd0e0f10); } test "comptime function with the same args is memoized" { comptime { - assertOrPanic(MakeType(i32) == MakeType(i32)); - assertOrPanic(MakeType(i32) != MakeType(f64)); + expect(MakeType(i32) == MakeType(i32)); + expect(MakeType(i32) != MakeType(f64)); } } @@ -470,7 +470,7 @@ test "comptime function with mutable pointer is not memoized" { const ptr = &x; increment(ptr); increment(ptr); - assertOrPanic(x == 3); + expect(x == 3); } } @@ -496,14 +496,14 @@ fn doesAlotT(comptime T: type, value: usize) T { } test "@setEvalBranchQuota at same scope as generic function call" { - assertOrPanic(doesAlotT(u32, 2) == 2); + expect(doesAlotT(u32, 2) == 2); } test "comptime slice of slice preserves comptime var" { comptime { var buff: [10]u8 = undefined; buff[0..][0..][0] = 1; - assertOrPanic(buff[0..][0..][0] == 1); + expect(buff[0..][0..][0] == 1); } } @@ -512,7 +512,7 @@ test "comptime slice of pointer preserves comptime var" { var buff: [10]u8 = undefined; var a = buff[0..].ptr; a[0..1][0] = 1; - assertOrPanic(buff[0..][0..][0] == 1); + expect(buff[0..][0..][0] == 1); } } @@ -526,9 +526,9 @@ const SingleFieldStruct = struct { test "const ptr to comptime mutable data is not memoized" { comptime { var foo = SingleFieldStruct{ .x = 1 }; - assertOrPanic(foo.read_x() == 1); + expect(foo.read_x() == 1); foo.x = 2; - assertOrPanic(foo.read_x() == 2); + expect(foo.read_x() == 2); } } @@ -537,7 +537,7 @@ test "array concat of slices gives slice" { var a: []const u8 = "aoeu"; var b: []const u8 = "asdf"; const c = a ++ b; - assertOrPanic(std.mem.eql(u8, c, "aoeuasdf")); + expect(std.mem.eql(u8, c, "aoeuasdf")); } } @@ -554,14 +554,14 @@ test "comptime shlWithOverflow" { break :amt amt; }; - assertOrPanic(ct_shifted == rt_shifted); + expect(ct_shifted == rt_shifted); } test "runtime 128 bit integer division" { var a: u128 = 152313999999999991610955792383; var b: u128 = 10000000000000000000; var c = a / b; - assertOrPanic(c == 15231399999); + expect(c == 15231399999); } pub const Info = struct { @@ -574,20 +574,20 @@ test "comptime modification of const struct field" { comptime { var res = diamond_info; res.version = 1; - assertOrPanic(diamond_info.version == 0); - assertOrPanic(res.version == 1); + expect(diamond_info.version == 0); + expect(res.version == 1); } } test "pointer to type" { comptime { var T: type = i32; - assertOrPanic(T == i32); + expect(T == i32); var ptr = &T; - assertOrPanic(@typeOf(ptr) == *type); + expect(@typeOf(ptr) == *type); ptr.* = f32; - assertOrPanic(T == f32); - assertOrPanic(*T == *f32); + expect(T == f32); + expect(*T == *f32); } } @@ -596,17 +596,17 @@ test "slice of type" { var types_array = []type{ i32, f64, type }; for (types_array) |T, i| { switch (i) { - 0 => assertOrPanic(T == i32), - 1 => assertOrPanic(T == f64), - 2 => assertOrPanic(T == type), + 0 => expect(T == i32), + 1 => expect(T == f64), + 2 => expect(T == type), else => unreachable, } } for (types_array[0..]) |T, i| { switch (i) { - 0 => assertOrPanic(T == i32), - 1 => assertOrPanic(T == f64), - 2 => assertOrPanic(T == type), + 0 => expect(T == i32), + 1 => expect(T == f64), + 2 => expect(T == type), else => unreachable, } } @@ -623,7 +623,7 @@ fn wrap(comptime T: type) Wrapper { test "function which returns struct with type field causes implicit comptime" { const ty = wrap(i32).T; - assertOrPanic(ty == i32); + expect(ty == i32); } test "call method with comptime pass-by-non-copying-value self parameter" { @@ -637,12 +637,12 @@ test "call method with comptime pass-by-non-copying-value self parameter" { const s = S{ .a = 2 }; var b = s.b(); - assertOrPanic(b == 2); + expect(b == 2); } test "@tagName of @typeId" { const str = @tagName(@typeId(u8)); - assertOrPanic(std.mem.eql(u8, str, "Int")); + expect(std.mem.eql(u8, str, "Int")); } test "setting backward branch quota just before a generic fn call" { @@ -663,8 +663,8 @@ fn testVarInsideInlineLoop(args: ...) void { comptime var i = 0; inline while (i < args.len) : (i += 1) { const x = args[i]; - if (i == 0) assertOrPanic(x); - if (i == 1) assertOrPanic(x == 42); + if (i == 0) expect(x); + if (i == 1) expect(x == 42); } } @@ -674,7 +674,7 @@ test "inline for with same type but different values" { var a: T = undefined; res += a.len; } - assertOrPanic(res == 5); + expect(res == 5); } test "refer to the type of a generic function" { @@ -688,13 +688,13 @@ fn doNothingWithType(comptime T: type) void {} test "zero extend from u0 to u1" { var zero_u0: u0 = 0; var zero_u1: u1 = zero_u0; - assertOrPanic(zero_u1 == 0); + expect(zero_u1 == 0); } test "bit shift a u1" { var x: u1 = 1; var y = x << 0; - assertOrPanic(y == 1); + expect(y == 1); } test "@bytesToslice on a packed struct" { @@ -704,7 +704,7 @@ test "@bytesToslice on a packed struct" { var b = [1]u8{9}; var f = @bytesToSlice(F, b); - assertOrPanic(f[0].a == 9); + expect(f[0].a == 9); } test "comptime pointer cast array and then slice" { @@ -716,8 +716,8 @@ test "comptime pointer cast array and then slice" { const ptrB: [*]const u8 = &array; const sliceB: []const u8 = ptrB[0..2]; - assertOrPanic(sliceA[1] == 2); - assertOrPanic(sliceB[1] == 2); + expect(sliceA[1] == 2); + expect(sliceB[1] == 2); } test "slice bounds in comptime concatenation" { @@ -726,47 +726,47 @@ test "slice bounds in comptime concatenation" { break :blk b[8..9]; }; const str = "" ++ bs; - assertOrPanic(str.len == 1); - assertOrPanic(std.mem.eql(u8, str, "1")); + expect(str.len == 1); + expect(std.mem.eql(u8, str, "1")); const str2 = bs ++ ""; - assertOrPanic(str2.len == 1); - assertOrPanic(std.mem.eql(u8, str2, "1")); + expect(str2.len == 1); + expect(std.mem.eql(u8, str2, "1")); } test "comptime bitwise operators" { comptime { - assertOrPanic(3 & 1 == 1); - assertOrPanic(3 & -1 == 3); - assertOrPanic(-3 & -1 == -3); - assertOrPanic(3 | -1 == -1); - assertOrPanic(-3 | -1 == -1); - assertOrPanic(3 ^ -1 == -4); - assertOrPanic(-3 ^ -1 == 2); - assertOrPanic(~i8(-1) == 0); - assertOrPanic(~i128(-1) == 0); - assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611); - assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); - assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff); + expect(3 & 1 == 1); + expect(3 & -1 == 3); + expect(-3 & -1 == -3); + expect(3 | -1 == -1); + expect(-3 | -1 == -1); + expect(3 ^ -1 == -4); + expect(-3 ^ -1 == 2); + expect(~i8(-1) == 0); + expect(~i128(-1) == 0); + expect(18446744073709551615 & 18446744073709551611 == 18446744073709551611); + expect(-18446744073709551615 & -18446744073709551611 == -18446744073709551615); + expect(~u128(0) == 0xffffffffffffffffffffffffffffffff); } } test "*align(1) u16 is the same as *align(1:0:2) u16" { comptime { - assertOrPanic(*align(1:0:2) u16 == *align(1) u16); + expect(*align(1:0:2) u16 == *align(1) u16); // TODO add parsing support for this syntax - //assertOrPanic(*align(:0:2) u16 == *u16); + //expect(*align(:0:2) u16 == *u16); } } test "array concatenation forces comptime" { var a = oneItem(3) ++ oneItem(4); - assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 })); + expect(std.mem.eql(i32, a, []i32{ 3, 4 })); } test "array multiplication forces comptime" { var a = oneItem(3) ** scalar(2); - assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 })); + expect(std.mem.eql(i32, a, []i32{ 3, 3 })); } fn oneItem(x: i32) [1]i32 { diff --git a/test/stage1/behavior/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig index ed2487c020..6026a49d12 100644 --- a/test/stage1/behavior/field_parent_ptr.zig +++ b/test/stage1/behavior/field_parent_ptr.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@fieldParentPtr non-first field" { testParentFieldPtr(&foo.c); @@ -25,17 +25,17 @@ const foo = Foo{ }; fn testParentFieldPtr(c: *const i32) void { - assertOrPanic(c == &foo.c); + expect(c == &foo.c); const base = @fieldParentPtr(Foo, "c", c); - assertOrPanic(base == &foo); - assertOrPanic(&base.c == c); + expect(base == &foo); + expect(&base.c == c); } fn testParentFieldPtrFirst(a: *const bool) void { - assertOrPanic(a == &foo.a); + expect(a == &foo.a); const base = @fieldParentPtr(Foo, "a", a); - assertOrPanic(base == &foo); - assertOrPanic(&base.a == a); + expect(base == &foo); + expect(&base.a == a); } diff --git a/test/stage1/behavior/fn.zig b/test/stage1/behavior/fn.zig index 3011bc41d0..3f78c80290 100644 --- a/test/stage1/behavior/fn.zig +++ b/test/stage1/behavior/fn.zig @@ -1,7 +1,7 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "params" { - assertOrPanic(testParamsAdd(22, 11) == 33); + expect(testParamsAdd(22, 11) == 33); } fn testParamsAdd(a: i32, b: i32) i32 { return a + b; @@ -21,32 +21,32 @@ test "void parameters" { fn voidFun(a: i32, b: void, c: i32, d: void) void { const v = b; const vv: void = if (a == 1) v else {}; - assertOrPanic(a + c == 3); + expect(a + c == 3); return vv; } test "mutable local variables" { var zero: i32 = 0; - assertOrPanic(zero == 0); + expect(zero == 0); var i = i32(0); while (i != 3) { i += 1; } - assertOrPanic(i == 3); + expect(i == 3); } test "separate block scopes" { { const no_conflict: i32 = 5; - assertOrPanic(no_conflict == 5); + expect(no_conflict == 5); } const c = x: { const no_conflict = i32(10); break :x no_conflict; }; - assertOrPanic(c == 10); + expect(c == 10); } test "call function with empty string" { @@ -59,7 +59,7 @@ fn @"weird function name"() i32 { return 1234; } test "weird function name" { - assertOrPanic(@"weird function name"() == 1234); + expect(@"weird function name"() == 1234); } test "implicit cast function unreachable return" { @@ -80,7 +80,7 @@ test "function pointers" { fn4, }; for (fns) |f, i| { - assertOrPanic(f() == @intCast(u32, i) + 5); + expect(f() == @intCast(u32, i) + 5); } } fn fn1() u32 { @@ -97,7 +97,7 @@ fn fn4() u32 { } test "inline function call" { - assertOrPanic(@inlineCall(add, 3, 9) == 12); + expect(@inlineCall(add, 3, 9) == 12); } fn add(a: i32, b: i32) i32 { @@ -110,7 +110,7 @@ test "number literal as an argument" { } fn numberLiteralArg(a: var) void { - assertOrPanic(a == 3); + expect(a == 3); } test "assign inline fn to const variable" { @@ -121,7 +121,7 @@ test "assign inline fn to const variable" { inline fn inlineFn() void {} test "pass by non-copying value" { - assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); + expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } const Point = struct { @@ -134,17 +134,17 @@ fn addPointCoords(pt: Point) i32 { } test "pass by non-copying value through var arg" { - assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); + expect(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3); } fn addPointCoordsVar(pt: var) i32 { - comptime assertOrPanic(@typeOf(pt) == Point); + comptime expect(@typeOf(pt) == Point); return pt.x + pt.y; } test "pass by non-copying value as method" { var pt = Point2{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords() == 3); + expect(pt.addPointCoords() == 3); } const Point2 = struct { @@ -158,7 +158,7 @@ const Point2 = struct { test "pass by non-copying value as method, which is generic" { var pt = Point3{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords(i32) == 3); + expect(pt.addPointCoords(i32) == 3); } const Point3 = struct { @@ -173,7 +173,7 @@ const Point3 = struct { test "pass by non-copying value as method, at comptime" { comptime { var pt = Point2{ .x = 1, .y = 2 }; - assertOrPanic(pt.addPointCoords() == 3); + expect(pt.addPointCoords() == 3); } } @@ -189,7 +189,7 @@ fn outer(y: u32) fn (u32) u32 { test "return inner function which references comptime variable of outer function" { var func = outer(10); - assertOrPanic(func(3) == 7); + expect(func(3) == 7); } test "extern struct with stdcallcc fn pointer" { @@ -203,6 +203,6 @@ test "extern struct with stdcallcc fn pointer" { var s: S = undefined; s.ptr = S.foo; - assertOrPanic(s.ptr() == 1234); + expect(s.ptr() == 1234); } diff --git a/test/stage1/behavior/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig index 0af076d40a..030693ac59 100644 --- a/test/stage1/behavior/fn_in_struct_in_comptime.zig +++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn get_foo() fn (*u8) usize { comptime { @@ -13,5 +13,5 @@ fn get_foo() fn (*u8) usize { test "define a function in an anonymous struct in comptime" { const foo = get_foo(); - assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345); + expect(foo(@intToPtr(*u8, 12345)) == 12345); } diff --git a/test/stage1/behavior/for.zig b/test/stage1/behavior/for.zig index b6d1ef24c4..b10dd14fa4 100644 --- a/test/stage1/behavior/for.zig +++ b/test/stage1/behavior/for.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; test "continue in for loop" { @@ -26,7 +26,7 @@ test "for loop with pointer elem var" { var target: [source.len]u8 = undefined; mem.copy(u8, target[0..], source); mangleString(target[0..]); - assertOrPanic(mem.eql(u8, target, "bcdefgh")); + expect(mem.eql(u8, target, "bcdefgh")); } fn mangleString(s: []u8) void { for (s) |*c| { @@ -68,7 +68,7 @@ test "basic for loop" { buf_index += 1; } - assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result)); + expect(mem.eql(u8, buffer[0..buf_index], expected_result)); } test "break from outer for loop" { @@ -85,7 +85,7 @@ fn testBreakOuter() void { break :outer; } } - assertOrPanic(count == 1); + expect(count == 1); } test "continue outer for loop" { @@ -102,5 +102,5 @@ fn testContinueOuter() void { continue :outer; } } - assertOrPanic(counter == array.len); + expect(counter == array.len); } diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig index a0928634a7..637f9b88ae 100644 --- a/test/stage1/behavior/generics.zig +++ b/test/stage1/behavior/generics.zig @@ -1,9 +1,9 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "simple generic fn" { - assertOrPanic(max(i32, 3, -1) == 3); - assertOrPanic(max(f32, 0.123, 0.456) == 0.456); - assertOrPanic(add(2, 3) == 5); + expect(max(i32, 3, -1) == 3); + expect(max(f32, 0.123, 0.456) == 0.456); + expect(add(2, 3) == 5); } fn max(comptime T: type, a: T, b: T) T { @@ -16,7 +16,7 @@ fn add(comptime a: i32, b: i32) i32 { const the_max = max(u32, 1234, 5678); test "compile time generic eval" { - assertOrPanic(the_max == 5678); + expect(the_max == 5678); } fn gimmeTheBigOne(a: u32, b: u32) u32 { @@ -32,19 +32,19 @@ fn sameButWithFloats(a: f64, b: f64) f64 { } test "fn with comptime args" { - assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678); - assertOrPanic(shouldCallSameInstance(34, 12) == 34); - assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49); + expect(gimmeTheBigOne(1234, 5678) == 5678); + expect(shouldCallSameInstance(34, 12) == 34); + expect(sameButWithFloats(0.43, 0.49) == 0.49); } test "var params" { - assertOrPanic(max_i32(12, 34) == 34); - assertOrPanic(max_f64(1.2, 3.4) == 3.4); + expect(max_i32(12, 34) == 34); + expect(max_f64(1.2, 3.4) == 3.4); } comptime { - assertOrPanic(max_i32(12, 34) == 34); - assertOrPanic(max_f64(1.2, 3.4) == 3.4); + expect(max_i32(12, 34) == 34); + expect(max_f64(1.2, 3.4) == 3.4); } fn max_var(a: var, b: var) @typeOf(a + b) { @@ -76,8 +76,8 @@ test "function with return type type" { var list2: List(i32) = undefined; list.length = 10; list2.length = 10; - assertOrPanic(list.prealloc_items.len == 8); - assertOrPanic(list2.prealloc_items.len == 8); + expect(list.prealloc_items.len == 8); + expect(list2.prealloc_items.len == 8); } test "generic struct" { @@ -89,9 +89,9 @@ test "generic struct" { .value = true, .next = null, }; - assertOrPanic(a1.value == 13); - assertOrPanic(a1.value == a1.getVal()); - assertOrPanic(b1.getVal()); + expect(a1.value == 13); + expect(a1.value == a1.getVal()); + expect(b1.getVal()); } fn GenNode(comptime T: type) type { return struct { @@ -104,7 +104,7 @@ fn GenNode(comptime T: type) type { } test "const decls in struct" { - assertOrPanic(GenericDataThing(3).count_plus_one == 4); + expect(GenericDataThing(3).count_plus_one == 4); } fn GenericDataThing(comptime count: isize) type { return struct { @@ -113,15 +113,15 @@ fn GenericDataThing(comptime count: isize) type { } test "use generic param in generic param" { - assertOrPanic(aGenericFn(i32, 3, 4) == 7); + expect(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(comptime T: type, comptime a: T, b: T) T { return a + b; } test "generic fn with implicit cast" { - assertOrPanic(getFirstByte(u8, []u8{13}) == 13); - assertOrPanic(getFirstByte(u16, []u16{ + expect(getFirstByte(u8, []u8{13}) == 13); + expect(getFirstByte(u16, []u16{ 0, 13, }) == 0); @@ -146,6 +146,6 @@ fn foo2(arg: var) bool { } test "array of generic fns" { - assertOrPanic(foos[0](true)); - assertOrPanic(!foos[1](true)); + expect(foos[0](true)); + expect(!foos[1](true)); } diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig index 58d1b8fd73..a61b9dcfb4 100644 --- a/test/stage1/behavior/if.zig +++ b/test/stage1/behavior/if.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "if statements" { shouldBeEqual(1, 1); @@ -24,7 +24,7 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void { } test "else if expression" { - assertOrPanic(elseIfExpressionF(1) == 1); + expect(elseIfExpressionF(1) == 1); } fn elseIfExpressionF(c: u8) u8 { if (c == 0) { diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig index 736e4c219d..9a8c6848e2 100644 --- a/test/stage1/behavior/import.zig +++ b/test/stage1/behavior/import.zig @@ -1,10 +1,10 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const a_namespace = @import("import/a_namespace.zig"); test "call fn via namespace lookup" { - assertOrPanic(a_namespace.foo() == 1234); + expect(a_namespace.foo() == 1234); } test "importing the same thing gives the same import" { - assertOrPanic(@import("std") == @import("std")); + expect(@import("std") == @import("std")); } diff --git a/test/stage1/behavior/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig index d062311b2e..77a3dfd221 100644 --- a/test/stage1/behavior/incomplete_struct_param_tld.zig +++ b/test/stage1/behavior/incomplete_struct_param_tld.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const A = struct { b: B, @@ -26,5 +26,5 @@ test "incomplete struct param top level declaration" { .c = C{ .x = 13 }, }, }; - assertOrPanic(foo(a) == 13); + expect(foo(a) == 13); } diff --git a/test/stage1/behavior/inttoptr.zig b/test/stage1/behavior/inttoptr.zig index bf657fc86a..b1780f93d6 100644 --- a/test/stage1/behavior/inttoptr.zig +++ b/test/stage1/behavior/inttoptr.zig @@ -1,6 +1,6 @@ const builtin = @import("builtin"); const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "casting random address to function pointer" { randomAddressToFunction(); diff --git a/test/stage1/behavior/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig index bc61e11df7..821079df79 100644 --- a/test/stage1/behavior/ir_block_deps.zig +++ b/test/stage1/behavior/ir_block_deps.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn foo(id: u64) !i32 { return switch (id) { @@ -16,6 +16,6 @@ fn getErrInt() anyerror!i32 { } test "ir block deps" { - assertOrPanic((foo(1) catch unreachable) == 0); - assertOrPanic((foo(2) catch unreachable) == 0); + expect((foo(1) catch unreachable) == 0); + expect((foo(2) catch unreachable) == 0); } diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index 9d6a5a4997..0b88cc4497 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const maxInt = std.math.maxInt; const minInt = std.math.minInt; @@ -8,57 +8,57 @@ test "division" { comptime testDivision(); } fn testDivision() void { - assertOrPanic(div(u32, 13, 3) == 4); - assertOrPanic(div(f16, 1.0, 2.0) == 0.5); - assertOrPanic(div(f32, 1.0, 2.0) == 0.5); - - assertOrPanic(divExact(u32, 55, 11) == 5); - assertOrPanic(divExact(i32, -55, 11) == -5); - assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0); - assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0); - assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0); - assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0); - - assertOrPanic(divFloor(i32, 5, 3) == 1); - assertOrPanic(divFloor(i32, -5, 3) == -2); - assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0); - assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0); - assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0); - assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0); - assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000); - assertOrPanic(divFloor(i32, 0, -0x80000000) == 0); - assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2); - assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000); - - assertOrPanic(divTrunc(i32, 5, 3) == 1); - assertOrPanic(divTrunc(i32, -5, 3) == -1); - assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0); - assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0); - assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0); - assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0); + expect(div(u32, 13, 3) == 4); + expect(div(f16, 1.0, 2.0) == 0.5); + expect(div(f32, 1.0, 2.0) == 0.5); + + expect(divExact(u32, 55, 11) == 5); + expect(divExact(i32, -55, 11) == -5); + expect(divExact(f16, 55.0, 11.0) == 5.0); + expect(divExact(f16, -55.0, 11.0) == -5.0); + expect(divExact(f32, 55.0, 11.0) == 5.0); + expect(divExact(f32, -55.0, 11.0) == -5.0); + + expect(divFloor(i32, 5, 3) == 1); + expect(divFloor(i32, -5, 3) == -2); + expect(divFloor(f16, 5.0, 3.0) == 1.0); + expect(divFloor(f16, -5.0, 3.0) == -2.0); + expect(divFloor(f32, 5.0, 3.0) == 1.0); + expect(divFloor(f32, -5.0, 3.0) == -2.0); + expect(divFloor(i32, -0x80000000, -2) == 0x40000000); + expect(divFloor(i32, 0, -0x80000000) == 0); + expect(divFloor(i32, -0x40000001, 0x40000000) == -2); + expect(divFloor(i32, -0x80000000, 1) == -0x80000000); + + expect(divTrunc(i32, 5, 3) == 1); + expect(divTrunc(i32, -5, 3) == -1); + expect(divTrunc(f16, 5.0, 3.0) == 1.0); + expect(divTrunc(f16, -5.0, 3.0) == -1.0); + expect(divTrunc(f32, 5.0, 3.0) == 1.0); + expect(divTrunc(f32, -5.0, 3.0) == -1.0); + expect(divTrunc(f64, 5.0, 3.0) == 1.0); + expect(divTrunc(f64, -5.0, 3.0) == -1.0); comptime { - assertOrPanic( + expect( 1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600, ); - assertOrPanic( + expect( @rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600, ); - assertOrPanic( + expect( 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, ); - assertOrPanic( + expect( @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, ); - assertOrPanic( + expect( @divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, ); - assertOrPanic( + expect( @divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, ); - assertOrPanic( + expect( 4126227191251978491697987544882340798050766755606969681711 % 10 == 1, ); } @@ -78,9 +78,9 @@ fn divTrunc(comptime T: type, a: T, b: T) T { test "@addWithOverflow" { var result: u8 = undefined; - assertOrPanic(@addWithOverflow(u8, 250, 100, &result)); - assertOrPanic(!@addWithOverflow(u8, 100, 150, &result)); - assertOrPanic(result == 250); + expect(@addWithOverflow(u8, 250, 100, &result)); + expect(!@addWithOverflow(u8, 100, 150, &result)); + expect(result == 250); } // TODO test mulWithOverflow @@ -88,9 +88,9 @@ test "@addWithOverflow" { test "@shlWithOverflow" { var result: u16 = undefined; - assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); - assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); - assertOrPanic(result == 0b1011111111111100); + expect(@shlWithOverflow(u16, 0b0010111111111111, 3, &result)); + expect(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result)); + expect(result == 0b1011111111111100); } test "@clz" { @@ -99,11 +99,11 @@ test "@clz" { } fn testClz() void { - assertOrPanic(clz(u8(0b00001010)) == 4); - assertOrPanic(clz(u8(0b10001010)) == 0); - assertOrPanic(clz(u8(0b00000000)) == 8); - assertOrPanic(clz(u128(0xffffffffffffffff)) == 64); - assertOrPanic(clz(u128(0x10000000000000000)) == 63); + expect(clz(u8(0b00001010)) == 4); + expect(clz(u8(0b10001010)) == 0); + expect(clz(u8(0b00000000)) == 8); + expect(clz(u128(0xffffffffffffffff)) == 64); + expect(clz(u128(0x10000000000000000)) == 63); } fn clz(x: var) usize { @@ -116,9 +116,9 @@ test "@ctz" { } fn testCtz() void { - assertOrPanic(ctz(u8(0b10100000)) == 5); - assertOrPanic(ctz(u8(0b10001010)) == 1); - assertOrPanic(ctz(u8(0b00000000)) == 8); + expect(ctz(u8(0b10100000)) == 5); + expect(ctz(u8(0b10001010)) == 1); + expect(ctz(u8(0b00000000)) == 8); } fn ctz(x: var) usize { @@ -128,27 +128,27 @@ fn ctz(x: var) usize { test "assignment operators" { var i: u32 = 0; i += 5; - assertOrPanic(i == 5); + expect(i == 5); i -= 2; - assertOrPanic(i == 3); + expect(i == 3); i *= 20; - assertOrPanic(i == 60); + expect(i == 60); i /= 3; - assertOrPanic(i == 20); + expect(i == 20); i %= 11; - assertOrPanic(i == 9); + expect(i == 9); i <<= 1; - assertOrPanic(i == 18); + expect(i == 18); i >>= 2; - assertOrPanic(i == 4); + expect(i == 4); i = 6; i &= 5; - assertOrPanic(i == 4); + expect(i == 4); i ^= 6; - assertOrPanic(i == 2); + expect(i == 2); i = 6; i |= 3; - assertOrPanic(i == 7); + expect(i == 7); } test "three expr in a row" { @@ -170,14 +170,14 @@ fn testThreeExprInARow(f: bool, t: bool) void { assertFalse(i32(7) != --(i32(7))); } fn assertFalse(b: bool) void { - assertOrPanic(!b); + expect(!b); } test "const number literal" { const one = 1; const eleven = ten + one; - assertOrPanic(eleven == 11); + expect(eleven == 11); } const ten = 10; @@ -187,9 +187,9 @@ test "unsigned wrapping" { } fn testUnsignedWrappingEval(x: u32) void { const zero = x +% 1; - assertOrPanic(zero == 0); + expect(zero == 0); const orig = zero -% 1; - assertOrPanic(orig == maxInt(u32)); + expect(orig == maxInt(u32)); } test "signed wrapping" { @@ -198,9 +198,9 @@ test "signed wrapping" { } fn testSignedWrappingEval(x: i32) void { const min_val = x +% 1; - assertOrPanic(min_val == minInt(i32)); + expect(min_val == minInt(i32)); const max_val = min_val -% 1; - assertOrPanic(max_val == maxInt(i32)); + expect(max_val == maxInt(i32)); } test "negation wrapping" { @@ -208,9 +208,9 @@ test "negation wrapping" { comptime testNegationWrappingEval(minInt(i16)); } fn testNegationWrappingEval(x: i16) void { - assertOrPanic(x == -32768); + expect(x == -32768); const neg = -%x; - assertOrPanic(neg == -32768); + expect(neg == -32768); } test "unsigned 64-bit division" { @@ -219,8 +219,8 @@ test "unsigned 64-bit division" { } fn test_u64_div() void { const result = divWithResult(1152921504606846976, 34359738365); - assertOrPanic(result.quotient == 33554432); - assertOrPanic(result.remainder == 100663296); + expect(result.quotient == 33554432); + expect(result.remainder == 100663296); } fn divWithResult(a: u64, b: u64) DivResult { return DivResult{ @@ -234,36 +234,36 @@ const DivResult = struct { }; test "binary not" { - assertOrPanic(comptime x: { + expect(comptime x: { break :x ~u16(0b1010101010101010) == 0b0101010101010101; }); - assertOrPanic(comptime x: { + expect(comptime x: { break :x ~u64(2147483647) == 18446744071562067968; }); testBinaryNot(0b1010101010101010); } fn testBinaryNot(x: u16) void { - assertOrPanic(~x == 0b0101010101010101); + expect(~x == 0b0101010101010101); } test "small int addition" { var x: @IntType(false, 2) = 0; - assertOrPanic(x == 0); + expect(x == 0); x += 1; - assertOrPanic(x == 1); + expect(x == 1); x += 1; - assertOrPanic(x == 2); + expect(x == 2); x += 1; - assertOrPanic(x == 3); + expect(x == 3); var result: @typeOf(x) = 3; - assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result)); + expect(@addWithOverflow(@typeOf(x), x, 1, &result)); - assertOrPanic(result == 0); + expect(result == 0); } test "float equality" { @@ -276,20 +276,20 @@ test "float equality" { fn testFloatEqualityImpl(x: f64, y: f64) void { const y2 = x + 1.0; - assertOrPanic(y == y2); + expect(y == y2); } test "allow signed integer division/remainder when values are comptime known and positive or exact" { - assertOrPanic(5 / 3 == 1); - assertOrPanic(-5 / -3 == 1); - assertOrPanic(-6 / 3 == -2); + expect(5 / 3 == 1); + expect(-5 / -3 == 1); + expect(-6 / 3 == -2); - assertOrPanic(5 % 3 == 2); - assertOrPanic(-6 % 3 == 0); + expect(5 % 3 == 2); + expect(-6 % 3 == 0); } test "hex float literal parsing" { - comptime assertOrPanic(0x1.0 == 1.0); + comptime expect(0x1.0 == 1.0); } test "quad hex float literal parsing in range" { @@ -304,7 +304,7 @@ test "quad hex float literal parsing accurate" { // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing. const expected: u128 = 0x3fff1111222233334444555566667777; - assertOrPanic(@bitCast(u128, a) == expected); + expect(@bitCast(u128, a) == expected); } test "hex float literal within range" { @@ -319,7 +319,7 @@ test "truncating shift left" { } fn testShlTrunc(x: u16) void { const shifted = x << 1; - assertOrPanic(shifted == 65534); + expect(shifted == 65534); } test "truncating shift right" { @@ -328,7 +328,7 @@ test "truncating shift right" { } fn testShrTrunc(x: u16) void { const shifted = x >> 1; - assertOrPanic(shifted == 32767); + expect(shifted == 32767); } test "exact shift left" { @@ -337,7 +337,7 @@ test "exact shift left" { } fn testShlExact(x: u8) void { const shifted = @shlExact(x, 2); - assertOrPanic(shifted == 0b11010100); + expect(shifted == 0b11010100); } test "exact shift right" { @@ -346,22 +346,22 @@ test "exact shift right" { } fn testShrExact(x: u8) void { const shifted = @shrExact(x, 2); - assertOrPanic(shifted == 0b00101101); + expect(shifted == 0b00101101); } test "comptime_int addition" { comptime { - assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); - assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); + expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950); + expect(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380); } } test "comptime_int multiplication" { comptime { - assertOrPanic( + expect( 45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567, ); - assertOrPanic( + expect( 594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016, ); } @@ -369,7 +369,7 @@ test "comptime_int multiplication" { test "comptime_int shifting" { comptime { - assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000); + expect((u128(1) << 127) == 0x80000000000000000000000000000000); } } @@ -377,16 +377,16 @@ test "comptime_int multi-limb shift and mask" { comptime { var a = 0xefffffffa0000001eeeeeeefaaaaaaab; - assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab); + expect(u32(a & 0xffffffff) == 0xaaaaaaab); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef); + expect(u32(a & 0xffffffff) == 0xeeeeeeef); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xa0000001); + expect(u32(a & 0xffffffff) == 0xa0000001); a >>= 32; - assertOrPanic(u32(a & 0xffffffff) == 0xefffffff); + expect(u32(a & 0xffffffff) == 0xefffffff); a >>= 32; - assertOrPanic(a == 0); + expect(a == 0); } } @@ -394,7 +394,7 @@ test "comptime_int multi-limb partial shift right" { comptime { var a = 0x1ffffffffeeeeeeee; a >>= 16; - assertOrPanic(a == 0x1ffffffffeeee); + expect(a == 0x1ffffffffeeee); } } @@ -404,23 +404,23 @@ test "xor" { } fn test_xor() void { - assertOrPanic(0xFF ^ 0x00 == 0xFF); - assertOrPanic(0xF0 ^ 0x0F == 0xFF); - assertOrPanic(0xFF ^ 0xF0 == 0x0F); - assertOrPanic(0xFF ^ 0x0F == 0xF0); - assertOrPanic(0xFF ^ 0xFF == 0x00); + expect(0xFF ^ 0x00 == 0xFF); + expect(0xF0 ^ 0x0F == 0xFF); + expect(0xFF ^ 0xF0 == 0x0F); + expect(0xFF ^ 0x0F == 0xF0); + expect(0xFF ^ 0xFF == 0x00); } test "comptime_int xor" { comptime { - assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); - assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); - assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); - assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); - assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); - assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); + expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF); + expect(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000); + expect(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000); + expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + expect(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF); + expect(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000); } } @@ -434,23 +434,23 @@ fn make_f128(x: f128) f128 { } fn test_f128() void { - assertOrPanic(@sizeOf(f128) == 16); - assertOrPanic(make_f128(1.0) == 1.0); - assertOrPanic(make_f128(1.0) != 1.1); - assertOrPanic(make_f128(1.0) > 0.9); - assertOrPanic(make_f128(1.0) >= 0.9); - assertOrPanic(make_f128(1.0) >= 1.0); + expect(@sizeOf(f128) == 16); + expect(make_f128(1.0) == 1.0); + expect(make_f128(1.0) != 1.1); + expect(make_f128(1.0) > 0.9); + expect(make_f128(1.0) >= 0.9); + expect(make_f128(1.0) >= 1.0); should_not_be_zero(1.0); } fn should_not_be_zero(x: f128) void { - assertOrPanic(x != 0.0); + expect(x != 0.0); } test "comptime float rem int" { comptime { var x = f32(1) % 2; - assertOrPanic(x == 1.0); + expect(x == 1.0); } } @@ -465,8 +465,8 @@ test "remainder division" { } fn remdiv(comptime T: type) void { - assertOrPanic(T(1) == T(1) % T(2)); - assertOrPanic(T(1) == T(7) % T(3)); + expect(T(1) == T(1) % T(2)); + expect(T(1) == T(7) % T(3)); } test "@sqrt" { @@ -480,19 +480,19 @@ test "@sqrt" { const x = 14.0; const y = x * x; const z = @sqrt(@typeOf(y), y); - comptime assertOrPanic(z == x); + comptime expect(z == x); } fn testSqrt(comptime T: type, x: T) void { - assertOrPanic(@sqrt(T, x * x) == x); + expect(@sqrt(T, x * x) == x); } test "comptime_int param and return" { const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702); - assertOrPanic(a == 137114567242441932203689521744947848950); + expect(a == 137114567242441932203689521744947848950); const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768); - assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380); + expect(b == 985095453608931032642182098849559179469148836107390954364380); } fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int { diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 3cc8e5f31e..91cab78bc7 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; const cstr = std.cstr; const builtin = @import("builtin"); @@ -26,38 +26,38 @@ test "call disabled extern fn" { } test "@IntType builtin" { - assertOrPanic(@IntType(true, 8) == i8); - assertOrPanic(@IntType(true, 16) == i16); - assertOrPanic(@IntType(true, 32) == i32); - assertOrPanic(@IntType(true, 64) == i64); - - assertOrPanic(@IntType(false, 8) == u8); - assertOrPanic(@IntType(false, 16) == u16); - assertOrPanic(@IntType(false, 32) == u32); - assertOrPanic(@IntType(false, 64) == u64); - - assertOrPanic(i8.bit_count == 8); - assertOrPanic(i16.bit_count == 16); - assertOrPanic(i32.bit_count == 32); - assertOrPanic(i64.bit_count == 64); - - assertOrPanic(i8.is_signed); - assertOrPanic(i16.is_signed); - assertOrPanic(i32.is_signed); - assertOrPanic(i64.is_signed); - assertOrPanic(isize.is_signed); - - assertOrPanic(!u8.is_signed); - assertOrPanic(!u16.is_signed); - assertOrPanic(!u32.is_signed); - assertOrPanic(!u64.is_signed); - assertOrPanic(!usize.is_signed); + expect(@IntType(true, 8) == i8); + expect(@IntType(true, 16) == i16); + expect(@IntType(true, 32) == i32); + expect(@IntType(true, 64) == i64); + + expect(@IntType(false, 8) == u8); + expect(@IntType(false, 16) == u16); + expect(@IntType(false, 32) == u32); + expect(@IntType(false, 64) == u64); + + expect(i8.bit_count == 8); + expect(i16.bit_count == 16); + expect(i32.bit_count == 32); + expect(i64.bit_count == 64); + + expect(i8.is_signed); + expect(i16.is_signed); + expect(i32.is_signed); + expect(i64.is_signed); + expect(isize.is_signed); + + expect(!u8.is_signed); + expect(!u16.is_signed); + expect(!u32.is_signed); + expect(!u64.is_signed); + expect(!usize.is_signed); } test "floating point primitive bit counts" { - assertOrPanic(f16.bit_count == 16); - assertOrPanic(f32.bit_count == 32); - assertOrPanic(f64.bit_count == 64); + expect(f16.bit_count == 16); + expect(f32.bit_count == 32); + expect(f64.bit_count == 64); } test "short circuit" { @@ -72,7 +72,7 @@ fn testShortCircuit(f: bool, t: bool) void { var hit_4 = f; if (t or x: { - assertOrPanic(f); + expect(f); break :x f; }) { hit_1 = t; @@ -81,31 +81,31 @@ fn testShortCircuit(f: bool, t: bool) void { hit_2 = t; break :x f; }) { - assertOrPanic(f); + expect(f); } if (t and x: { hit_3 = t; break :x f; }) { - assertOrPanic(f); + expect(f); } if (f and x: { - assertOrPanic(f); + expect(f); break :x f; }) { - assertOrPanic(f); + expect(f); } else { hit_4 = t; } - assertOrPanic(hit_1); - assertOrPanic(hit_2); - assertOrPanic(hit_3); - assertOrPanic(hit_4); + expect(hit_1); + expect(hit_2); + expect(hit_3); + expect(hit_4); } test "truncate" { - assertOrPanic(testTruncate(0x10fd) == 0xfd); + expect(testTruncate(0x10fd) == 0xfd); } fn testTruncate(x: u32) u8 { return @truncate(u8, x); @@ -116,16 +116,16 @@ fn first4KeysOfHomeRow() []const u8 { } test "return string from function" { - assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); + expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu")); } const g1: i32 = 1233 + 1; var g2: i32 = 0; test "global variables" { - assertOrPanic(g2 == 0); + expect(g2 == 0); g2 = g1; - assertOrPanic(g2 == 1234); + expect(g2 == 1234); } test "memcpy and memset intrinsics" { @@ -142,7 +142,7 @@ test "builtin static eval" { const x: i32 = comptime x: { break :x 1 + 2 + 3; }; - assertOrPanic(x == comptime 6); + expect(x == comptime 6); } test "slicing" { @@ -163,7 +163,7 @@ test "slicing" { test "constant equal function pointers" { const alias = emptyFn; - assertOrPanic(comptime x: { + expect(comptime x: { break :x emptyFn == alias; }); } @@ -171,25 +171,25 @@ test "constant equal function pointers" { fn emptyFn() void {} test "hex escape" { - assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); + expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); } test "string concatenation" { - assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); + expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); } test "array mult operator" { - assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab")); + expect(mem.eql(u8, "ab" ** 5, "ababababab")); } test "string escapes" { - assertOrPanic(mem.eql(u8, "\"", "\x22")); - assertOrPanic(mem.eql(u8, "\'", "\x27")); - assertOrPanic(mem.eql(u8, "\n", "\x0a")); - assertOrPanic(mem.eql(u8, "\r", "\x0d")); - assertOrPanic(mem.eql(u8, "\t", "\x09")); - assertOrPanic(mem.eql(u8, "\\", "\x5c")); - assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); + expect(mem.eql(u8, "\"", "\x22")); + expect(mem.eql(u8, "\'", "\x27")); + expect(mem.eql(u8, "\n", "\x0a")); + expect(mem.eql(u8, "\r", "\x0d")); + expect(mem.eql(u8, "\t", "\x09")); + expect(mem.eql(u8, "\\", "\x5c")); + expect(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69")); } test "multiline string" { @@ -199,7 +199,7 @@ test "multiline string" { \\three ; const s2 = "one\ntwo)\nthree"; - assertOrPanic(mem.eql(u8, s1, s2)); + expect(mem.eql(u8, s1, s2)); } test "multiline C string" { @@ -209,11 +209,11 @@ test "multiline C string" { c\\three ; const s2 = c"one\ntwo)\nthree"; - assertOrPanic(cstr.cmp(s1, s2) == 0); + expect(cstr.cmp(s1, s2) == 0); } test "type equality" { - assertOrPanic(*const u8 != *u8); + expect(*const u8 != *u8); } const global_a: i32 = 1234; @@ -221,7 +221,7 @@ const global_b: *const i32 = &global_a; const global_c: *const f32 = @ptrCast(*const f32, global_b); test "compile time global reinterpret" { const d = @ptrCast(*const i32, global_c); - assertOrPanic(d.* == 1234); + expect(d.* == 1234); } test "explicit cast maybe pointers" { @@ -247,8 +247,8 @@ test "cast undefined" { fn testCastUndefined(x: []const u8) void {} test "cast small unsigned to larger signed" { - assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200)); - assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); + expect(castSmallUnsignedToLargerSigned1(200) == i16(200)); + expect(castSmallUnsignedToLargerSigned2(9999) == i64(9999)); } fn castSmallUnsignedToLargerSigned1(x: u8) i16 { return x; @@ -258,7 +258,7 @@ fn castSmallUnsignedToLargerSigned2(x: u16) i64 { } test "implicit cast after unreachable" { - assertOrPanic(outer() == 1234); + expect(outer() == 1234); } fn inner() i32 { return 1234; @@ -273,13 +273,13 @@ test "pointer dereferencing" { y.* += 1; - assertOrPanic(x == 4); - assertOrPanic(y.* == 4); + expect(x == 4); + expect(y.* == 4); } test "call result of if else expression" { - assertOrPanic(mem.eql(u8, f2(true), "a")); - assertOrPanic(mem.eql(u8, f2(false), "b")); + expect(mem.eql(u8, f2(true), "a")); + expect(mem.eql(u8, f2(false), "b")); } fn f2(x: bool) []const u8 { return (if (x) fA else fB)(); @@ -321,8 +321,8 @@ const test3_bar = Test3Foo{ .Two = 13 }; fn test3_1(f: Test3Foo) void { switch (f) { Test3Foo.Three => |pt| { - assertOrPanic(pt.x == 3); - assertOrPanic(pt.y == 4); + expect(pt.x == 3); + expect(pt.y == 4); }, else => unreachable, } @@ -330,14 +330,14 @@ fn test3_1(f: Test3Foo) void { fn test3_2(f: Test3Foo) void { switch (f) { Test3Foo.Two => |x| { - assertOrPanic(x == 13); + expect(x == 13); }, else => unreachable, } } test "character literals" { - assertOrPanic('\'' == single_quote); + expect('\'' == single_quote); } const single_quote = '\''; @@ -346,13 +346,13 @@ test "take address of parameter" { } fn testTakeAddressOfParameter(f: f32) void { const f_ptr = &f; - assertOrPanic(f_ptr.* == 12.34); + expect(f_ptr.* == 12.34); } test "pointer comparison" { const a = ([]const u8)("a"); const b = &a; - assertOrPanic(ptrEql(b, b)); + expect(ptrEql(b, b)); } fn ptrEql(a: *const []const u8, b: *const []const u8) bool { return a == b; @@ -367,31 +367,31 @@ test "C string concatenation" { { var i: u32 = 0; while (i < len_with_null) : (i += 1) { - assertOrPanic(a[i] == b[i]); + expect(a[i] == b[i]); } } - assertOrPanic(a[len] == 0); - assertOrPanic(b[len] == 0); + expect(a[len] == 0); + expect(b[len] == 0); } test "cast slice to u8 slice" { - assertOrPanic(@sizeOf(i32) == 4); + expect(@sizeOf(i32) == 4); var big_thing_array = []i32{ 1, 2, 3, 4 }; const big_thing_slice: []i32 = big_thing_array[0..]; const bytes = @sliceToBytes(big_thing_slice); - assertOrPanic(bytes.len == 4 * 4); + expect(bytes.len == 4 * 4); bytes[4] = 0; bytes[5] = 0; bytes[6] = 0; bytes[7] = 0; - assertOrPanic(big_thing_slice[1] == 0); + expect(big_thing_slice[1] == 0); const big_thing_again = @bytesToSlice(i32, bytes); - assertOrPanic(big_thing_again[2] == 3); + expect(big_thing_again[2] == 3); big_thing_again[2] = -1; - assertOrPanic(bytes[8] == maxInt(u8)); - assertOrPanic(bytes[9] == maxInt(u8)); - assertOrPanic(bytes[10] == maxInt(u8)); - assertOrPanic(bytes[11] == maxInt(u8)); + expect(bytes[8] == maxInt(u8)); + expect(bytes[9] == maxInt(u8)); + expect(bytes[10] == maxInt(u8)); + expect(bytes[11] == maxInt(u8)); } test "pointer to void return type" { @@ -408,7 +408,7 @@ fn testPointerToVoidReturnType2() *const void { test "non const ptr to aliased type" { const int = i32; - assertOrPanic(?*int == ?*i32); + expect(?*int == ?*i32); } test "array 2D const double ptr" { @@ -421,8 +421,8 @@ test "array 2D const double ptr" { fn testArray2DConstDoublePtr(ptr: *const f32) void { const ptr2 = @ptrCast([*]const f32, ptr); - assertOrPanic(ptr2[0] == 1.0); - assertOrPanic(ptr2[1] == 2.0); + expect(ptr2[0] == 1.0); + expect(ptr2[1] == 2.0); } const Tid = builtin.TypeId; @@ -444,32 +444,32 @@ const AUnion = union { test "@typeId" { comptime { - assertOrPanic(@typeId(type) == Tid.Type); - assertOrPanic(@typeId(void) == Tid.Void); - assertOrPanic(@typeId(bool) == Tid.Bool); - assertOrPanic(@typeId(noreturn) == Tid.NoReturn); - assertOrPanic(@typeId(i8) == Tid.Int); - assertOrPanic(@typeId(u8) == Tid.Int); - assertOrPanic(@typeId(i64) == Tid.Int); - assertOrPanic(@typeId(u64) == Tid.Int); - assertOrPanic(@typeId(f32) == Tid.Float); - assertOrPanic(@typeId(f64) == Tid.Float); - assertOrPanic(@typeId(*f32) == Tid.Pointer); - assertOrPanic(@typeId([2]u8) == Tid.Array); - assertOrPanic(@typeId(AStruct) == Tid.Struct); - assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt); - assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); - assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined); - assertOrPanic(@typeId(@typeOf(null)) == Tid.Null); - assertOrPanic(@typeId(?i32) == Tid.Optional); - assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion); - assertOrPanic(@typeId(anyerror) == Tid.ErrorSet); - assertOrPanic(@typeId(AnEnum) == Tid.Enum); - assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); - assertOrPanic(@typeId(AUnionEnum) == Tid.Union); - assertOrPanic(@typeId(AUnion) == Tid.Union); - assertOrPanic(@typeId(fn () void) == Tid.Fn); - assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace); + expect(@typeId(type) == Tid.Type); + expect(@typeId(void) == Tid.Void); + expect(@typeId(bool) == Tid.Bool); + expect(@typeId(noreturn) == Tid.NoReturn); + expect(@typeId(i8) == Tid.Int); + expect(@typeId(u8) == Tid.Int); + expect(@typeId(i64) == Tid.Int); + expect(@typeId(u64) == Tid.Int); + expect(@typeId(f32) == Tid.Float); + expect(@typeId(f64) == Tid.Float); + expect(@typeId(*f32) == Tid.Pointer); + expect(@typeId([2]u8) == Tid.Array); + expect(@typeId(AStruct) == Tid.Struct); + expect(@typeId(@typeOf(1)) == Tid.ComptimeInt); + expect(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); + expect(@typeId(@typeOf(undefined)) == Tid.Undefined); + expect(@typeId(@typeOf(null)) == Tid.Null); + expect(@typeId(?i32) == Tid.Optional); + expect(@typeId(anyerror!i32) == Tid.ErrorUnion); + expect(@typeId(anyerror) == Tid.ErrorSet); + expect(@typeId(AnEnum) == Tid.Enum); + expect(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); + expect(@typeId(AUnionEnum) == Tid.Union); + expect(@typeId(AUnion) == Tid.Union); + expect(@typeId(fn () void) == Tid.Fn); + expect(@typeId(@typeOf(builtin)) == Tid.Namespace); // TODO bound fn // TODO arg tuple // TODO opaque @@ -485,13 +485,13 @@ test "@typeName" { Unused, }; comptime { - assertOrPanic(mem.eql(u8, @typeName(i64), "i64")); - assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize")); + expect(mem.eql(u8, @typeName(i64), "i64")); + expect(mem.eql(u8, @typeName(*usize), "*usize")); // https://github.com/ziglang/zig/issues/675 - assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); - assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct")); - assertOrPanic(mem.eql(u8, @typeName(Union), "Union")); - assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum")); + expect(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)")); + expect(mem.eql(u8, @typeName(Struct), "Struct")); + expect(mem.eql(u8, @typeName(Union), "Union")); + expect(mem.eql(u8, @typeName(Enum), "Enum")); } } @@ -501,14 +501,14 @@ fn TypeFromFn(comptime T: type) type { test "double implicit cast in same expression" { var x = i32(u16(nine())); - assertOrPanic(x == 9); + expect(x == 9); } fn nine() u8 { return 9; } test "global variable initialized to global variable array element" { - assertOrPanic(global_ptr == &gdt[0]); + expect(global_ptr == &gdt[0]); } const GDTEntry = struct { field: i32, @@ -529,9 +529,9 @@ export fn writeToVRam() void { const OpaqueA = @OpaqueType(); const OpaqueB = @OpaqueType(); test "@OpaqueType" { - assertOrPanic(*OpaqueA != *OpaqueB); - assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); - assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); + expect(*OpaqueA != *OpaqueB); + expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA")); + expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB")); } test "variable is allowed to be a pointer to an opaque type" { @@ -571,7 +571,7 @@ fn fnThatClosesOverLocalConst() type { test "function closes over local const" { const x = fnThatClosesOverLocalConst().g(); - assertOrPanic(x == 1); + expect(x == 1); } test "cold function" { @@ -608,21 +608,21 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: Pack test "slicing zero length array" { const s1 = ""[0..]; const s2 = ([]u32{})[0..]; - assertOrPanic(s1.len == 0); - assertOrPanic(s2.len == 0); - assertOrPanic(mem.eql(u8, s1, "")); - assertOrPanic(mem.eql(u32, s2, []u32{})); + expect(s1.len == 0); + expect(s2.len == 0); + expect(mem.eql(u8, s1, "")); + expect(mem.eql(u32, s2, []u32{})); } const addr1 = @ptrCast(*const u8, emptyFn); test "comptime cast fn to ptr" { const addr2 = @ptrCast(*const u8, emptyFn); - comptime assertOrPanic(addr1 == addr2); + comptime expect(addr1 == addr2); } test "equality compare fn ptrs" { var a = emptyFn; - assertOrPanic(a == a); + expect(a == a); } test "self reference through fn ptr field" { @@ -637,26 +637,26 @@ test "self reference through fn ptr field" { }; var a: S.A = undefined; a.f = S.foo; - assertOrPanic(a.f(a) == 12); + expect(a.f(a) == 12); } test "volatile load and store" { var number: i32 = 1234; const ptr = (*volatile i32)(&number); ptr.* += 1; - assertOrPanic(ptr.* == 1235); + expect(ptr.* == 1235); } test "slice string literal has type []const u8" { comptime { - assertOrPanic(@typeOf("aoeu"[0..]) == []const u8); + expect(@typeOf("aoeu"[0..]) == []const u8); const array = []i32{ 1, 2, 3, 4 }; - assertOrPanic(@typeOf(array[0..]) == []const i32); + expect(@typeOf(array[0..]) == []const i32); } } test "pointer child field" { - assertOrPanic((*u32).Child == u32); + expect((*u32).Child == u32); } test "struct inside function" { @@ -675,11 +675,11 @@ fn testStructInFn() void { block.kind += 1; - assertOrPanic(block.kind == 1235); + expect(block.kind == 1235); } test "fn call returning scalar optional in equality expression" { - assertOrPanic(getNull() == null); + expect(getNull() == null); } fn getNull() ?*i32 { @@ -691,5 +691,5 @@ test "thread local variable" { threadlocal var t: i32 = 1234; }; S.t += 1; - assertOrPanic(S.t == 1235); + expect(S.t == 1235); } diff --git a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig index fe3e0cc020..32feaced10 100644 --- a/test/stage1/behavior/namespace_depends_on_compile_var/index.zig +++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig @@ -1,11 +1,11 @@ const builtin = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "namespace depends on compile var" { if (some_namespace.a_bool) { - assertOrPanic(some_namespace.a_bool); + expect(some_namespace.a_bool); } else { - assertOrPanic(!some_namespace.a_bool); + expect(!some_namespace.a_bool); } } const some_namespace = switch (builtin.os) { diff --git a/test/stage1/behavior/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig index b9ae2d27cd..1e01a5a8a2 100644 --- a/test/stage1/behavior/new_stack_call.zig +++ b/test/stage1/behavior/new_stack_call.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; var new_stack_bytes: [1024]u8 = undefined; @@ -10,17 +10,17 @@ test "calling a function with a new stack" { const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); _ = targetFunction(arg); - assertOrPanic(arg == 1234); - assertOrPanic(a < b); + expect(arg == 1234); + expect(a < b); } fn targetFunction(x: i32) usize { - assertOrPanic(x == 1234); + expect(x == 1234); var local_variable: i32 = 42; const ptr = &local_variable; ptr.* += 1; - assertOrPanic(local_variable == 43); + expect(local_variable == 43); return @ptrToInt(ptr); } diff --git a/test/stage1/behavior/null.zig b/test/stage1/behavior/null.zig index e2f86a05ba..8c9b86b260 100644 --- a/test/stage1/behavior/null.zig +++ b/test/stage1/behavior/null.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "optional type" { const x: ?bool = true; @@ -17,13 +17,13 @@ test "optional type" { const z = next_x orelse 1234; - assertOrPanic(z == 1234); + expect(z == 1234); const final_x: ?i32 = 13; const num = final_x orelse unreachable; - assertOrPanic(num == 13); + expect(num == 13); } test "test maybe object and get a pointer to the inner value" { @@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" { b.* = false; } - assertOrPanic(maybe_bool.? == false); + expect(maybe_bool.? == false); } test "rhs maybe unwrap return" { @@ -47,9 +47,9 @@ test "maybe return" { } fn maybeReturnImpl() void { - assertOrPanic(foo(1235).?); + expect(foo(1235).?); if (foo(null) != null) unreachable; - assertOrPanic(!foo(1234).?); + expect(!foo(1234).?); } fn foo(x: ?i32) ?bool { @@ -58,7 +58,7 @@ fn foo(x: ?i32) ?bool { } test "if var maybe pointer" { - assertOrPanic(shouldBeAPlus1(Particle{ + expect(shouldBeAPlus1(Particle{ .a = 14, .b = 1, .c = 1, @@ -84,10 +84,10 @@ const Particle = struct { test "null literal outside function" { const is_null = here_is_a_null_literal.context == null; - assertOrPanic(is_null); + expect(is_null); const is_non_null = here_is_a_null_literal.context != null; - assertOrPanic(!is_non_null); + expect(!is_non_null); } const SillyStruct = struct { context: ?i32, @@ -98,8 +98,8 @@ test "test null runtime" { testTestNullRuntime(null); } fn testTestNullRuntime(x: ?i32) void { - assertOrPanic(x == null); - assertOrPanic(!(x != null)); + expect(x == null); + expect(!(x != null)); } test "optional void" { @@ -108,8 +108,8 @@ test "optional void" { } fn optionalVoidImpl() void { - assertOrPanic(bar(null) == null); - assertOrPanic(bar({}) != null); + expect(bar(null) == null); + expect(bar({}) != null); } fn bar(x: ?void) ?void { @@ -133,7 +133,7 @@ test "unwrap optional which is field of global var" { } struct_with_optional.field = 1234; if (struct_with_optional.field) |payload| { - assertOrPanic(payload == 1234); + expect(payload == 1234); } else { unreachable; } @@ -141,13 +141,13 @@ test "unwrap optional which is field of global var" { test "null with default unwrap" { const x: i32 = null orelse 1; - assertOrPanic(x == 1); + expect(x == 1); } test "optional types" { comptime { const opt_type_struct = StructWithOptionalType{ .t = u8 }; - assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8); + expect(opt_type_struct.t != null and opt_type_struct.t.? == u8); } } @@ -158,5 +158,5 @@ const StructWithOptionalType = struct { test "optional pointer to 0 bit type null value at runtime" { const EmptyStruct = struct {}; var x: ?*EmptyStruct = null; - assertOrPanic(x == null); + expect(x == null); } diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 14692cb1ea..a65bed020c 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -1,11 +1,11 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; pub const EmptyStruct = struct {}; test "optional pointer to size zero struct" { var e = EmptyStruct{}; var o: ?*EmptyStruct = &e; - assertOrPanic(o != null); + expect(o != null); } test "equality compare nullable pointers" { @@ -18,15 +18,15 @@ fn testNullPtrsEql() void { var x: ?*i32 = null; var y: ?*i32 = null; - assertOrPanic(x == y); + expect(x == y); y = &number; - assertOrPanic(x != y); - assertOrPanic(x != &number); - assertOrPanic(&number != x); + expect(x != y); + expect(x != &number); + expect(&number != x); x = &number; - assertOrPanic(x == y); - assertOrPanic(x == &number); - assertOrPanic(&number == x); + expect(x == y); + expect(x == &number); + expect(&number == x); } test "address of unwrap optional" { @@ -43,7 +43,7 @@ test "address of unwrap optional" { }; S.global = S.Foo{ .a = 1234 }; const foo = S.getFoo() catch unreachable; - assertOrPanic(foo.a == 1234); + expect(foo.a == 1234); } test "passing an optional integer as a parameter" { @@ -57,15 +57,15 @@ test "passing an optional integer as a parameter" { return x.? == 1234; } }; - assertOrPanic(S.entry()); - comptime assertOrPanic(S.entry()); + expect(S.entry()); + comptime expect(S.entry()); } test "unwrap function call with optional pointer return value" { const S = struct { fn entry() void { - assertOrPanic(foo().?.* == 1234); - assertOrPanic(bar() == null); + expect(foo().?.* == 1234); + expect(bar() == null); } const global: i32 = 1234; fn foo() ?*const i32 { diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 1142d89ab5..47b19700ee 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "dereference pointer" { comptime testDerefPtr(); @@ -10,33 +10,33 @@ fn testDerefPtr() void { var x: i32 = 1234; var y = &x; y.* += 1; - assertOrPanic(x == 1235); + expect(x == 1235); } test "pointer arithmetic" { var ptr = c"abcd"; - assertOrPanic(ptr[0] == 'a'); + expect(ptr[0] == 'a'); ptr += 1; - assertOrPanic(ptr[0] == 'b'); + expect(ptr[0] == 'b'); ptr += 1; - assertOrPanic(ptr[0] == 'c'); + expect(ptr[0] == 'c'); ptr += 1; - assertOrPanic(ptr[0] == 'd'); + expect(ptr[0] == 'd'); ptr += 1; - assertOrPanic(ptr[0] == 0); + expect(ptr[0] == 0); ptr -= 1; - assertOrPanic(ptr[0] == 'd'); + expect(ptr[0] == 'd'); ptr -= 1; - assertOrPanic(ptr[0] == 'c'); + expect(ptr[0] == 'c'); ptr -= 1; - assertOrPanic(ptr[0] == 'b'); + expect(ptr[0] == 'b'); ptr -= 1; - assertOrPanic(ptr[0] == 'a'); + expect(ptr[0] == 'a'); } test "double pointer parsing" { - comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32); + comptime expect(PtrOf(PtrOf(i32)) == **i32); } fn PtrOf(comptime T: type) type { diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig index f7f8bb523b..2b63284720 100644 --- a/test/stage1/behavior/popcount.zig +++ b/test/stage1/behavior/popcount.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@popCount" { comptime testPopCount(); @@ -8,18 +8,18 @@ test "@popCount" { fn testPopCount() void { { var x: u32 = 0xaa; - assertOrPanic(@popCount(x) == 4); + expect(@popCount(x) == 4); } { var x: u32 = 0xaaaaaaaa; - assertOrPanic(@popCount(x) == 16); + expect(@popCount(x) == 16); } { var x: i16 = -1; - assertOrPanic(@popCount(x) == 16); + expect(@popCount(x) == 16); } comptime { - assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); + expect(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24); } } diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 54c3dda849..3787382aea 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -1,6 +1,6 @@ const builtin = @import("builtin"); const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "reinterpret bytes as integer with nonzero offset" { testReinterpretBytesAsInteger(); @@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void { builtin.Endian.Little => 0xab785634, builtin.Endian.Big => 0x345678ab, }; - assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); + expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); } test "reinterpret bytes of an array into an extern struct" { @@ -32,12 +32,12 @@ fn testReinterpretBytesAsExternStruct() void { var ptr = @ptrCast(*const S, &bytes); var val = ptr.c; - assertOrPanic(val == 5); + expect(val == 5); } test "reinterpret struct field at comptime" { const numLittle = comptime Bytes.init(0x12345678); - assertOrPanic(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); + expect(std.mem.eql(u8, []u8{ 0x78, 0x56, 0x34, 0x12 }, numLittle.bytes)); } const Bytes = struct { diff --git a/test/stage1/behavior/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig index 181113f6bf..15e4114c2d 100644 --- a/test/stage1/behavior/pub_enum/index.zig +++ b/test/stage1/behavior/pub_enum/index.zig @@ -1,13 +1,13 @@ const other = @import("other.zig"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "pub enum" { pubEnumTest(other.APubEnum.Two); } fn pubEnumTest(foo: other.APubEnum) void { - assertOrPanic(foo == other.APubEnum.Two); + expect(foo == other.APubEnum.Two); } test "cast with imported symbol" { - assertOrPanic(other.size_t(42) == 42); + expect(other.size_t(42) == 42); } diff --git a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig index acbe6b2459..2c1cf06268 100644 --- a/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig +++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -1,14 +1,14 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; var ok: bool = false; test "reference a variable in an if after an if in the 2nd switch prong" { foo(true, Num.Two, false, "aoeu"); - assertOrPanic(!ok); + expect(!ok); foo(false, Num.One, false, "aoeu"); - assertOrPanic(!ok); + expect(!ok); foo(true, Num.One, false, "aoeu"); - assertOrPanic(ok); + expect(ok); } const Num = enum { @@ -32,6 +32,6 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void { } fn a(x: []const u8) void { - assertOrPanic(mem.eql(u8, x, "aoeu")); + expect(mem.eql(u8, x, "aoeu")); ok = true; } diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig index f4c142e0f7..55efc85b97 100644 --- a/test/stage1/behavior/reflection.zig +++ b/test/stage1/behavior/reflection.zig @@ -1,25 +1,25 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const reflection = @This(); test "reflection: array, pointer, optional, error union type child" { comptime { - assertOrPanic(([10]u8).Child == u8); - assertOrPanic((*u8).Child == u8); - assertOrPanic((anyerror!u8).Payload == u8); - assertOrPanic((?u8).Child == u8); + expect(([10]u8).Child == u8); + expect((*u8).Child == u8); + expect((anyerror!u8).Payload == u8); + expect((?u8).Child == u8); } } test "reflection: function return type, var args, and param types" { comptime { - assertOrPanic(@typeOf(dummy).ReturnType == i32); - assertOrPanic(!@typeOf(dummy).is_var_args); - assertOrPanic(@typeOf(dummy_varargs).is_var_args); - assertOrPanic(@typeOf(dummy).arg_count == 3); - assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool); - assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32); - assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32); + expect(@typeOf(dummy).ReturnType == i32); + expect(!@typeOf(dummy).is_var_args); + expect(@typeOf(dummy_varargs).is_var_args); + expect(@typeOf(dummy).arg_count == 3); + expect(@ArgType(@typeOf(dummy), 0) == bool); + expect(@ArgType(@typeOf(dummy), 1) == i32); + expect(@ArgType(@typeOf(dummy), 2) == f32); } } @@ -30,31 +30,31 @@ fn dummy_varargs(args: ...) void {} test "reflection: struct member types and names" { comptime { - assertOrPanic(@memberCount(Foo) == 3); + expect(@memberCount(Foo) == 3); - assertOrPanic(@memberType(Foo, 0) == i32); - assertOrPanic(@memberType(Foo, 1) == bool); - assertOrPanic(@memberType(Foo, 2) == void); + expect(@memberType(Foo, 0) == i32); + expect(@memberType(Foo, 1) == bool); + expect(@memberType(Foo, 2) == void); - assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one")); - assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two")); - assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three")); + expect(mem.eql(u8, @memberName(Foo, 0), "one")); + expect(mem.eql(u8, @memberName(Foo, 1), "two")); + expect(mem.eql(u8, @memberName(Foo, 2), "three")); } } test "reflection: enum member types and names" { comptime { - assertOrPanic(@memberCount(Bar) == 4); + expect(@memberCount(Bar) == 4); - assertOrPanic(@memberType(Bar, 0) == void); - assertOrPanic(@memberType(Bar, 1) == i32); - assertOrPanic(@memberType(Bar, 2) == bool); - assertOrPanic(@memberType(Bar, 3) == f64); + expect(@memberType(Bar, 0) == void); + expect(@memberType(Bar, 1) == i32); + expect(@memberType(Bar, 2) == bool); + expect(@memberType(Bar, 3) == f64); - assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three")); - assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four")); + expect(mem.eql(u8, @memberName(Bar, 0), "One")); + expect(mem.eql(u8, @memberName(Bar, 1), "Two")); + expect(mem.eql(u8, @memberName(Bar, 2), "Three")); + expect(mem.eql(u8, @memberName(Bar, 3), "Four")); } } @@ -65,18 +65,18 @@ test "reflection: @field" { .three = void{}, }; - assertOrPanic(f.one == f.one); - assertOrPanic(@field(f, "o" ++ "ne") == f.one); - assertOrPanic(@field(f, "t" ++ "wo") == f.two); - assertOrPanic(@field(f, "th" ++ "ree") == f.three); - assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant); - assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One); - assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two); - assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three); - assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four); - assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); + expect(f.one == f.one); + expect(@field(f, "o" ++ "ne") == f.one); + expect(@field(f, "t" ++ "wo") == f.two); + expect(@field(f, "th" ++ "ree") == f.three); + expect(@field(Foo, "const" ++ "ant") == Foo.constant); + expect(@field(Bar, "O" ++ "ne") == Bar.One); + expect(@field(Bar, "T" ++ "wo") == Bar.Two); + expect(@field(Bar, "Th" ++ "ree") == Bar.Three); + expect(@field(Bar, "F" ++ "our") == Bar.Four); + expect(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2)); @field(f, "o" ++ "ne") = 4; - assertOrPanic(f.one == 4); + expect(f.one == 4); } const Foo = struct { diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig index ddaea4c242..58a6c81759 100644 --- a/test/stage1/behavior/sizeof_and_typeof.zig +++ b/test/stage1/behavior/sizeof_and_typeof.zig @@ -1,9 +1,9 @@ const builtin = @import("builtin"); -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "@sizeOf and @typeOf" { const y: @typeOf(x) = 120; - assertOrPanic(@sizeOf(@typeOf(y)) == 2); + expect(@sizeOf(@typeOf(y)) == 2); } const x: u16 = 13; const z: @typeOf(x) = 19; @@ -30,40 +30,40 @@ const P = packed struct { test "@byteOffsetOf" { // Packed structs have fixed memory layout - assertOrPanic(@byteOffsetOf(P, "a") == 0); - assertOrPanic(@byteOffsetOf(P, "b") == 1); - assertOrPanic(@byteOffsetOf(P, "c") == 5); - assertOrPanic(@byteOffsetOf(P, "d") == 6); - assertOrPanic(@byteOffsetOf(P, "e") == 6); - assertOrPanic(@byteOffsetOf(P, "f") == 7); - assertOrPanic(@byteOffsetOf(P, "g") == 9); + expect(@byteOffsetOf(P, "a") == 0); + expect(@byteOffsetOf(P, "b") == 1); + expect(@byteOffsetOf(P, "c") == 5); + expect(@byteOffsetOf(P, "d") == 6); + expect(@byteOffsetOf(P, "e") == 6); + expect(@byteOffsetOf(P, "f") == 7); + expect(@byteOffsetOf(P, "g") == 9); // Normal struct fields can be moved/padded var a: A = undefined; - assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); - assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); - assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); - assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); - assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); - assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); - assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); + expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a")); + expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b")); + expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c")); + expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d")); + expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e")); + expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f")); + expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g")); } test "@bitOffsetOf" { // Packed structs have fixed memory layout - assertOrPanic(@bitOffsetOf(P, "a") == 0); - assertOrPanic(@bitOffsetOf(P, "b") == 8); - assertOrPanic(@bitOffsetOf(P, "c") == 40); - assertOrPanic(@bitOffsetOf(P, "d") == 48); - assertOrPanic(@bitOffsetOf(P, "e") == 51); - assertOrPanic(@bitOffsetOf(P, "f") == 56); - assertOrPanic(@bitOffsetOf(P, "g") == 72); + expect(@bitOffsetOf(P, "a") == 0); + expect(@bitOffsetOf(P, "b") == 8); + expect(@bitOffsetOf(P, "c") == 40); + expect(@bitOffsetOf(P, "d") == 48); + expect(@bitOffsetOf(P, "e") == 51); + expect(@bitOffsetOf(P, "f") == 56); + expect(@bitOffsetOf(P, "g") == 72); - assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); - assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); - assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); - assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); - assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); - assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); - assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); + expect(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); + expect(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); + expect(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); + expect(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); + expect(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); + expect(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); + expect(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); } diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index cc29e43485..13fa84d0fa 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -1,20 +1,20 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { - assertOrPanic(@ptrToInt(x.ptr) == 0x1000); - assertOrPanic(x.len == 0x500); + expect(@ptrToInt(x.ptr) == 0x1000); + expect(x.len == 0x500); - assertOrPanic(@ptrToInt(y.ptr) == 0x1100); - assertOrPanic(y.len == 0x400); + expect(@ptrToInt(y.ptr) == 0x1100); + expect(y.len == 0x400); } test "slice child property" { var array: [5]i32 = undefined; var slice = array[0..]; - assertOrPanic(@typeOf(slice).Child == i32); + expect(@typeOf(slice).Child == i32); } test "runtime safety lets us slice from len..len" { @@ -23,7 +23,7 @@ test "runtime safety lets us slice from len..len" { 2, 3, }; - assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); + expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); } fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { @@ -36,5 +36,5 @@ test "implicitly cast array of size 0 to slice" { } fn assertLenIsZero(msg: []const u8) void { - assertOrPanic(msg.len == 0); + expect(msg.len == 0); } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 92ae2baa15..a045f482a2 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const builtin = @import("builtin"); const maxInt = std.math.maxInt; @@ -12,7 +12,7 @@ const empty_global_instance = StructWithNoFields{}; test "call struct static method" { const result = StructWithNoFields.add(3, 4); - assertOrPanic(result == 7); + expect(result == 7); } test "return empty struct instance" { @@ -25,7 +25,7 @@ fn returnEmptyStructInstance() StructWithNoFields { const should_be_11 = StructWithNoFields.add(5, 6); test "invoke static method in global scope" { - assertOrPanic(should_be_11 == 11); + expect(should_be_11 == 11); } test "void struct fields" { @@ -34,8 +34,8 @@ test "void struct fields" { .b = 1, .c = void{}, }; - assertOrPanic(foo.b == 1); - assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4); + expect(foo.b == 1); + expect(@sizeOf(VoidStructFieldsFoo) == 4); } const VoidStructFieldsFoo = struct { a: void, @@ -50,7 +50,7 @@ test "structs" { foo.b = foo.a == 1; testFoo(foo); testMutation(&foo); - assertOrPanic(foo.c == 100); + expect(foo.c == 100); } const StructFoo = struct { a: i32, @@ -58,7 +58,7 @@ const StructFoo = struct { c: f32, }; fn testFoo(foo: StructFoo) void { - assertOrPanic(foo.b); + expect(foo.b); } fn testMutation(foo: *StructFoo) void { foo.c = 100; @@ -83,7 +83,7 @@ test "struct point to self" { root.next = &node; - assertOrPanic(node.next.next.next.val.x == 1); + expect(node.next.next.next.val.x == 1); } test "struct byval assign" { @@ -92,18 +92,18 @@ test "struct byval assign" { foo1.a = 1234; foo2.a = 0; - assertOrPanic(foo2.a == 0); + expect(foo2.a == 0); foo2 = foo1; - assertOrPanic(foo2.a == 1234); + expect(foo2.a == 1234); } fn structInitializer() void { const val = Val{ .x = 42 }; - assertOrPanic(val.x == 42); + expect(val.x == 42); } test "fn call of struct field" { - assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13); + expect(callStructField(Foo{ .ptr = aFunc }) == 13); } const Foo = struct { @@ -122,7 +122,7 @@ test "store member function in variable" { const instance = MemberFnTestFoo{ .x = 1234 }; const memberFn = MemberFnTestFoo.member; const result = memberFn(instance); - assertOrPanic(result == 1234); + expect(result == 1234); } const MemberFnTestFoo = struct { x: i32, @@ -134,12 +134,12 @@ const MemberFnTestFoo = struct { test "call member function directly" { const instance = MemberFnTestFoo{ .x = 1234 }; const result = MemberFnTestFoo.member(instance); - assertOrPanic(result == 1234); + expect(result == 1234); } test "member functions" { const r = MemberFnRand{ .seed = 1234 }; - assertOrPanic(r.getSeed() == 1234); + expect(r.getSeed() == 1234); } const MemberFnRand = struct { seed: u32, @@ -150,7 +150,7 @@ const MemberFnRand = struct { test "return struct byval from function" { const bar = makeBar(1234, 5678); - assertOrPanic(bar.y == 5678); + expect(bar.y == 5678); } const Bar = struct { x: i32, @@ -165,7 +165,7 @@ fn makeBar(x: i32, y: i32) Bar { test "empty struct method call" { const es = EmptyStruct{}; - assertOrPanic(es.method() == 1234); + expect(es.method() == 1234); } const EmptyStruct = struct { fn method(es: *const EmptyStruct) i32 { @@ -182,7 +182,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 { } test "pass slice of empty struct to fn" { - assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); + expect(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1); } fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { return slice.len; @@ -200,7 +200,7 @@ test "packed struct" { }; foo.y += 1; const four = foo.x + foo.y; - assertOrPanic(four == 4); + expect(four == 4); } const BitField1 = packed struct { @@ -217,17 +217,17 @@ const bit_field_1 = BitField1{ test "bit field access" { var data = bit_field_1; - assertOrPanic(getA(&data) == 1); - assertOrPanic(getB(&data) == 2); - assertOrPanic(getC(&data) == 3); - comptime assertOrPanic(@sizeOf(BitField1) == 1); + expect(getA(&data) == 1); + expect(getB(&data) == 2); + expect(getC(&data) == 3); + comptime expect(@sizeOf(BitField1) == 1); data.b += 1; - assertOrPanic(data.b == 3); + expect(data.b == 3); data.a += 1; - assertOrPanic(data.a == 2); - assertOrPanic(data.b == 3); + expect(data.a == 2); + expect(data.b == 3); } fn getA(data: *const BitField1) u3 { @@ -254,8 +254,8 @@ const Foo96Bits = packed struct { test "packed struct 24bits" { comptime { - assertOrPanic(@sizeOf(Foo24Bits) == 3); - assertOrPanic(@sizeOf(Foo96Bits) == 12); + expect(@sizeOf(Foo24Bits) == 3); + expect(@sizeOf(Foo96Bits) == 12); } var value = Foo96Bits{ @@ -265,28 +265,28 @@ test "packed struct 24bits" { .d = 0, }; value.a += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 0); - assertOrPanic(value.c == 0); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 0); + expect(value.c == 0); + expect(value.d == 0); value.b += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 0); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 0); + expect(value.d == 0); value.c += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 1); - assertOrPanic(value.d == 0); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 1); + expect(value.d == 0); value.d += 1; - assertOrPanic(value.a == 1); - assertOrPanic(value.b == 1); - assertOrPanic(value.c == 1); - assertOrPanic(value.d == 1); + expect(value.a == 1); + expect(value.b == 1); + expect(value.c == 1); + expect(value.d == 1); } const FooArray24Bits = packed struct { @@ -297,43 +297,43 @@ const FooArray24Bits = packed struct { test "packed array 24bits" { comptime { - assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3); - assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); + expect(@sizeOf([9]Foo24Bits) == 9 * 3); + expect(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2); } var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1); bytes[bytes.len - 1] = 0xaa; const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; - assertOrPanic(ptr.a == 0); - assertOrPanic(ptr.b[0].field == 0); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == 0); + expect(ptr.b[0].field == 0); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.a = maxInt(u16); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == 0); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == 0); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.b[0].field = maxInt(u24); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == 0); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == 0); + expect(ptr.c == 0); ptr.b[1].field = maxInt(u24); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == maxInt(u24)); - assertOrPanic(ptr.c == 0); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == maxInt(u24)); + expect(ptr.c == 0); ptr.c = maxInt(u16); - assertOrPanic(ptr.a == maxInt(u16)); - assertOrPanic(ptr.b[0].field == maxInt(u24)); - assertOrPanic(ptr.b[1].field == maxInt(u24)); - assertOrPanic(ptr.c == maxInt(u16)); + expect(ptr.a == maxInt(u16)); + expect(ptr.b[0].field == maxInt(u24)); + expect(ptr.b[1].field == maxInt(u24)); + expect(ptr.c == maxInt(u16)); - assertOrPanic(bytes[bytes.len - 1] == 0xaa); + expect(bytes[bytes.len - 1] == 0xaa); } const FooStructAligned = packed struct { @@ -347,17 +347,17 @@ const FooArrayOfAligned = packed struct { test "aligned array of packed struct" { comptime { - assertOrPanic(@sizeOf(FooStructAligned) == 2); - assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2); + expect(@sizeOf(FooStructAligned) == 2); + expect(@sizeOf(FooArrayOfAligned) == 2 * 2); } var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned); const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; - assertOrPanic(ptr.a[0].a == 0xbb); - assertOrPanic(ptr.a[0].b == 0xbb); - assertOrPanic(ptr.a[1].a == 0xbb); - assertOrPanic(ptr.a[1].b == 0xbb); + expect(ptr.a[0].a == 0xbb); + expect(ptr.a[0].b == 0xbb); + expect(ptr.a[1].a == 0xbb); + expect(ptr.a[1].b == 0xbb); } test "runtime struct initialization of bitfield" { @@ -370,10 +370,10 @@ test "runtime struct initialization of bitfield" { .y = @intCast(u4, x2), }; - assertOrPanic(s1.x == x1); - assertOrPanic(s1.y == x1); - assertOrPanic(s2.x == @intCast(u4, x2)); - assertOrPanic(s2.y == @intCast(u4, x2)); + expect(s1.x == x1); + expect(s1.y == x1); + expect(s2.x == @intCast(u4, x2)); + expect(s2.y == @intCast(u4, x2)); } var x1 = u4(1); @@ -400,18 +400,18 @@ test "native bit field understands endianness" { @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; - assertOrPanic(bitfields.f1 == 0x1111); - assertOrPanic(bitfields.f2 == 0x2222); - assertOrPanic(bitfields.f3 == 0x33); - assertOrPanic(bitfields.f4 == 0x44); - assertOrPanic(bitfields.f5 == 0x5); - assertOrPanic(bitfields.f6 == 0x6); - assertOrPanic(bitfields.f7 == 0x77); + expect(bitfields.f1 == 0x1111); + expect(bitfields.f2 == 0x2222); + expect(bitfields.f3 == 0x33); + expect(bitfields.f4 == 0x44); + expect(bitfields.f5 == 0x5); + expect(bitfields.f6 == 0x6); + expect(bitfields.f7 == 0x77); } test "align 1 field before self referential align 8 field as slice return type" { const result = alloc(Expr); - assertOrPanic(result.len == 0); + expect(result.len == 0); } const Expr = union(enum) { @@ -434,10 +434,10 @@ test "call method with mutable reference to struct with no fields" { }; var s = S{}; - assertOrPanic(S.doC(&s)); - assertOrPanic(s.doC()); - assertOrPanic(S.do(&s)); - assertOrPanic(s.do()); + expect(S.doC(&s)); + expect(s.doC()); + expect(S.do(&s)); + expect(s.do()); } test "implicit cast packed struct field to const ptr" { @@ -453,7 +453,7 @@ test "implicit cast packed struct field to const ptr" { var lup: LevelUpMove = undefined; lup.level = 12; const res = LevelUpMove.toInt(lup.level); - assertOrPanic(res == 12); + expect(res == 12); } test "pointer to packed struct member in a stack variable" { @@ -464,7 +464,7 @@ test "pointer to packed struct member in a stack variable" { var s = S{ .a = 2, .b = 0 }; var b_ptr = &s.b; - assertOrPanic(s.b == 0); + expect(s.b == 0); b_ptr.* = 2; - assertOrPanic(s.b == 2); + expect(s.b == 2); } diff --git a/test/stage1/behavior/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig index 4cc479f31c..991d742cec 100644 --- a/test/stage1/behavior/struct_contains_null_ptr_itself.zig +++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig @@ -1,9 +1,9 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "struct contains null pointer which contains original struct" { var x: ?*NodeLineComment = null; - assertOrPanic(x == null); + expect(x == null); } pub const Node = struct { diff --git a/test/stage1/behavior/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig index 15780a7c44..52c6579654 100644 --- a/test/stage1/behavior/struct_contains_slice_of_itself.zig +++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Node = struct { payload: i32, @@ -39,12 +39,12 @@ test "struct contains slice of itself" { .payload = 1234, .children = nodes[0..], }; - assertOrPanic(root.payload == 1234); - assertOrPanic(root.children[0].payload == 1); - assertOrPanic(root.children[1].payload == 2); - assertOrPanic(root.children[2].payload == 3); - assertOrPanic(root.children[2].children[0].payload == 31); - assertOrPanic(root.children[2].children[1].payload == 32); + expect(root.payload == 1234); + expect(root.children[0].payload == 1); + expect(root.children[1].payload == 2); + expect(root.children[2].payload == 3); + expect(root.children[2].children[0].payload == 31); + expect(root.children[2].children[1].payload == 32); } test "struct contains aligned slice of itself" { @@ -76,10 +76,10 @@ test "struct contains aligned slice of itself" { .payload = 1234, .children = nodes[0..], }; - assertOrPanic(root.payload == 1234); - assertOrPanic(root.children[0].payload == 1); - assertOrPanic(root.children[1].payload == 2); - assertOrPanic(root.children[2].payload == 3); - assertOrPanic(root.children[2].children[0].payload == 31); - assertOrPanic(root.children[2].children[1].payload == 32); + expect(root.payload == 1234); + expect(root.children[0].payload == 1); + expect(root.children[1].payload == 2); + expect(root.children[2].payload == 3); + expect(root.children[2].children[0].payload == 31); + expect(root.children[2].children[1].payload == 32); } diff --git a/test/stage1/behavior/switch.zig b/test/stage1/behavior/switch.zig index 4ac971397e..1059bf28f8 100644 --- a/test/stage1/behavior/switch.zig +++ b/test/stage1/behavior/switch.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "switch with numbers" { testSwitchWithNumbers(13); @@ -10,14 +10,14 @@ fn testSwitchWithNumbers(x: u32) void { 13 => true, else => false, }; - assertOrPanic(result); + expect(result); } test "switch with all ranges" { - assertOrPanic(testSwitchWithAllRanges(50, 3) == 1); - assertOrPanic(testSwitchWithAllRanges(101, 0) == 2); - assertOrPanic(testSwitchWithAllRanges(300, 5) == 3); - assertOrPanic(testSwitchWithAllRanges(301, 6) == 6); + expect(testSwitchWithAllRanges(50, 3) == 1); + expect(testSwitchWithAllRanges(101, 0) == 2); + expect(testSwitchWithAllRanges(300, 5) == 3); + expect(testSwitchWithAllRanges(301, 6) == 6); } fn testSwitchWithAllRanges(x: u32, y: u32) u32 { @@ -40,7 +40,7 @@ test "implicit comptime switch" { }; comptime { - assertOrPanic(result + 1 == 14); + expect(result + 1 == 14); } } @@ -71,7 +71,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) void { SwitchStatmentFoo.C => 3, SwitchStatmentFoo.D => 4, }; - assertOrPanic(val == 3); + expect(val == 3); } const SwitchStatmentFoo = enum { A, @@ -93,10 +93,10 @@ const SwitchProngWithVarEnum = union(enum) { fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void { switch (a) { SwitchProngWithVarEnum.One => |x| { - assertOrPanic(x == 13); + expect(x == 13); }, SwitchProngWithVarEnum.Two => |x| { - assertOrPanic(x == 13.0); + expect(x == 13.0); }, SwitchProngWithVarEnum.Meh => |x| { const v: void = x; @@ -116,7 +116,7 @@ fn testSwitchEnumPtrCapture() void { else => unreachable, } switch (value) { - SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235), + SwitchProngWithVarEnum.One => |x| expect(x == 1235), else => unreachable, } } @@ -127,7 +127,7 @@ test "switch with multiple expressions" { 4, 5, 6 => 2, else => i32(3), }; - assertOrPanic(x == 2); + expect(x == 2); } fn returnsFive() i32 { return 5; @@ -149,12 +149,12 @@ fn returnsFalse() bool { } } test "switch on const enum with var" { - assertOrPanic(!returnsFalse()); + expect(!returnsFalse()); } test "switch on type" { - assertOrPanic(trueIfBoolFalseOtherwise(bool)); - assertOrPanic(!trueIfBoolFalseOtherwise(i32)); + expect(trueIfBoolFalseOtherwise(bool)); + expect(!trueIfBoolFalseOtherwise(i32)); } fn trueIfBoolFalseOtherwise(comptime T: type) bool { @@ -170,16 +170,16 @@ test "switch handles all cases of number" { } fn testSwitchHandleAllCases() void { - assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3); - assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2); - assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1); - assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0); + expect(testSwitchHandleAllCasesExhaustive(0) == 3); + expect(testSwitchHandleAllCasesExhaustive(1) == 2); + expect(testSwitchHandleAllCasesExhaustive(2) == 1); + expect(testSwitchHandleAllCasesExhaustive(3) == 0); - assertOrPanic(testSwitchHandleAllCasesRange(100) == 0); - assertOrPanic(testSwitchHandleAllCasesRange(200) == 1); - assertOrPanic(testSwitchHandleAllCasesRange(201) == 2); - assertOrPanic(testSwitchHandleAllCasesRange(202) == 4); - assertOrPanic(testSwitchHandleAllCasesRange(230) == 3); + expect(testSwitchHandleAllCasesRange(100) == 0); + expect(testSwitchHandleAllCasesRange(200) == 1); + expect(testSwitchHandleAllCasesRange(201) == 2); + expect(testSwitchHandleAllCasesRange(202) == 4); + expect(testSwitchHandleAllCasesRange(230) == 3); } fn testSwitchHandleAllCasesExhaustive(x: u2) u2 { @@ -207,8 +207,8 @@ test "switch all prongs unreachable" { } fn testAllProngsUnreachable() void { - assertOrPanic(switchWithUnreachable(1) == 2); - assertOrPanic(switchWithUnreachable(2) == 10); + expect(switchWithUnreachable(1) == 2); + expect(switchWithUnreachable(2) == 10); } fn switchWithUnreachable(x: i32) i32 { @@ -230,7 +230,7 @@ test "capture value of switch with all unreachable prongs" { const x = return_a_number() catch |err| switch (err) { else => unreachable, }; - assertOrPanic(x == 1); + expect(x == 1); } test "switching on booleans" { @@ -239,14 +239,14 @@ test "switching on booleans" { } fn testSwitchOnBools() void { - assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false); - assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true); + expect(testSwitchOnBoolsTrueAndFalse(true) == false); + expect(testSwitchOnBoolsTrueAndFalse(false) == true); - assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false); - assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true); + expect(testSwitchOnBoolsTrueWithElse(true) == false); + expect(testSwitchOnBoolsTrueWithElse(false) == true); - assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false); - assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true); + expect(testSwitchOnBoolsFalseWithElse(true) == false); + expect(testSwitchOnBoolsFalseWithElse(false) == true); } fn testSwitchOnBoolsTrueAndFalse(x: bool) bool { diff --git a/test/stage1/behavior/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig index 6ac1919f0d..3593eabb5a 100644 --- a/test/stage1/behavior/switch_prong_err_enum.zig +++ b/test/stage1/behavior/switch_prong_err_enum.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; var read_count: u64 = 0; @@ -22,9 +22,9 @@ fn doThing(form_id: u64) anyerror!FormValue { test "switch prong returns error enum" { switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { - assertOrPanic(payload == 1); + expect(payload == 1); }, else => unreachable, } - assertOrPanic(read_count == 1); + expect(read_count == 1); } diff --git a/test/stage1/behavior/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig index 4ca031e2e1..da965915ca 100644 --- a/test/stage1/behavior/switch_prong_implicit_cast.zig +++ b/test/stage1/behavior/switch_prong_implicit_cast.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const FormValue = union(enum) { One: void, @@ -18,5 +18,5 @@ test "switch prong implicit cast" { FormValue.One => false, FormValue.Two => |x| x, }; - assertOrPanic(result); + expect(result); } diff --git a/test/stage1/behavior/this.zig b/test/stage1/behavior/this.zig index 0e3a7a03ae..a0bee3a3ee 100644 --- a/test/stage1/behavior/this.zig +++ b/test/stage1/behavior/this.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const module = @This(); @@ -20,7 +20,7 @@ fn add(x: i32, y: i32) i32 { } test "this refer to module call private fn" { - assertOrPanic(module.add(1, 2) == 3); + expect(module.add(1, 2) == 3); } test "this refer to container" { @@ -29,7 +29,7 @@ test "this refer to container" { .y = 34, }; pt.addOne(); - assertOrPanic(pt.x == 13); - assertOrPanic(pt.y == 35); + expect(pt.x == 13); + expect(pt.y == 35); } diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig index b7904bc7fb..c195b64cbf 100644 --- a/test/stage1/behavior/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -1,8 +1,8 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "truncate u0 to larger integer allowed and has comptime known result" { var x: u0 = 0; const y = @truncate(u8, x); - comptime assertOrPanic(y == 0); + comptime expect(y == 0); } diff --git a/test/stage1/behavior/try.zig b/test/stage1/behavior/try.zig index ed48875eb4..9c700f6260 100644 --- a/test/stage1/behavior/try.zig +++ b/test/stage1/behavior/try.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "try on error union" { tryOnErrorUnionImpl(); @@ -11,7 +11,7 @@ fn tryOnErrorUnionImpl() void { error.CrappedOut => i32(2), else => unreachable, }; - assertOrPanic(x == 11); + expect(x == 11); } fn returnsTen() anyerror!i32 { @@ -20,10 +20,10 @@ fn returnsTen() anyerror!i32 { test "try without vars" { const result1 = if (failIfTrue(true)) 1 else |_| i32(2); - assertOrPanic(result1 == 2); + expect(result1 == 2); const result2 = if (failIfTrue(false)) 1 else |_| i32(2); - assertOrPanic(result2 == 1); + expect(result2 == 1); } fn failIfTrue(ok: bool) anyerror!void { @@ -38,6 +38,6 @@ test "try then not executed with assignment" { if (failIfTrue(true)) { unreachable; } else |err| { - assertOrPanic(err == error.ItBroke); + expect(err == error.ItBroke); } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index f3bb17b282..ce0ad795b4 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; const TypeInfo = @import("builtin").TypeInfo; const TypeId = @import("builtin").TypeId; @@ -9,10 +9,10 @@ test "type info: tag type, void info" { } fn testBasic() void { - assertOrPanic(@TagType(TypeInfo) == TypeId); + expect(@TagType(TypeInfo) == TypeId); const void_info = @typeInfo(void); - assertOrPanic(TypeId(void_info) == TypeId.Void); - assertOrPanic(void_info.Void == {}); + expect(TypeId(void_info) == TypeId.Void); + expect(void_info.Void == {}); } test "type info: integer, floating point type info" { @@ -22,13 +22,13 @@ test "type info: integer, floating point type info" { fn testIntFloat() void { const u8_info = @typeInfo(u8); - assertOrPanic(TypeId(u8_info) == TypeId.Int); - assertOrPanic(!u8_info.Int.is_signed); - assertOrPanic(u8_info.Int.bits == 8); + expect(TypeId(u8_info) == TypeId.Int); + expect(!u8_info.Int.is_signed); + expect(u8_info.Int.bits == 8); const f64_info = @typeInfo(f64); - assertOrPanic(TypeId(f64_info) == TypeId.Float); - assertOrPanic(f64_info.Float.bits == 64); + expect(TypeId(f64_info) == TypeId.Float); + expect(f64_info.Float.bits == 64); } test "type info: pointer type info" { @@ -38,12 +38,12 @@ test "type info: pointer type info" { fn testPointer() void { const u32_ptr_info = @typeInfo(*u32); - assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); - assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); - assertOrPanic(u32_ptr_info.Pointer.is_const == false); - assertOrPanic(u32_ptr_info.Pointer.is_volatile == false); - assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32)); - assertOrPanic(u32_ptr_info.Pointer.child == u32); + expect(TypeId(u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One); + expect(u32_ptr_info.Pointer.is_const == false); + expect(u32_ptr_info.Pointer.is_volatile == false); + expect(u32_ptr_info.Pointer.alignment == @alignOf(u32)); + expect(u32_ptr_info.Pointer.child == u32); } test "type info: unknown length pointer type info" { @@ -53,12 +53,12 @@ test "type info: unknown length pointer type info" { fn testUnknownLenPtr() void { const u32_ptr_info = @typeInfo([*]const volatile f64); - assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer); - assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); - assertOrPanic(u32_ptr_info.Pointer.is_const == true); - assertOrPanic(u32_ptr_info.Pointer.is_volatile == true); - assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64)); - assertOrPanic(u32_ptr_info.Pointer.child == f64); + expect(TypeId(u32_ptr_info) == TypeId.Pointer); + expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); + expect(u32_ptr_info.Pointer.is_const == true); + expect(u32_ptr_info.Pointer.is_volatile == true); + expect(u32_ptr_info.Pointer.alignment == @alignOf(f64)); + expect(u32_ptr_info.Pointer.child == f64); } test "type info: slice type info" { @@ -68,12 +68,12 @@ test "type info: slice type info" { fn testSlice() void { const u32_slice_info = @typeInfo([]u32); - assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer); - assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); - assertOrPanic(u32_slice_info.Pointer.is_const == false); - assertOrPanic(u32_slice_info.Pointer.is_volatile == false); - assertOrPanic(u32_slice_info.Pointer.alignment == 4); - assertOrPanic(u32_slice_info.Pointer.child == u32); + expect(TypeId(u32_slice_info) == TypeId.Pointer); + expect(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice); + expect(u32_slice_info.Pointer.is_const == false); + expect(u32_slice_info.Pointer.is_volatile == false); + expect(u32_slice_info.Pointer.alignment == 4); + expect(u32_slice_info.Pointer.child == u32); } test "type info: array type info" { @@ -83,9 +83,9 @@ test "type info: array type info" { fn testArray() void { const arr_info = @typeInfo([42]bool); - assertOrPanic(TypeId(arr_info) == TypeId.Array); - assertOrPanic(arr_info.Array.len == 42); - assertOrPanic(arr_info.Array.child == bool); + expect(TypeId(arr_info) == TypeId.Array); + expect(arr_info.Array.len == 42); + expect(arr_info.Array.child == bool); } test "type info: optional type info" { @@ -95,8 +95,8 @@ test "type info: optional type info" { fn testOptional() void { const null_info = @typeInfo(?void); - assertOrPanic(TypeId(null_info) == TypeId.Optional); - assertOrPanic(null_info.Optional.child == void); + expect(TypeId(null_info) == TypeId.Optional); + expect(null_info.Optional.child == void); } test "type info: promise info" { @@ -106,12 +106,12 @@ test "type info: promise info" { fn testPromise() void { const null_promise_info = @typeInfo(promise); - assertOrPanic(TypeId(null_promise_info) == TypeId.Promise); - assertOrPanic(null_promise_info.Promise.child == null); + expect(TypeId(null_promise_info) == TypeId.Promise); + expect(null_promise_info.Promise.child == null); const promise_info = @typeInfo(promise->usize); - assertOrPanic(TypeId(promise_info) == TypeId.Promise); - assertOrPanic(promise_info.Promise.child.? == usize); + expect(TypeId(promise_info) == TypeId.Promise); + expect(promise_info.Promise.child.? == usize); } test "type info: error set, error union info" { @@ -127,15 +127,15 @@ fn testErrorSet() void { }; const error_set_info = @typeInfo(TestErrorSet); - assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet); - assertOrPanic(error_set_info.ErrorSet.errors.len == 3); - assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); - assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); + expect(TypeId(error_set_info) == TypeId.ErrorSet); + expect(error_set_info.ErrorSet.errors.len == 3); + expect(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First")); + expect(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third)); const error_union_info = @typeInfo(TestErrorSet!usize); - assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion); - assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet); - assertOrPanic(error_union_info.ErrorUnion.payload == usize); + expect(TypeId(error_union_info) == TypeId.ErrorUnion); + expect(error_union_info.ErrorUnion.error_set == TestErrorSet); + expect(error_union_info.ErrorUnion.payload == usize); } test "type info: enum info" { @@ -152,13 +152,13 @@ fn testEnum() void { }; const os_info = @typeInfo(Os); - assertOrPanic(TypeId(os_info) == TypeId.Enum); - assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(os_info.Enum.fields.len == 4); - assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); - assertOrPanic(os_info.Enum.fields[3].value == 3); - assertOrPanic(os_info.Enum.tag_type == u2); - assertOrPanic(os_info.Enum.defs.len == 0); + expect(TypeId(os_info) == TypeId.Enum); + expect(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto); + expect(os_info.Enum.fields.len == 4); + expect(mem.eql(u8, os_info.Enum.fields[1].name, "Macos")); + expect(os_info.Enum.fields[3].value == 3); + expect(os_info.Enum.tag_type == u2); + expect(os_info.Enum.defs.len == 0); } test "type info: union info" { @@ -168,14 +168,14 @@ test "type info: union info" { fn testUnion() void { const typeinfo_info = @typeInfo(TypeInfo); - assertOrPanic(TypeId(typeinfo_info) == TypeId.Union); - assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId); - assertOrPanic(typeinfo_info.Union.fields.len == 25); - assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null); - assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4); - assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); - assertOrPanic(typeinfo_info.Union.defs.len == 21); + expect(TypeId(typeinfo_info) == TypeId.Union); + expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); + expect(typeinfo_info.Union.tag_type.? == TypeId); + expect(typeinfo_info.Union.fields.len == 25); + expect(typeinfo_info.Union.fields[4].enum_field != null); + expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); + expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); + expect(typeinfo_info.Union.defs.len == 21); const TestNoTagUnion = union { Foo: void, @@ -183,22 +183,22 @@ fn testUnion() void { }; const notag_union_info = @typeInfo(TestNoTagUnion); - assertOrPanic(TypeId(notag_union_info) == TypeId.Union); - assertOrPanic(notag_union_info.Union.tag_type == null); - assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); - assertOrPanic(notag_union_info.Union.fields.len == 2); - assertOrPanic(notag_union_info.Union.fields[0].enum_field == null); - assertOrPanic(notag_union_info.Union.fields[1].field_type == u32); + expect(TypeId(notag_union_info) == TypeId.Union); + expect(notag_union_info.Union.tag_type == null); + expect(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto); + expect(notag_union_info.Union.fields.len == 2); + expect(notag_union_info.Union.fields[0].enum_field == null); + expect(notag_union_info.Union.fields[1].field_type == u32); const TestExternUnion = extern union { foo: *c_void, }; const extern_union_info = @typeInfo(TestExternUnion); - assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); - assertOrPanic(extern_union_info.Union.tag_type == null); - assertOrPanic(extern_union_info.Union.fields[0].enum_field == null); - assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void); + expect(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern); + expect(extern_union_info.Union.tag_type == null); + expect(extern_union_info.Union.fields[0].enum_field == null); + expect(extern_union_info.Union.fields[0].field_type == *c_void); } test "type info: struct info" { @@ -208,17 +208,17 @@ test "type info: struct info" { fn testStruct() void { const struct_info = @typeInfo(TestStruct); - assertOrPanic(TypeId(struct_info) == TypeId.Struct); - assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); - assertOrPanic(struct_info.Struct.fields.len == 3); - assertOrPanic(struct_info.Struct.fields[1].offset == null); - assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct); - assertOrPanic(struct_info.Struct.defs.len == 2); - assertOrPanic(struct_info.Struct.defs[0].is_pub); - assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void); - assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); + expect(TypeId(struct_info) == TypeId.Struct); + expect(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed); + expect(struct_info.Struct.fields.len == 3); + expect(struct_info.Struct.fields[1].offset == null); + expect(struct_info.Struct.fields[2].field_type == *TestStruct); + expect(struct_info.Struct.defs.len == 2); + expect(struct_info.Struct.defs[0].is_pub); + expect(!struct_info.Struct.defs[0].data.Fn.is_extern); + expect(struct_info.Struct.defs[0].data.Fn.lib_name == null); + expect(struct_info.Struct.defs[0].data.Fn.return_type == void); + expect(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void); } const TestStruct = packed struct { @@ -238,18 +238,18 @@ test "type info: function type info" { fn testFunction() void { const fn_info = @typeInfo(@typeOf(foo)); - assertOrPanic(TypeId(fn_info) == TypeId.Fn); - assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); - assertOrPanic(fn_info.Fn.is_generic); - assertOrPanic(fn_info.Fn.args.len == 2); - assertOrPanic(fn_info.Fn.is_var_args); - assertOrPanic(fn_info.Fn.return_type == null); - assertOrPanic(fn_info.Fn.async_allocator_type == null); + expect(TypeId(fn_info) == TypeId.Fn); + expect(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified); + expect(fn_info.Fn.is_generic); + expect(fn_info.Fn.args.len == 2); + expect(fn_info.Fn.is_var_args); + expect(fn_info.Fn.return_type == null); + expect(fn_info.Fn.async_allocator_type == null); const test_instance: TestStruct = undefined; const bound_fn_info = @typeInfo(@typeOf(test_instance.foo)); - assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn); - assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); + expect(TypeId(bound_fn_info) == TypeId.BoundFn); + expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct); } fn foo(comptime a: usize, b: bool, args: ...) usize { @@ -270,7 +270,7 @@ test "type info: vectors" { fn testVector() void { const vec_info = @typeInfo(@Vector(4, i32)); - assertOrPanic(TypeId(vec_info) == TypeId.Vector); - assertOrPanic(vec_info.Vector.len == 4); - assertOrPanic(vec_info.Vector.child == i32); + expect(TypeId(vec_info) == TypeId.Vector); + expect(vec_info.Vector.len == 4); + expect(vec_info.Vector.child == i32); } diff --git a/test/stage1/behavior/undefined.zig b/test/stage1/behavior/undefined.zig index 333e217d49..4c233576cd 100644 --- a/test/stage1/behavior/undefined.zig +++ b/test/stage1/behavior/undefined.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const mem = @import("std").mem; fn initStaticArray() [10]i32 { @@ -11,16 +11,16 @@ fn initStaticArray() [10]i32 { } const static_array = initStaticArray(); test "init static array to undefined" { - assertOrPanic(static_array[0] == 1); - assertOrPanic(static_array[4] == 2); - assertOrPanic(static_array[7] == 3); - assertOrPanic(static_array[9] == 4); + expect(static_array[0] == 1); + expect(static_array[4] == 2); + expect(static_array[7] == 3); + expect(static_array[9] == 4); comptime { - assertOrPanic(static_array[0] == 1); - assertOrPanic(static_array[4] == 2); - assertOrPanic(static_array[7] == 3); - assertOrPanic(static_array[9] == 4); + expect(static_array[0] == 1); + expect(static_array[4] == 2); + expect(static_array[7] == 3); + expect(static_array[9] == 4); } } @@ -40,12 +40,12 @@ test "assign undefined to struct" { comptime { var foo: Foo = undefined; setFooX(&foo); - assertOrPanic(foo.x == 2); + expect(foo.x == 2); } { var foo: Foo = undefined; setFooX(&foo); - assertOrPanic(foo.x == 2); + expect(foo.x == 2); } } @@ -53,17 +53,17 @@ test "assign undefined to struct with method" { comptime { var foo: Foo = undefined; foo.setFooXMethod(); - assertOrPanic(foo.x == 3); + expect(foo.x == 3); } { var foo: Foo = undefined; foo.setFooXMethod(); - assertOrPanic(foo.x == 3); + expect(foo.x == 3); } } test "type name of undefined" { const x = undefined; - assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); + expect(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)")); } diff --git a/test/stage1/behavior/underscore.zig b/test/stage1/behavior/underscore.zig index 7443319336..fd5aebc87e 100644 --- a/test/stage1/behavior/underscore.zig +++ b/test/stage1/behavior/underscore.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "ignore lval with underscore" { _ = false; diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index c8e8feb11e..0a4e2cfb92 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Value = union(enum) { Int: u64, @@ -27,11 +27,11 @@ const array = []Value{ test "unions embedded in aggregate types" { switch (array[1]) { - Value.Array => |arr| assertOrPanic(arr[4] == 3), + Value.Array => |arr| expect(arr[4] == 3), else => unreachable, } switch ((err catch unreachable).val1) { - Value.Int => |x| assertOrPanic(x == 1234), + Value.Int => |x| expect(x == 1234), else => unreachable, } } @@ -43,18 +43,18 @@ const Foo = union { test "basic unions" { var foo = Foo{ .int = 1 }; - assertOrPanic(foo.int == 1); + expect(foo.int == 1); foo = Foo{ .float = 12.34 }; - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); } test "comptime union field access" { comptime { var foo = Foo{ .int = 0 }; - assertOrPanic(foo.int == 0); + expect(foo.int == 0); foo = Foo{ .float = 42.42 }; - assertOrPanic(foo.float == 42.42); + expect(foo.float == 42.42); } } @@ -62,10 +62,10 @@ test "init union with runtime value" { var foo: Foo = undefined; setFloat(&foo, 12.34); - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); setInt(&foo, 42); - assertOrPanic(foo.int == 42); + expect(foo.int == 42); } fn setFloat(foo: *Foo, x: f64) void { @@ -83,9 +83,9 @@ const FooExtern = extern union { test "basic extern unions" { var foo = FooExtern{ .int = 1 }; - assertOrPanic(foo.int == 1); + expect(foo.int == 1); foo.float = 12.34; - assertOrPanic(foo.float == 12.34); + expect(foo.float == 12.34); } const Letter = enum { @@ -105,11 +105,11 @@ test "union with specified enum tag" { } fn doTest() void { - assertOrPanic(bar(Payload{ .A = 1234 }) == -10); + expect(bar(Payload{ .A = 1234 }) == -10); } fn bar(value: Payload) i32 { - assertOrPanic(Letter(value) == Letter.A); + expect(Letter(value) == Letter.A); return switch (value) { Payload.A => |x| return x - 1244, Payload.B => |x| if (x == 12.34) i32(20) else 21, @@ -125,8 +125,8 @@ const MultipleChoice = union(enum(u32)) { }; test "simple union(enum(u32))" { var x = MultipleChoice.C; - assertOrPanic(x == MultipleChoice.C); - assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60); + expect(x == MultipleChoice.C); + expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60); } const MultipleChoice2 = union(enum(u32)) { @@ -142,14 +142,14 @@ const MultipleChoice2 = union(enum(u32)) { }; test "union(enum(u32)) with specified and unspecified tag values" { - comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32); + comptime expect(@TagType(@TagType(MultipleChoice2)) == u32); testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); - assertOrPanic(1123 == switch (x) { + expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); + expect(1123 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, MultipleChoice2.C => |v| i32(1000) + v, @@ -167,7 +167,7 @@ const ExternPtrOrInt = extern union { int: u64, }; test "extern union size" { - comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8); + comptime expect(@sizeOf(ExternPtrOrInt) == 8); } const PackedPtrOrInt = packed union { @@ -175,14 +175,14 @@ const PackedPtrOrInt = packed union { int: u64, }; test "extern union size" { - comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8); + comptime expect(@sizeOf(PackedPtrOrInt) == 8); } const ZeroBits = union { OnlyField: void, }; test "union with only 1 field which is void should be zero bits" { - comptime assertOrPanic(@sizeOf(ZeroBits) == 0); + comptime expect(@sizeOf(ZeroBits) == 0); } const TheTag = enum { @@ -196,9 +196,9 @@ const TheUnion = union(TheTag) { C: i32, }; test "union field access gives the enum values" { - assertOrPanic(TheUnion.A == TheTag.A); - assertOrPanic(TheUnion.B == TheTag.B); - assertOrPanic(TheUnion.C == TheTag.C); + expect(TheUnion.A == TheTag.A); + expect(TheUnion.B == TheTag.B); + expect(TheUnion.C == TheTag.C); } test "cast union to tag type of union" { @@ -207,12 +207,12 @@ test "cast union to tag type of union" { } fn testCastUnionToTagType(x: TheUnion) void { - assertOrPanic(TheTag(x) == TheTag.B); + expect(TheTag(x) == TheTag.B); } test "cast tag type of union to union" { var x: Value2 = Letter2.B; - assertOrPanic(Letter2(x) == Letter2.B); + expect(Letter2(x) == Letter2.B); } const Letter2 = enum { A, @@ -227,11 +227,11 @@ const Value2 = union(Letter2) { test "implicit cast union to its tag type" { var x: Value2 = Letter2.B; - assertOrPanic(x == Letter2.B); + expect(x == Letter2.B); giveMeLetterB(x); } fn giveMeLetterB(x: Letter2) void { - assertOrPanic(x == Value2.B); + expect(x == Value2.B); } pub const PackThis = union(enum) { @@ -244,7 +244,7 @@ test "constant packed union" { } fn testConstPackedUnion(expected_tokens: []const PackThis) void { - assertOrPanic(expected_tokens[0].StringLiteral == 1); + expect(expected_tokens[0].StringLiteral == 1); } test "switch on union with only 1 field" { @@ -256,7 +256,7 @@ test "switch on union with only 1 field" { z = PartialInstWithPayload{ .Compiled = 1234 }; switch (z) { PartialInstWithPayload.Compiled => |x| { - assertOrPanic(x == 1234); + expect(x == 1234); return; }, } @@ -282,11 +282,11 @@ test "access a member of tagged union with conflicting enum tag name" { const B = void; }; - comptime assertOrPanic(Bar.A == u8); + comptime expect(Bar.A == u8); } test "tagged union initialization with runtime void" { - assertOrPanic(testTaggedUnionInit({})); + expect(testTaggedUnionInit({})); } const TaggedUnionWithAVoid = union(enum) { @@ -324,9 +324,9 @@ test "union with only 1 field casted to its enum type" { var e = Expr{ .Literal = Literal{ .Bool = true } }; const Tag = @TagType(Expr); - comptime assertOrPanic(@TagType(Tag) == comptime_int); + comptime expect(@TagType(Tag) == comptime_int); var t = Tag(e); - assertOrPanic(t == Expr.Literal); + expect(t == Expr.Literal); } test "union with only 1 field casted to its enum type which has enum value specified" { @@ -344,9 +344,9 @@ test "union with only 1 field casted to its enum type which has enum value speci }; var e = Expr{ .Literal = Literal{ .Bool = true } }; - comptime assertOrPanic(@TagType(Tag) == comptime_int); + comptime expect(@TagType(Tag) == comptime_int); var t = Tag(e); - assertOrPanic(t == Expr.Literal); - assertOrPanic(@enumToInt(t) == 33); - comptime assertOrPanic(@enumToInt(t) == 33); + expect(t == Expr.Literal); + expect(@enumToInt(t) == 33); + comptime expect(@enumToInt(t) == 33); } diff --git a/test/stage1/behavior/var_args.zig b/test/stage1/behavior/var_args.zig index 1f782a3bb3..cc93b57f06 100644 --- a/test/stage1/behavior/var_args.zig +++ b/test/stage1/behavior/var_args.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; fn add(args: ...) i32 { var sum = i32(0); @@ -12,9 +12,9 @@ fn add(args: ...) i32 { } test "add arbitrary args" { - assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10); - assertOrPanic(add(i32(1234)) == 1234); - assertOrPanic(add() == 0); + expect(add(i32(1), i32(2), i32(3), i32(4)) == 10); + expect(add(i32(1234)) == 1234); + expect(add() == 0); } fn readFirstVarArg(args: ...) void { @@ -26,9 +26,9 @@ test "send void arg to var args" { } test "pass args directly" { - assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); - assertOrPanic(addSomeStuff(i32(1234)) == 1234); - assertOrPanic(addSomeStuff() == 0); + expect(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10); + expect(addSomeStuff(i32(1234)) == 1234); + expect(addSomeStuff() == 0); } fn addSomeStuff(args: ...) i32 { @@ -36,24 +36,24 @@ fn addSomeStuff(args: ...) i32 { } test "runtime parameter before var args" { - assertOrPanic(extraFn(10) == 0); - assertOrPanic(extraFn(10, false) == 1); - assertOrPanic(extraFn(10, false, true) == 2); + expect(extraFn(10) == 0); + expect(extraFn(10, false) == 1); + expect(extraFn(10, false, true) == 2); // TODO issue #313 //comptime { - // assertOrPanic(extraFn(10) == 0); - // assertOrPanic(extraFn(10, false) == 1); - // assertOrPanic(extraFn(10, false, true) == 2); + // expect(extraFn(10) == 0); + // expect(extraFn(10, false) == 1); + // expect(extraFn(10, false, true) == 2); //} } fn extraFn(extra: u32, args: ...) usize { if (args.len >= 1) { - assertOrPanic(args[0] == false); + expect(args[0] == false); } if (args.len >= 2) { - assertOrPanic(args[1] == true); + expect(args[1] == true); } return args.len; } @@ -71,8 +71,8 @@ fn foo2(args: ...) bool { } test "array of var args functions" { - assertOrPanic(foos[0]()); - assertOrPanic(!foos[1]()); + expect(foos[0]()); + expect(!foos[1]()); } test "pass zero length array to var args param" { diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index c97ee0e3d6..7cead12b65 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -1,15 +1,15 @@ const std = @import("std"); const mem = std.mem; -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; test "vector wrap operators" { const S = struct { fn doTheTest() void { const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 }; const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 }; - assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); - assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); - assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); + expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 })); + expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 })); + expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 })); } }; S.doTheTest(); diff --git a/test/stage1/behavior/void.zig b/test/stage1/behavior/void.zig index 431d3f4eb1..9722791946 100644 --- a/test/stage1/behavior/void.zig +++ b/test/stage1/behavior/void.zig @@ -1,4 +1,4 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; const Foo = struct { a: void, @@ -13,14 +13,14 @@ test "compare void with void compile time known" { .b = 1, .c = {}, }; - assertOrPanic(foo.a == {}); + expect(foo.a == {}); } } test "iterate over a void slice" { var j: usize = 0; for (times(10)) |_, i| { - assertOrPanic(i == j); + expect(i == j); j += 1; } } @@ -31,5 +31,5 @@ fn times(n: usize) []const void { test "void optional" { var x: ?void = {}; - assertOrPanic(x != null); + expect(x != null); } diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig index 579b4e4db8..29ad90ed17 100644 --- a/test/stage1/behavior/while.zig +++ b/test/stage1/behavior/while.zig @@ -1,12 +1,12 @@ -const assertOrPanic = @import("std").debug.assertOrPanic; +const expect = @import("std").testing.expect; test "while loop" { var i: i32 = 0; while (i < 4) { i += 1; } - assertOrPanic(i == 4); - assertOrPanic(whileLoop1() == 1); + expect(i == 4); + expect(whileLoop1() == 1); } fn whileLoop1() i32 { return whileLoop2(); @@ -18,7 +18,7 @@ fn whileLoop2() i32 { } test "static eval while" { - assertOrPanic(static_eval_while_number == 1); + expect(static_eval_while_number == 1); } const static_eval_while_number = staticWhileLoop1(); fn staticWhileLoop1() i32 { @@ -32,7 +32,7 @@ fn staticWhileLoop2() i32 { test "continue and break" { runContinueAndBreakTest(); - assertOrPanic(continue_and_break_counter == 8); + expect(continue_and_break_counter == 8); } var continue_and_break_counter: i32 = 0; fn runContinueAndBreakTest() void { @@ -45,7 +45,7 @@ fn runContinueAndBreakTest() void { } break; } - assertOrPanic(i == 4); + expect(i == 4); } test "return with implicit cast from while loop" { @@ -66,7 +66,7 @@ test "while with continue expression" { sum += i; } } - assertOrPanic(sum == 40); + expect(sum == 40); } test "while with else" { @@ -78,8 +78,8 @@ test "while with else" { } else { got_else += 1; } - assertOrPanic(sum == 10); - assertOrPanic(got_else == 1); + expect(sum == 10); + expect(got_else == 1); } test "while with optional as condition" { @@ -88,7 +88,7 @@ test "while with optional as condition" { while (getNumberOrNull()) |value| { sum += value; } - assertOrPanic(sum == 45); + expect(sum == 45); } test "while with optional as condition with else" { @@ -97,12 +97,12 @@ test "while with optional as condition with else" { var got_else: i32 = 0; while (getNumberOrNull()) |value| { sum += value; - assertOrPanic(got_else == 0); + expect(got_else == 0); } else { got_else += 1; } - assertOrPanic(sum == 45); - assertOrPanic(got_else == 1); + expect(sum == 45); + expect(got_else == 1); } test "while with error union condition" { @@ -112,11 +112,11 @@ test "while with error union condition" { while (getNumberOrErr()) |value| { sum += value; } else |err| { - assertOrPanic(err == error.OutOfNumbers); + expect(err == error.OutOfNumbers); got_else += 1; } - assertOrPanic(sum == 45); - assertOrPanic(got_else == 1); + expect(sum == 45); + expect(got_else == 1); } var numbers_left: i32 = undefined; @@ -138,7 +138,7 @@ test "while on optional with else result follow else prong" { break value; } else i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on optional with else result follow break prong" { @@ -146,7 +146,7 @@ test "while on optional with else result follow break prong" { break value; } else i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "while on error union with else result follow else prong" { @@ -154,7 +154,7 @@ test "while on error union with else result follow else prong" { break value; } else |err| i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on error union with else result follow break prong" { @@ -162,7 +162,7 @@ test "while on error union with else result follow break prong" { break value; } else |err| i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "while on bool with else result follow else prong" { @@ -170,7 +170,7 @@ test "while on bool with else result follow else prong" { break i32(10); } else i32(2); - assertOrPanic(result == 2); + expect(result == 2); } test "while on bool with else result follow break prong" { @@ -178,7 +178,7 @@ test "while on bool with else result follow break prong" { break i32(10); } else i32(2); - assertOrPanic(result == 10); + expect(result == 10); } test "break from outer while loop" { diff --git a/test/stage1/behavior/widening.zig b/test/stage1/behavior/widening.zig index 7577868aff..f7c238ee8d 100644 --- a/test/stage1/behavior/widening.zig +++ b/test/stage1/behavior/widening.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; const mem = std.mem; test "integer widening" { @@ -9,13 +9,13 @@ test "integer widening" { var d: u64 = c; var e: u64 = d; var f: u128 = e; - assertOrPanic(f == a); + expect(f == a); } test "implicit unsigned integer to signed integer" { var a: u8 = 250; var b: i16 = a; - assertOrPanic(b == 250); + expect(b == 250); } test "float widening" { @@ -23,6 +23,6 @@ test "float widening" { var b: f32 = a; var c: f64 = b; var d: f128 = c; - assertOrPanic(d == a); + expect(d == a); } diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 196311a283..4805fc9896 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const assertOrPanic = std.debug.assertOrPanic; +const expect = std.testing.expect; extern fn run_c_tests() void; @@ -33,28 +33,28 @@ test "C ABI integers" { } export fn zig_u8(x: u8) void { - assertOrPanic(x == 0xff); + expect(x == 0xff); } export fn zig_u16(x: u16) void { - assertOrPanic(x == 0xfffe); + expect(x == 0xfffe); } export fn zig_u32(x: u32) void { - assertOrPanic(x == 0xfffffffd); + expect(x == 0xfffffffd); } export fn zig_u64(x: u64) void { - assertOrPanic(x == 0xfffffffffffffffc); + expect(x == 0xfffffffffffffffc); } export fn zig_i8(x: i8) void { - assertOrPanic(x == -1); + expect(x == -1); } export fn zig_i16(x: i16) void { - assertOrPanic(x == -2); + expect(x == -2); } export fn zig_i32(x: i32) void { - assertOrPanic(x == -3); + expect(x == -3); } export fn zig_i64(x: i64) void { - assertOrPanic(x == -4); + expect(x == -4); } extern fn c_f32(f32) void; @@ -66,10 +66,10 @@ test "C ABI floats" { } export fn zig_f32(x: f32) void { - assertOrPanic(x == 12.34); + expect(x == 12.34); } export fn zig_f64(x: f64) void { - assertOrPanic(x == 56.78); + expect(x == 56.78); } extern fn c_ptr(*c_void) void; @@ -79,7 +79,7 @@ test "C ABI pointer" { } export fn zig_ptr(x: *c_void) void { - assertOrPanic(@ptrToInt(x) == 0xdeadbeef); + expect(@ptrToInt(x) == 0xdeadbeef); } extern fn c_bool(bool) void; @@ -89,7 +89,7 @@ test "C ABI bool" { } export fn zig_bool(x: bool) void { - assertOrPanic(x); + expect(x); } extern fn c_array([10]u8) void; @@ -100,7 +100,7 @@ test "C ABI array" { } export fn zig_array(x: [10]u8) void { - assertOrPanic(std.mem.eql(u8, x, "1234567890")); + expect(std.mem.eql(u8, x, "1234567890")); } const BigStruct = extern struct { @@ -124,11 +124,11 @@ test "C ABI big struct" { } export fn zig_big_struct(x: BigStruct) void { - assertOrPanic(x.a == 1); - assertOrPanic(x.b == 2); - assertOrPanic(x.c == 3); - assertOrPanic(x.d == 4); - assertOrPanic(x.e == 5); + expect(x.a == 1); + expect(x.b == 2); + expect(x.c == 3); + expect(x.d == 4); + expect(x.e == 5); } const BigUnion = extern union { @@ -150,11 +150,11 @@ test "C ABI big union" { } export fn zig_big_union(x: BigUnion) void { - assertOrPanic(x.a.a == 1); - assertOrPanic(x.a.b == 2); - assertOrPanic(x.a.c == 3); - assertOrPanic(x.a.d == 4); - assertOrPanic(x.a.e == 5); + expect(x.a.a == 1); + expect(x.a.b == 2); + expect(x.a.c == 3); + expect(x.a.d == 4); + expect(x.a.e == 5); } const SmallStructInts = extern struct { @@ -176,10 +176,10 @@ test "C ABI small struct of ints" { } export fn zig_small_struct_ints(x: SmallStructInts) void { - assertOrPanic(x.a == 1); - assertOrPanic(x.b == 2); - assertOrPanic(x.c == 3); - assertOrPanic(x.d == 4); + expect(x.a == 1); + expect(x.b == 2); + expect(x.c == 3); + expect(x.d == 4); } const SplitStructInt = extern struct { @@ -199,9 +199,9 @@ test "C ABI split struct of ints" { } export fn zig_split_struct_ints(x: SplitStructInt) void { - assertOrPanic(x.a == 1234); - assertOrPanic(x.b == 100); - assertOrPanic(x.c == 1337); + expect(x.a == 1234); + expect(x.b == 100); + expect(x.c == 1337); } extern fn c_big_struct_both(BigStruct) BigStruct; @@ -215,19 +215,19 @@ test "C ABI sret and byval together" { .e = 5, }; var y = c_big_struct_both(s); - assertOrPanic(y.a == 10); - assertOrPanic(y.b == 11); - assertOrPanic(y.c == 12); - assertOrPanic(y.d == 13); - assertOrPanic(y.e == 14); + expect(y.a == 10); + expect(y.b == 11); + expect(y.c == 12); + expect(y.d == 13); + expect(y.e == 14); } export fn zig_big_struct_both(x: BigStruct) BigStruct { - assertOrPanic(x.a == 30); - assertOrPanic(x.b == 31); - assertOrPanic(x.c == 32); - assertOrPanic(x.d == 33); - assertOrPanic(x.e == 34); + expect(x.a == 30); + expect(x.b == 31); + expect(x.c == 32); + expect(x.d == 33); + expect(x.e == 34); var s = BigStruct{ .a = 20, .b = 21, diff --git a/test/standalone/brace_expansion/main.zig b/test/standalone/brace_expansion/main.zig index 52863d5fa4..f5bcd59ecf 100644 --- a/test/standalone/brace_expansion/main.zig +++ b/test/standalone/brace_expansion/main.zig @@ -3,6 +3,7 @@ const io = std.io; const mem = std.mem; const debug = std.debug; const assert = debug.assert; +const testing = std.testing; const Buffer = std.Buffer; const ArrayList = std.ArrayList; const maxInt = std.math.maxInt; @@ -220,11 +221,7 @@ fn expectError(test_input: []const u8, expected_err: anyerror) void { var output_buf = Buffer.initSize(global_allocator, 0) catch unreachable; defer output_buf.deinit(); - if (expandString(test_input, &output_buf)) { - unreachable; - } else |err| { - assert(expected_err == err); - } + testing.expectError(expected_err, expandString(test_input, &output_buf)); } test "valid inputs" { @@ -256,5 +253,5 @@ fn expectExpansion(test_input: []const u8, expected_result: []const u8) void { expandString(test_input, &result) catch unreachable; - assert(mem.eql(u8, result.toSlice(), expected_result)); + testing.expectEqualSlices(u8, expected_result, result.toSlice()); } diff --git a/test/standalone/issue_794/main.zig b/test/standalone/issue_794/main.zig index 356a106418..191bdc9b4f 100644 --- a/test/standalone/issue_794/main.zig +++ b/test/standalone/issue_794/main.zig @@ -1,7 +1,7 @@ const c = @cImport(@cInclude("foo.h")); const std = @import("std"); -const assert = std.debug.assert; +const testing = std.testing; test "c import" { - comptime assert(c.NUMBER == 1234); + comptime testing.expect(c.NUMBER == 1234); } -- cgit v1.2.3 From 46ddd5f5f4db7977010f78129fade7dfa5b9d8d3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Feb 2019 19:23:46 -0500 Subject: fix compiler assertion failure when returning value from test closes #1935 --- src/ir.cpp | 11 +++++++---- test/compile_errors.zig | 7 +++++++ test/tests.zig | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index efda2b321b..d87486bbdd 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11510,10 +11510,13 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio return ir_unreach_error(ira); IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); - if (type_is_invalid(casted_value->value.type) && ira->explicit_return_type_source_node != nullptr) { - ErrorMsg *msg = ira->codegen->errors.last(); - add_error_note(ira->codegen, msg, ira->explicit_return_type_source_node, - buf_sprintf("return type declared here")); + if (type_is_invalid(casted_value->value.type)) { + AstNode *source_node = ira->explicit_return_type_source_node; + if (source_node != nullptr) { + ErrorMsg *msg = ira->codegen->errors.last(); + add_error_note(ira->codegen, msg, source_node, + buf_sprintf("return type declared here")); + } return ir_unreach_error(ira); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index acd1eada06..de01a5ac45 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,13 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "return invalid type from test", + \\test "example" { return 1; } + , + ".tmp_source.zig:1:25: error: integer value 1 cannot be implicitly casted to type 'void'", + ); + cases.add( "threadlocal qualifier on const", \\threadlocal const x: i32 = 1234; diff --git a/test/tests.zig b/test/tests.zig index 670c410509..800ddc1ccd 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -538,6 +538,7 @@ pub const CompileErrorContext = struct { expected_errors: ArrayList([]const u8), link_libc: bool, is_exe: bool, + is_test: bool, const SourceFile = struct { filename: []const u8, @@ -596,7 +597,13 @@ pub const CompileErrorContext = struct { var zig_args = ArrayList([]const u8).init(b.allocator); zig_args.append(b.zig_exe) catch unreachable; - zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj") catch unreachable; + if (self.case.is_exe) { + try zig_args.append("build-exe"); + } else if (self.case.is_test) { + try zig_args.append("test"); + } else { + try zig_args.append("build-obj"); + } zig_args.append(b.pathFromRoot(root_src)) catch unreachable; zig_args.append("--name") catch unreachable; @@ -699,6 +706,7 @@ pub const CompileErrorContext = struct { .expected_errors = ArrayList([]const u8).init(self.b.allocator), .link_libc = false, .is_exe = false, + .is_test = false, }; tc.addSourceFile(".tmp_source.zig", source); @@ -726,6 +734,12 @@ pub const CompileErrorContext = struct { self.addCase(tc); } + pub fn addTest(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) void { + const tc = self.create(name, source, expected_lines); + tc.is_test = true; + self.addCase(tc); + } + pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void { const b = self.b; -- cgit v1.2.3 From caf672c49586f1af5e3d41ae200aded991b8b0f7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Feb 2019 21:10:59 -0500 Subject: `@truncate`: comptime 0 when target type is 0 bits also if the dest type is a comptime_int, then treat it as an implicit cast. also compile error for attempting to truncate undefined closes #1568 --- doc/langref.html.in | 11 +++++++---- src/ir.cpp | 24 ++++++++++++++++-------- test/compile_errors.zig | 11 ++++++++++- test/stage1/behavior/truncate.zig | 23 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 13 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index dfea8e1e04..779eb6a31b 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6381,14 +6381,14 @@ fn List(comptime T: type) type { {#header_close#} {#header_open|@truncate#} -
{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}
+
{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}

This function truncates bits from an integer type, resulting in a smaller integer type.

- The following produces a crash in debug mode and undefined behavior in - release mode: + The following produces a crash in {#link|Debug#} mode and {#link|Undefined Behavior#} in + {#link|ReleaseFast#} mode:

{#syntax#}const a: u16 = 0xabcd;
 const b: u8 = u8(a);{#endsyntax#}
@@ -6402,7 +6402,10 @@ const b: u8 = @truncate(u8, a); This function always truncates the significant bits of the integer, regardless of endianness on the target platform.

- +

+ If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#}, + then this is semantically equivalent to an {#link|implicit cast|Implicit Casts#}. +

{#header_close#} {#header_open|@typeId#} diff --git a/src/ir.cpp b/src/ir.cpp index d87486bbdd..5d4013b4b9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18491,7 +18491,22 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (src_type->data.integral.bit_count == 0) { + if (dest_type->id == ZigTypeIdComptimeInt) { + return ir_implicit_cast(ira, target, dest_type); + } + + if (instr_is_comptime(target)) { + ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_instruction; + + IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint, + dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); + return result; + } + + if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) { IrInstruction *result = ir_const(ira, &instruction->base, dest_type); bigint_init_unsigned(&result->value.data.x_bigint, 0); return result; @@ -18507,13 +18522,6 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - if (target->value.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - bigint_truncate(&result->value.data.x_bigint, &target->value.data.x_bigint, - dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); - return result; - } - IrInstruction *new_instruction = ir_build_truncate(&ira->new_irb, instruction->base.scope, instruction->base.source_node, dest_type_value, target); new_instruction->value.type = dest_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index de01a5ac45..b47cdf2ed1 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,15 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "@truncate undefined value", + \\export fn entry() void { + \\ var z = @truncate(u8, u16(undefined)); + \\} + , + ".tmp_source.zig:2:30: error: use of undefined value", + ); + cases.addTest( "return invalid type from test", \\test "example" { return 1; } @@ -3335,7 +3344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "truncate sign mismatch", \\fn f() i8 { - \\ const x: u32 = 10; + \\ var x: u32 = 10; \\ return @truncate(i8, x); \\} \\ diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig index c195b64cbf..568346369f 100644 --- a/test/stage1/behavior/truncate.zig +++ b/test/stage1/behavior/truncate.zig @@ -6,3 +6,26 @@ test "truncate u0 to larger integer allowed and has comptime known result" { const y = @truncate(u8, x); comptime expect(y == 0); } + +test "truncate.u0.literal" { + var z = @truncate(u0, 0); + expect(z == 0); +} + +test "truncate.u0.const" { + const c0: usize = 0; + var z = @truncate(u0, c0); + expect(z == 0); +} + +test "truncate.u0.var" { + var d: u8 = 2; + var z = @truncate(u0, d); + expect(z == 0); +} + +test "truncate sign mismatch but comptime known so it works anyway" { + const x: u32 = 10; + var result = @truncate(i8, x); + expect(result == 10); +} -- cgit v1.2.3 From b8cbe3872e702ab8ec388e75cb711330a45825b0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 00:14:30 -0500 Subject: added C pointer type and implicit int-to-ptr for this type See #1059 --- src/all_types.hpp | 1 + src/analyze.cpp | 14 ++- src/ir.cpp | 236 ++++++++++++++++++++++++++------------ src/parser.cpp | 8 ++ src/tokenizer.cpp | 19 ++- src/tokenizer.hpp | 1 + test/stage1/behavior/pointers.zig | 6 + 7 files changed, 210 insertions(+), 75 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 908c0e327c..fd66b77ad2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1038,6 +1038,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); enum PtrLen { PtrLenUnknown, PtrLenSingle, + PtrLenC, }; struct ZigTypePointer { diff --git a/src/analyze.cpp b/src/analyze.cpp index 970d1cc382..e561050e0d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -417,6 +417,18 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { return entry; } +static const char *ptr_len_to_star_str(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return "*"; + case PtrLenUnknown: + return "[*]"; + case PtrLenC: + return "[*c]"; + } + zig_unreachable(); +} + ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) @@ -466,7 +478,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]"; + const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; buf_resize(&entry->name, 0); diff --git a/src/ir.cpp b/src/ir.cpp index 5d4013b4b9..76277f541b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -169,6 +169,10 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); +static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, + ZigType *ptr_type); +static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *dest_type); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -5019,10 +5023,23 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction * return ir_build_ref(irb, scope, value->source_node, value, false, false); } +static PtrLen star_token_to_ptr_len(TokenId token_id) { + switch (token_id) { + case TokenIdStar: + case TokenIdStarStar: + return PtrLenSingle; + case TokenIdBracketStarBracket: + return PtrLenUnknown; + case TokenIdBracketStarCBracket: + return PtrLenC; + default: + zig_unreachable(); + } +} + static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypePointerType); - PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar || - node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown; + PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id); bool is_const = node->data.pointer_type.is_const; bool is_volatile = node->data.pointer_type.is_volatile; AstNode *expr_node = node->data.pointer_type.op_expr; @@ -8538,6 +8555,20 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } } } + if (other_type->id == ZigTypeIdPointer && other_type->data.pointer.ptr_len == PtrLenC && const_val_is_int) { + if (!bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, true) && + !bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, false)) + { + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); + + ir_add_error(ira, instruction, + buf_sprintf("integer value %s outside of pointer address range", + buf_ptr(val_buf))); + return false; + } + return true; + } const char *num_lit_str; Buf *val_buf = buf_alloc(); @@ -10811,6 +10842,37 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * return ir_build_vector_to_array(ira, source_instr, vector, array_type); } +static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *integer, ZigType *dest_type) +{ + IrInstruction *unsigned_integer; + if (instr_is_comptime(integer)) { + unsigned_integer = integer; + } else { + assert(integer->value.type->id == ZigTypeIdInt); + + if (integer->value.type->data.integral.bit_count > + ira->codegen->builtin_types.entry_usize->data.integral.bit_count) + { + ir_add_error(ira, source_instr, + buf_sprintf("integer type too big for implicit @intToPtr to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (integer->value.type->data.integral.is_signed) { + ZigType *unsigned_int_type = get_int_type(ira->codegen, false, + integer->value.type->data.integral.bit_count); + unsigned_integer = ir_analyze_bit_cast(ira, source_instr, integer, unsigned_int_type); + if (type_is_invalid(unsigned_integer->value.type)) + return ira->codegen->invalid_instruction; + } else { + unsigned_integer = integer; + } + } + + return ir_analyze_int_to_ptr(ira, source_instr, unsigned_integer, dest_type); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, ZigType *wanted_type, IrInstruction *value) { @@ -11217,6 +11279,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); } + // casting to C pointers + if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC) { + // cast from integer to C pointer + if (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt) { + return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); + } + } + // cast from undefined to anything if (actual_type->id == ZigTypeIdUndefined) { return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); @@ -20674,32 +20744,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_unreachable(); } -static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { - Error err; - IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_instruction; - - IrInstruction *value = instruction->value->child; - ZigType *src_type = value->value.type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_instruction; - - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - - if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - - if (get_codegen_ptr_type(src_type) != nullptr) { - ir_add_error(ira, value, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - switch (src_type->id) { +static bool type_can_bit_cast(ZigType *t) { + switch (t->id) { case ZigTypeIdInvalid: + zig_unreachable(); case ZigTypeIdMetaType: case ZigTypeIdOpaque: case ZigTypeIdBoundFn: @@ -20710,42 +20758,36 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct case ZigTypeIdComptimeInt: case ZigTypeIdUndefined: case ZigTypeIdNull: - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; + case ZigTypeIdPointer: + return false; default: - break; + // TODO list these types out explicitly, there are probably some other invalid ones here + return true; } +} - if (get_codegen_ptr_type(dest_type) != nullptr) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); +static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *dest_type) +{ + Error err; + + ZigType *src_type = value->value.type; + assert(get_codegen_ptr_type(src_type) == nullptr); + assert(type_can_bit_cast(src_type)); + assert(get_codegen_ptr_type(dest_type) == nullptr); + assert(type_can_bit_cast(dest_type)); + + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_instruction; + + if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - } - switch (dest_type->id) { - case ZigTypeIdInvalid: - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdNamespace: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - default: - break; - } uint64_t dest_size_bytes = type_size(ira->codegen, dest_type); uint64_t src_size_bytes = type_size(ira->codegen, src_type); if (dest_size_bytes != src_size_bytes) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64, buf_ptr(&dest_type->name), dest_size_bytes, buf_ptr(&src_type->name), src_size_bytes)); @@ -20755,7 +20797,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type); uint64_t src_size_bits = type_size_bits(ira->codegen, src_type); if (dest_size_bits != src_size_bits) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits", buf_ptr(&dest_type->name), dest_size_bits, buf_ptr(&src_type->name), src_size_bits)); @@ -20767,44 +20809,63 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + IrInstruction *result = ir_const(ira, source_instr, dest_type); uint8_t *buf = allocate_nonzero(src_size_bytes); buf_write_value_bytes(ira->codegen, buf, val); - if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value))) + if ((err = buf_read_value_bytes(ira, ira->codegen, source_instr->source_node, buf, &result->value))) return ira->codegen->invalid_instruction; return result; } - IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, nullptr, value); + IrInstruction *result = ir_build_bit_cast(&ira->new_irb, source_instr->scope, + source_instr->source_node, nullptr, value); result->value.type = dest_type; return result; } -static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { - Error err; +static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { IrInstruction *dest_type_value = instruction->dest_type->child; ZigType *dest_type = ir_resolve_type(ira, dest_type_value); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - // We explicitly check for the size, so we can use get_src_ptr_type - if (get_src_ptr_type(dest_type) == nullptr) { - ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + IrInstruction *value = instruction->value->child; + ZigType *src_type = value->value.type; + if (type_is_invalid(src_type)) + return ira->codegen->invalid_instruction; + + if (get_codegen_ptr_type(src_type) != nullptr) { + ir_add_error(ira, value, + buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } - if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) + if (!type_can_bit_cast(src_type)) { + ir_add_error(ira, dest_type_value, + buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; - if (!type_has_bits(dest_type)) { + } + + if (get_codegen_ptr_type(dest_type) != nullptr) { ir_add_error(ira, dest_type_value, - buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); + buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } - IrInstruction *target = instruction->target->child; - if (type_is_invalid(target->value.type)) + if (!type_can_bit_cast(dest_type)) { + ir_add_error(ira, dest_type_value, + buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; + } + + return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type); +} + +static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, + ZigType *ptr_type) +{ + assert(get_src_ptr_type(ptr_type) != nullptr); + assert(type_has_bits(ptr_type)); IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize); if (type_is_invalid(casted_int->value.type)) @@ -20815,19 +20876,48 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru if (!val) return ira->codegen->invalid_instruction; - IrInstruction *result = ir_const(ira, &instruction->base, dest_type); + IrInstruction *result = ir_const(ira, source_instr, ptr_type); result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint); return result; } - IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, nullptr, casted_int); - result->value.type = dest_type; + IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, nullptr, casted_int); + result->value.type = ptr_type; return result; } +static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { + Error err; + IrInstruction *dest_type_value = instruction->dest_type->child; + ZigType *dest_type = ir_resolve_type(ira, dest_type_value); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + // We explicitly check for the size, so we can use get_src_ptr_type + if (get_src_ptr_type(dest_type) == nullptr) { + ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + if (!type_has_bits(dest_type)) { + ir_add_error(ira, dest_type_value, + buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + + IrInstruction *target = instruction->target->child; + if (type_is_invalid(target->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_int_to_ptr(ira, &instruction->base, target, dest_type); +} + static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { diff --git a/src/parser.cpp b/src/parser.cpp index 1c1af87c51..160a7268b0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2779,6 +2779,7 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { // <- ASTERISK // / ASTERISK2 // / LBRACKET ASTERISK RBRACKET +// / LBRACKET ASTERISK C RBRACKET static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { Token *asterisk = eat_token_if(pc, TokenIdStar); if (asterisk != nullptr) { @@ -2804,6 +2805,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { return res; } + Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket); + if (cptr != nullptr) { + AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr); + res->data.pointer_type.star_token = cptr; + return res; + } + return nullptr; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 3acd605748..9ff6ed3bbe 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -221,6 +221,7 @@ enum TokenizeState { TokenizeStateError, TokenizeStateLBracket, TokenizeStateLBracketStar, + TokenizeStateLBracketStarC, }; @@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case '*': t.state = TokenizeStateLBracketStar; - set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket); break; default: // reinterpret as just an lbracket @@ -857,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) { } break; case TokenizeStateLBracketStar: + switch (c) { + case 'c': + t.state = TokenizeStateLBracketStarC; + set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket); + break; + case ']': + set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket); + end_token(&t); + t.state = TokenizeStateStart; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeStateLBracketStarC: switch (c) { case ']': end_token(&t); @@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateLineStringContinue: case TokenizeStateLineStringContinueC: case TokenizeStateLBracketStar: + case TokenizeStateLBracketStarC: tokenize_error(&t, "unexpected EOF"); break; case TokenizeStateLineComment: @@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) { case TokenIdBitShiftRightEq: return ">>="; case TokenIdBitXorEq: return "^="; case TokenIdBracketStarBracket: return "[*]"; + case TokenIdBracketStarCBracket: return "[*c]"; case TokenIdCharLiteral: return "CharLiteral"; case TokenIdCmpEq: return "=="; case TokenIdCmpGreaterOrEq: return ">="; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 17f36699b3..62117b5779 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -29,6 +29,7 @@ enum TokenId { TokenIdBitShiftRightEq, TokenIdBitXorEq, TokenIdBracketStarBracket, + TokenIdBracketStarCBracket, TokenIdCharLiteral, TokenIdCmpEq, TokenIdCmpGreaterOrEq, diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 47b19700ee..6969e151df 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -42,3 +42,9 @@ test "double pointer parsing" { fn PtrOf(comptime T: type) type { return *T; } + +test "assigning integer to C pointer" { + var x: i32 = 0; + var ptr: [*c]u8 = 0; + var ptr2: [*c]u8 = x; +} -- cgit v1.2.3 From 73e8e46257ac8f34e941a357a860d19e0d38dbac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Feb 2019 01:11:30 -0500 Subject: casting between C pointers and normal pointers See #1059 --- src/ir.cpp | 41 ++++++++++++++++++++++++--------------- test/stage1/behavior/pointers.zig | 8 ++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 76277f541b..30350d75de 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2462,7 +2462,7 @@ static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode * ir_ref_instruction(type_value, irb->current_basic_block); - return &instruction->base; + return &instruction->base; } static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node, @@ -6739,7 +6739,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode atomic_state_field_name); // set the is_canceled bit - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, is_canceled_mask, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); @@ -6817,7 +6817,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode atomic_state_field_name); // clear the is_suspended bit - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr, AtomicRmwOp_and, AtomicOrderSeqCst); @@ -6933,7 +6933,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle); IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false); - IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); @@ -6976,7 +6976,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block); - IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false); @@ -7008,7 +7008,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, cleanup_block); IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false); - IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, + IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr, AtomicRmwOp_or, AtomicOrderSeqCst); IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false); @@ -11279,12 +11279,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type); } - // casting to C pointers - if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC) { - // cast from integer to C pointer - if (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt) { - return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); - } + // casting between C pointers and normal pointers + if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer && + (wanted_type->data.pointer.ptr_len == PtrLenC || actual_type->data.pointer.ptr_len == PtrLenC) && + types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + actual_type->data.pointer.child_type, source_node, + !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + } + + // cast from integer to C pointer + if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC && + (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt)) + { + return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type); } // cast from undefined to anything @@ -16436,7 +16445,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, pointee_val = const_ptr_pointee(ira, ira->codegen, &target_value_ptr->value, target_value_ptr->source_node); if (pointee_val == nullptr) return ira->codegen->invalid_instruction; - + if (pointee_val->special == ConstValSpecialRuntime) pointee_val = nullptr; } @@ -17186,7 +17195,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, static TypeStructField *validate_byte_offset(IrAnalyze *ira, IrInstruction *type_value, IrInstruction *field_name_value, - size_t *byte_offset) + size_t *byte_offset) { ZigType *container_type = ir_resolve_type(ira, type_value); if (type_is_invalid(container_type)) @@ -17360,7 +17369,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco // Loop through the definitions and generate info. decl_it = decls_scope->decl_table.entry_iterator(); - curr_entry = nullptr; + curr_entry = nullptr; int definition_index = 0; while ((curr_entry = decl_it.next()) != nullptr) { // Skip comptime blocks and test functions. @@ -20312,7 +20321,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, } else { seenFalse += 1; } - + if ((seenTrue > 1) || (seenFalse > 1)) { ir_add_error(ira, value, buf_sprintf("duplicate switch value")); return ira->codegen->invalid_instruction; diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 6969e151df..79832bc316 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -48,3 +48,11 @@ test "assigning integer to C pointer" { var ptr: [*c]u8 = 0; var ptr2: [*c]u8 = x; } + +test "implicit cast single item pointer to C pointer and back" { + var y: u8 = 11; + var x: [*c]u8 = &y; + var z: *u8 = x; + z.* += 1; + expect(y == 12); +} -- cgit v1.2.3 From 342bca7f4627454435e9f6c2d12b099f95a2fd47 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 15:31:09 -0500 Subject: C pointer comparison and arithmetic See #1059 --- src/analyze.cpp | 2 +- src/codegen.cpp | 4 ++-- src/ir.cpp | 46 ++++++++++++++++++++++++++++++++++----- src/translate_c.cpp | 8 ++++--- test/stage1/behavior/pointers.zig | 20 +++++++++++++++++ test/translate_c.zig | 18 +++++++-------- 6 files changed, 78 insertions(+), 20 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 691579200e..af6200cc82 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -434,7 +434,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint32_t bit_offset_in_host, uint32_t host_int_bytes) { assert(!type_is_invalid(child_type)); - assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); + assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); if (byte_alignment != 0) { uint32_t abi_alignment = get_abi_alignment(g, child_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4868576b49..605ea59b06 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2657,7 +2657,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) || (op1->value.type->id == ZigTypeIdPointer && (op_id == IrBinOpAdd || op_id == IrBinOpSub) && - op1->value.type->data.pointer.ptr_len == PtrLenUnknown) + op1->value.type->data.pointer.ptr_len != PtrLenSingle) ); ZigType *operand_type = op1->value.type; ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; @@ -2716,7 +2716,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, AddSubMulMul; if (scalar_type->id == ZigTypeIdPointer) { - assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown); + assert(scalar_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef subscript_value; if (operand_type->id == ZigTypeIdVector) zig_panic("TODO: Implement vector operations on pointers."); diff --git a/src/ir.cpp b/src/ir.cpp index 30350d75de..bc37ac9b54 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8943,7 +8943,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t * *errors = reallocate(*errors, old_errors_count, *errors_count); } -static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) { +static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, + IrInstruction **instructions, size_t instruction_count) +{ Error err; assert(instruction_count >= 1); IrInstruction *prev_inst = instructions[0]; @@ -9260,6 +9262,19 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT continue; } + if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC && + (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt)) + { + continue; + } + + if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC && + (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt)) + { + prev_inst = cur_inst; + continue; + } + if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { continue; } @@ -11852,7 +11867,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdBool: case ZigTypeIdMetaType: case ZigTypeIdVoid: - case ZigTypeIdPointer: case ZigTypeIdErrorSet: case ZigTypeIdFn: case ZigTypeIdOpaque: @@ -11864,6 +11878,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * operator_allowed = is_equality_cmp; break; + case ZigTypeIdPointer: + operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); + break; + case ZigTypeIdUnreachable: case ZigTypeIdArray: case ZigTypeIdStruct: @@ -12324,6 +12342,26 @@ static bool ok_float_op(IrBinOp op) { zig_unreachable(); } +static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { + if (lhs_type->id != ZigTypeIdPointer) + return false; + switch (op) { + case IrBinOpAdd: + case IrBinOpSub: + break; + default: + return false; + } + switch (lhs_type->data.pointer.ptr_len) { + case PtrLenSingle: + return false; + case PtrLenUnknown: + case PtrLenC: + break; + } + return true; +} + static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) @@ -12336,9 +12374,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp IrBinOp op_id = instruction->op_id; // look for pointer math - if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown && - (op_id == IrBinOpAdd || op_id == IrBinOpSub)) - { + if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); if (casted_op2 == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index b06a28d12d..63f04dae6c 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1677,7 +1677,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im return node; } case CK_NullToPointer: - return trans_create_node(c, NodeTypeNullLiteral); + return trans_create_node_unsigned(c, 0); case CK_Dependent: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); return nullptr; @@ -2409,7 +2409,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * case BuiltinType::Float16: return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); case BuiltinType::NullPtr: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); + return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, + trans_create_node_unsigned(c, 0)); case BuiltinType::Void: case BuiltinType::Half: @@ -2494,7 +2495,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope * break; } case Type::Pointer: - return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral)); + return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, + trans_create_node_unsigned(c, 0)); case Type::Typedef: { diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 79832bc316..63e4c314b1 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -56,3 +56,23 @@ test "implicit cast single item pointer to C pointer and back" { z.* += 1; expect(y == 12); } + +test "C pointer comparison and arithmetic" { + var one: usize = 1; + var ptr1: [*c]u8 = 0; + var ptr2 = ptr1 + 10; + expect(ptr1 == 0); + expect(ptr1 >= 0); + expect(ptr1 <= 0); + expect(ptr1 < 1); + expect(ptr1 < one); + expect(1 > ptr1); + expect(one > ptr1); + expect(ptr1 < ptr2); + expect(ptr2 > ptr1); + expect(ptr2 >= 10); + expect(ptr2 == 10); + expect(ptr2 <= 10); + ptr2 -= 10; + expect(ptr1 == ptr2); +} diff --git a/test/translate_c.zig b/test/translate_c.zig index 746fa60b18..b87b962edc 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; - \\ if ((b != 0) and (c != null)) return 1; - \\ if ((a != 0) and (c != null)) return 2; + \\ if ((b != 0) and (c != 0)) return 1; + \\ if ((a != 0) and (c != 0)) return 2; \\ if ((a != 0) or (b != 0)) return 3; - \\ if ((b != 0) or (c != null)) return 4; - \\ if ((a != 0) or (c != null)) return 5; + \\ if ((b != 0) or (c != 0)) return 4; + \\ if ((a != 0) or (c != 0)) return 5; \\ return 6; \\} ); @@ -778,7 +778,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub export fn foo() [*c]c_int { - \\ return null; + \\ return 0; \\} ); @@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); - \\ return !(c != null); + \\ return !(c != 0); \\} ); @@ -1337,7 +1337,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; - \\ if (c != null) return 2; + \\ if (c != 0) return 2; \\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3; \\ return 4; \\} @@ -1354,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != null) return 2; + \\ while (c != 0) return 2; \\ return 3; \\} ); @@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; - \\ while (c != null) return 2; + \\ while (c != 0) return 2; \\ return 3; \\} ); -- cgit v1.2.3 From 90b8cd4a45bcb2ca131b6ed6466f799aaa162d13 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 16:07:40 -0500 Subject: add C pointer type to @typeInfo See #1059 --- src-self-hosted/type.zig | 2 ++ src/codegen.cpp | 1 + src/ir.cpp | 14 +++++++++++++- std/fmt/index.zig | 3 +++ std/meta/index.zig | 9 ++++++--- std/testing.zig | 3 +-- test/stage1/behavior/type_info.zig | 15 +++++++++++++++ 7 files changed, 41 insertions(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 8a05594b30..790b51b7be 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -794,6 +794,7 @@ pub const Type = struct { Size.One => "*", Size.Many => "[*]", Size.Slice => "[]", + Size.C => "[*c]", }; const mut_str = switch (self.key.mut) { Mut.Const => "const ", @@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 { builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed), builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"), builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"), + builtin.TypeInfo.Pointer.Size.C => unreachable, } }, builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed), diff --git a/src/codegen.cpp b/src/codegen.cpp index 605ea59b06..142e8174f5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7309,6 +7309,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " One,\n" " Many,\n" " Slice,\n" + " C,\n" " };\n" " };\n" "\n" diff --git a/src/ir.cpp b/src/ir.cpp index bc37ac9b54..36ea50ed52 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17584,6 +17584,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco return ErrorNone; } +static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return 0; + case PtrLenUnknown: + return 1; + case PtrLenC: + return 3; + } + zig_unreachable(); +} + static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) { Error err; ZigType *attrs_type; @@ -17593,7 +17605,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty size_enum_index = 2; } else if (ptr_type_entry->id == ZigTypeIdPointer) { attrs_type = ptr_type_entry; - size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1; + size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len); } else { zig_unreachable(); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 05b028112f..b09fe21032 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -236,6 +236,9 @@ pub fn formatType( const casted_value = ([]const u8)(value); return output(context, casted_value); }, + builtin.TypeInfo.Pointer.Size.C => { + return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)); + }, }, builtin.TypeId.Array => |info| { if (info.child == u8) { diff --git a/std/meta/index.zig b/std/meta/index.zig index 3f8ea762a6..652e2d39ec 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Pointer => { const info = @typeInfo(T).Pointer; switch (info.size) { - builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b, + builtin.TypeInfo.Pointer.Size.One, + builtin.TypeInfo.Pointer.Size.Many, + builtin.TypeInfo.Pointer.Size.C, + => return a == b, builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len, } }, builtin.TypeId.Optional => { - if(a == null and b == null) return true; - if(a == null or b == null) return false; + if (a == null and b == null) return true; + if (a == null or b == null) return false; return eql(a.?, b.?); }, else => return a == b, diff --git a/std/testing.zig b/std/testing.zig index ade6e8b0dd..f3ce69659d 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -69,7 +69,7 @@ pub fn expectEqual(expected: var, actual: var) void { } }, - builtin.TypeInfo.Pointer.Size.Slice => { + builtin.TypeInfo.Pointer.Size.Slice => { if (actual.ptr != expected.ptr) { std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr); } @@ -122,7 +122,6 @@ pub fn expectEqual(expected: var, actual: var) void { } } }, - } } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index ce0ad795b4..dc185cc960 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -61,6 +61,21 @@ fn testUnknownLenPtr() void { expect(u32_ptr_info.Pointer.child == f64); } +test "type info: C pointer type info" { + testCPtr(); + comptime testCPtr(); +} + +fn testCPtr() void { + const ptr_info = @typeInfo([*c]align(4) const i8); + expect(TypeId(ptr_info) == TypeId.Pointer); + expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); + expect(ptr_info.Pointer.is_const); + expect(!ptr_info.Pointer.is_volatile); + expect(ptr_info.Pointer.alignment == 4); + expect(ptr_info.Pointer.child == i8); +} + test "type info: slice type info" { testSlice(); comptime testSlice(); -- cgit v1.2.3 From 57a7ab0d330416f15c0288004b67101c1c3e9629 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 19:12:01 -0500 Subject: comptime support for pointer arithmetic with hard coded addresses --- src/ir.cpp | 109 ++++++++++++++++++++++++++++++-------- test/stage1/behavior/pointers.zig | 40 ++++++++------ 2 files changed, 109 insertions(+), 40 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 36ea50ed52..5ec397b0b2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11682,28 +11682,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp } static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { - if (op_id == IrBinOpCmpEq) { - return cmp == CmpEQ; - } else if (op_id == IrBinOpCmpNotEq) { - return cmp != CmpEQ; - } else if (op_id == IrBinOpCmpLessThan) { - return cmp == CmpLT; - } else if (op_id == IrBinOpCmpGreaterThan) { - return cmp == CmpGT; - } else if (op_id == IrBinOpCmpLessOrEq) { - return cmp != CmpGT; - } else if (op_id == IrBinOpCmpGreaterOrEq) { - return cmp != CmpLT; - } else { - zig_unreachable(); + switch (op_id) { + case IrBinOpCmpEq: + return cmp == CmpEQ; + case IrBinOpCmpNotEq: + return cmp != CmpEQ; + case IrBinOpCmpLessThan: + return cmp == CmpLT; + case IrBinOpCmpGreaterThan: + return cmp == CmpGT; + case IrBinOpCmpLessOrEq: + return cmp != CmpGT; + case IrBinOpCmpGreaterOrEq: + return cmp != CmpLT; + default: + zig_unreachable(); } } static bool optional_value_is_null(ConstExprValue *val) { assert(val->special == ConstValSpecialStatic); if (get_codegen_ptr_type(val->type) != nullptr) { - return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && - val->data.x_ptr.data.hard_coded_addr.addr == 0; + if (val->data.x_ptr.special == ConstPtrSpecialNull) { + return true; + } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { + return val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else { + return false; + } } else if (is_opt_err_set(val->type)) { return val->data.x_err_set == nullptr; } else { @@ -11879,7 +11885,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * break; case ZigTypeIdPointer: - operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len != PtrLenSingle); + operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC); break; case ZigTypeIdUnreachable: @@ -11929,15 +11935,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * if (op2_val == nullptr) return ira->codegen->invalid_instruction; - bool answer; if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { Cmp cmp_result = float_cmp(op1_val, op2_val); - answer = resolve_cmp_op_id(op_id, cmp_result); + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) { Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); - answer = resolve_cmp_op_id(op_id, cmp_result); + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); + } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { + if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op1_val->data.x_ptr.special == ConstPtrSpecialNull) && + (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op2_val->data.x_ptr.special == ConstPtrSpecialNull)) + { + uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? + 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; + uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? + 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; + Cmp cmp_result; + if (op1_addr > op2_addr) { + cmp_result = CmpGT; + } else if (op1_addr < op2_addr) { + cmp_result = CmpLT; + } else { + cmp_result = CmpEQ; + } + bool answer = resolve_cmp_op_id(op_id, cmp_result); + return ir_const_bool(ira, &bin_op_instruction->base, answer); + } } else { bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); + bool answer; if (op_id == IrBinOpCmpEq) { answer = are_equal; } else if (op_id == IrBinOpCmpNotEq) { @@ -11945,9 +11974,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * } else { zig_unreachable(); } + return ir_const_bool(ira, &bin_op_instruction->base, answer); } - - return ir_const_bool(ira, &bin_op_instruction->base, answer); } // some comparisons with unsigned numbers can be evaluated @@ -12363,6 +12391,8 @@ static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { } static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { + Error err; + IrInstruction *op1 = instruction->op1->child; if (type_is_invalid(op1->value.type)) return ira->codegen->invalid_instruction; @@ -12376,9 +12406,42 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp // look for pointer math if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) { IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize); - if (casted_op2 == ira->codegen->invalid_instruction) + if (type_is_invalid(casted_op2->value.type)) return ira->codegen->invalid_instruction; + if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { + IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); + result->value.special = ConstValSpecialUndef; + return result; + } + if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic && + (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || + op1->value.data.x_ptr.special == ConstPtrSpecialNull)) + { + uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? + 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; + uint64_t elem_offset; + if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) + return ira->codegen->invalid_instruction; + ZigType *elem_type = op1->value.type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return ira->codegen->invalid_instruction; + uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; + uint64_t new_addr; + if (op_id == IrBinOpAdd) { + new_addr = start_addr + byte_offset; + } else if (op_id == IrBinOpSub) { + new_addr = start_addr - byte_offset; + } else { + zig_unreachable(); + } + IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); + result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; + result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; + return result; + } + IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope, instruction->base.source_node, op_id, op1, casted_op2, true); result->value.type = op1->value.type; diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 63e4c314b1..4375a6971f 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -58,21 +58,27 @@ test "implicit cast single item pointer to C pointer and back" { } test "C pointer comparison and arithmetic" { - var one: usize = 1; - var ptr1: [*c]u8 = 0; - var ptr2 = ptr1 + 10; - expect(ptr1 == 0); - expect(ptr1 >= 0); - expect(ptr1 <= 0); - expect(ptr1 < 1); - expect(ptr1 < one); - expect(1 > ptr1); - expect(one > ptr1); - expect(ptr1 < ptr2); - expect(ptr2 > ptr1); - expect(ptr2 >= 10); - expect(ptr2 == 10); - expect(ptr2 <= 10); - ptr2 -= 10; - expect(ptr1 == ptr2); + const S = struct { + fn doTheTest() void { + var one: usize = 1; + var ptr1: [*c]u32 = 0; + var ptr2 = ptr1 + 10; + expect(ptr1 == 0); + expect(ptr1 >= 0); + expect(ptr1 <= 0); + expect(ptr1 < 1); + expect(ptr1 < one); + expect(1 > ptr1); + expect(one > ptr1); + expect(ptr1 < ptr2); + expect(ptr2 > ptr1); + expect(ptr2 >= 40); + expect(ptr2 == 40); + expect(ptr2 <= 40); + ptr2 -= 10; + expect(ptr1 == ptr2); + } + }; + S.doTheTest(); + comptime S.doTheTest(); } -- cgit v1.2.3 From 069fc1a26990b3946cf788b4ebe5edefca5a3bfd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Feb 2019 19:21:59 -0500 Subject: peer type resolution with C pointers See #1059 --- src/ir.cpp | 18 ++++++++++++++++++ test/stage1/behavior/pointers.zig | 15 +++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 5ec397b0b2..91c8503234 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9275,6 +9275,24 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT continue; } + if (prev_type->id == ZigTypeIdPointer && cur_type->id == ZigTypeIdPointer) { + if (prev_type->data.pointer.ptr_len == PtrLenC && + types_match_const_cast_only(ira, prev_type->data.pointer.child_type, + cur_type->data.pointer.child_type, source_node, + !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + continue; + } + if (cur_type->data.pointer.ptr_len == PtrLenC && + types_match_const_cast_only(ira, cur_type->data.pointer.child_type, + prev_type->data.pointer.child_type, source_node, + !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + prev_inst = cur_inst; + continue; + } + } + if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) { continue; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 4375a6971f..3f62bd1cec 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -82,3 +82,18 @@ test "C pointer comparison and arithmetic" { S.doTheTest(); comptime S.doTheTest(); } + +test "peer type resolution with C pointers" { + var ptr_one: *u8 = undefined; + var ptr_many: [*]u8 = undefined; + var ptr_c: [*c]u8 = undefined; + var t = true; + var x1 = if (t) ptr_one else ptr_c; + var x2 = if (t) ptr_many else ptr_c; + var x3 = if (t) ptr_c else ptr_one; + var x4 = if (t) ptr_c else ptr_many; + expect(@typeOf(x1) == [*c]u8); + expect(@typeOf(x2) == [*c]u8); + expect(@typeOf(x3) == [*c]u8); + expect(@typeOf(x4) == [*c]u8); +} -- cgit v1.2.3 From 0abe6d668eb52aefa59c75a8d8f782f2372f8600 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 00:39:08 -0500 Subject: C pointers: delete dead code in ir_num_lit_fits_in_other_type --- src/ir.cpp | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 91c8503234..1f0edc910d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8555,20 +8555,6 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } } } - if (other_type->id == ZigTypeIdPointer && other_type->data.pointer.ptr_len == PtrLenC && const_val_is_int) { - if (!bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, true) && - !bigint_fits_in_bits(&const_val->data.x_bigint, ira->codegen->pointer_size_bytes * 8, false)) - { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &const_val->data.x_bigint, 10); - - ir_add_error(ira, instruction, - buf_sprintf("integer value %s outside of pointer address range", - buf_ptr(val_buf))); - return false; - } - return true; - } const char *num_lit_str; Buf *val_buf = buf_alloc(); -- cgit v1.2.3 From 285e2f62ba0648d6d8e7ff64d1ee7d2900481e2f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 00:51:06 -0500 Subject: disallow C pointers to non-C-ABI-compatible element types See #1059 --- src/analyze.cpp | 2 +- src/analyze.hpp | 2 +- src/ir.cpp | 4 ++++ test/compile_errors.zig | 10 ++++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index af6200cc82..ab2afba561 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1469,7 +1469,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { zig_unreachable(); } -static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { +bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); diff --git a/src/analyze.hpp b/src/analyze.hpp index 1e4f2f2ce7..c8141b02ff 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -44,7 +44,7 @@ void find_libc_include_path(CodeGen *g); void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); - +bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/ir.cpp b/src/ir.cpp index 1f0edc910d..64e08ef7ea 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21145,6 +21145,10 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); return ira->codegen->invalid_instruction; + } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; } uint32_t align_bytes; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index b47cdf2ed1..63850bb888 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "C pointer pointing to non C ABI compatible type", + \\const Foo = struct {}; + \\export fn entry() [*c]Foo { + \\ return undefined; + \\} + , + ".tmp_source.zig:2:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ); + cases.addTest( "@truncate undefined value", \\export fn entry() void { -- cgit v1.2.3 From 6f05e8d1be083a429673e717e8b3c736c7ddb8d2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 01:38:11 -0500 Subject: implicit casting between C pointer and optional non-C pointer See #1059 --- src/ir.cpp | 34 +++++++++++++++++++++------------- test/stage1/behavior/pointers.zig | 10 ++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 64e08ef7ea..00d82c9224 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8669,33 +8669,41 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } // pointer const - if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) { - ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const); + ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); + ZigType *actual_ptr_type = get_src_ptr_type(actual_type); + bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; + bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; + if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) || + (wanted_ptr_type != nullptr && actual_is_c_ptr) || + (actual_ptr_type != nullptr && wanted_is_c_ptr)) + { + ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, + actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) return child; if (child.id != ConstCastResultIdOk) { result.id = ConstCastResultIdPointerChild; result.data.pointer_mismatch = allocate_nonzero(1); result.data.pointer_mismatch->child = child; - result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type; - result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type; + result.data.pointer_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type; + result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; return result; } - if ((err = type_resolve(g, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; } - if ((err = type_resolve(g, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { + if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; } - if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) && - (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && - (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) && - actual_type->data.pointer.bit_offset_in_host == wanted_type->data.pointer.bit_offset_in_host && - actual_type->data.pointer.host_int_bytes == wanted_type->data.pointer.host_int_bytes && - get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type)) + bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; + if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && + (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && + (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && + actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && + actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && + get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type)) { return result; } diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 3f62bd1cec..8d87fe2a20 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -97,3 +97,13 @@ test "peer type resolution with C pointers" { expect(@typeOf(x3) == [*c]u8); expect(@typeOf(x4) == [*c]u8); } + +test "implicit casting between C pointer and optional non-C pointer" { + var slice: []const u8 = "aoeu"; + const opt_many_ptr: ?[*]const u8 = slice.ptr; + var ptr_opt_many_ptr = &opt_many_ptr; + var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + expect(c_ptr.*.* == 'a'); + ptr_opt_many_ptr = c_ptr; + expect(ptr_opt_many_ptr.*.?[1] == 'o'); +} -- cgit v1.2.3 From 270933b1e997c91a9c2d28b6896d625c0ae1b163 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 10:25:21 -0500 Subject: compile error test for casting integer to c pointer when the int has more bits than pointers See #1059 --- src/ir.cpp | 4 +++- test/compile_errors.zig | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 00d82c9224..50b5661e12 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10882,7 +10882,9 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou ira->codegen->builtin_types.entry_usize->data.integral.bit_count) { ir_add_error(ira, source_instr, - buf_sprintf("integer type too big for implicit @intToPtr to type '%s'", buf_ptr(&dest_type->name))); + buf_sprintf("integer type '%s' too big for implicit @intToPtr to type '%s'", + buf_ptr(&integer->value.type->name), + buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 63850bb888..8f8e2a0bdf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,20 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting too big integers to C pointers", + \\export fn a() void { + \\ var ptr: [*c]u8 = (1 << 64) + 1; + \\} + \\export fn b() void { + \\ var x: @IntType(false, 65) = 0x1234; + \\ var ptr: [*c]u8 = x; + \\} + , + ".tmp_source.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'", + ".tmp_source.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'", + ); + cases.addTest( "C pointer pointing to non C ABI compatible type", \\const Foo = struct {}; -- cgit v1.2.3 From 5699ab5e77f8d13cac1e34775e6e51358119965c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Feb 2019 18:20:00 -0500 Subject: C pointers: errors for nested pointer casting regarding null See #1059 --- src/all_types.hpp | 12 +++-- src/analyze.cpp | 45 ++++++++++++++----- src/ir.cpp | 99 +++++++++++++++++++++++++++++------------ test/compile_errors.zig | 114 +++++++++++++++++++++++++++++------------------- 4 files changed, 181 insertions(+), 89 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index fd66b77ad2..230dba9a42 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -691,15 +691,17 @@ struct AstNodePointerType { AstNode *align_expr; BigInt *bit_offset_start; BigInt *host_int_bytes; + AstNode *op_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; - AstNode *op_expr; }; struct AstNodeArrayType { AstNode *size; AstNode *child_type; AstNode *align_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; }; @@ -1050,6 +1052,7 @@ struct ZigTypePointer { uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned bool is_const; bool is_volatile; + bool allow_zero; }; struct ZigTypeInt { @@ -1499,11 +1502,12 @@ struct TypeId { struct { ZigType *child_type; PtrLen ptr_len; - bool is_const; - bool is_volatile; uint32_t alignment; uint32_t bit_offset_in_host; uint32_t host_int_bytes; + bool is_const; + bool is_volatile; + bool allow_zero; } pointer; struct { ZigType *child_type; @@ -2592,6 +2596,7 @@ struct IrInstructionPtrType { PtrLen ptr_len; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionPromiseType { @@ -2607,6 +2612,7 @@ struct IrInstructionSliceType { IrInstruction *child_type; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionAsm { diff --git a/src/analyze.cpp b/src/analyze.cpp index ab2afba561..900def52d4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -433,6 +433,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) { + // TODO when implementing https://github.com/ziglang/zig/issues/1953 + // move this to a parameter + bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); @@ -452,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons TypeId type_id = {}; ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { + if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; @@ -461,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; type_id.data.pointer.host_int_bytes = host_int_bytes; type_id.data.pointer.ptr_len = ptr_len; + type_id.data.pointer.allow_zero = allow_zero; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -481,18 +485,28 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; + const char *allow_zero_str; + if (ptr_len == PtrLenC) { + assert(allow_zero); + allow_zero_str = ""; + } else { + allow_zero_str = allow_zero ? "allowzero " : ""; + } buf_resize(&entry->name, 0); if (host_int_bytes == 0 && byte_alignment == 0) { - buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%s%s%s%s%s", + star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (host_int_bytes == 0) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, - const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (byte_alignment == 0) { - buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } else { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } assert(child_type->id != ZigTypeIdInvalid); @@ -500,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->zero_bits = !type_has_bits(child_type); if (!entry->zero_bits) { - if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) { + if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || + bit_offset_in_host != 0 || allow_zero) + { ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenSingle, 0, 0, host_int_bytes); entry->type_ref = peer_type->type_ref; @@ -534,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.bit_offset_in_host = bit_offset_in_host; entry->data.pointer.host_int_bytes = host_int_bytes; + entry->data.pointer.allow_zero = allow_zero; if (parent_pointer) { *parent_pointer = entry; @@ -850,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_type = ptr_type->data.pointer.child_type; if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0) + ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenUnknown, 0, 0, 0); @@ -873,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0) + child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero) { ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, @@ -4053,7 +4070,9 @@ ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdPromise) return type; if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type; + if (type->data.maybe.child_type->id == ZigTypeIdPointer) { + return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; + } if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type; } @@ -6289,6 +6308,7 @@ uint32_t type_id_hash(TypeId x) { ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + + (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); @@ -6339,6 +6359,7 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.ptr_len == b.data.pointer.ptr_len && a.data.pointer.is_const == b.data.pointer.is_const && a.data.pointer.is_volatile == b.data.pointer.is_volatile && + a.data.pointer.allow_zero == b.data.pointer.allow_zero && a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; diff --git a/src/ir.cpp b/src/ir.cpp index 50b5661e12..19bec193d5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -61,7 +61,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdNullWrapPtr + ConstCastResultIdBadAllowsZero, }; struct ConstCastOnly; @@ -83,6 +83,7 @@ struct ConstCastErrUnionErrSetMismatch; struct ConstCastErrUnionPayloadMismatch; struct ConstCastErrSetMismatch; struct ConstCastTypeMismatch; +struct ConstCastBadAllowsZero; struct ConstCastOnly { ConstCastResultId id; @@ -99,6 +100,7 @@ struct ConstCastOnly { ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; + ConstCastBadAllowsZero *bad_allows_zero; } data; }; @@ -141,6 +143,12 @@ struct ConstCastErrSetMismatch { ZigList missing_errors; }; +struct ConstCastBadAllowsZero { + ZigType *wanted_type; + ZigType *actual_type; +}; + + enum UndefAllowed { UndefOk, UndefBad, @@ -8636,6 +8644,14 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } +static bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) @@ -8649,34 +8665,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type == actual_type) return result; - // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively - // but not if we want a mutable pointer - // and not if the actual pointer has zero bits - if (!wanted_is_mutable && wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && - actual_type->id == ZigTypeIdPointer && type_has_bits(actual_type)) - { - ConstCastOnly child = types_match_const_cast_only(ira, - wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdNullWrapPtr; - result.data.null_wrap_ptr_child = allocate_nonzero(1); - *result.data.null_wrap_ptr_child = child; - } - return result; - } - - // pointer const + // If pointers have the same representation in memory, they can be "const-casted". + // `const` attribute can be gained + // `volatile` attribute can be gained + // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) + // but only if !wanted_is_mutable + // alignment can be decreased + // bit offset attributes must match exactly + // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); ZigType *actual_ptr_type = get_src_ptr_type(actual_type); + bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(actual_type); bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; - if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) || - (wanted_ptr_type != nullptr && actual_is_c_ptr) || - (actual_ptr_type != nullptr && wanted_is_c_ptr)) - { + bool wanted_opt_or_ptr = wanted_ptr_type != nullptr && + (wanted_type->id == ZigTypeIdPointer || wanted_type->id == ZigTypeIdOptional); + bool actual_opt_or_ptr = actual_ptr_type != nullptr && + (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); + if (wanted_opt_or_ptr && actual_opt_or_ptr) { + bool ok_allows_zero = (wanted_allows_zero && + (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (!wanted_allows_zero && !actual_allows_zero); + if (!ok_allows_zero) { + result.id = ConstCastResultIdBadAllowsZero; + result.data.bad_allows_zero = allocate_nonzero(1); + result.data.bad_allows_zero->wanted_type = wanted_type; + result.data.bad_allows_zero->actual_type = actual_type; + return result; + } ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -8699,6 +8716,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && + type_has_bits(wanted_type) == type_has_bits(actual_type) && (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && @@ -9922,7 +9940,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un if (undef_allowed == UndefOk) { return &value->value; } else { - ir_add_error(ira, value, buf_sprintf("use of undefined value")); + ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior")); return nullptr; } } @@ -10828,6 +10846,26 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); break; } + case ConstCastResultIdBadAllowsZero: { + bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type); + ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type; + ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type; + if (actual_allows_zero && !wanted_allows_zero) { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("'%s' could have null values which are illegal in type '%s'", + buf_ptr(&actual_elem_type->name), + buf_ptr(&wanted_elem_type->name))); + } else { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", + buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name), + buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name))); + } + break; + } case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO @@ -10838,7 +10876,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa case ConstCastResultIdFnArgNoAlias: // TODO case ConstCastResultIdUnresolvedInferredErrSet: // TODO case ConstCastResultIdAsyncAllocatorType: // TODO - case ConstCastResultIdNullWrapPtr: // TODO break; } } @@ -20589,12 +20626,14 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. - if (get_src_ptr_type(src_type) == nullptr) { + ZigType *src_ptr_type = get_src_ptr_type(src_type); + if (src_ptr_type == nullptr) { ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } - if (get_src_ptr_type(dest_type) == nullptr) { + ZigType *dest_ptr_type = get_src_ptr_type(dest_type); + if (dest_ptr_type == nullptr) { ir_add_error(ira, dest_type_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; @@ -20606,6 +20645,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } if (instr_is_comptime(ptr)) { + // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern + // of the pointer as the new pointer type. ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); if (!val) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8f8e2a0bdf..c51a65cadf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,30 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting C pointers which would mess up null semantics", + \\export fn entry() void { + \\ var slice: []const u8 = "aoeu"; + \\ const opt_many_ptr: [*]const u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + \\ ptr_opt_many_ptr = c_ptr; + \\} + \\export fn entry2() void { + \\ var buf: [4]u8 = "aoeu"; + \\ var slice: []u8 = &buf; + \\ var opt_many_ptr: [*]u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]u8 = ptr_opt_many_ptr; + \\} + , + ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'", + ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'", + ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'", + ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", + ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]u8'", + ); + cases.addTest( "implicit casting too big integers to C pointers", \\export fn a() void { @@ -31,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var z = @truncate(u8, u16(undefined)); \\} , - ".tmp_source.zig:2:30: error: use of undefined value", + ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior", ); cases.addTest( @@ -392,7 +416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ f(i32); \\} , - ".tmp_source.zig:4:5: error: use of undefined value", + ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -792,7 +816,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -805,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2776,7 +2800,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(x)); } , - ".tmp_source.zig:1:15: error: use of undefined value", + ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2786,7 +2810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a / a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2796,7 +2820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a /= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2806,7 +2830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a % a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2816,7 +2840,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a %= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2826,7 +2850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a + a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2836,7 +2860,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a += a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2846,7 +2870,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a +% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2856,7 +2880,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a +%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2866,7 +2890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a - a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2876,7 +2900,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2886,7 +2910,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a -% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2896,7 +2920,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2906,7 +2930,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a * a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2916,7 +2940,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2926,7 +2950,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a *% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2936,7 +2960,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2946,7 +2970,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a << 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2956,7 +2980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a <<= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2966,7 +2990,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >> 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2976,7 +3000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a >>= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2986,7 +3010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a & a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2996,7 +3020,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a &= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3006,7 +3030,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a | a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3016,7 +3040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a |= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3026,7 +3050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a ^ a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3036,7 +3060,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a ^= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3046,7 +3070,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a == a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3056,7 +3080,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a != a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3066,7 +3090,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a > a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3076,7 +3100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3086,7 +3110,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a < a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3096,7 +3120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a <= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3106,7 +3130,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a and a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3116,7 +3140,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a or a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3126,7 +3150,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3136,7 +3160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -%a; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3146,7 +3170,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = ~a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3156,7 +3180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = !a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3166,7 +3190,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a orelse false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3176,7 +3200,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a catch |err| false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( -- cgit v1.2.3 From d4d2718bca9e23ceec029bb505c0ea1b91c875b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 00:40:39 -0500 Subject: comptime detection of casting null to pointer See #1059 --- src/ir.cpp | 17 ++++++++++++++--- test/compile_errors.zig | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 19bec193d5..f064adb128 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20645,12 +20645,23 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } if (instr_is_comptime(ptr)) { - // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern - // of the pointer as the new pointer type. - ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); + bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); + UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; + ConstExprValue *val = ir_resolve_const(ira, ptr, is_undef_allowed); if (!val) return ira->codegen->invalid_instruction; + if (val->special == ConstValSpecialStatic) { + bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || + (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + val->data.x_ptr.data.hard_coded_addr.addr == 0); + if (is_addr_zero && !dest_allows_addr_zero) { + ir_add_error(ira, source_instr, + buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + } + IrInstruction *result = ir_const(ira, source_instr, dest_type); copy_const_val(&result->value, val, false); result->value.type = dest_type; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index c51a65cadf..71ee4901ff 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,26 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting null c pointer to zig pointer", + \\comptime { + \\ var c_ptr: [*c]u8 = 0; + \\ var zig_ptr: *u8 = c_ptr; + \\} + , + ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'", + ); + + cases.addTest( + "implicit casting undefined c pointer to zig pointer", + \\comptime { + \\ var c_ptr: [*c]u8 = undefined; + \\ var zig_ptr: *u8 = c_ptr; + \\} + , + ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior", + ); + cases.addTest( "implicit casting C pointers which would mess up null semantics", \\export fn entry() void { -- cgit v1.2.3 From 59de24817e8538434f35a20a401f40c2f0231a9a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 01:09:33 -0500 Subject: runtime safety check for casting null to pointer see #1059 --- src/all_types.hpp | 3 +++ src/analyze.cpp | 9 +++++++++ src/analyze.hpp | 1 + src/codegen.cpp | 19 +++++++++++++++++- src/ir.cpp | 52 ++++++++++++++++++++++++------------------------- test/runtime_safety.zig | 10 ++++++++++ 6 files changed, 67 insertions(+), 27 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 230dba9a42..bafe316c3d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1488,6 +1488,7 @@ enum PanicMsgId { PanicMsgIdBadUnionField, PanicMsgIdBadEnumValue, PanicMsgIdFloatToInt, + PanicMsgIdPtrCastNull, PanicMsgIdCount, }; @@ -3001,12 +3002,14 @@ struct IrInstructionPtrCastSrc { IrInstruction *dest_type; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionPtrCastGen { IrInstruction base; IrInstruction *ptr; + bool safety_check_on; }; struct IrInstructionBitCast { diff --git a/src/analyze.cpp b/src/analyze.cpp index 900def52d4..6a8090a843 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6902,3 +6902,12 @@ const char *container_string(ContainerKind kind) { } zig_unreachable(); } + +bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index c8141b02ff..50e841baa1 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -45,6 +45,7 @@ void find_libc_lib_path(CodeGen *g); bool type_has_bits(ZigType *type_entry); bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry); +bool ptr_allows_addr_zero(ZigType *ptr_type); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); diff --git a/src/codegen.cpp b/src/codegen.cpp index 142e8174f5..dbb13ca885 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -950,6 +950,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("invalid enum value"); case PanicMsgIdFloatToInt: return buf_create_from_str("integer part of floating point value out of bounds"); + case PanicMsgIdPtrCastNull: + return buf_create_from_str("cast causes pointer to be null"); } zig_unreachable(); } @@ -3028,7 +3030,22 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, return nullptr; } LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); - return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, ""); + bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); + if (!want_safety_check || ptr_allows_addr_zero(wanted_type)) + return result_ptr; + + LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr)); + LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, ""); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk"); + LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); + + LLVMPositionBuilderAtEnd(g->builder, fail_block); + gen_safety_crash(g, PanicMsgIdPtrCastNull); + + LLVMPositionBuilderAtEnd(g->builder, ok_block); + return result_ptr; } static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, diff --git a/src/ir.cpp b/src/ir.cpp index f064adb128..dfbc36e02c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -172,7 +172,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *out_val, ConstExprValue *ptr_val); static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src); + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on); static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); @@ -2202,12 +2202,13 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo } static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *ptr) + IrInstruction *dest_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastSrc *instruction = ir_build_instruction( irb, scope, source_node); instruction->dest_type = dest_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -2216,12 +2217,13 @@ static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, - ZigType *ptr_type, IrInstruction *ptr) + ZigType *ptr_type, IrInstruction *ptr, bool safety_check_on) { IrInstructionPtrCastGen *instruction = ir_build_instruction( &ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ptr_type; instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); @@ -4505,7 +4507,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); return ir_lval_wrap(irb, scope, ptr_cast, lval); } case BuiltinFnIdBitCast: @@ -6740,7 +6742,8 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -6818,7 +6821,8 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); // TODO relies on Zig not re-ordering fields - IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst); + IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst, + false); IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, @@ -7363,7 +7367,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec u8_ptr_type = ir_build_const_type(irb, coro_scope, node, get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); - IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); + IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, + coro_promise_ptr, false); coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); @@ -7387,7 +7392,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec ir_build_return(irb, coro_scope, node, undef); ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr, + false); irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); @@ -7465,9 +7471,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); - IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr); - IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, - irb->exec->coro_result_field_ptr); + IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + result_ptr, false); + IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, + u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false); IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, fn_entry->type_entry->data.fn.fn_type_id.return_type); IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); @@ -7517,7 +7524,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8, false, false, PtrLenUnknown, 0, 0, 0)); - IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe); + IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, + coro_mem_ptr_maybe, false); IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); @@ -8644,15 +8652,6 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } -static bool ptr_allows_addr_zero(ZigType *ptr_type) { - if (ptr_type->id == ZigTypeIdPointer) { - return ptr_type->data.pointer.allow_zero; - } else if (ptr_type->id == ZigTypeIdOptional) { - return true; - } - return false; -} - static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) { @@ -11310,7 +11309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes && get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type)) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } } @@ -11352,7 +11351,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); + return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true); } // cast from integer to C pointer @@ -20616,7 +20615,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 } static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, - ZigType *dest_type, IrInstruction *dest_type_src) + ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on) { Error err; @@ -20685,7 +20684,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ return ira->codegen->invalid_instruction; } - IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr); + IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); if (type_has_bits(dest_type) && !type_has_bits(src_type)) { ErrorMsg *msg = ir_add_error(ira, source_instr, @@ -20722,7 +20721,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); + return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value, + instruction->safety_check_on); } static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) { diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 821328b7a6..12cac64b3a 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { + cases.addRuntimeSafety("pointer casting null to non-optional pointer", + \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { + \\ @import("std").os.exit(126); + \\} + \\pub fn main() void { + \\ var c_ptr: [*c]u8 = 0; + \\ var zig_ptr: *u8 = c_ptr; + \\} + ); + cases.addRuntimeSafety("@intToEnum - no matching tag value", \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { \\ @import("std").os.exit(126); -- cgit v1.2.3 From c58b80203443dcbf8b737ebdaa1f17fb20c77711 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 10:51:59 -0500 Subject: remove the "top of the comptime stack" compile error It's still best practice to put `@setEvalBranchQuota` at the top of the comptime stack, but as Jimmi notes in #1949, when a function can be called at comptime and also can be the top of the comptime stack, this compile error is fundamentally unsound. So now it's gone. closes #1949 --- src/ir.cpp | 6 ------ test/compile_errors.zig | 14 -------------- 2 files changed, 20 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 5d4013b4b9..03dea10b10 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18172,12 +18172,6 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, IrInstructionSetEvalBranchQuota *instruction) { - if (ira->new_irb.exec->parent_exec != nullptr && !ira->new_irb.exec->is_generic_instantiation) { - ir_add_error(ira, &instruction->base, - buf_sprintf("@setEvalBranchQuota must be called from the top of the comptime stack")); - return ira->codegen->invalid_instruction; - } - uint64_t new_quota; if (!ir_resolve_usize(ira, instruction->new_quota->child, &new_quota)) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index b895e2c2d1..6a2ded1844 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -4554,20 +4554,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal", ); - cases.add( - "@setEvalBranchQuota in non-root comptime execution context", - \\comptime { - \\ foo(); - \\} - \\fn foo() void { - \\ @setEvalBranchQuota(1001); - \\} - , - ".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack", - ".tmp_source.zig:2:8: note: called from here", - ".tmp_source.zig:1:10: note: called from here", - ); - cases.add( "wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); -- cgit v1.2.3 From e03c770145b5dc7b428d53b3cac97c2733fb84d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 12:28:50 -0500 Subject: compile error tests for implicit C pointer casting See #1059 --- src/ir.cpp | 38 ++++++++++++++++++-------------------- test/compile_errors.zig | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 20 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index dfbc36e02c..89528db185 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8683,16 +8683,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted bool actual_opt_or_ptr = actual_ptr_type != nullptr && (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); if (wanted_opt_or_ptr && actual_opt_or_ptr) { - bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || - (!wanted_allows_zero && !actual_allows_zero); - if (!ok_allows_zero) { - result.id = ConstCastResultIdBadAllowsZero; - result.data.bad_allows_zero = allocate_nonzero(1); - result.data.bad_allows_zero->wanted_type = wanted_type; - result.data.bad_allows_zero->actual_type = actual_type; - return result; - } ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -8705,6 +8695,16 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type; return result; } + bool ok_allows_zero = (wanted_allows_zero && + (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (!wanted_allows_zero && !actual_allows_zero); + if (!ok_allows_zero) { + result.id = ConstCastResultIdBadAllowsZero; + result.data.bad_allows_zero = allocate_nonzero(1); + result.data.bad_allows_zero->wanted_type = wanted_type; + result.data.bad_allows_zero->actual_type = actual_type; + return result; + } if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { result.id = ConstCastResultIdInvalid; return result; @@ -10846,22 +10846,20 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa break; } case ConstCastResultIdBadAllowsZero: { - bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type); - bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type); - ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type); - ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type); - ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type; - ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type; + ZigType *wanted_type = cast_result->data.bad_allows_zero->wanted_type; + ZigType *actual_type = cast_result->data.bad_allows_zero->actual_type; + bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(actual_type); if (actual_allows_zero && !wanted_allows_zero) { add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("'%s' could have null values which are illegal in type '%s'", - buf_ptr(&actual_elem_type->name), - buf_ptr(&wanted_elem_type->name))); + buf_ptr(&actual_type->name), + buf_ptr(&wanted_type->name))); } else { add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", - buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name), - buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name))); + buf_ptr(&wanted_type->name), + buf_ptr(&actual_type->name))); } break; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 71ee4901ff..630386aa4f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,42 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit cast between C pointer and Zig pointer - bad const/align/child", + \\export fn a() void { + \\ var x: [*c]u8 = undefined; + \\ var y: *align(4) u8 = x; + \\} + \\export fn b() void { + \\ var x: [*c]const u8 = undefined; + \\ var y: *u8 = x; + \\} + \\export fn c() void { + \\ var x: [*c]u8 = undefined; + \\ var y: *u32 = x; + \\} + \\export fn d() void { + \\ var y: *align(1) u32 = undefined; + \\ var x: [*c]u32 = y; + \\} + \\export fn e() void { + \\ var y: *const u8 = undefined; + \\ var x: [*c]u8 = y; + \\} + \\export fn f() void { + \\ var y: *u8 = undefined; + \\ var x: [*c]u32 = y; + \\} + , + ".tmp_source.zig:3:27: error: cast increases pointer alignment", + ".tmp_source.zig:7:18: error: cast discards const qualifier", + ".tmp_source.zig:11:19: error: expected type '*u32', found '[*c]u8'", + ".tmp_source.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'", + ".tmp_source.zig:15:22: error: cast increases pointer alignment", + ".tmp_source.zig:19:21: error: cast discards const qualifier", + ".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'", + ); + cases.addTest( "implicit casting null c pointer to zig pointer", \\comptime { @@ -39,6 +75,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'", + ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'", ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'", ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'", ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", -- cgit v1.2.3 From 6769183a9d5f5ec69747f46d4d13c0f8709b2f46 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 15:48:28 -0500 Subject: fix implicit cast error unions with non-optional to optional pointer and update self hosted compiler for C pointers See #1059 --- doc/docgen.zig | 1 + src-self-hosted/codegen.zig | 42 ++++----- src-self-hosted/compilation.zig | 22 ++--- src-self-hosted/ir.zig | 20 ++--- src-self-hosted/llvm.zig | 181 +++++++++++++++++++++++++++----------- src-self-hosted/scope.zig | 2 +- src-self-hosted/target.zig | 4 +- src-self-hosted/type.zig | 42 ++++----- src-self-hosted/value.zig | 16 ++-- src/ir.cpp | 2 +- std/hash_map.zig | 2 + test/compile_errors.zig | 8 +- test/stage1/behavior/pointers.zig | 17 ++++ 13 files changed, 228 insertions(+), 131 deletions(-) (limited to 'src/ir.cpp') diff --git a/doc/docgen.zig b/doc/docgen.zig index 45f6dc2684..082f308a57 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok std.zig.Token.Id.AngleBracketAngleBracketRightEqual, std.zig.Token.Id.Tilde, std.zig.Token.Id.BracketStarBracket, + std.zig.Token.Id.BracketStarCBracket, => try writeEscaped(out, src[token.start..token.end]), std.zig.Token.Id.Invalid => return parseError( diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 45cfa98942..1c671b61e2 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) pub const ObjectFile = struct { comp: *Compilation, - module: llvm.ModuleRef, - builder: llvm.BuilderRef, + module: *llvm.Module, + builder: *llvm.Builder, dibuilder: *llvm.DIBuilder, - context: llvm.ContextRef, + context: *llvm.Context, lock: event.Lock, arena: *std.mem.Allocator, @@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) fn addLLVMAttr( ofile: *ObjectFile, - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, ) !void { @@ -335,7 +335,7 @@ fn addLLVMAttr( fn addLLVMAttrStr( ofile: *ObjectFile, - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, attr_val: []const u8, @@ -351,7 +351,7 @@ fn addLLVMAttrStr( } fn addLLVMAttrInt( - val: llvm.ValueRef, + val: *llvm.Value, attr_index: llvm.AttributeIndex, attr_name: []const u8, attr_val: u64, @@ -362,25 +362,25 @@ fn addLLVMAttrInt( llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); } -fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void { +fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void { return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name); } -fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void { +fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void { return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); } -fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void { +fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void { return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); } fn renderLoadUntyped( ofile: *ObjectFile, - ptr: llvm.ValueRef, + ptr: *llvm.Value, alignment: Type.Pointer.Align, vol: Type.Pointer.Vol, name: [*]const u8, -) !llvm.ValueRef { +) !*llvm.Value { const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; switch (vol) { Type.Pointer.Vol.Non => {}, @@ -390,11 +390,11 @@ fn renderLoadUntyped( return result; } -fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef { +fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value { return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); } -pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef { +pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value { const child_type = ptr_type.key.child_type; if (!child_type.hasBits()) { return null; @@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po pub fn renderStoreUntyped( ofile: *ObjectFile, - value: llvm.ValueRef, - ptr: llvm.ValueRef, + value: *llvm.Value, + ptr: *llvm.Value, alignment: Type.Pointer.Align, vol: Type.Pointer.Vol, -) !llvm.ValueRef { +) !*llvm.Value { const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory; switch (vol) { Type.Pointer.Vol.Non => {}, @@ -423,10 +423,10 @@ pub fn renderStoreUntyped( pub fn renderStore( ofile: *ObjectFile, - value: llvm.ValueRef, - ptr: llvm.ValueRef, + value: *llvm.Value, + ptr: *llvm.Value, ptr_type: *Type.Pointer, -) !llvm.ValueRef { +) !*llvm.Value { return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol); } @@ -435,7 +435,7 @@ pub fn renderAlloca( var_type: *Type, name: []const u8, alignment: Type.Pointer.Align, -) !llvm.ValueRef { +) !*llvm.Value { const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); const name_with_null = try std.cstr.addNullByte(ofile.arena, name); const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory; @@ -443,7 +443,7 @@ pub fn renderAlloca( return result; } -pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 { +pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 { return switch (alignment) { Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type), Type.Pointer.Align.Override => |a| a, diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index e55d8ccda6..de956f1525 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB /// Data that is local to the event loop. pub const ZigCompiler = struct { loop: *event.Loop, - llvm_handle_pool: std.atomic.Stack(llvm.ContextRef), + llvm_handle_pool: std.atomic.Stack(*llvm.Context), lld_lock: event.Lock, /// TODO pool these so that it doesn't have to lock @@ -60,7 +60,7 @@ pub const ZigCompiler = struct { return ZigCompiler{ .loop = loop, .lld_lock = event.Lock.init(loop), - .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), + .llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(), .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), .native_libc = event.Future(LibCInstallation).init(loop), }; @@ -70,7 +70,7 @@ pub const ZigCompiler = struct { fn deinit(self: *ZigCompiler) void { self.lld_lock.deinit(); while (self.llvm_handle_pool.pop()) |node| { - c.LLVMContextDispose(node.data); + llvm.ContextDispose(node.data); self.loop.allocator.destroy(node); } } @@ -80,11 +80,11 @@ pub const ZigCompiler = struct { pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle { if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node }; - const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; - errdefer c.LLVMContextDispose(context_ref); + const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory; + errdefer llvm.ContextDispose(context_ref); - const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node); - node.* = std.atomic.Stack(llvm.ContextRef).Node{ + const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node); + node.* = std.atomic.Stack(*llvm.Context).Node{ .next = undefined, .data = context_ref, }; @@ -114,7 +114,7 @@ pub const ZigCompiler = struct { }; pub const LlvmHandle = struct { - node: *std.atomic.Stack(llvm.ContextRef).Node, + node: *std.atomic.Stack(*llvm.Context).Node, pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void { zig_compiler.llvm_handle_pool.push(self.node); @@ -128,7 +128,7 @@ pub const Compilation = struct { llvm_triple: Buffer, root_src_path: ?[]const u8, target: Target, - llvm_target: llvm.TargetRef, + llvm_target: *llvm.Target, build_mode: builtin.Mode, zig_lib_dir: []const u8, zig_std_dir: []const u8, @@ -212,8 +212,8 @@ pub const Compilation = struct { false_value: *Value.Bool, noreturn_value: *Value.NoReturn, - target_machine: llvm.TargetMachineRef, - target_data_ref: llvm.TargetDataRef, + target_machine: *llvm.TargetMachine, + target_data_ref: *llvm.TargetData, target_layout_str: [*]u8, target_ptr_bits: u32, diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 0362bb4ef8..dc1b0dc943 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -67,7 +67,7 @@ pub const Inst = struct { parent: ?*Inst, /// populated durign codegen - llvm_value: ?llvm.ValueRef, + llvm_value: ?*llvm.Value, pub fn cast(base: *Inst, comptime T: type) ?*T { if (base.id == comptime typeToId(T)) { @@ -129,7 +129,7 @@ pub const Inst = struct { } } - pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { + pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) { switch (base.id) { Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val), Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val), @@ -313,10 +313,10 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const fn_ref = self.params.fn_ref.llvm_value.?; - const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len); + const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len); for (self.params.args) |arg, i| { args[i] = arg.llvm_value.?; } @@ -360,7 +360,7 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { return self.base.val.KnownValue.getLlvmConst(ofile); } }; @@ -392,7 +392,7 @@ pub const Inst = struct { return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value }); } - pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const value = self.params.return_value.llvm_value; const return_type = self.params.return_value.getKnownType(); @@ -540,7 +540,7 @@ pub const Inst = struct { } } - pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef { + pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value { switch (self.params.var_scope.data) { Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass Scope.Var.Data.Param => |param| return param.llvm_value, @@ -596,7 +596,7 @@ pub const Inst = struct { return new_inst; } - pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { + pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value { const child_type = self.base.getKnownType(); if (!child_type.hasBits()) { return null; @@ -935,8 +935,8 @@ pub const BasicBlock = struct { ref_instruction: ?*Inst, /// for codegen - llvm_block: llvm.BasicBlockRef, - llvm_exit_block: llvm.BasicBlockRef, + llvm_block: *llvm.BasicBlock, + llvm_exit_block: *llvm.BasicBlock, /// the basic block that is derived from this one in analysis child: ?*BasicBlock, diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 778d3fae07..704e83c3c6 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -11,45 +11,31 @@ const assert = @import("std").debug.assert; pub const AttributeIndex = c_uint; pub const Bool = c_int; -pub const BuilderRef = removeNullability(c.LLVMBuilderRef); -pub const ContextRef = removeNullability(c.LLVMContextRef); -pub const ModuleRef = removeNullability(c.LLVMModuleRef); -pub const ValueRef = removeNullability(c.LLVMValueRef); -pub const TypeRef = removeNullability(c.LLVMTypeRef); -pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); -pub const AttributeRef = removeNullability(c.LLVMAttributeRef); -pub const TargetRef = removeNullability(c.LLVMTargetRef); -pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef); -pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef); +pub const Builder = c.LLVMBuilderRef.Child; +pub const Context = c.LLVMContextRef.Child; +pub const Module = c.LLVMModuleRef.Child; +pub const Value = c.LLVMValueRef.Child; +pub const Type = c.LLVMTypeRef.Child; +pub const BasicBlock = c.LLVMBasicBlockRef.Child; +pub const Attribute = c.LLVMAttributeRef.Child; +pub const Target = c.LLVMTargetRef.Child; +pub const TargetMachine = c.LLVMTargetMachineRef.Child; +pub const TargetData = c.LLVMTargetDataRef.Child; pub const DIBuilder = c.ZigLLVMDIBuilder; +pub const DIFile = c.ZigLLVMDIFile; +pub const DICompileUnit = c.ZigLLVMDICompileUnit; pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType; pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; -pub const AddFunction = c.LLVMAddFunction; -pub const AddGlobal = c.LLVMAddGlobal; pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; -pub const ArrayType = c.LLVMArrayType; -pub const BuildLoad = c.LLVMBuildLoad; pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; pub const ConstAllOnes = c.LLVMConstAllOnes; pub const ConstArray = c.LLVMConstArray; pub const ConstBitCast = c.LLVMConstBitCast; -pub const ConstInt = c.LLVMConstInt; pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; pub const ConstNeg = c.LLVMConstNeg; -pub const ConstNull = c.LLVMConstNull; -pub const ConstStringInContext = c.LLVMConstStringInContext; pub const ConstStructInContext = c.LLVMConstStructInContext; -pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData; -pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; -pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit; -pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder; -pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute; -pub const CreateFile = c.ZigLLVMCreateFile; -pub const CreateStringAttribute = c.LLVMCreateStringAttribute; -pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout; -pub const CreateTargetMachine = c.LLVMCreateTargetMachine; pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize; pub const DisposeBuilder = c.LLVMDisposeBuilder; pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder; @@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule; pub const FP128TypeInContext = c.LLVMFP128TypeInContext; pub const FloatTypeInContext = c.LLVMFloatTypeInContext; pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; -pub const GetHostCPUName = c.ZigLLVMGetHostCPUName; pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; -pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures; pub const GetUndef = c.LLVMGetUndef; pub const HalfTypeInContext = c.LLVMHalfTypeInContext; pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers; @@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext; pub const Int8TypeInContext = c.LLVMInt8TypeInContext; pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext; pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext; -pub const IntTypeInContext = c.LLVMIntTypeInContext; pub const LabelTypeInContext = c.LLVMLabelTypeInContext; pub const MDNodeInContext = c.LLVMMDNodeInContext; pub const MDStringInContext = c.LLVMMDStringInContext; pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; -pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; -pub const PointerType = c.LLVMPointerType; pub const SetAlignment = c.LLVMSetAlignment; pub const SetDataLayout = c.LLVMSetDataLayout; pub const SetGlobalConstant = c.LLVMSetGlobalConstant; @@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr; pub const SetVolatile = c.LLVMSetVolatile; pub const StructTypeInContext = c.LLVMStructTypeInContext; pub const TokenTypeInContext = c.LLVMTokenTypeInContext; -pub const VoidTypeInContext = c.LLVMVoidTypeInContext; pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; +pub const AddGlobal = LLVMAddGlobal; +extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value; + +pub const ConstStringInContext = LLVMConstStringInContext; +extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; + +pub const ConstInt = LLVMConstInt; +extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; + +pub const BuildLoad = LLVMBuildLoad; +extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value; + +pub const ConstNull = LLVMConstNull; +extern fn LLVMConstNull(Ty: *Type) ?*Value; + +pub const CreateStringAttribute = LLVMCreateStringAttribute; +extern fn LLVMCreateStringAttribute( + C: *Context, + K: [*]const u8, + KLength: c_uint, + V: [*]const u8, + VLength: c_uint, +) ?*Attribute; + +pub const CreateEnumAttribute = LLVMCreateEnumAttribute; +extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute; + +pub const AddFunction = LLVMAddFunction; +extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value; + +pub const CreateCompileUnit = ZigLLVMCreateCompileUnit; +extern fn ZigLLVMCreateCompileUnit( + dibuilder: *DIBuilder, + lang: c_uint, + difile: *DIFile, + producer: [*]const u8, + is_optimized: bool, + flags: [*]const u8, + runtime_version: c_uint, + split_name: [*]const u8, + dwo_id: u64, + emit_debug_info: bool, +) ?*DICompileUnit; + +pub const CreateFile = ZigLLVMCreateFile; +extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile; + +pub const ArrayType = LLVMArrayType; +extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type; + +pub const CreateDIBuilder = ZigLLVMCreateDIBuilder; +extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder; + +pub const PointerType = LLVMPointerType; +extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type; + +pub const CreateBuilderInContext = LLVMCreateBuilderInContext; +extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder; + +pub const IntTypeInContext = LLVMIntTypeInContext; +extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type; + +pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext; +extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module; + +pub const VoidTypeInContext = LLVMVoidTypeInContext; +extern fn LLVMVoidTypeInContext(C: *Context) ?*Type; + +pub const ContextCreate = LLVMContextCreate; +extern fn LLVMContextCreate() ?*Context; + +pub const ContextDispose = LLVMContextDispose; +extern fn LLVMContextDispose(C: *Context) void; + +pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData; +extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8; + +pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout; +extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; + +pub const CreateTargetMachine = LLVMCreateTargetMachine; +extern fn LLVMCreateTargetMachine( + T: *Target, + Triple: [*]const u8, + CPU: [*]const u8, + Features: [*]const u8, + Level: CodeGenOptLevel, + Reloc: RelocMode, + CodeModel: CodeModel, +) ?*TargetMachine; + +pub const GetHostCPUName = LLVMGetHostCPUName; +extern fn LLVMGetHostCPUName() ?[*]u8; + +pub const GetNativeFeatures = ZigLLVMGetNativeFeatures; +extern fn ZigLLVMGetNativeFeatures() ?[*]u8; + pub const GetElementType = LLVMGetElementType; -extern fn LLVMGetElementType(Ty: TypeRef) TypeRef; +extern fn LLVMGetElementType(Ty: *Type) *Type; pub const TypeOf = LLVMTypeOf; -extern fn LLVMTypeOf(Val: ValueRef) TypeRef; +extern fn LLVMTypeOf(Val: *Value) *Type; pub const BuildStore = LLVMBuildStore; -extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef; +extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value; pub const BuildAlloca = LLVMBuildAlloca; -extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef; +extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value; pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; -pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef; +pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value; pub const GetTargetFromTriple = LLVMGetTargetFromTriple; -extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool; +extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool; pub const VerifyModule = LLVMVerifyModule; -extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; +extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; pub const GetInsertBlock = LLVMGetInsertBlock; -extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef; +extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock; pub const FunctionType = LLVMFunctionType; extern fn LLVMFunctionType( - ReturnType: TypeRef, - ParamTypes: [*]TypeRef, + ReturnType: *Type, + ParamTypes: [*]*Type, ParamCount: c_uint, IsVarArg: Bool, -) ?TypeRef; +) ?*Type; pub const GetParam = LLVMGetParam; -extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef; +extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value; pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; -extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef; +extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock; pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; -extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void; +extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void; pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction; pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; @@ -190,17 +267,17 @@ pub const FnInline = extern enum { }; fn removeNullability(comptime T: type) type { - comptime assert(@typeId(T) == builtin.TypeId.Optional); - return T.Child; + comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C); + return *T.Child; } pub const BuildRet = LLVMBuildRet; -extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef; +extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value; pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; extern fn ZigLLVMTargetMachineEmitToFile( - targ_machine_ref: TargetMachineRef, - module_ref: ModuleRef, + targ_machine_ref: *TargetMachine, + module_ref: *Module, filename: [*]const u8, output_type: EmitOutputType, error_message: *[*]u8, @@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile( ) bool; pub const BuildCall = ZigLLVMBuildCall; -extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef; +extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value; pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig index b14c073a9e..9a84ad256e 100644 --- a/src-self-hosted/scope.zig +++ b/src-self-hosted/scope.zig @@ -362,7 +362,7 @@ pub const Scope = struct { pub const Param = struct { index: usize, typ: *Type, - llvm_value: llvm.ValueRef, + llvm_value: *llvm.Value, }; pub fn createParam( diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig index 36381b820d..121242b505 100644 --- a/src-self-hosted/target.zig +++ b/src-self-hosted/target.zig @@ -457,8 +457,8 @@ pub const Target = union(enum) { } } - pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef { - var result: llvm.TargetRef = undefined; + pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target { + var result: *llvm.Target = undefined; var err_msg: [*]u8 = undefined; if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) { std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 790b51b7be..7d611bb787 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -51,8 +51,8 @@ pub const Type = struct { pub fn getLlvmType( base: *Type, allocator: *Allocator, - llvm_context: llvm.ContextRef, - ) (error{OutOfMemory}!llvm.TypeRef) { + llvm_context: *llvm.Context, + ) (error{OutOfMemory}!*llvm.Type) { switch (base.id) { Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), @@ -196,7 +196,7 @@ pub const Type = struct { } /// If you have an llvm conext handy, you can use it here. - pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { + pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*; base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable); @@ -205,7 +205,7 @@ pub const Type = struct { } /// Lower level function that does the work. See getAbiAlignment. - async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { + async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 { const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); } @@ -218,7 +218,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -496,13 +496,13 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const normal = &self.key.data.Normal; const llvm_return_type = switch (normal.return_type.id) { Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory, else => try normal.return_type.getLlvmType(allocator, llvm_context), }; - const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len); + const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len); defer allocator.free(llvm_param_types); for (llvm_param_types) |*llvm_param_type, i| { llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context); @@ -559,7 +559,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -658,7 +658,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory; } }; @@ -670,7 +670,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -836,7 +836,7 @@ pub const Type = struct { return self; } - pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context); return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory; } @@ -904,7 +904,7 @@ pub const Type = struct { return self; } - pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { + pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type { const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context); return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory; } @@ -917,7 +917,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -967,7 +967,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -979,7 +979,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -991,7 +991,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1003,7 +1003,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1015,7 +1015,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1035,7 +1035,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1055,7 +1055,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; @@ -1067,7 +1067,7 @@ pub const Type = struct { comp.gpa().destroy(self); } - pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { + pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type { @panic("TODO"); } }; diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 9431c614b9..d9d4c3d1d9 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -57,7 +57,7 @@ pub const Value = struct { std.debug.warn("{}", @tagName(base.id)); } - pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) { + pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) { switch (base.id) { Id.Type => unreachable, Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile), @@ -153,7 +153,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, @@ -238,7 +238,7 @@ pub const Value = struct { /// We know that the function definition will end up in an .o file somewhere. /// Here, all we have to do is generate a global prototype. /// TODO cache the prototype per ObjectFile - pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value { const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn = llvm.AddFunction( ofile.module, @@ -283,7 +283,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { + pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?*llvm.Value { const llvm_type = llvm.Int1TypeInContext(ofile.context); if (self.x) { return llvm.ConstAllOnes(llvm_type); @@ -381,7 +381,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value { const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context); // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr switch (self.special) { @@ -391,7 +391,7 @@ pub const Value = struct { const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; const ptr_bit_count = ofile.comp.target_ptr_bits; const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; - const indices = []llvm.ValueRef{ + const indices = []*llvm.Value{ llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, }; @@ -459,7 +459,7 @@ pub const Value = struct { comp.gpa().destroy(self); } - pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value { switch (self.special) { Special.Undefined => { const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); @@ -534,7 +534,7 @@ pub const Value = struct { return self; } - pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef { + pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value { switch (self.base.typ.id) { Type.Id.Int => { const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context); diff --git a/src/ir.cpp b/src/ir.cpp index 89528db185..7c46b21717 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8696,7 +8696,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted return result; } bool ok_allows_zero = (wanted_allows_zero && - (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (actual_allows_zero || !wanted_is_mutable)) || (!wanted_allows_zero && !actual_allows_zero); if (!ok_allows_zero) { result.id = ConstCastResultIdBadAllowsZero; diff --git a/std/hash_map.zig b/std/hash_map.zig index 716f04ff34..4519890bb7 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"), + builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"), builtin.TypeInfo.Pointer.Size.Slice => { const interval = std.math.max(1, key.len / 256); var i: usize = 0; @@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"), + builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"), builtin.TypeInfo.Pointer.Size.Slice => { if (a.len != b.len) return false; for (a) |a_item, i| { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ac8d413d2c..5e9b691641 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -92,15 +92,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var slice: []u8 = &buf; \\ var opt_many_ptr: [*]u8 = slice.ptr; \\ var ptr_opt_many_ptr = &opt_many_ptr; - \\ var c_ptr: [*c]const [*c]u8 = ptr_opt_many_ptr; + \\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr; \\} , ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'", ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'", ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'", - ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'", - ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", - ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]u8'", + ".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'", + ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'", + ".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'", ); cases.addTest( diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index 8d87fe2a20..eed7a765d7 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -1,5 +1,6 @@ const std = @import("std"); const expect = std.testing.expect; +const expectError = std.testing.expectError; test "dereference pointer" { comptime testDerefPtr(); @@ -107,3 +108,19 @@ test "implicit casting between C pointer and optional non-C pointer" { ptr_opt_many_ptr = c_ptr; expect(ptr_opt_many_ptr.*.?[1] == 'o'); } + +test "implicit cast error unions with non-optional to optional pointer" { + const S = struct { + fn doTheTest() void { + expectError(error.Fail, foo()); + } + fn foo() anyerror!?*u8 { + return bar() orelse error.Fail; + } + fn bar() ?*u8 { + return null; + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From cc7060d0d934135d797bd2bc24288ecab095051a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 19:53:46 -0500 Subject: compile error for C pointer with align attribute See #1059 --- src/ir.cpp | 5 +++++ test/compile_errors.zig | 12 ++++++++---- test/stage1/behavior/type_info.zig | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 7c46b21717..6e190adf6f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5057,6 +5057,11 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode IrInstruction *align_value; if (align_expr != nullptr) { + if (ptr_len == PtrLenC) { + exec_add_error_node(irb->codegen, irb->exec, node, + buf_sprintf("[*c] pointers may not have align attribute")); + return irb->codegen->invalid_instruction; + } align_value = ir_gen_node(irb, align_expr, scope); if (align_value == irb->codegen->invalid_instruction) return align_value; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 5e9b691641..ab9eda3f15 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -118,13 +118,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.addTest( - "C pointer pointing to non C ABI compatible type", + "C pointer pointing to non C ABI compatible type or has align attr", \\const Foo = struct {}; - \\export fn entry() [*c]Foo { - \\ return undefined; + \\export fn a() void { + \\ const T = [*c]Foo; + \\} + \\export fn b() void { + \\ const T = [*c]align(4) u8; \\} , - ".tmp_source.zig:2:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", + ".tmp_source.zig:6:15: error: [*c] pointers may not have align attribute", ); cases.addTest( diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index dc185cc960..52e03c2d73 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -67,12 +67,12 @@ test "type info: C pointer type info" { } fn testCPtr() void { - const ptr_info = @typeInfo([*c]align(4) const i8); + const ptr_info = @typeInfo([*c]const i8); expect(TypeId(ptr_info) == TypeId.Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); - expect(ptr_info.Pointer.alignment == 4); + expect(ptr_info.Pointer.alignment == 1); expect(ptr_info.Pointer.child == i8); } -- cgit v1.2.3 From d5bbd748711abc82272199869cf70faf1ea30f52 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 20:04:13 -0500 Subject: allow C pointers to have alignment clang/gcc support pointer alignment attribute: https://clang.llvm.org/docs/AttributeReference.html#align-value --- src/ir.cpp | 5 ----- test/compile_errors.zig | 4 ---- test/stage1/behavior/type_info.zig | 4 ++-- 3 files changed, 2 insertions(+), 11 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 6e190adf6f..7c46b21717 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5057,11 +5057,6 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode IrInstruction *align_value; if (align_expr != nullptr) { - if (ptr_len == PtrLenC) { - exec_add_error_node(irb->codegen, irb->exec, node, - buf_sprintf("[*c] pointers may not have align attribute")); - return irb->codegen->invalid_instruction; - } align_value = ir_gen_node(irb, align_expr, scope); if (align_value == irb->codegen->invalid_instruction) return align_value; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index ab9eda3f15..a2fd901197 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -123,12 +123,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export fn a() void { \\ const T = [*c]Foo; \\} - \\export fn b() void { - \\ const T = [*c]align(4) u8; - \\} , ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", - ".tmp_source.zig:6:15: error: [*c] pointers may not have align attribute", ); cases.addTest( diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 52e03c2d73..dc185cc960 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -67,12 +67,12 @@ test "type info: C pointer type info" { } fn testCPtr() void { - const ptr_info = @typeInfo([*c]const i8); + const ptr_info = @typeInfo([*c]align(4) const i8); expect(TypeId(ptr_info) == TypeId.Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); - expect(ptr_info.Pointer.alignment == 1); + expect(ptr_info.Pointer.alignment == 4); expect(ptr_info.Pointer.child == i8); } -- cgit v1.2.3 From d6e0d82c328b4f9d733364382cce0941a601e91a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Feb 2019 23:09:12 -0500 Subject: translate-c: back to *c_void for opaque types See #1059 --- src/analyze.cpp | 2 +- src/ir.cpp | 13 +++++++++---- src/translate_c.cpp | 34 ++++++++++++++++++++++++++++++++-- test/compile_errors.zig | 10 ++++++++++ test/translate_c.zig | 20 ++++++++++---------- 5 files changed, 62 insertions(+), 17 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 55deafb3a8..1917784511 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -437,7 +437,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons // move this to a parameter bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); - assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); + assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); if (byte_alignment != 0) { uint32_t abi_alignment = get_abi_alignment(g, child_type); diff --git a/src/ir.cpp b/src/ir.cpp index 7c46b21717..707eac0181 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21205,10 +21205,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); return ira->codegen->invalid_instruction; - } else if (instruction->ptr_len == PtrLenC && !type_allowed_in_extern(ira->codegen, child_type)) { - ir_add_error(ira, &instruction->base, - buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); - return ira->codegen->invalid_instruction; + } else if (instruction->ptr_len == PtrLenC) { + if (!type_allowed_in_extern(ira->codegen, child_type)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); + return ira->codegen->invalid_instruction; + } else if (child_type->id == ZigTypeIdOpaque) { + ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); + return ira->codegen->invalid_instruction; + } } uint32_t align_bytes; diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 63f04dae6c..42a7ab436d 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -763,6 +763,30 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { } } +static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) { + switch (ty->getTypeClass()) { + case Type::Builtin: { + const BuiltinType *builtin_ty = static_cast(ty); + return builtin_ty->getKind() == BuiltinType::Void; + } + case Type::Record: { + const RecordType *record_ty = static_cast(ty); + return record_ty->getDecl()->getDefinition() == nullptr; + } + case Type::Elaborated: { + const ElaboratedType *elaborated_ty = static_cast(ty); + return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc); + } + case Type::Typedef: { + const TypedefType *typedef_ty = static_cast(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc); + } + default: + return false; + } +} + static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { switch (ty->getTypeClass()) { case Type::Builtin: @@ -912,8 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - return trans_create_node_ptr_type(c, child_qt.isConstQualified(), - child_qt.isVolatileQualified(), child_node, PtrLenC); + if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) { + AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenSingle); + return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); + } else { + return trans_create_node_ptr_type(c, child_qt.isConstQualified(), + child_qt.isVolatileQualified(), child_node, PtrLenC); + } } case Type::Typedef: { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a2fd901197..1f641a9052 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,16 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "C pointer to c_void", + \\export fn a() void { + \\ var x: *c_void = undefined; + \\ var y: [*c]c_void = x; + \\} + , + ".tmp_source.zig:3:12: error: C pointers cannot point opaque types", + ); + cases.addTest( "directly embedding opaque type in struct and union", \\const O = @OpaqueType(); diff --git a/test/translate_c.zig b/test/translate_c.zig index b87b962edc..7385427dbe 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -202,7 +202,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("restrict -> noalias", \\void foo(void *restrict bar, void *restrict); , - \\pub extern fn foo(noalias bar: [*c]c_void, noalias arg1: [*c]c_void) void; + \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; ); cases.add("simple struct", @@ -275,7 +275,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const struct_Foo = @OpaqueType(); , - \\pub extern fn some_func(foo: [*c]struct_Foo, x: c_int) [*c]struct_Foo; + \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; , \\pub const Foo = struct_Foo; ); @@ -336,7 +336,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const Foo = c_void; , - \\pub extern fn fun(a: [*c]Foo) Foo; + \\pub extern fn fun(a: ?*Foo) Foo; ); cases.add("generate inline func for #define global extern fn", @@ -608,7 +608,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 6; \\} , - \\pub export fn and_or_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ if ((a != 0) and (b != 0)) return 0; \\ if ((b != 0) and (c != 0)) return 1; \\ if ((a != 0) and (c != 0)) return 2; @@ -756,8 +756,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return x; \\} , - \\pub export fn foo(x: [*c]c_ushort) [*c]c_void { - \\ return @ptrCast([*c]c_void, x); + \\pub export fn foo(x: [*c]c_ushort) ?*c_void { + \\ return @ptrCast(?*c_void, x); \\} ); @@ -1276,7 +1276,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return !c; \\} , - \\pub fn foo(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { \\ return !(a == 0); \\ return !(a != 0); \\ return !(b != 0); @@ -1334,7 +1334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ B, \\ C, \\}; - \\pub fn if_none_bool(a: c_int, b: f32, c: [*c]c_void, d: enum_SomeEnum) c_int { + \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { \\ if (a != 0) return 0; \\ if (b != 0) return 1; \\ if (c != 0) return 2; @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn while_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2; @@ -1367,7 +1367,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 3; \\} , - \\pub fn for_none_bool(a: c_int, b: f32, c: [*c]c_void) c_int { + \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { \\ while (a != 0) return 0; \\ while (b != 0) return 1; \\ while (c != 0) return 2; -- cgit v1.2.3 From 7293e012d7956b892380517e914108ffadc6941b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Feb 2019 18:05:50 -0500 Subject: breaking: fix @sizeOf to be alloc size rather than store size * Fixes breaches of the guarantee that `@sizeOf(T) >= @alignOf(T)` * Fixes std.mem.secureZero for integers where this guarantee previously was breached * Fixes std.mem.Allocator for integers where this guarantee previously was breached Closes #1851 Closes #1864 --- doc/langref.html.in | 7 +++++- src/analyze.cpp | 37 ++++++++++++++++++++++++---- src/analyze.hpp | 1 + src/ir.cpp | 28 +++++++++++++++------- std/io.zig | 13 ++++------ std/mem.zig | 49 ++++++++++++++++---------------------- test/stage1/behavior.zig | 1 + test/stage1/behavior/bugs/1851.zig | 27 +++++++++++++++++++++ 8 files changed, 112 insertions(+), 51 deletions(-) create mode 100644 test/stage1/behavior/bugs/1851.zig (limited to 'src/ir.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index e5a60b0bc1..1341bf1be5 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -6299,10 +6299,15 @@ pub const FloatMode = enum {
{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}

This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory. + The result is a target-specific compile time constant.

- The result is a target-specific compile time constant. + This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset + in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#}, + consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or + {#syntax#}@typeInfo(T).Int.bits{#endsyntax#}.

+ {#see_also|@typeInfo#} {#header_close#} {#header_open|@sliceToBytes#} diff --git a/src/analyze.cpp b/src/analyze.cpp index e2a96da7c3..7949493586 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -356,6 +356,28 @@ uint64_t type_size(CodeGen *g, ZigType *type_entry) { } } + return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref); +} + +uint64_t type_size_store(CodeGen *g, ZigType *type_entry) { + assert(type_is_complete(type_entry)); + + if (!type_has_bits(type_entry)) + return 0; + + if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } else if (type_entry->id == ZigTypeIdArray) { + ZigType *child_type = type_entry->data.array.child_type; + if (child_type->id == ZigTypeIdStruct && + child_type->data.structure.layout == ContainerLayoutPacked) + { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } + } + return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); } @@ -6230,14 +6252,19 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdStruct: { if (is_slice(type_entry)) { - ConstPtrValue *ptr = &const_val->data.x_struct.fields[slice_ptr_index].data.x_ptr; - assert(ptr->special == ConstPtrSpecialBaseArray); - ConstExprValue *array = ptr->data.base_array.array_val; - size_t start = ptr->data.base_array.elem_index; - ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; size_t len = bigint_as_unsigned(&len_val->data.x_bigint); + ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; + if (ptr_val->special == ConstValSpecialUndef) { + assert(len == 0); + buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name)); + return; + } + assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array = ptr_val->data.x_ptr.data.base_array.array_val; + size_t start = ptr_val->data.x_ptr.data.base_array.elem_index; + render_const_val_array(g, buf, &type_entry->name, array, start, len); } else { buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); diff --git a/src/analyze.hpp b/src/analyze.hpp index 845fb62534..7ded651e95 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -19,6 +19,7 @@ ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count); uint64_t type_size(CodeGen *g, ZigType *type_entry); +uint64_t type_size_store(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type); diff --git a/src/ir.cpp b/src/ir.cpp index c9262038e0..92cdd8c891 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14331,15 +14331,15 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source if ((err = type_resolve(codegen, out_val->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; - size_t src_size = type_size(codegen, pointee->type); - size_t dst_size = type_size(codegen, out_val->type); - - if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { - copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); - return ErrorNone; - } + // We don't need to read the padding bytes, so we look at type_size_store bytes + size_t src_size = type_size_store(codegen, pointee->type); + size_t dst_size = type_size_store(codegen, out_val->type); if (dst_size <= src_size) { + if (types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { + copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); + return ErrorNone; + } Buf buf = BUF_INIT; buf_resize(&buf, src_size); buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); @@ -15798,6 +15798,8 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, IrInstructionToPtrType *to_ptr_type_instruction) { + Error err; + IrInstruction *value = to_ptr_type_instruction->value->child; ZigType *type_entry = value->value.type; if (type_is_invalid(type_entry)) @@ -15813,7 +15815,17 @@ static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.pointer.child_type->data.array.child_type, type_entry->data.pointer.is_const); } else if (is_slice(type_entry)) { - ptr_type = adjust_ptr_len(ira->codegen, type_entry->data.structure.fields[0].type_entry, PtrLenSingle); + ZigType *slice_ptr_type = type_entry->data.structure.fields[0].type_entry; + ptr_type = adjust_ptr_len(ira->codegen, slice_ptr_type, PtrLenSingle); + // If the pointer is over-aligned, we may have to reduce it based on the alignment of the element type. + if (slice_ptr_type->data.pointer.explicit_alignment != 0) { + ZigType *elem_type = slice_ptr_type->data.pointer.child_type; + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + uint32_t elem_align = get_abi_alignment(ira->codegen, elem_type); + uint32_t reduced_align = min(elem_align, slice_ptr_type->data.pointer.explicit_alignment); + ptr_type = adjust_ptr_align(ira->codegen, ptr_type, reduced_align); + } } else if (type_entry->id == ZigTypeIdArgTuple) { ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad); if (!arg_tuple_val) diff --git a/std/io.zig b/std/io.zig index d7e8507f9b..6c70834b52 100644 --- a/std/io.zig +++ b/std/io.zig @@ -935,8 +935,6 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { }; } - - pub const BufferedAtomicFile = struct { atomic_file: os.AtomicFile, file_stream: os.File.OutStream, @@ -978,7 +976,6 @@ pub const BufferedAtomicFile = struct { } }; - pub fn readLine(buf: *std.Buffer) ![]u8 { var stdin = try getStdIn(); var stdin_stream = stdin.inStream(); @@ -1073,13 +1070,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E else => in_stream, } }; } - + pub fn alignToByte(self: *Self) void { - if(!is_packed) return; + if (!is_packed) return; self.in_stream.alignToByte(); } - //@BUG: inferred error issue. See: #1386 + //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T { comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); @@ -1088,7 +1085,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; if (is_packed) { const result = try self.in_stream.readBitsNoEof(U, t_bit_count); @@ -1301,7 +1298,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com const U = @IntType(false, t_bit_count); const Log2U = math.Log2Int(U); - const int_size = @sizeOf(U); + const int_size = (U.bit_count + 7) / 8; const u_value = @bitCast(U, value); diff --git a/std/mem.zig b/std/mem.zig index 1c7523bf13..39b9701754 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. -pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { - comptime assert(T.bit_count % 8 == 0); +pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @ptrCast(*align(1) const T, bytes).*; } @@ -432,7 +431,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. /// Assumes the endianness of memory is foreign, so it must byte-swap. -pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { +pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { return @bswap(T, readIntNative(T, bytes)); } @@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) { builtin.Endian.Big => readIntNative, }; -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is native. This means the function can /// simply pointer cast memory. pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); + return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. /// Assumes the endianness of memory is foreign, so it must byte-swap. pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { @@ -481,7 +478,7 @@ pub const readIntSliceBig = switch (builtin.endian) { /// Reads an integer from memory with bit count specified by T. /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. -pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { +pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T { if (endian == builtin.endian) { return readIntNative(T, bytes); } else { @@ -489,15 +486,14 @@ pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.E } } -/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 /// and ignores extra bytes. -/// Note that @sizeOf(u24) is 3. /// The bit count of T must be evenly divisible by 8. pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { - assert(@sizeOf(u24) == 3); - assert(bytes.len >= @sizeOf(T)); + const n = @divExact(T.bit_count, 8); + assert(bytes.len >= n); // TODO https://github.com/ziglang/zig/issues/863 - return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); + return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); } test "comptime read/write int" { @@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" { /// accepts any integer bit width. /// This function stores in native endian, which means it is implemented as a simple /// memory store. -pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void { @ptrCast(*align(1) T, buf).* = value; } @@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. /// This function stores in foreign endian, which means it does a @bswap first. -pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { +pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void { writeIntNative(T, buf, @bswap(T, value)); } @@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) { /// Writes an integer to memory, storing it in twos-complement. /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. -pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { - comptime assert(T.bit_count % 8 == 0); +pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void { if (endian == builtin.endian) { return writeIntNative(T, buffer, value); } else { @@ -575,15 +570,13 @@ pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: bui } /// Writes a twos-complement little-endian integer to memory. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer after writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntLittle /// instead. pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -595,14 +588,12 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { } /// Writes a twos-complement big-endian integer to memory. -/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buffer.len >= T.bit_count / 8. /// The bit count of T must be divisible by 8. /// Any extra bytes in buffer before writing the integer are set to zero. To /// avoid the branch to check for extra buffer bytes, use writeIntBig instead. pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { - comptime assert(@sizeOf(u24) == 3); - comptime assert(T.bit_count % 8 == 0); - assert(buffer.len >= @sizeOf(T)); + assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); @@ -626,7 +617,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) { }; /// Writes a twos-complement integer to memory, with the specified endianness. -/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// Asserts that buf.len >= T.bit_count / 8. /// The bit count of T must be evenly divisible by 8. /// Any extra bytes in buffer not part of the integer are set to zero, with /// respect to endianness. To avoid the branch to check for extra buffer bytes, diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 1fa00b34fd..df311637fa 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -17,6 +17,7 @@ comptime { _ = @import("behavior/bugs/1421.zig"); _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1486.zig"); + _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/394.zig"); _ = @import("behavior/bugs/655.zig"); _ = @import("behavior/bugs/656.zig"); diff --git a/test/stage1/behavior/bugs/1851.zig b/test/stage1/behavior/bugs/1851.zig new file mode 100644 index 0000000000..ff9ab419f8 --- /dev/null +++ b/test/stage1/behavior/bugs/1851.zig @@ -0,0 +1,27 @@ +const std = @import("std"); +const expect = std.testing.expect; + +test "allocation and looping over 3-byte integer" { + expect(@sizeOf(u24) == 4); + expect(@sizeOf([1]u24) == 4); + expect(@alignOf(u24) == 4); + expect(@alignOf([1]u24) == 4); + var buffer: [100]u8 = undefined; + const a = &std.heap.FixedBufferAllocator.init(&buffer).allocator; + + var x = a.alloc(u24, 2) catch unreachable; + expect(x.len == 2); + x[0] = 0xFFFFFF; + x[1] = 0xFFFFFF; + + const bytes = @sliceToBytes(x); + expect(@typeOf(bytes) == []align(4) u8); + expect(bytes.len == 8); + + for (bytes) |*b| { + b.* = 0x00; + } + + expect(x[0] == 0x00); + expect(x[1] == 0x00); +} -- cgit v1.2.3 From a05e224150a5a4bcad5ab1b399b43db8a0e28104 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Feb 2019 19:19:28 -0500 Subject: typecheck the panic function this adds the prototype of panic to @import("builtin") and then uses it to do an implicit cast of the panic function to this prototype, rather than redoing all the implicit cast logic. closes #1894 closes #1895 --- src/all_types.hpp | 1 + src/analyze.cpp | 61 ++++++++++++++++++------------------------------- src/analyze.hpp | 1 + src/codegen.cpp | 4 ++++ src/ir.cpp | 15 +++++++----- src/ir.hpp | 2 +- test/compile_errors.zig | 14 ++++++++++-- 7 files changed, 50 insertions(+), 48 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index bafe316c3d..6fbd987b9e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1758,6 +1758,7 @@ struct CodeGen { ZigFn *cur_fn; ZigFn *main_fn; ZigFn *panic_fn; + TldFn *panic_tld_fn; AstNode *root_export_decl; CacheHash cache_hash; diff --git a/src/analyze.cpp b/src/analyze.cpp index 7949493586..12e245bd72 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1351,7 +1351,7 @@ static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *no size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr); + nullptr, nullptr, node, type_name, nullptr, nullptr); } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { @@ -3247,36 +3247,19 @@ static bool scope_is_root_decls(Scope *scope) { zig_unreachable(); } -static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) { - add_node_error(g, proto_node, - buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'", - buf_ptr(&fn_type->name))); -} - -static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) { - AstNode *proto_node = panic_fn->proto_node; - assert(proto_node->type == NodeTypeFnProto); - ZigType *fn_type = panic_fn->type_entry; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (fn_type_id->param_count != 2) { - return wrong_panic_prototype(g, proto_node, fn_type); - } - ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0); - ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr); - if (fn_type_id->param_info[0].type != const_u8_slice) { - return wrong_panic_prototype(g, proto_node, fn_type); - } +void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { + ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn"); + assert(panic_fn_type_val != nullptr); + assert(panic_fn_type_val->type->id == ZigTypeIdMetaType); + ZigType *panic_fn_type = panic_fn_type_val->data.x_type; - ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g)); - if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + AstNode *fake_decl = allocate(1); + *fake_decl = *panic_fn->proto_node; + fake_decl->type = NodeTypeSymbol; + fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name; - ZigType *actual_return_type = fn_type_id->return_type; - if (actual_return_type != g->builtin_types.entry_unreachable) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + // call this for the side effects of casting to panic_fn_type + analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr); } ZigType *get_test_fn_type(CodeGen *g) { @@ -3371,18 +3354,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (!fn_table_entry->type_entry->data.fn.is_generic) { if (fn_def_node) g->fn_defs.append(fn_table_entry); + } - if (scope_is_root_decls(tld_fn->base.parent_scope) && - (import == g->root_import || import->package == g->panic_package)) + if (scope_is_root_decls(tld_fn->base.parent_scope) && + (import == g->root_import || import->package == g->panic_package)) + { + if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { + g->main_fn = fn_table_entry; + } else if ((import->package == g->panic_package || g->have_pub_panic) && + buf_eql_str(&fn_table_entry->symbol_name, "panic")) { - if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { - g->main_fn = fn_table_entry; - } else if ((import->package == g->panic_package || g->have_pub_panic) && - buf_eql_str(&fn_table_entry->symbol_name, "panic")) - { - g->panic_fn = fn_table_entry; - typecheck_panic_fn(g, fn_table_entry); - } + g->panic_fn = fn_table_entry; + g->panic_tld_fn = tld_fn; } } } else if (source_node->type == NodeTypeTestDecl) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 7ded651e95..956ef47309 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -239,4 +239,5 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, ConstExprValue *const_val, ZigType *wanted_type); +void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index d2662b10d2..d2b2836b0c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7144,6 +7144,8 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " instruction_addresses: []usize,\n" "};\n\n"); + buf_append_str(contents, "pub const PanicFn = fn([]const u8, ?*StackTrace) noreturn;\n\n"); + const char *cur_os = nullptr; { buf_appendf(contents, "pub const Os = enum {\n"); @@ -7913,6 +7915,8 @@ static void gen_root_source(CodeGen *g) { } } + typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn); + report_errors_and_maybe_exit(g); } diff --git a/src/ir.cpp b/src/ir.cpp index 92cdd8c891..0fcbb60fe8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9949,7 +9949,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec) + IrExecutable *parent_exec, AstNode *expected_type_source_node) { if (expected_type != nullptr && type_is_invalid(expected_type)) return &codegen->invalid_instruction->value; @@ -9985,7 +9985,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod analyzed_executable->backward_branch_count = backward_branch_count; analyzed_executable->backward_branch_quota = backward_branch_quota; analyzed_executable->begin_scope = scope; - ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node); + ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node); if (type_is_invalid(result_type)) return &codegen->invalid_instruction->value; @@ -10863,10 +10863,13 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } break; } + case ConstCastResultIdFnIsGeneric: + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("only one of the functions is generic")); + break; case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO - case ConstCastResultIdFnIsGeneric: // TODO case ConstCastResultIdFnReturnType: // TODO case ConstCastResultIdFnArgCount: // TODO case ConstCastResultIdFnGenericArgCount: // TODO @@ -13856,7 +13859,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call AstNode *body_node = fn_entry->body_node; result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, - nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); + nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node); if (inferred_err_set_type != nullptr) { inferred_err_set_type->data.error_set.infer_fn = nullptr; @@ -14052,7 +14055,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, - nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec); + nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); const_instruction->base.value = *align_result; @@ -18464,7 +18467,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct ZigType *void_type = ira->codegen->builtin_types.entry_void; ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node, nullptr, nullptr); + &cimport_scope->buf, block_node, nullptr, nullptr, nullptr); if (type_is_invalid(cimport_result->type)) return ira->codegen->invalid_instruction; diff --git a/src/ir.hpp b/src/ir.hpp index 0a7c614812..0b85ad2c55 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, - IrExecutable *parent_exec); + IrExecutable *parent_exec, AstNode *expected_type_source_node); ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, ZigType *expected_type, AstNode *expected_type_source_node); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e7108cb36a..9ef4af4162 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -346,13 +346,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "Panic declared with wrong type signature in tests", + "wrong panic signature, runtime function", \\test "" {} \\ \\pub fn panic() void {} \\ , - ".tmp_source.zig:3:5: error: expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'", + ".tmp_source.zig:3:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn() void'", + ); + + cases.add( + "wrong panic signature, generic function", + \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { + \\ while (true) {} + \\} + , + ".tmp_source.zig:1:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn([]const u8,var)var'", + ".tmp_source.zig:1:5: note: only one of the functions is generic", ); cases.add( -- cgit v1.2.3