From 50b936cd58723a86e121a5ec26561c438c4949eb Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 24 Apr 2026 01:17:20 +0300 Subject: [PATCH] checker: fix Compiler doesn't catch type mismatch with `int` and `time.Duration` (fixes #18873) --- vlib/v/checker/struct.v | 21 +++++++++++++++++++ .../tests/time_duration_assign_to_int_err.out | 14 +++++++++++++ .../tests/time_duration_assign_to_int_err.vv | 20 ++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 vlib/v/checker/tests/time_duration_assign_to_int_err.out create mode 100644 vlib/v/checker/tests/time_duration_assign_to_int_err.vv diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index b10acfa14..1c9dce493 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -1099,6 +1099,11 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', pos: init_field.expr.pos() } init_field.typ = exp_type + } else if c.has_direct_numeric_alias_struct_init_mismatch(init_field.expr, + got_type, exp_type) + { + c.error('cannot assign to field `${field_info.name}`: ${c.expected_msg(got_type, + exp_type)}', init_field.pos) } else { c.check_expected(c.unwrap_generic(got_type), c.unwrap_generic(exp_type)) or { // For generic types, the same concrete type may have been @@ -1313,6 +1318,22 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', return node.typ } +fn (c &Checker) has_direct_numeric_alias_struct_init_mismatch(expr ast.Expr, got ast.Type, expected ast.Type) bool { + if expr.remove_par() !is ast.Ident && expr.remove_par() !is ast.SelectorExpr { + return false + } + got_sym := c.table.sym(got) + if got_sym.kind != .alias || got_sym.info !is ast.Alias { + return false + } + got_num_type := c.table.unalias_num_type(got).clear_flags() + expected_num_type := c.table.unalias_num_type(expected).clear_flags() + if !got_num_type.is_number() || !expected_num_type.is_number() { + return false + } + return c.promote_num(expected_num_type, got_num_type) != expected_num_type +} + // Check uninitialized refs/sum types // The variable `fields` contains two parts, the first part is the same as info.fields, // and the second part is all fields embedded in the structure diff --git a/vlib/v/checker/tests/time_duration_assign_to_int_err.out b/vlib/v/checker/tests/time_duration_assign_to_int_err.out new file mode 100644 index 000000000..e1090c2b6 --- /dev/null +++ b/vlib/v/checker/tests/time_duration_assign_to_int_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/time_duration_assign_to_int_err.vv:10:3: error: cannot assign to field `x`: expected `int`, not `time.Duration` + 8 | d := time.second + 9 | _ := Foo{ + 10 | x: d + | ~~~~ + 11 | } + 12 | } +vlib/v/checker/tests/time_duration_assign_to_int_err.vv:16:3: error: cannot assign to field `x`: expected `int`, not `time.Duration` + 14 | fn bad_struct_init_direct() { + 15 | _ := Foo{ + 16 | x: time.second + | ~~~~~~~~~~~~~~ + 17 | } + 18 | } diff --git a/vlib/v/checker/tests/time_duration_assign_to_int_err.vv b/vlib/v/checker/tests/time_duration_assign_to_int_err.vv new file mode 100644 index 000000000..dd11b858c --- /dev/null +++ b/vlib/v/checker/tests/time_duration_assign_to_int_err.vv @@ -0,0 +1,20 @@ +import time + +struct Foo { + x int +} + +fn bad_struct_init() { + d := time.second + _ := Foo{ + x: d + } +} + +fn bad_struct_init_direct() { + _ := Foo{ + x: time.second + } +} + +fn main() {} -- 2.39.5