fix: require exact contextual integer to float typing
This commit is contained in:
@@ -761,11 +761,20 @@ ct_coerce_value :: proc(state: ^Ct_State, id: Ct_Value_Id, expected: types.Type,
|
||||
return ct_add_value(state, value), true
|
||||
}
|
||||
if types.is_float(expected, state.checker.target) {
|
||||
if !integer_fits_float(value.integer, expected, state.checker.target) {
|
||||
return INVALID_CT_VALUE, ct_failf(
|
||||
state, .Not_Comptime, span, "integer constant %d is not exactly representable in %s",
|
||||
value.integer, type_label(state.checker, expected),
|
||||
)
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=expected, float=f64(value.integer)}), true
|
||||
}
|
||||
}
|
||||
if value.kind == .Float && types.is_float(expected, state.checker.target) {
|
||||
value.type = expected
|
||||
if types.bits(expected, state.checker.target) == 32 {
|
||||
value.float = f64(f32(value.float))
|
||||
}
|
||||
return ct_add_value(state, value), true
|
||||
}
|
||||
return INVALID_CT_VALUE, ct_failf(
|
||||
@@ -1351,6 +1360,12 @@ ct_eval_expr :: proc(
|
||||
if numeric_operation {
|
||||
if representation, distinct_ok := types.distinct_scalar_backing(expected, store); distinct_ok {
|
||||
if types.is_float(representation, checker.target) {
|
||||
if !integer_fits_float(i128(expr.integer), representation, checker.target) {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(
|
||||
state, .Not_Comptime, expr.span, "integer constant %d is not exactly representable in %s",
|
||||
i128(expr.integer), type_label(checker, expected),
|
||||
)
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{
|
||||
kind=.Float, type=expected, float=f64(expr.integer),
|
||||
}), ct_flow(.Normal), true
|
||||
@@ -1376,13 +1391,21 @@ ct_eval_expr :: proc(
|
||||
if numeric_operation {
|
||||
if representation, distinct_ok := types.distinct_scalar_backing(expected, store);
|
||||
distinct_ok && types.is_float(representation, checker.target) {
|
||||
value := transmute(f64)expr.integer
|
||||
if types.bits(representation, checker.target) == 32 {
|
||||
value = f64(f32(value))
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{
|
||||
kind=.Float, type=expected, float=transmute(f64)expr.integer,
|
||||
kind=.Float, type=expected, float=value,
|
||||
}), ct_flow(.Normal), true
|
||||
}
|
||||
}
|
||||
value_type := expected if types.is_float(expected, checker.target) else types.F64
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=value_type, float=transmute(f64)expr.integer}), ct_flow(.Normal), true
|
||||
value := transmute(f64)expr.integer
|
||||
if types.bits(value_type, checker.target) == 32 {
|
||||
value = f64(f32(value))
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=value_type, float=value}), ct_flow(.Normal), true
|
||||
case .String:
|
||||
return ct_add_value(state, Ct_Value{kind=.String, type=string_literal_type(checker, expr.integer), index=expr.integer}), ct_flow(.Normal), true
|
||||
case .Name:
|
||||
@@ -2679,6 +2702,30 @@ ct_eval_binary :: proc(state: ^Ct_State, op: ast.Expr_Kind, left_id, right_id: C
|
||||
if distinct_operation && (!compatible || !types.is_float(operation.representation, state.checker.target)) {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, span, "comptime binary expression requires compatible operands")
|
||||
}
|
||||
result_type := operation.result
|
||||
if !distinct_operation {
|
||||
result_type = types.widest(left.type, right.type)
|
||||
if left.kind != .Float {
|
||||
result_type = right.type
|
||||
} else if right.kind != .Float {
|
||||
result_type = left.type
|
||||
}
|
||||
if !types.is_float(result_type, state.checker.target) {
|
||||
result_type = types.F64
|
||||
}
|
||||
}
|
||||
representation := types.runtime_representation(result_type, store)
|
||||
operands := [2]Ct_Value_Id{left_id, right_id}
|
||||
for operand_id in operands {
|
||||
operand := &state.values[operand_id]
|
||||
if operand.kind != .Float &&
|
||||
!integer_fits_float(operand.integer, representation, state.checker.target) {
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(
|
||||
state, .Not_Comptime, span, "integer constant %d is not exactly representable in %s",
|
||||
operand.integer, type_label(state.checker, result_type),
|
||||
)
|
||||
}
|
||||
}
|
||||
lf := left.float if left.kind == .Float else f64(left.integer)
|
||||
rf := right.float if right.kind == .Float else f64(right.integer)
|
||||
if is_compare {
|
||||
@@ -2702,14 +2749,7 @@ ct_eval_binary :: proc(state: ^Ct_State, op: ast.Expr_Kind, left_id, right_id: C
|
||||
case:
|
||||
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, span, "comptime binary expression requires compatible operands")
|
||||
}
|
||||
result_type := operation.result
|
||||
if !distinct_operation {
|
||||
result_type = types.widest(left.type, right.type)
|
||||
if !types.is_float(result_type, state.checker.target) {
|
||||
result_type = types.F64
|
||||
}
|
||||
}
|
||||
if types.bits(result_type, state.checker.target) == 32 {
|
||||
if types.bits(representation, state.checker.target) == 32 {
|
||||
result = f64(f32(result))
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=result_type, float=result}), ct_flow(.Normal), true
|
||||
@@ -3144,13 +3184,20 @@ ct_scalar_cast :: proc(state: ^Ct_State, id: Ct_Value_Id, target: types.Type, sp
|
||||
if value.kind == .Float {
|
||||
if types.is_float(target, state.checker.target) {
|
||||
value.type = target
|
||||
if types.bits(target, state.checker.target) == 32 {
|
||||
value.float = f64(f32(value.float))
|
||||
}
|
||||
return ct_add_value(state, value), ct_flow(.Normal), true
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{kind=.Integer, type=target, integer=i128(value.float)}), ct_flow(.Normal), true
|
||||
}
|
||||
if ct_is_integer_like(value) {
|
||||
if types.is_float(target, state.checker.target) {
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=target, float=f64(value.integer)}), ct_flow(.Normal), true
|
||||
result := f64(value.integer)
|
||||
if types.bits(target, state.checker.target) == 32 {
|
||||
result = f64(f32(result))
|
||||
}
|
||||
return ct_add_value(state, Ct_Value{kind=.Float, type=target, float=result}), ct_flow(.Normal), true
|
||||
}
|
||||
value.kind = .Integer
|
||||
value.type = target
|
||||
|
||||
Reference in New Issue
Block a user