| ... | @@ -12447,12 +12447,6 @@ fn coerce( | ... | @@ -12447,12 +12447,6 @@ fn coerce( |
| 12447 | } | 12447 | } |
| 12448 | assert(inst_ty.zigTypeTag() != .Undefined); | 12448 | assert(inst_ty.zigTypeTag() != .Undefined); |
| 12449 | | 12449 | |
| 12450 | // comptime known number to other number | | |
| 12451 | // TODO why is this a separate function? should just be flattened into the | | |
| 12452 | // switch expression below. | | |
| 12453 | if (try sema.coerceNum(block, dest_ty, inst, inst_src)) |some| | | |
| 12454 | return some; | | |
| 12455 | | | |
| 12456 | switch (dest_ty.zigTypeTag()) { | 12450 | switch (dest_ty.zigTypeTag()) { |
| 12457 | .Optional => { | 12451 | .Optional => { |
| 12458 | // null to ?T | 12452 | // null to ?T |
| ... | @@ -12584,11 +12578,31 @@ fn coerce( | ... | @@ -12584,11 +12578,31 @@ fn coerce( |
| 12584 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 12578 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 12585 | } | 12579 | } |
| 12586 | }, | 12580 | }, |
| 12587 | .Int => { | 12581 | .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) { |
| 12588 | // integer widening | 12582 | .Float, .ComptimeFloat => float: { |
| 12589 | if (inst_ty.zigTypeTag() == .Int) { | 12583 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :float; |
| 12590 | assert(!(try sema.isComptimeKnown(block, inst_src, inst))); // handled above | | |
| 12591 | | 12584 | |
| | 12585 | if (val.floatHasFraction()) { |
| | 12586 | return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty }); |
| | 12587 | } |
| | 12588 | const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) { |
| | 12589 | error.FloatCannotFit => { |
| | 12590 | return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty }); |
| | 12591 | }, |
| | 12592 | else => |e| return e, |
| | 12593 | }; |
| | 12594 | return try sema.addConstant(dest_ty, result_val); |
| | 12595 | }, |
| | 12596 | .Int, .ComptimeInt => { |
| | 12597 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| | 12598 | // comptime known integer to other number |
| | 12599 | if (!val.intFitsInType(dest_ty, target)) { |
| | 12600 | return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val }); |
| | 12601 | } |
| | 12602 | return try sema.addConstant(dest_ty, val); |
| | 12603 | } |
| | 12604 | |
| | 12605 | // integer widening |
| 12592 | const dst_info = dest_ty.intInfo(target); | 12606 | const dst_info = dest_ty.intInfo(target); |
| 12593 | const src_info = inst_ty.intInfo(target); | 12607 | const src_info = inst_ty.intInfo(target); |
| 12594 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | 12608 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or |
| ... | @@ -12598,20 +12612,53 @@ fn coerce( | ... | @@ -12598,20 +12612,53 @@ fn coerce( |
| 12598 | try sema.requireRuntimeBlock(block, inst_src); | 12612 | try sema.requireRuntimeBlock(block, inst_src); |
| 12599 | return block.addTyOp(.intcast, dest_ty, inst); | 12613 | return block.addTyOp(.intcast, dest_ty, inst); |
| 12600 | } | 12614 | } |
| 12601 | } | 12615 | }, |
| | 12616 | else => {}, |
| 12602 | }, | 12617 | }, |
| 12603 | .Float => { | 12618 | .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) { |
| 12604 | // float widening | 12619 | .ComptimeFloat => { |
| 12605 | if (inst_ty.zigTypeTag() == .Float) { | 12620 | const val = try sema.resolveConstValue(block, inst_src, inst); |
| 12606 | assert(!(try sema.isComptimeKnown(block, inst_src, inst))); // handled above | 12621 | const result_val = try val.floatCast(sema.arena, dest_ty); |
| | 12622 | return try sema.addConstant(dest_ty, result_val); |
| | 12623 | }, |
| | 12624 | .Float => { |
| | 12625 | if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| { |
| | 12626 | const result_val = try val.floatCast(sema.arena, dest_ty); |
| | 12627 | if (!val.eql(result_val, dest_ty)) { |
| | 12628 | return sema.fail( |
| | 12629 | block, |
| | 12630 | inst_src, |
| | 12631 | "type {} cannot represent float value {}", |
| | 12632 | .{ dest_ty, val }, |
| | 12633 | ); |
| | 12634 | } |
| | 12635 | return try sema.addConstant(dest_ty, result_val); |
| | 12636 | } |
| 12607 | | 12637 | |
| | 12638 | // float widening |
| 12608 | const src_bits = inst_ty.floatBits(target); | 12639 | const src_bits = inst_ty.floatBits(target); |
| 12609 | const dst_bits = dest_ty.floatBits(target); | 12640 | const dst_bits = dest_ty.floatBits(target); |
| 12610 | if (dst_bits >= src_bits) { | 12641 | if (dst_bits >= src_bits) { |
| 12611 | try sema.requireRuntimeBlock(block, inst_src); | 12642 | try sema.requireRuntimeBlock(block, inst_src); |
| 12612 | return block.addTyOp(.fpext, dest_ty, inst); | 12643 | return block.addTyOp(.fpext, dest_ty, inst); |
| 12613 | } | 12644 | } |
| 12614 | } | 12645 | }, |
| | 12646 | .Int, .ComptimeInt => int: { |
| | 12647 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int; |
| | 12648 | const result_val = try val.intToFloat(sema.arena, dest_ty, target); |
| | 12649 | // TODO implement this compile error |
| | 12650 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| | 12651 | //if (!int_again_val.eql(val, inst_ty)) { |
| | 12652 | // return sema.fail( |
| | 12653 | // block, |
| | 12654 | // inst_src, |
| | 12655 | // "type {} cannot represent integer value {}", |
| | 12656 | // .{ dest_ty, val }, |
| | 12657 | // ); |
| | 12658 | //} |
| | 12659 | return try sema.addConstant(dest_ty, result_val); |
| | 12660 | }, |
| | 12661 | else => {}, |
| 12615 | }, | 12662 | }, |
| 12616 | .Enum => switch (inst_ty.zigTypeTag()) { | 12663 | .Enum => switch (inst_ty.zigTypeTag()) { |
| 12617 | .EnumLiteral => { | 12664 | .EnumLiteral => { |
| ... | @@ -12962,80 +13009,6 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -12962,80 +13009,6 @@ fn coerceInMemoryAllowedPtrs( |
| 12962 | return .ok; | 13009 | return .ok; |
| 12963 | } | 13010 | } |
| 12964 | | 13011 | |
| 12965 | fn coerceNum( | | |
| 12966 | sema: *Sema, | | |
| 12967 | block: *Block, | | |
| 12968 | dest_ty: Type, | | |
| 12969 | inst: Air.Inst.Ref, | | |
| 12970 | inst_src: LazySrcLoc, | | |
| 12971 | ) CompileError!?Air.Inst.Ref { | | |
| 12972 | const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse return null; | | |
| 12973 | const inst_ty = sema.typeOf(inst); | | |
| 12974 | const src_zig_tag = inst_ty.zigTypeTag(); | | |
| 12975 | const dst_zig_tag = dest_ty.zigTypeTag(); | | |
| 12976 | | | |
| 12977 | const target = sema.mod.getTarget(); | | |
| 12978 | | | |
| 12979 | switch (dst_zig_tag) { | | |
| 12980 | .ComptimeInt, .Int => switch (src_zig_tag) { | | |
| 12981 | .Float, .ComptimeFloat => { | | |
| 12982 | if (val.floatHasFraction()) { | | |
| 12983 | return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty }); | | |
| 12984 | } | | |
| 12985 | const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) { | | |
| 12986 | error.FloatCannotFit => { | | |
| 12987 | return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty }); | | |
| 12988 | }, | | |
| 12989 | else => |e| return e, | | |
| 12990 | }; | | |
| 12991 | return try sema.addConstant(dest_ty, result_val); | | |
| 12992 | }, | | |
| 12993 | .Int, .ComptimeInt => { | | |
| 12994 | if (!val.intFitsInType(dest_ty, target)) { | | |
| 12995 | return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val }); | | |
| 12996 | } | | |
| 12997 | return try sema.addConstant(dest_ty, val); | | |
| 12998 | }, | | |
| 12999 | else => {}, | | |
| 13000 | }, | | |
| 13001 | .ComptimeFloat, .Float => switch (src_zig_tag) { | | |
| 13002 | .ComptimeFloat => { | | |
| 13003 | const result_val = try val.floatCast(sema.arena, dest_ty); | | |
| 13004 | return try sema.addConstant(dest_ty, result_val); | | |
| 13005 | }, | | |
| 13006 | .Float => { | | |
| 13007 | const result_val = try val.floatCast(sema.arena, dest_ty); | | |
| 13008 | if (!val.eql(result_val, dest_ty)) { | | |
| 13009 | return sema.fail( | | |
| 13010 | block, | | |
| 13011 | inst_src, | | |
| 13012 | "type {} cannot represent float value {}", | | |
| 13013 | .{ dest_ty, val }, | | |
| 13014 | ); | | |
| 13015 | } | | |
| 13016 | return try sema.addConstant(dest_ty, result_val); | | |
| 13017 | }, | | |
| 13018 | .Int, .ComptimeInt => { | | |
| 13019 | const result_val = try val.intToFloat(sema.arena, dest_ty, target); | | |
| 13020 | // TODO implement this compile error | | |
| 13021 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); | | |
| 13022 | //if (!int_again_val.eql(val, inst_ty)) { | | |
| 13023 | // return sema.fail( | | |
| 13024 | // block, | | |
| 13025 | // inst_src, | | |
| 13026 | // "type {} cannot represent integer value {}", | | |
| 13027 | // .{ dest_ty, val }, | | |
| 13028 | // ); | | |
| 13029 | //} | | |
| 13030 | return try sema.addConstant(dest_ty, result_val); | | |
| 13031 | }, | | |
| 13032 | else => {}, | | |
| 13033 | }, | | |
| 13034 | else => {}, | | |
| 13035 | } | | |
| 13036 | return null; | | |
| 13037 | } | | |
| 13038 | | | |
| 13039 | fn coerceVarArgParam( | 13012 | fn coerceVarArgParam( |
| 13040 | sema: *Sema, | 13013 | sema: *Sema, |
| 13041 | block: *Block, | 13014 | block: *Block, |