Commit f8a782fb2e

Andrew Kelley <superjoe30@gmail.com>
2018-11-19 01:36:27
all numbers with comptime known values implicitly cast
to all number types. If the value does not fit, a compile error is emitted. closes #422 closes #1712
1 parent e9b47d9
Changed files (4)
doc/langref.html.in
@@ -6659,7 +6659,7 @@ fn foo(x: []const u8) u8 {
       {#header_close#}
       {#header_open|Cast Negative Number to Unsigned Integer#}
       <p>At compile-time:</p>
-      {#code_begin|test_err|attempt to cast negative value to unsigned integer#}
+      {#code_begin|test_err|cannot cast negative value -1 to unsigned integer type 'u32'#}
 comptime {
     const value: i32 = -1;
     const unsigned = @intCast(u32, value);
@@ -6681,7 +6681,7 @@ pub fn main() void {
       {#header_close#}
       {#header_open|Cast Truncates Data#}
       <p>At compile-time:</p>
-      {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}
+      {#code_begin|test_err|integer value 300 cannot be implicitly casted to type 'u8'#}
 comptime {
     const spartan_count: u16 = 300;
     const byte = @intCast(u8, spartan_count);
src/ir.cpp
@@ -138,6 +138,11 @@ struct ConstCastErrSetMismatch {
     ZigList<ErrorTableEntry *> missing_errors;
 };
 
+enum UndefAllowed {
+    UndefOk,
+    UndefBad,
+};
+
 static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
 static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
 static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
@@ -157,6 +162,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, 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);
+static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
 
 static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
     assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -8063,15 +8069,153 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
         return false;
     }
 
-    ConstExprValue *const_val = &instruction->value;
-    assert(const_val->special != ConstValSpecialRuntime);
+    ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad);
+    assert(const_val != nullptr);
+
+    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);
 
-    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);
     if (other_type->id == ZigTypeIdFloat) {
-        return true;
+        if (const_val->type->id == ZigTypeIdComptimeInt || const_val->type->id == ZigTypeIdComptimeFloat) {
+            return true;
+        }
+        if (const_val->type->id == ZigTypeIdInt) {
+            BigFloat tmp_bf;
+            bigfloat_init_bigint(&tmp_bf, &const_val->data.x_bigint);
+            BigFloat orig_bf;
+            switch (other_type->data.floating.bit_count) {
+                case 16: {
+                    float16_t tmp = bigfloat_to_f16(&tmp_bf);
+                    bigfloat_init_16(&orig_bf, tmp);
+                    break;
+                }
+                case 32: {
+                    float tmp = bigfloat_to_f32(&tmp_bf);
+                    bigfloat_init_32(&orig_bf, tmp);
+                    break;
+                }
+                case 64: {
+                    double tmp = bigfloat_to_f64(&tmp_bf);
+                    bigfloat_init_64(&orig_bf, tmp);
+                    break;
+                }
+                case 80:
+                    zig_panic("TODO");
+                case 128: {
+                    float128_t tmp = bigfloat_to_f128(&tmp_bf);
+                    bigfloat_init_128(&orig_bf, tmp);
+                    break;
+                }
+                default:
+                    zig_unreachable();
+            }
+            BigInt orig_bi;
+            bigint_init_bigfloat(&orig_bi, &orig_bf);
+            if (bigint_cmp(&orig_bi, &const_val->data.x_bigint) == CmpEQ) {
+                return true;
+            }
+            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 has no representation in type '%s'",
+                    buf_ptr(val_buf),
+                    buf_ptr(&other_type->name)));
+            return false;
+        }
+        if (other_type->data.floating.bit_count >= const_val->type->data.floating.bit_count) {
+            return true;
+        }
+        switch (other_type->data.floating.bit_count) {
+            case 16:
+                switch (const_val->type->data.floating.bit_count) {
+                    case 32: {
+                        float16_t tmp = zig_double_to_f16(const_val->data.x_f32);
+                        float orig = zig_f16_to_double(tmp);
+                        if (const_val->data.x_f32 == orig) {
+                            return true;
+                        }
+                        break;
+                    }
+                    case 64: {
+                        float16_t tmp = zig_double_to_f16(const_val->data.x_f64);
+                        double orig = zig_f16_to_double(tmp);
+                        if (const_val->data.x_f64 == orig) {
+                            return true;
+                        }
+                        break;
+                    }
+                    case 80:
+                        zig_panic("TODO");
+                    case 128: {
+                        float16_t tmp = f128M_to_f16(&const_val->data.x_f128);
+                        float128_t orig;
+                        f16_to_f128M(tmp, &orig);
+                        if (f128M_eq(&orig, &const_val->data.x_f128)) {
+                            return true;
+                        }
+                        break;
+                    }
+                    default:
+                        zig_unreachable();
+                }
+                break;
+            case 32:
+                switch (const_val->type->data.floating.bit_count) {
+                    case 64: {
+                        float tmp = const_val->data.x_f64;
+                        double orig = tmp;
+                        if (const_val->data.x_f64 == orig) {
+                            return true;
+                        }
+                        break;
+                    }
+                    case 80:
+                        zig_panic("TODO");
+                    case 128: {
+                        float32_t tmp = f128M_to_f32(&const_val->data.x_f128);
+                        float128_t orig;
+                        f32_to_f128M(tmp, &orig);
+                        if (f128M_eq(&orig, &const_val->data.x_f128)) {
+                            return true;
+                        }
+                        break;
+                    }
+                    default:
+                        zig_unreachable();
+                }
+                break;
+            case 64:
+                switch (const_val->type->data.floating.bit_count) {
+                    case 80:
+                        zig_panic("TODO");
+                    case 128: {
+                        float64_t tmp = f128M_to_f64(&const_val->data.x_f128);
+                        float128_t orig;
+                        f64_to_f128M(tmp, &orig);
+                        if (f128M_eq(&orig, &const_val->data.x_f128)) {
+                            return true;
+                        }
+                        break;
+                    }
+                    default:
+                        zig_unreachable();
+                }
+                break;
+            case 80:
+                assert(const_val->type->data.floating.bit_count == 128);
+                zig_panic("TODO");
+            case 128:
+                return true;
+            default:
+                zig_unreachable();
+        }
+        Buf *val_buf = buf_alloc();
+        float_append_buf(val_buf, const_val);
+        ir_add_error(ira, instruction,
+            buf_sprintf("cast of value %s to type '%s' loses information",
+                buf_ptr(val_buf),
+                buf_ptr(&other_type->name)));
+        return false;
     } else if (other_type->id == ZigTypeIdInt && const_val_is_int) {
         if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) {
             Buf *val_buf = buf_alloc();
@@ -9453,11 +9597,6 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
     return const_instr;
 }
 
-enum UndefAllowed {
-    UndefOk,
-    UndefBad,
-};
-
 static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) {
     switch (value->value.special) {
         case ConstValSpecialStatic:
@@ -10370,6 +10509,121 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
     }
 
+    // cast from T to ?T
+    // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
+    if (wanted_type->id == ZigTypeIdOptional) {
+        ZigType *wanted_child_type = wanted_type->data.maybe.child_type;
+        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);
+        } 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);
+            } else {
+                return ira->codegen->invalid_instruction;
+            }
+        } else if (
+            wanted_child_type->id == ZigTypeIdPointer &&
+            wanted_child_type->data.pointer.ptr_len == PtrLenUnknown &&
+            actual_type->id == ZigTypeIdPointer &&
+            actual_type->data.pointer.ptr_len == PtrLenSingle &&
+            actual_type->data.pointer.child_type->id == ZigTypeIdArray)
+        {
+            if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+                return ira->codegen->invalid_instruction;
+            if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+                return ira->codegen->invalid_instruction;
+            if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) &&
+                types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type,
+                actual_type->data.pointer.child_type->data.array.child_type, source_node,
+                !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk)
+            {
+                IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value,
+                        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);
+            }
+        }
+    }
+
+    // T to E!T
+    if (wanted_type->id == ZigTypeIdErrorUnion) {
+        if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
+            source_node, false).id == ConstCastResultIdOk)
+        {
+            return ir_analyze_err_wrap_payload(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_type->data.error_union.payload_type, true)) {
+                return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
+            } else {
+                return ira->codegen->invalid_instruction;
+            }
+        }
+    }
+
+    // cast from T to E!?T
+    if (wanted_type->id == ZigTypeIdErrorUnion &&
+        wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional &&
+        actual_type->id != ZigTypeIdOptional)
+    {
+        ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
+        if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
+            actual_type->id == ZigTypeIdNull ||
+            actual_type->id == ZigTypeIdComptimeInt ||
+            actual_type->id == ZigTypeIdComptimeFloat)
+        {
+            IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
+            if (type_is_invalid(cast1->value.type))
+                return ira->codegen->invalid_instruction;
+
+            IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
+            if (type_is_invalid(cast2->value.type))
+                return ira->codegen->invalid_instruction;
+
+            return cast2;
+        }
+    }
+
+
+    // cast from comptime-known number to another number type
+    if (instr_is_comptime(value) &&
+        (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt ||
+        actual_type->id == ZigTypeIdFloat || actual_type->id == ZigTypeIdComptimeFloat) &&
+        (wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt ||
+        wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat))
+    {
+        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);
+                if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) {
+                    bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint);
+                } else {
+                    float_init_bigint(&result->value.data.x_bigint, &value->value);
+                }
+                return result;
+            } else if (wanted_type->id == ZigTypeIdComptimeFloat || wanted_type->id == ZigTypeIdFloat) {
+                IrInstruction *result = ir_const(ira, source_instr, wanted_type);
+                if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) {
+                    BigFloat bf;
+                    bigfloat_init_bigint(&bf, &value->value.data.x_bigint);
+                    float_init_bigfloat(&result->value, &bf);
+                } else {
+                    float_init_float(&result->value, &value->value);
+                }
+                return result;
+            }
+            zig_unreachable();
+        } else {
+            return ira->codegen->invalid_instruction;
+        }
+    }
+
     // widening conversion
     if (wanted_type->id == ZigTypeIdInt &&
         actual_type->id == ZigTypeIdInt &&
@@ -10472,47 +10726,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
     }
 
 
