From ee94af07e0e8a626fbf30d44b972ef93bc4da925 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 14 Apr 2026 12:45:27 +0300 Subject: [PATCH] checker: Compiler accepts &int as a key for map[int]int (fixes #23069) --- vlib/v/checker/checker.v | 33 ++++++++++++++++++++++++++++++-- vlib/v/checker/infix.v | 6 +++--- vlib/v/checker/tests/map_ops.out | 26 ++++++++++++++++++++----- vlib/v/checker/tests/map_ops.vv | 5 +++++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4e4a301b1..5d61ebf59 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -7284,6 +7284,35 @@ fn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_ty } } +fn (mut c Checker) check_map_key_type(got ast.Type, expected ast.Type) bool { + if c.map_key_pointer_mismatch(got, expected) { + return false + } + return c.check_types(got, expected) +} + +fn (c &Checker) map_key_pointer_mismatch(got ast.Type, expected ast.Type) bool { + got_final_sym := c.table.final_sym(got) + expected_final_sym := c.table.final_sym(expected) + if got_final_sym.idx != expected_final_sym.idx { + return false + } + if got.is_any_kind_of_pointer() != expected.is_any_kind_of_pointer() { + return true + } + return got.is_ptr() && expected.is_ptr() && got.nr_muls() != expected.nr_muls() +} + +fn (c &Checker) map_key_expected_msg(got ast.Type, expected ast.Type, key_expr ast.Expr, + container string) string { + mut msg := c.expected_msg(got, expected) + if container.len > 0 && c.map_key_pointer_mismatch(got, expected) && got.is_ptr() + && !expected.is_any_kind_of_pointer() && got.nr_muls() == expected.nr_muls() + 1 { + msg += '; did you mean `${container}[*${key_expr}]`?' + } + return msg +} + fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type { mut typ := c.expr(mut node.left) if typ == 0 { @@ -7420,8 +7449,8 @@ fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type { got_typ_str, expected_typ_str := c.get_string_names_of(actual_index_type, key_type) c.error('invalid key: cannot use `${got_typ_str}` as `${expected_typ_str}`, it must be unwrapped first', node.index.pos()) - } else if !c.check_types(index_type, key_type) { - err := c.expected_msg(index_type, key_type) + } else if !c.check_map_key_type(index_type, key_type) { + err := c.map_key_expected_msg(index_type, key_type, node.index, '${node.left}') c.error('invalid key: ${err}', node.pos) } value_sym := c.table.sym(info.value_type) diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index b7d9cba40..0fdd1e992 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -415,9 +415,9 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } .map { map_info := right_final_sym.map_info() - c.check_expected(left_type, map_info.key_type) or { - c.error('left operand to `${node.op}` does not match the map key type: ${err.msg()}', - left_right_pos) + if !c.check_map_key_type(left_type, map_info.key_type) { + c.error('left operand to `${node.op}` does not match the map key type: ${c.map_key_expected_msg(left_type, + map_info.key_type, node.left, '')}', left_right_pos) } node.left_type = map_info.key_type } diff --git a/vlib/v/checker/tests/map_ops.out b/vlib/v/checker/tests/map_ops.out index d88625153..af1093c2f 100644 --- a/vlib/v/checker/tests/map_ops.out +++ b/vlib/v/checker/tests/map_ops.out @@ -11,29 +11,45 @@ vlib/v/checker/tests/map_ops.vv:4:3: error: invalid key: expected `int`, not `st 4 | m['hi'] = 8 | ~~~~~~ 5 | m[&m] += 4 - 6 | } + 6 | a := 10 vlib/v/checker/tests/map_ops.vv:4:12: error: cannot assign to `m['hi']`: expected `string`, not `int literal` 2 | mut m := map[int]string{} 3 | _ = m[`!`] 4 | m['hi'] = 8 | ^ 5 | m[&m] += 4 - 6 | } + 6 | a := 10 vlib/v/checker/tests/map_ops.vv:5:3: error: invalid key: expected `int`, not `&map[int]string` 3 | _ = m[`!`] 4 | m['hi'] = 8 5 | m[&m] += 4 | ~~~~ - 6 | } + 6 | a := 10 + 7 | ptr := &a vlib/v/checker/tests/map_ops.vv:5:11: error: invalid right operand: string += int literal 3 | _ = m[`!`] 4 | m['hi'] = 8 5 | m[&m] += 4 | ^ - 6 | } + 6 | a := 10 + 7 | ptr := &a vlib/v/checker/tests/map_ops.vv:5:11: error: cannot assign to `m[&m]`: expected `string`, not `int literal` 3 | _ = m[`!`] 4 | m['hi'] = 8 5 | m[&m] += 4 | ^ - 6 | } + 6 | a := 10 + 7 | ptr := &a +vlib/v/checker/tests/map_ops.vv:9:3: error: invalid key: expected `int`, not `&int`; did you mean `n[*ptr]`? + 7 | ptr := &a + 8 | mut n := map[int]int{} + 9 | n[ptr] = 1 + | ~~~~~ + 10 | _ = ptr in n + 11 | } +vlib/v/checker/tests/map_ops.vv:10:6: error: left operand to `in` does not match the map key type: expected `int`, not `&int` + 8 | mut n := map[int]int{} + 9 | n[ptr] = 1 + 10 | _ = ptr in n + | ~~~~~~~~ + 11 | } diff --git a/vlib/v/checker/tests/map_ops.vv b/vlib/v/checker/tests/map_ops.vv index 0522021b8..f5e161e35 100644 --- a/vlib/v/checker/tests/map_ops.vv +++ b/vlib/v/checker/tests/map_ops.vv @@ -3,4 +3,9 @@ fn test_map() { _ = m[`!`] m['hi'] = 8 m[&m] += 4 + a := 10 + ptr := &a + mut n := map[int]int{} + n[ptr] = 1 + _ = ptr in n } -- 2.39.5