Skip to content

Commit b51dfcf

Browse files
authored
checker: fix missing check for concrete type on match branch expr (fix #23506) (#23508)
1 parent fda0af4 commit b51dfcf

7 files changed

+75
-19
lines changed

vlib/v/checker/match.v

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,18 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
7171
} else {
7272
node.expected_type
7373
}
74-
expr_type := if stmt.expr is ast.CallExpr {
74+
expr_type := c.unwrap_generic(if stmt.expr is ast.CallExpr {
7575
stmt.typ
7676
} else {
7777
c.expr(mut stmt.expr)
78-
}
78+
})
79+
unwrapped_expected_type := c.unwrap_generic(node.expected_type)
7980
stmt.typ = expr_type
8081
if first_iteration {
81-
if node.expected_type.has_option_or_result()
82-
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return] {
83-
c.check_match_branch_last_stmt(stmt, node.expected_type, expr_type)
82+
if unwrapped_expected_type.has_option_or_result()
83+
|| c.table.type_kind(unwrapped_expected_type) in [.sum_type, .multi_return] {
84+
c.check_match_branch_last_stmt(stmt, unwrapped_expected_type,
85+
expr_type)
8486
ret_type = node.expected_type
8587
} else {
8688
ret_type = expr_type
@@ -105,10 +107,9 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
105107
}
106108
} else {
107109
if ret_type.idx() != expr_type.idx() {
108-
if node.expected_type.has_option_or_result()
110+
if unwrapped_expected_type.has_option_or_result()
109111
&& c.table.sym(stmt.typ).kind == .struct
110-
&& (c.table.sym(ret_type).kind != .sum_type
111-
|| !c.check_types(expr_type, ret_type))
112+
&& !c.check_types(expr_type, c.unwrap_generic(ret_type))
112113
&& c.type_implements(stmt.typ, ast.error_type, node.pos) {
113114
stmt.expr = ast.CastExpr{
114115
expr: stmt.expr
@@ -119,7 +120,8 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
119120
}
120121
stmt.typ = ast.error_type
121122
} else {
122-
c.check_match_branch_last_stmt(stmt, ret_type, expr_type)
123+
c.check_match_branch_last_stmt(stmt, c.unwrap_generic(ret_type),
124+
expr_type)
123125
if ret_type.is_number() && expr_type.is_number() && !c.inside_return {
124126
ret_type = c.promote_num(ret_type, expr_type)
125127
}
@@ -130,13 +132,13 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
130132
stmt_sym := c.table.sym(stmt.typ)
131133
if ret_sym.kind !in [.sum_type, .interface]
132134
&& stmt_sym.kind in [.sum_type, .interface] {
133-
c.error('return type mismatch, it should be `${ret_sym.name}`',
135+
c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
134136
stmt.pos)
135137
}
136138
if ret_type.nr_muls() != stmt.typ.nr_muls()
137139
&& stmt.typ.idx() !in [ast.voidptr_type_idx, ast.nil_type_idx] {
138140
type_name := '&'.repeat(ret_type.nr_muls()) + ret_sym.name
139-
c.error('return type mismatch, it should be `${type_name}`',
141+
c.error('return type mismatch, it should be `${type_name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
140142
stmt.pos)
141143
}
142144
}
@@ -279,7 +281,8 @@ fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type
279281
return
280282
}
281283
}
282-
c.error('return type mismatch, it should be `${ret_sym.name}`', last_stmt.pos)
284+
c.error('return type mismatch, it should be `${ret_sym.name}`, but it is instead `${c.table.type_to_str(expr_type)}`',
285+
last_stmt.pos)
283286
}
284287
} else if expr_type == ast.void_type && ret_type.idx() == ast.void_type_idx
285288
&& ret_type.has_option_or_result() {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/match_generic_case_err.vv:16:4: error: return type mismatch, it should be `int`, but it is instead `string`
2+
14 | }
3+
15 | 'int' {
4+
16 | v
5+
| ^
6+
17 | }
7+
18 | else {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module main
2+
3+
import strconv
4+
5+
fn main() {
6+
println(to_int('1'))
7+
println(to_int(1))
8+
}
9+
10+
fn to_int[T](v T) i64 {
11+
return match typeof(v).name {
12+
'string' {
13+
strconv.atoi(v) or { 0 }
14+
}
15+
'int' {
16+
v
17+
}
18+
else {
19+
0
20+
}
21+
}
22+
}

vlib/v/checker/tests/match_return_mismatch_type_err.out

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,35 @@ vlib/v/checker/tests/match_return_mismatch_type_err.vv:27:6: warning: cannot ass
55
| ^
66
28 | string { &any }
77
29 | else { &variable }
8-
vlib/v/checker/tests/match_return_mismatch_type_err.vv:4:10: error: return type mismatch, it should be `string`
8+
vlib/v/checker/tests/match_return_mismatch_type_err.vv:4:10: error: return type mismatch, it should be `string`, but it is instead `int literal`
99
2 | a := match 1 {
1010
3 | 1 { 'aa' }
1111
4 | else { 22 }
1212
| ~~
1313
5 | }
1414
6 | println(a)
15-
vlib/v/checker/tests/match_return_mismatch_type_err.vv:18:10: error: return type mismatch, it should be `&string`
15+
vlib/v/checker/tests/match_return_mismatch_type_err.vv:18:10: error: return type mismatch, it should be `&string`, but it is instead `string`
1616
16 | _ = match any {
1717
17 | string { &any }
1818
18 | else { variable }
1919
| ~~~~~~~~
2020
19 | }
2121
20 |
22-
vlib/v/checker/tests/match_return_mismatch_type_err.vv:23:10: error: return type mismatch, it should be `string`
22+
vlib/v/checker/tests/match_return_mismatch_type_err.vv:23:10: error: return type mismatch, it should be `string`, but it is instead `&string`
2323
21 | _ = match any {
2424
22 | string { any }
2525
23 | else { &variable }
2626
| ^
2727
24 | }
2828
25 |
29-
vlib/v/checker/tests/match_return_mismatch_type_err.vv:43:10: error: return type mismatch, it should be `&string`
29+
vlib/v/checker/tests/match_return_mismatch_type_err.vv:43:10: error: return type mismatch, it should be `&string`, but it is instead `string`
3030
41 | _ = match any {
3131
42 | string { &any }
3232
43 | else { variable }
3333
| ~~~~~~~~
3434
44 | }
3535
45 |
36-
vlib/v/checker/tests/match_return_mismatch_type_err.vv:48:10: error: return type mismatch, it should be `string`
36+
vlib/v/checker/tests/match_return_mismatch_type_err.vv:48:10: error: return type mismatch, it should be `string`, but it is instead `&string`
3737
46 | _ = match any {
3838
47 | string { any }
3939
48 | else { &variable }

vlib/v/checker/tests/match_return_sumtype_mismatch_err.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
vlib/v/checker/tests/match_return_sumtype_mismatch_err.vv:15:11: error: return type mismatch, it should be `Myt`
1+
vlib/v/checker/tests/match_return_sumtype_mismatch_err.vv:15:11: error: return type mismatch, it should be `Myt`, but it is instead `rune`
22
13 | return match b {
33
14 | true { St('TRUE') }
44
15 | false { `F` }

vlib/v/checker/tests/return_match_expr_type_mismatch.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
vlib/v/checker/tests/return_match_expr_type_mismatch.vv:18:16: error: return type mismatch, it should be `SomeTuple`
1+
vlib/v/checker/tests/return_match_expr_type_mismatch.vv:18:16: error: return type mismatch, it should be `SomeTuple`, but it is instead `Poss1`
22
16 | fn get_file(item PossOwner) ?SomeTuple {
33
17 | return match item.pos {
44
18 | Poss1 { item.pos }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
struct Foo[T] {
2+
a T
3+
}
4+
5+
fn r[T]() Foo[T] {
6+
return Foo[T]{}
7+
}
8+
9+
fn t[T](v T) !Foo[T] {
10+
return match typeof(v).name {
11+
'string' {
12+
r[T]()
13+
}
14+
else {
15+
r[T]()
16+
}
17+
}
18+
}
19+
20+
fn test_main() {
21+
t(1)!
22+
t('')!
23+
assert true
24+
}

0 commit comments

Comments
 (0)