-    // cast from T to ?T
-    // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
-    if (wanted_type->id == ZigTypeIdOptional) {
-        ZigType *wanted_child_type = wanted_type->data.maybe.child_type;
-        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);
-        } 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);
-            } else {
-                return ira->codegen->invalid_instruction;
-            }
-        } else if (
-            wanted_child_type->id == ZigTypeIdPointer &&
-            wanted_child_type->data.pointer.ptr_len == PtrLenUnknown &&
-            actual_type->id == ZigTypeIdPointer &&
-            actual_type->data.pointer.ptr_len == PtrLenSingle &&
-            actual_type->data.pointer.child_type->id == ZigTypeIdArray)
-        {
-            if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
-                return ira->codegen->invalid_instruction;
-            if ((err = type_resolve(ira->codegen, wanted_child_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
-                return ira->codegen->invalid_instruction;
-            if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_child_type) &&
-                types_match_const_cast_only(ira, wanted_child_type->data.pointer.child_type,
-                actual_type->data.pointer.child_type->data.array.child_type, source_node,
-                !wanted_child_type->data.pointer.is_const).id == ConstCastResultIdOk)
-            {
-                IrInstruction *cast1 = ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value,
-                        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);
-            }
-        }
-    }
-
     // cast from null literal to maybe type
     if (wanted_type->id == ZigTypeIdOptional &&
         actual_type->id == ZigTypeIdNull)
