| ... | ... | @@ -3358,6 +3358,14 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { |
| 3358 | 3358 | return self.bitcast(scope, dest_type, inst); |
| 3359 | 3359 | } |
| 3360 | 3360 | |
| 3361 | // undefined to anything |
| 3362 | if (inst.value()) |val| { |
| 3363 | if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) { |
| 3364 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 3365 | } |
| 3366 | } |
| 3367 | assert(inst.ty.zigTypeTag() != .Undefined); |
| 3368 | |
| 3361 | 3369 | // *[N]T to []T |
| 3362 | 3370 | if (inst.ty.isSinglePointer() and dest_type.isSlice() and |
| 3363 | 3371 | (!inst.ty.pointerIsConst() or dest_type.pointerIsConst())) |
| ... | ... | @@ -3371,34 +3379,58 @@ fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { |
| 3371 | 3379 | } |
| 3372 | 3380 | } |
| 3373 | 3381 | |
| 3374 | | // comptime_int to fixed-width integer |
| 3375 | | if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) { |
| 3376 | | // The representation is already correct; we only need to make sure it fits in the destination type. |
| 3377 | | const val = inst.value().?; // comptime_int always has comptime known value |
| 3378 | | if (!val.intFitsInType(dest_type, self.target())) { |
| 3379 | | return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val }); |
| 3382 | // comptime known number to other number |
| 3383 | if (inst.value()) |val| { |
| 3384 | const src_zig_tag = inst.ty.zigTypeTag(); |
| 3385 | const dst_zig_tag = dest_type.zigTypeTag(); |
| 3386 | |
| 3387 | if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) { |
| 3388 | if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) { |
| 3389 | if (val.floatHasFraction()) { |
| 3390 | return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty }); |
| 3391 | } |
| 3392 | return self.fail(scope, inst.src, "TODO float to int", .{}); |
| 3393 | } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) { |
| 3394 | if (!val.intFitsInType(dest_type, self.target())) { |
| 3395 | return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val }); |
| 3396 | } |
| 3397 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 3398 | } |
| 3399 | } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) { |
| 3400 | if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) { |
| 3401 | return self.fail(scope, inst.src, "TODO float cast", .{}); |
| 3402 | } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) { |
| 3403 | return self.fail(scope, inst.src, "TODO int to float", .{}); |
| 3404 | } |
| 3380 | 3405 | } |
| 3381 | | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 3382 | 3406 | } |
| 3383 | 3407 | |
| 3384 | 3408 | // integer widening |
| 3385 | 3409 | if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) { |
| 3410 | assert(inst.value() == null); // handled above |
| 3411 | |
| 3386 | 3412 | const src_info = inst.ty.intInfo(self.target()); |
| 3387 | 3413 | const dst_info = dest_type.intInfo(self.target()); |
| 3388 | 3414 | if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) { |
| 3389 | | if (inst.value()) |val| { |
| 3390 | | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); |
| 3391 | | } else { |
| 3392 | | return self.fail(scope, inst.src, "TODO implement runtime integer widening ({} to {})", .{ |
| 3393 | | inst.ty, |
| 3394 | | dest_type, |
| 3395 | | }); |
| 3396 | | } |
| 3415 | const b = try self.requireRuntimeBlock(scope, inst.src); |
| 3416 | return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst }); |
| 3397 | 3417 | } else { |
| 3398 | 3418 | return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type }); |
| 3399 | 3419 | } |
| 3400 | 3420 | } |
| 3401 | 3421 | |
| 3422 | // float widening |
| 3423 | if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) { |
| 3424 | assert(inst.value() == null); // handled above |
| 3425 | |
| 3426 | const src_bits = inst.ty.floatBits(self.target()); |
| 3427 | const dst_bits = dest_type.floatBits(self.target()); |
| 3428 | if (dst_bits >= src_bits) { |
| 3429 | const b = try self.requireRuntimeBlock(scope, inst.src); |
| 3430 | return self.addNewInstArgs(b, inst.src, dest_type, Inst.WidenOrShorten, .{ .operand = inst }); |
| 3431 | } |
| 3432 | } |
| 3433 | |
| 3402 | 3434 | return self.fail(scope, inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type }); |
| 3403 | 3435 | } |
| 3404 | 3436 | |