1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: check type mismatch of return match expr (#16019)

This commit is contained in:
yuyi 2022-10-11 00:41:55 +08:00 committed by GitHub
parent 89eb8358cf
commit 8f3f717736
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 19 deletions

View File

@ -64,30 +64,13 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
if node.is_expr && (node.expected_type.has_flag(.optional)
|| node.expected_type.has_flag(.result)
|| c.table.type_kind(node.expected_type) in [.sum_type, .multi_return]) {
c.check_match_branch_last_stmt(stmt, node.expected_type, expr_type)
ret_type = node.expected_type
} else {
ret_type = expr_type
}
} else if node.is_expr && ret_type.idx() != expr_type.idx() {
if !c.check_types(ret_type, expr_type) && !c.check_types(expr_type, ret_type) {
ret_sym := c.table.sym(ret_type)
is_noreturn := is_noreturn_callexpr(stmt.expr)
if !(node.is_expr && ret_sym.kind == .sum_type
&& (ret_type.has_flag(.generic)
|| c.table.is_sumtype_or_in_variant(ret_type, expr_type)))
&& !is_noreturn {
expr_sym := c.table.sym(expr_type)
if expr_sym.kind == .multi_return && ret_sym.kind == .multi_return {
ret_types := ret_sym.mr_info().types
expr_types := expr_sym.mr_info().types.map(ast.mktyp(it))
if expr_types == ret_types {
continue
}
}
c.error('return type mismatch, it should be `$ret_sym.name`',
stmt.expr.pos())
}
}
c.check_match_branch_last_stmt(stmt, ret_type, expr_type)
}
} else {
if node.is_expr && ret_type != ast.void_type {
@ -137,6 +120,25 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
return ret_type
}
fn (mut c Checker) check_match_branch_last_stmt(last_stmt ast.ExprStmt, ret_type ast.Type, expr_type ast.Type) {
if !c.check_types(ret_type, expr_type) && !c.check_types(expr_type, ret_type) {
ret_sym := c.table.sym(ret_type)
is_noreturn := is_noreturn_callexpr(last_stmt.expr)
if !(ret_sym.kind == .sum_type && (ret_type.has_flag(.generic)
|| c.table.is_sumtype_or_in_variant(ret_type, expr_type))) && !is_noreturn {
expr_sym := c.table.sym(expr_type)
if expr_sym.kind == .multi_return && ret_sym.kind == .multi_return {
ret_types := ret_sym.mr_info().types
expr_types := expr_sym.mr_info().types.map(ast.mktyp(it))
if expr_types == ret_types {
return
}
}
c.error('return type mismatch, it should be `$ret_sym.name`', last_stmt.pos)
}
}
}
fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSymbol) {
// branch_exprs is a histogram of how many times
// an expr was used in the match

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/return_match_expr_type_mismatch.vv:18:16: error: return type mismatch, it should be `SomeTuple`
16 | fn get_file(item PossOwner) ?SomeTuple {
17 | return match item.pos {
18 | Poss1 { item.pos }
| ~~~
19 | else { error('not poss1') }
20 | }

View File

@ -0,0 +1,34 @@
struct Poss1 {}
struct Poss2 {}
type Possibilities = Poss1 | Poss2
struct PossOwner {
pos Possibilities
}
struct SomeTuple {
p PossOwner
f Poss1
}
fn get_file(item PossOwner) ?SomeTuple {
return match item.pos {
Poss1 { item.pos }
else { error('not poss1') }
}
}
fn main() {
item := PossOwner{
pos: Poss1{}
}
r := get_file(item) or {
println('err=$err')
return
}
println('got $r')
}