@@ -10520,23 +10733,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
     }
 
-    // cast from child type of error type to error type
-    if (wanted_type->id == ZigTypeIdErrorUnion) {
-        if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
-            source_node, false).id == ConstCastResultIdOk)
-        {
-            return ir_analyze_err_wrap_payload(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_type->data.error_union.payload_type, true)) {
-                return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
-            } else {
-                return ira->codegen->invalid_instruction;
-            }
-        }
-    }
-
     // cast from [N]T to E![]const T
     if (wanted_type->id == ZigTypeIdErrorUnion &&
         is_slice(wanted_type->data.error_union.payload_type) &&
@@ -10568,54 +10764,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
     }
 
-    // cast from T to E!?T
-    if (wanted_type->id == ZigTypeIdErrorUnion &&
-        wanted_type->data.error_union.payload_type->id == ZigTypeIdOptional &&
-        actual_type->id != ZigTypeIdOptional)
-    {
-        ZigType *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
-        if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
-            actual_type->id == ZigTypeIdNull ||
-            actual_type->id == ZigTypeIdComptimeInt ||
-            actual_type->id == ZigTypeIdComptimeFloat)
-        {
-            IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
-            if (type_is_invalid(cast1->value.type))
-                return ira->codegen->invalid_instruction;
-
-            IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
-            if (type_is_invalid(cast2->value.type))
-                return ira->codegen->invalid_instruction;
-
-            return cast2;
-        }
-    }
-
-    // cast from number literal to another type
-    if (actual_type->id == ZigTypeIdComptimeFloat ||
-        actual_type->id == ZigTypeIdComptimeInt)
-    {
-        if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
-            CastOp op;
-            if ((actual_type->id == ZigTypeIdComptimeFloat &&
-                 wanted_type->id == ZigTypeIdFloat) ||
-                (actual_type->id == ZigTypeIdComptimeInt &&
-                 wanted_type->id == ZigTypeIdInt))
-            {
-                op = CastOpNumLitToConcrete;
-            } else if (wanted_type->id == ZigTypeIdInt) {
-                op = CastOpFloatToInt;
-            } else if (wanted_type->id == ZigTypeIdFloat) {
-                op = CastOpIntToFloat;
-            } else {
-                zig_unreachable();
-            }
-            return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false);
-        } else {
-            return ira->codegen->invalid_instruction;
-        }
-    }
-
     // cast from typed number to integer or float literal.
     // works when the number is known at compile time
     if (instr_is_comptime(value) &&
@@ -17878,7 +18026,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct
     if (type_is_invalid(dest_type))
         return ira->codegen->invalid_instruction;
 
-    if (dest_type->id != ZigTypeIdInt) {
+    if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) {
         ir_add_error(ira, instruction->dest_type, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name)));
         return ira->codegen->invalid_instruction;
     }
