From 98c5c73725ccbf4685fae5a40422199944032e0e Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 26 Feb 2026 20:06:01 +0300 Subject: [PATCH] checker: fix i64 transfer to f64 should be explicit (fixes #14934) --- vlib/benchmark/benchmark.v | 2 +- vlib/v/checker/check_types.v | 4 ++++ .../tests/i64_to_f64_implicit_cast_err.out | 21 +++++++++++++++++++ .../tests/i64_to_f64_implicit_cast_err.vv | 14 +++++++++++++ .../result_call_inside_infix_expr_err.out | 6 +++--- .../result_call_inside_infix_expr_err.vv | 10 ++++----- 6 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 vlib/v/checker/tests/i64_to_f64_implicit_cast_err.out create mode 100644 vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv diff --git a/vlib/benchmark/benchmark.v b/vlib/benchmark/benchmark.v index 3a08dd9cc..4ca03d627 100644 --- a/vlib/benchmark/benchmark.v +++ b/vlib/benchmark/benchmark.v @@ -146,7 +146,7 @@ pub fn (mut b Benchmark) record_measure(label string) i64 { b.ok() res := b.step_timer.elapsed().microseconds() b.measured_steps << b.step_message_with_label(b_spent, 'in ${label}') - b.step_data[label] << res + b.step_data[label] << f64(res) b.step() return res } diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index 178ddfba2..ae202839f 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -184,6 +184,10 @@ fn (mut c Checker) check_types(got ast.Type, expected ast.Type) bool { || (expected == ast.rune_type && got == ast.u8_type) { return true } + if !c.pref.translated && c.table.unalias_num_type(expected).idx() == ast.f64_type_idx + && c.table.unalias_num_type(got).idx() in [ast.i64_type_idx, ast.u64_type_idx] { + return false + } if c.promote_num(expected, got) != expected { // println('could not promote ${c.table.sym(got).name} to ${c.table.sym(expected).name}') return false diff --git a/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.out b/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.out new file mode 100644 index 000000000..c37880849 --- /dev/null +++ b/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.out @@ -0,0 +1,21 @@ +vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv:5:9: error: cannot use `i64` as type `f64` in return argument + 3 | fn returns_f64() f64 { + 4 | value := i64(9_223_372_036_854_775_000) + 5 | return value + | ~~~~~ + 6 | } + 7 | +vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv:11:11: error: cannot assign to `result`: expected `f64`, not `i64` + 9 | value := i64(9_223_372_036_854_775_000) + 10 | mut result := f64(0) + 11 | result = value + | ~~~~~ + 12 | takes_f64(value) + 13 | _ = result +vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv:12:12: error: cannot use `i64` as `f64` in argument 1 to `takes_f64` + 10 | mut result := f64(0) + 11 | result = value + 12 | takes_f64(value) + | ~~~~~ + 13 | _ = result + 14 | } diff --git a/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv b/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv new file mode 100644 index 000000000..8ca420422 --- /dev/null +++ b/vlib/v/checker/tests/i64_to_f64_implicit_cast_err.vv @@ -0,0 +1,14 @@ +fn takes_f64(value f64) {} + +fn returns_f64() f64 { + value := i64(9_223_372_036_854_775_000) + return value +} + +fn main() { + value := i64(9_223_372_036_854_775_000) + mut result := f64(0) + result = value + takes_f64(value) + _ = result +} diff --git a/vlib/v/checker/tests/result_call_inside_infix_expr_err.out b/vlib/v/checker/tests/result_call_inside_infix_expr_err.out index 0d9b49350..cfe659243 100644 --- a/vlib/v/checker/tests/result_call_inside_infix_expr_err.out +++ b/vlib/v/checker/tests/result_call_inside_infix_expr_err.out @@ -1,12 +1,12 @@ vlib/v/checker/tests/result_call_inside_infix_expr_err.vv:53:27: error: wrong return type `IError` in the `or {}` block, expected `StopAfter` - 51 | assert parse('10d')! == StopAfter{10 * time.hour * 24, .time} - 52 | assert parse('10t')! == StopAfter{10, .tx} + 51 | assert parse('10d')! == StopAfter{f64(10 * time.hour * 24), .time} + 52 | assert parse('10t')! == StopAfter{f64(10), .tx} 53 | assert parse('10x') or { err } == StopAfter{} | ~~~ 54 | assert StopAfter{} == parse('10x') or { err } 55 | } vlib/v/checker/tests/result_call_inside_infix_expr_err.vv:54:42: error: wrong return type `IError` in the `or {}` block, expected `StopAfter` - 52 | assert parse('10t')! == StopAfter{10, .tx} + 52 | assert parse('10t')! == StopAfter{f64(10), .tx} 53 | assert parse('10x') or { err } == StopAfter{} 54 | assert StopAfter{} == parse('10x') or { err } | ~~~ diff --git a/vlib/v/checker/tests/result_call_inside_infix_expr_err.vv b/vlib/v/checker/tests/result_call_inside_infix_expr_err.vv index 0de034cc9..904852f3e 100644 --- a/vlib/v/checker/tests/result_call_inside_infix_expr_err.vv +++ b/vlib/v/checker/tests/result_call_inside_infix_expr_err.vv @@ -45,11 +45,11 @@ pub fn parse(str string) !StopAfter { fn main() { assert parse('0s')! == StopAfter{} - assert parse('10s')! == StopAfter{10 * time.second, .time} - assert parse('10m')! == StopAfter{10 * time.minute, .time} - assert parse('10h')! == StopAfter{10 * time.hour, .time} - assert parse('10d')! == StopAfter{10 * time.hour * 24, .time} - assert parse('10t')! == StopAfter{10, .tx} + assert parse('10s')! == StopAfter{f64(10 * time.second), .time} + assert parse('10m')! == StopAfter{f64(10 * time.minute), .time} + assert parse('10h')! == StopAfter{f64(10 * time.hour), .time} + assert parse('10d')! == StopAfter{f64(10 * time.hour * 24), .time} + assert parse('10t')! == StopAfter{f64(10), .tx} assert parse('10x') or { err } == StopAfter{} assert StopAfter{} == parse('10x') or { err } } -- 2.39.5