mirror of
https://github.com/ziglang/zig.git
synced 2026-01-06 21:43:25 +00:00
Sema: simplify coercion logic
Instead of a separate function, `coerceNum` for handling comptime-known number coercion, outside of the main switch, the `coerce` function now has a single big switch statement that decides the control flow based on the zig type tag.
This commit is contained in:
parent
5d6380b38d
commit
6fdf7ce0af
153
src/Sema.zig
153
src/Sema.zig
@ -12447,12 +12447,6 @@ fn coerce(
|
||||
}
|
||||
assert(inst_ty.zigTypeTag() != .Undefined);
|
||||
|
||||
// comptime known number to other number
|
||||
// TODO why is this a separate function? should just be flattened into the
|
||||
// switch expression below.
|
||||
if (try sema.coerceNum(block, dest_ty, inst, inst_src)) |some|
|
||||
return some;
|
||||
|
||||
switch (dest_ty.zigTypeTag()) {
|
||||
.Optional => {
|
||||
// null to ?T
|
||||
@ -12584,11 +12578,31 @@ fn coerce(
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Int => {
|
||||
// integer widening
|
||||
if (inst_ty.zigTypeTag() == .Int) {
|
||||
assert(!(try sema.isComptimeKnown(block, inst_src, inst))); // handled above
|
||||
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
|
||||
.Float, .ComptimeFloat => float: {
|
||||
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :float;
|
||||
|
||||
if (val.floatHasFraction()) {
|
||||
return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty });
|
||||
}
|
||||
const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
|
||||
error.FloatCannotFit => {
|
||||
return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
||||
// comptime known integer to other number
|
||||
if (!val.intFitsInType(dest_ty, target)) {
|
||||
return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val });
|
||||
}
|
||||
return try sema.addConstant(dest_ty, val);
|
||||
}
|
||||
|
||||
// integer widening
|
||||
const dst_info = dest_ty.intInfo(target);
|
||||
const src_info = inst_ty.intInfo(target);
|
||||
if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
|
||||
@ -12598,20 +12612,53 @@ fn coerce(
|
||||
try sema.requireRuntimeBlock(block, inst_src);
|
||||
return block.addTyOp(.intcast, dest_ty, inst);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Float => {
|
||||
// float widening
|
||||
if (inst_ty.zigTypeTag() == .Float) {
|
||||
assert(!(try sema.isComptimeKnown(block, inst_src, inst))); // handled above
|
||||
.Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
|
||||
.ComptimeFloat => {
|
||||
const val = try sema.resolveConstValue(block, inst_src, inst);
|
||||
const result_val = try val.floatCast(sema.arena, dest_ty);
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
.Float => {
|
||||
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
|
||||
const result_val = try val.floatCast(sema.arena, dest_ty);
|
||||
if (!val.eql(result_val, dest_ty)) {
|
||||
return sema.fail(
|
||||
block,
|
||||
inst_src,
|
||||
"type {} cannot represent float value {}",
|
||||
.{ dest_ty, val },
|
||||
);
|
||||
}
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
}
|
||||
|
||||
// float widening
|
||||
const src_bits = inst_ty.floatBits(target);
|
||||
const dst_bits = dest_ty.floatBits(target);
|
||||
if (dst_bits >= src_bits) {
|
||||
try sema.requireRuntimeBlock(block, inst_src);
|
||||
return block.addTyOp(.fpext, dest_ty, inst);
|
||||
}
|
||||
}
|
||||
},
|
||||
.Int, .ComptimeInt => int: {
|
||||
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int;
|
||||
const result_val = try val.intToFloat(sema.arena, dest_ty, target);
|
||||
// TODO implement this compile error
|
||||
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
|
||||
//if (!int_again_val.eql(val, inst_ty)) {
|
||||
// return sema.fail(
|
||||
// block,
|
||||
// inst_src,
|
||||
// "type {} cannot represent integer value {}",
|
||||
// .{ dest_ty, val },
|
||||
// );
|
||||
//}
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Enum => switch (inst_ty.zigTypeTag()) {
|
||||
.EnumLiteral => {
|
||||
@ -12962,80 +13009,6 @@ fn coerceInMemoryAllowedPtrs(
|
||||
return .ok;
|
||||
}
|
||||
|
||||
fn coerceNum(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
dest_ty: Type,
|
||||
inst: Air.Inst.Ref,
|
||||
inst_src: LazySrcLoc,
|
||||
) CompileError!?Air.Inst.Ref {
|
||||
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse return null;
|
||||
const inst_ty = sema.typeOf(inst);
|
||||
const src_zig_tag = inst_ty.zigTypeTag();
|
||||
const dst_zig_tag = dest_ty.zigTypeTag();
|
||||
|
||||
const target = sema.mod.getTarget();
|
||||
|
||||
switch (dst_zig_tag) {
|
||||
.ComptimeInt, .Int => switch (src_zig_tag) {
|
||||
.Float, .ComptimeFloat => {
|
||||
if (val.floatHasFraction()) {
|
||||
return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty });
|
||||
}
|
||||
const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
|
||||
error.FloatCannotFit => {
|
||||
return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
if (!val.intFitsInType(dest_ty, target)) {
|
||||
return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty, val });
|
||||
}
|
||||
return try sema.addConstant(dest_ty, val);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.ComptimeFloat, .Float => switch (src_zig_tag) {
|
||||
.ComptimeFloat => {
|
||||
const result_val = try val.floatCast(sema.arena, dest_ty);
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
.Float => {
|
||||
const result_val = try val.floatCast(sema.arena, dest_ty);
|
||||
if (!val.eql(result_val, dest_ty)) {
|
||||
return sema.fail(
|
||||
block,
|
||||
inst_src,
|
||||
"type {} cannot represent float value {}",
|
||||
.{ dest_ty, val },
|
||||
);
|
||||
}
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
const result_val = try val.intToFloat(sema.arena, dest_ty, target);
|
||||
// TODO implement this compile error
|
||||
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
|
||||
//if (!int_again_val.eql(val, inst_ty)) {
|
||||
// return sema.fail(
|
||||
// block,
|
||||
// inst_src,
|
||||
// "type {} cannot represent integer value {}",
|
||||
// .{ dest_ty, val },
|
||||
// );
|
||||
//}
|
||||
return try sema.addConstant(dest_ty, result_val);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn coerceVarArgParam(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user