@@ -17887,20 +18035,22 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct
     if (type_is_invalid(target->value.type))
         return ira->codegen->invalid_instruction;
 
-    if (target->value.type->id == ZigTypeIdComptimeInt) {
-        if (ir_num_lit_fits_in_other_type(ira, target, dest_type, true)) {
-            return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpNumLitToConcrete, false);
-        } else {
-            return ira->codegen->invalid_instruction;
-        }
-    }
-
-    if (target->value.type->id != ZigTypeIdInt) {
+    if (target->value.type->id != ZigTypeIdInt && target->value.type->id != ZigTypeIdComptimeInt) {
         ir_add_error(ira, instruction->target, buf_sprintf("expected integer type, found '%s'",
                     buf_ptr(&target->value.type->name)));
         return ira->codegen->invalid_instruction;
     }
 
+    if (instr_is_comptime(target)) {
+        return ir_implicit_cast(ira, target, dest_type);
+    }
+
+    if (dest_type->id == ZigTypeIdComptimeInt) {
+        ir_add_error(ira, instruction->target, buf_sprintf("attempt to cast runtime value to '%s'",
+                buf_ptr(&dest_type->name)));
+        return ira->codegen->invalid_instruction;
+    }
+
     return ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type);
 }
 
test/cases/cast.zig
@@ -452,3 +452,13 @@ test "implicit ptr to *c_void" {
     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/compile_errors.zig
@@ -1,6 +1,61 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "cast negative value to unsigned integer",
+        \\comptime {
+        \\    const value: i32 = -1;
+        \\    const unsigned = @intCast(u32, value);
+        \\}
+        \\export fn entry1() void {
+        \\    const value: i32 = -1;
+        \\    const unsigned: u32 = value;
+        \\}
+    ,
+        ".tmp_source.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'",
+        ".tmp_source.zig:7:27: error: cannot cast negative value -1 to unsigned integer type 'u32'",
+    );
+
+    cases.add(
+        "integer cast truncates bits",
+        \\export fn entry1() void {
+        \\    const spartan_count: u16 = 300;
+        \\    const byte = @intCast(u8, spartan_count);
+        \\}
+        \\export fn entry2() void {
+        \\    const spartan_count: u16 = 300;
+        \\    const byte: u8 = spartan_count;
+        \\}
+        \\export fn entry3() void {
+        \\    var spartan_count: u16 = 300;
+        \\    var byte: u8 = spartan_count;
+        \\}
+    ,
+        ".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'",
+    );
+
+    cases.add(
+        "comptime implicit cast f64 to f32",
+        \\export fn entry() void {
+        \\    const x: f64 = 16777217;
+        \\    const y: f32 = x;
+        \\}
+    ,
+        ".tmp_source.zig:3:20: error: cast of value 16777217.000000 to type 'f32' loses information",
+    );
+
+    cases.add(
+        "implicit cast from f64 to f32",
+        \\var x: f64 = 1.0;
+        \\var y: f32 = x;
+        \\
+        \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
+    ,
+        ".tmp_source.zig:2:14: error: expected type 'f32', found 'f64'",
+    );
+
     cases.add(
         "exceeded maximum bit width of integer",
         \\export fn entry1() void {
@@ -1819,7 +1874,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    if (0) {}
         \\}
     ,
-        ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'",
+        ".tmp_source.zig:2:9: error: expected type 'bool', found 'comptime_int'",
     );
 
     cases.add(
@@ -2422,16 +2477,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         ".tmp_source.zig:1:36: error: expected type 'fn(i32) i32', found 'extern fn(i32) i32'",
     );
 
