add float constraint type
This commit is contained in:
@@ -1541,7 +1541,7 @@ merge_infer_local_type :: proc(
|
||||
return false
|
||||
}
|
||||
if types.is_constraint(local.declared) {
|
||||
if !types.is_concrete_integer(inferred) {
|
||||
if !types.constraint_accepts(local.declared, inferred) {
|
||||
return false
|
||||
}
|
||||
if !is_runtime_type(checker, local.type) {
|
||||
@@ -1553,7 +1553,7 @@ merge_infer_local_type :: proc(
|
||||
return false
|
||||
}
|
||||
merged := types.widest(local.type, inferred)
|
||||
if types.is_concrete_integer(merged) {
|
||||
if types.constraint_accepts(local.declared, merged) {
|
||||
local.type = merged
|
||||
record_infer_local_type(local^, local_types)
|
||||
return true
|
||||
@@ -1605,6 +1605,10 @@ infer_statements :: proc(
|
||||
}
|
||||
if is_runtime_type(checker, declared_local) {
|
||||
value_type = declared_local
|
||||
} else if types.is_constraint(declared_local) {
|
||||
// Seed the binding in-family (INVALID on mismatch, which
|
||||
// build_block reports). FLOAT defaults integers to f64.
|
||||
value_type = types.constraint_target(declared_local, value_type)
|
||||
}
|
||||
local := Infer_Local{
|
||||
name=statement.name,
|
||||
@@ -1749,6 +1753,9 @@ infer_spec_locals_and_result :: proc(
|
||||
result := types.INVALID
|
||||
infer_statements(checker, function.body, &locals, local_types, function.pkg, function.file, demanded, &result, result_hint)
|
||||
if types.is_constraint(declared) {
|
||||
// Params/results use a constraint as a generic passthrough (e.g. an
|
||||
// identity `func(v int) int` forwarding a range), so the result keeps
|
||||
// the inferred type as-is rather than being narrowed to the family.
|
||||
return local_types, result
|
||||
}
|
||||
return local_types, declared
|
||||
@@ -2067,6 +2074,25 @@ build_constant_expr :: proc(
|
||||
if types.is_concrete_integer(expected) {
|
||||
recovery_type = expected
|
||||
}
|
||||
// An integer constant in a float context (e.g. `pi float = 3`) folds to a
|
||||
// float literal, mirroring build_float_expr's bit packing.
|
||||
if constant.kind == .Value && types.is_float(expected, checker.target) {
|
||||
fval := f64(constant.value) // ponytail: silent precision loss past 2^53, like C int->double
|
||||
bits := transmute(i64)fval
|
||||
if types.bits(expected, checker.target) == 32 {
|
||||
bits = i64(transmute(u32)f32(fval))
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind = .Float,
|
||||
span = expr.span,
|
||||
type = expected,
|
||||
integer = bits,
|
||||
target = hir.INVALID_REF,
|
||||
left = hir.INVALID_EXPR,
|
||||
right = hir.INVALID_EXPR,
|
||||
diagnostic = source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if constant.kind == .Div_By_Zero {
|
||||
id := source.add(checker.diagnostics, expr.span, "division by zero in constant expression")
|
||||
return invalid_hir_expr(checker, expr.span, id, recovery_type)
|
||||
@@ -3427,6 +3453,24 @@ build_block :: proc(
|
||||
(types.is_constraint(declared) || is_undefined_expr(checker, statement.expr)) {
|
||||
declared = ctx.local_types[statement_id]
|
||||
}
|
||||
// A still-unresolved constraint means the initializer's numeric
|
||||
// family did not satisfy `int`/`float` (`undefined` reports its own).
|
||||
if types.is_constraint(declared) && !is_undefined_expr(checker, statement.expr) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
statement.span,
|
||||
"could not resolve the '%s' constraint for local '%s'",
|
||||
types.name(declared),
|
||||
symbol_text(checker, statement.name),
|
||||
)
|
||||
append(&body, hir.stmt_id(len(checker.module.statements)))
|
||||
append(&checker.module.statements, hir.Stmt{
|
||||
kind = .Trap, span = statement.span, expr = hir.INVALID_EXPR,
|
||||
local = hir.INVALID_LOCAL, diagnostic = id,
|
||||
})
|
||||
ctx.problematic^ = true
|
||||
continue
|
||||
}
|
||||
expected := types.INVALID
|
||||
value := hir.INVALID_EXPR
|
||||
value_type := types.INVALID
|
||||
|
||||
Reference in New Issue
Block a user