Commit a4e19f94f1

Andrew Kelley <superjoe30@gmail.com>
2016-02-01 05:22:05
support casting between floats
1 parent e74a726
src/all_types.hpp
@@ -340,7 +340,7 @@ enum CastOp {
     CastOpNoop, // fn call expr is a cast, but does nothing
     CastOpPtrToInt,
     CastOpIntToPtr,
-    CastOpIntWidenOrShorten,
+    CastOpWidenOrShorten,
     CastOpToUnknownSizeArray,
     CastOpMaybeWrap,
     CastOpErrorWrap,
src/analyze.cpp
@@ -1681,6 +1681,14 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
         return true;
     }
 
+    // implicit float widening conversion
+    if (expected_type->id == TypeTableEntryIdFloat &&
+        actual_type->id == TypeTableEntryIdFloat &&
+        expected_type->size_in_bits >= actual_type->size_in_bits)
+    {
+        return true;
+    }
+
     // implicit constant sized array to unknown size array conversion
     if (expected_type->id == TypeTableEntryIdStruct &&
         expected_type->data.structure.is_unknown_size_array &&
@@ -3366,7 +3374,7 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
         case CastOpNoCast:
             zig_unreachable();
         case CastOpNoop:
-        case CastOpIntWidenOrShorten:
+        case CastOpWidenOrShorten:
         case CastOpPointerReinterpret:
             *const_val = *other_val;
             break;
@@ -3477,11 +3485,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
         return wanted_type;
     }
 
-    // explicit cast from any int to any other int
-    if (wanted_type->id == TypeTableEntryIdInt &&
-        actual_type->id == TypeTableEntryIdInt)
+    // explicit widening or shortening cast
+    if ((wanted_type->id == TypeTableEntryIdInt &&
+        actual_type->id == TypeTableEntryIdInt) ||
+        (wanted_type->id == TypeTableEntryIdFloat &&
+        actual_type->id == TypeTableEntryIdFloat))
     {
-        node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten;
+        node->data.fn_call_expr.cast_op = CastOpWidenOrShorten;
         eval_const_expr_implicit_cast(g, node, expr_node);
         return wanted_type;
     }
src/codegen.cpp
@@ -349,20 +349,36 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
 static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type,
         TypeTableEntry *wanted_type, LLVMValueRef expr_val)
 {
+    assert(actual_type->id == wanted_type->id);
     if (actual_type->size_in_bits == wanted_type->size_in_bits) {
         return expr_val;
     } else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
-        if (actual_type->data.integral.is_signed) {
+        if (actual_type->id == TypeTableEntryIdFloat) {
             add_debug_source_node(g, source_node);
-            return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildFPExt(g->builder, expr_val, wanted_type->type_ref, "");
+        } else if (actual_type->id == TypeTableEntryIdInt) {
+            if (actual_type->data.integral.is_signed) {
+                add_debug_source_node(g, source_node);
+                return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
+            } else {
+                add_debug_source_node(g, source_node);
+                return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+            }
         } else {
+            zig_unreachable();
+        }
+    } else if (actual_type->size_in_bits > wanted_type->size_in_bits) {
+        if (actual_type->id == TypeTableEntryIdFloat) {
             add_debug_source_node(g, source_node);
-            return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
+            return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
+        } else if (actual_type->id == TypeTableEntryIdInt) {
+            add_debug_source_node(g, source_node);
+            return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
+        } else {
+            zig_unreachable();
         }
     } else {
-        assert(actual_type->size_in_bits > wanted_type->size_in_bits);
-        add_debug_source_node(g, source_node);
-        return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
+        zig_unreachable();
     }
 }
 
@@ -455,7 +471,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
         case CastOpPointerReinterpret:
             add_debug_source_node(g, node);
             return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
-        case CastOpIntWidenOrShorten:
+        case CastOpWidenOrShorten:
             return gen_widen_or_shorten(g, node, actual_type, wanted_type, expr_val);
         case CastOpToUnknownSizeArray:
             {
test/run_tests.cpp
@@ -1493,7 +1493,8 @@ c_import {
     @c_include("stdio.h");
 }
 export fn main(argc: c_int, argv: &&u8) -> c_int {
-    const x : f64 = 3.25;
+    const small: f32 = 3.25;
+    const x: f64 = small;
     const y = i32(x);
     const z = f64(y);
     printf(c"%.2f\n%d\n%.2f\n", x, y, z);
@@ -1945,6 +1946,12 @@ pub fn a(x: i32) -> i32 {x + 0}
 pub fn b(x: i32) -> i32 {x + 1}
 export fn c(x: i32) -> i32 {x + 2}
     )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
+
+
+    add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE(
+const x : f64 = 1.0;
+const y : f32 = x;
+    )SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', got 'f64'");
 }
 
 //////////////////////////////////////////////////////////////////////////////