-    cases.add(
-        "implicit cast from f64 to f32",
-        \\const x : f64 = 1.0;
-        \\const y : f32 = x;
-        \\
-        \\export fn entry() usize { return @sizeOf(@typeOf(y)); }
-    ,
-        ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'",
-    );
-
     cases.add(
         "colliding invalid top level functions",
         \\fn func() bogus {}
@@ -4049,16 +4094,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         ".tmp_source.zig:2:14: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod",
     );
 
-    cases.add(
-        "cast negative value to unsigned integer",
-        \\comptime {
-        \\    const value: i32 = -1;
-        \\    const unsigned = @intCast(u32, value);
-        \\}
-    ,
-        ".tmp_source.zig:3:22: error: attempt to cast negative value to unsigned integer",
-    );
-
     cases.add(
         "compile-time division by zero",
         \\comptime {
@@ -4081,16 +4116,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         ".tmp_source.zig:4:17: error: division by zero",
     );
 
-    cases.add(
-        "compile-time integer cast truncates bits",
-        \\comptime {
-        \\    const spartan_count: u16 = 300;
-        \\    const byte = @intCast(u8, spartan_count);
-        \\}
-    ,
-        ".tmp_source.zig:3:18: error: cast from 'u16' to 'u8' truncates bits",
-    );
-
     cases.add(
         "@setRuntimeSafety twice for same scope",
         \\export fn foo() void {