From 32665856064dde5a08a64de8641c8bec9c6f352f Mon Sep 17 00:00:00 2001 From: Raul Leal Date: Thu, 13 Apr 2017 09:59:39 +0000 Subject: [PATCH 1/2] Implicit cast from T to %?T closes #171 --- .vscode/settings.json | 8 ++++++++ src/ir.cpp | 42 +++++++++++++++++++++++++++++++++++++----- test/cases/cast.zig | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..edd3d2a13b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "files.associations": { + "*.zig": "c", + "type_traits": "cpp", + "*.inc": "cpp", + "thread": "cpp" + } +} \ No newline at end of file diff --git a/src/ir.cpp b/src/ir.cpp index e22f96fba0..1c9f1c5fe2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5826,11 +5826,12 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc { return true; } - } else if ((other_type->id == TypeTableEntryIdNumLitFloat && - const_val->data.x_bignum.kind == BigNumKindFloat) || - (other_type->id == TypeTableEntryIdNumLitInt && - const_val->data.x_bignum.kind == BigNumKindInt)) - { + } else if ((other_type->id == TypeTableEntryIdNumLitFloat && const_val->data.x_bignum.kind == BigNumKindFloat) || + (other_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) { + return true; + } else if ((other_type->id == TypeTableEntryIdMaybe && + other_type->data.maybe.child_type->id == TypeTableEntryIdInt && + const_val->data.x_bignum.kind == BigNumKindInt)) { return true; } @@ -5894,6 +5895,18 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, return ImplicitCastMatchResultYes; } + // implicit conversion from T to %?T + if (expected_type->id == TypeTableEntryIdErrorUnion && + expected_type->data.error.child_type->id == TypeTableEntryIdMaybe && + ir_types_match_with_implicit_cast( + ira, + expected_type->data.error.child_type->data.maybe.child_type, + actual_type, + value)) + { + return ImplicitCastMatchResultYes; + } + // implicit widening conversion if (expected_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdInt && @@ -7067,6 +7080,25 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); } + // explicit cast from T to %?T + if (wanted_type->id == TypeTableEntryIdErrorUnion && + wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe && + actual_type->id != TypeTableEntryIdMaybe) { + if (types_match_const_cast_only(wanted_type->data.error.child_type->data.maybe.child_type, actual_type) || + actual_type->id == TypeTableEntryIdNullLit || + actual_type->id == TypeTableEntryIdNumLitInt ) { + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + if (type_is_invalid(cast2->value.type)) + return ira->codegen->invalid_instruction; + + return cast2; + } + } + // explicit cast from number literal to another type // explicit cast from number literal to &const integer if (actual_type->id == TypeTableEntryIdNumLitFloat || diff --git a/test/cases/cast.zig b/test/cases/cast.zig index d0ea25452c..7a09dd0923 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -65,7 +65,6 @@ fn testPeerResolveArrayConstSlice(b: bool) { assert(mem.eql(u8, value2, "zz")); } - test "integer literal to &const int" { const x: &const i32 = 3; assert(*x == 3); @@ -75,3 +74,41 @@ test "string literal to &const []const u8" { const x: &const []const u8 = "hello"; assert(mem.eql(u8, *x, "hello")); } + +test "implicitly cast from T to %?T" { + castToMaybeTypeError(1); + comptime castToMaybeTypeError(1); +} +const A = struct { + a: i32, +}; +fn castToMaybeTypeError(z: i32) { + const x = i32(1); + const y: %?i32 = x; + assert(??%%y == 1); + + const f = z; + const g: %?i32 = f; + + const a = A{ .a = 1 }; + const b: %?A = a; + assert((??%%b).a == 1); +} + +test "implicitly cast from int to %?T" { + const f: %?i32 = 1; + comptime const g: %?i32 = 1; +} + +test "return null from fn() -> %?&T" { + const a = returnNullFromMaybeTypeErrorRef(); + const b = returnNullLitFromMaybeTypeErrorRef(); + assert(%%a == null and %%b == null); +} +fn returnNullFromMaybeTypeErrorRef() -> %?&A { + const a: ?&A = null; + return a; +} +fn returnNullLitFromMaybeTypeErrorRef() -> %?&A { + return null; +} \ No newline at end of file From c7852bd596a632644e9e94e785f32e6ddcf00c16 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Apr 2017 20:15:19 -0400 Subject: [PATCH 2/2] minor clean ups from previous commit --- .vscode/settings.json | 8 -------- src/ir.cpp | 41 ++++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 21 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index edd3d2a13b..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "files.associations": { - "*.zig": "c", - "type_traits": "cpp", - "*.inc": "cpp", - "thread": "cpp" - } -} \ No newline at end of file diff --git a/src/ir.cpp b/src/ir.cpp index 1c9f1c5fe2..9b6cb8ab36 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5827,12 +5827,25 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return true; } } else if ((other_type->id == TypeTableEntryIdNumLitFloat && const_val->data.x_bignum.kind == BigNumKindFloat) || - (other_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) { - return true; - } else if ((other_type->id == TypeTableEntryIdMaybe && - other_type->data.maybe.child_type->id == TypeTableEntryIdInt && - const_val->data.x_bignum.kind == BigNumKindInt)) { + (other_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) + { return true; + } else if (other_type->id == TypeTableEntryIdMaybe) { + TypeTableEntry *child_type = other_type->data.maybe.child_type; + if ((child_type->id == TypeTableEntryIdNumLitFloat && const_val->data.x_bignum.kind == BigNumKindFloat) || + (child_type->id == TypeTableEntryIdNumLitInt && const_val->data.x_bignum.kind == BigNumKindInt )) + { + return true; + } else if (child_type->id == TypeTableEntryIdInt && const_val->data.x_bignum.kind == BigNumKindInt) { + if (bignum_fits_in_bits(&const_val->data.x_bignum, + child_type->data.integral.bit_count, + child_type->data.integral.is_signed)) + { + return true; + } + } else if (child_type->id == TypeTableEntryIdFloat && const_val->data.x_bignum.kind == BigNumKindFloat) { + return true; + } } const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer"; @@ -5898,11 +5911,9 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, // implicit conversion from T to %?T if (expected_type->id == TypeTableEntryIdErrorUnion && expected_type->data.error.child_type->id == TypeTableEntryIdMaybe && - ir_types_match_with_implicit_cast( - ira, + ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type->data.maybe.child_type, - actual_type, - value)) + actual_type, value)) { return ImplicitCastMatchResultYes; } @@ -7083,10 +7094,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from T to %?T if (wanted_type->id == TypeTableEntryIdErrorUnion && wanted_type->data.error.child_type->id == TypeTableEntryIdMaybe && - actual_type->id != TypeTableEntryIdMaybe) { - if (types_match_const_cast_only(wanted_type->data.error.child_type->data.maybe.child_type, actual_type) || + actual_type->id != TypeTableEntryIdMaybe) + { + TypeTableEntry *wanted_child_type = wanted_type->data.error.child_type->data.maybe.child_type; + if (types_match_const_cast_only(wanted_child_type, actual_type) || actual_type->id == TypeTableEntryIdNullLit || - actual_type->id == TypeTableEntryIdNumLitInt ) { + actual_type->id == TypeTableEntryIdNumLitInt || + actual_type->id == TypeTableEntryIdNumLitFloat) + { IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error.child_type, value); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; @@ -7094,7 +7109,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst 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; } }