checker: check match for exhaustion
parent
1185f04868
commit
12e48c6fe2
|
@ -399,6 +399,7 @@ pub:
|
|||
stmts []Stmt
|
||||
pos token.Position
|
||||
comment Comment // comment above `xxx {`
|
||||
is_else bool
|
||||
}
|
||||
|
||||
pub struct CompIf {
|
||||
|
|
|
@ -1323,6 +1323,18 @@ pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
|
|||
if cond_type == 0 {
|
||||
c.error('match 0 cond type', node.pos)
|
||||
}
|
||||
// check for exhaustion when match is expr
|
||||
if node.is_sum_type && node.is_expr && !node.branches[node.branches.len - 1].is_else {
|
||||
type_sym := c.table.get_type_symbol(cond_type)
|
||||
info := type_sym.info as table.SumType
|
||||
mut used_sum_types_count := 0
|
||||
for branch in node.branches {
|
||||
used_sum_types_count += branch.exprs.len
|
||||
}
|
||||
if used_sum_types_count < info.variants.len {
|
||||
c.error('match must be exhaustive', node.pos)
|
||||
}
|
||||
}
|
||||
c.expected_type = cond_type
|
||||
mut ret_type := table.void_type
|
||||
for branch in node.branches {
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
vlib/v/checker/tests/inout/match_expr_else.v:5:9: error: match must be exhaustive
|
||||
3| fn main() {
|
||||
4| x := A('test')
|
||||
5| res := match x {
|
||||
~~~~~~~~~
|
||||
6| int {
|
||||
7| 'int'
|
|
@ -0,0 +1,13 @@
|
|||
type A = int | string | f64
|
||||
|
||||
fn main() {
|
||||
x := A('test')
|
||||
res := match x {
|
||||
int {
|
||||
'int'
|
||||
}
|
||||
string {
|
||||
'string'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -577,7 +577,7 @@ fn (f mut Fmt) expr(node ast.Expr) {
|
|||
if branch.comment.text != '' {
|
||||
f.comment(branch.comment)
|
||||
}
|
||||
if i < it.branches.len - 1 {
|
||||
if !branch.is_else {
|
||||
// normal branch
|
||||
for j, expr in branch.exprs {
|
||||
f.expr(expr)
|
||||
|
|
|
@ -1373,8 +1373,8 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
|
|||
// g.writeln(';') // $it.blocks.len')
|
||||
// mut sum_type_str = ''
|
||||
for j, branch in node.branches {
|
||||
if j == node.branches.len - 1 {
|
||||
// last block is an `else{}`
|
||||
is_last := j == node.branches.len - 1
|
||||
if branch.is_else || node.is_expr && is_last {
|
||||
if node.branches.len > 1 {
|
||||
if is_expr {
|
||||
// TODO too many branches. maybe separate ?: matches
|
||||
|
@ -1447,7 +1447,7 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
|
|||
}
|
||||
g.stmts(branch.stmts)
|
||||
if !g.inside_ternary && node.branches.len > 1 {
|
||||
g.writeln('}')
|
||||
g.write('}')
|
||||
}
|
||||
}
|
||||
g.inside_ternary = was_inside_ternary
|
||||
|
|
|
@ -1834,8 +1834,8 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
|
|||
}
|
||||
|
||||
fn (p mut Parser) match_expr() ast.MatchExpr {
|
||||
match_first_pos := p.tok.position()
|
||||
p.check(.key_match)
|
||||
pos := p.tok.position()
|
||||
is_mut := p.tok.kind == .key_mut
|
||||
mut is_sum_type := false
|
||||
if is_mut {
|
||||
|
@ -1844,15 +1844,15 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
|
|||
cond := p.expr(0)
|
||||
p.check(.lcbr)
|
||||
mut branches := []ast.MatchBranch
|
||||
mut have_final_else := false
|
||||
for {
|
||||
branch_first_pos := p.tok.position()
|
||||
comment := p.check_comment() // comment before {}
|
||||
mut exprs := []ast.Expr
|
||||
branch_pos := p.tok.position()
|
||||
p.open_scope()
|
||||
// final else
|
||||
mut is_else := false
|
||||
if p.tok.kind == .key_else {
|
||||
have_final_else = true
|
||||
is_else = true
|
||||
p.next()
|
||||
} else if p.tok.kind == .name && (p.tok.lit in table.builtin_type_names ||
|
||||
(p.tok.lit[0].is_capital() && !p.tok.lit.is_upper()) || p.peek_tok.kind == .dot) {
|
||||
|
@ -1890,21 +1890,31 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
|
|||
p.check(.comma)
|
||||
}
|
||||
}
|
||||
branch_last_pos := p.tok.position()
|
||||
// p.warn('match block')
|
||||
stmts := p.parse_block()
|
||||
pos := token.Position{
|
||||
line_nr: match_first_pos.line_nr
|
||||
pos: match_first_pos.pos
|
||||
len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len
|
||||
}
|
||||
branches << ast.MatchBranch{
|
||||
exprs: exprs
|
||||
stmts: stmts
|
||||
pos: branch_pos
|
||||
pos: pos
|
||||
comment: comment
|
||||
is_else: is_else
|
||||
}
|
||||
p.close_scope()
|
||||
if p.tok.kind == .rcbr {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !have_final_else {
|
||||
p.error('match must be exhaustive')
|
||||
match_last_pos := p.tok.position()
|
||||
pos := token.Position{
|
||||
line_nr: match_first_pos.line_nr
|
||||
pos: match_first_pos.pos
|
||||
len: match_last_pos.pos - match_first_pos.pos + match_last_pos.len
|
||||
}
|
||||
p.check(.rcbr)
|
||||
return ast.MatchExpr{
|
||||
|
|
|
@ -96,7 +96,9 @@ pub fn formatted_error(kind string /*error or warn*/, emsg string, filepath stri
|
|||
continue
|
||||
}
|
||||
if pos.len > 1 {
|
||||
underline := '~'.repeat(pos.len)
|
||||
max_len := sline.len - pointerline.len // rest of the line
|
||||
len := if pos.len > max_len { max_len } else { pos.len }
|
||||
underline := '~'.repeat(len)
|
||||
pointerline << if emanager.support_color { term.bold(term.blue(underline)) } else { underline }
|
||||
}else{
|
||||
pointerline << if emanager.support_color { term.bold(term.blue('^')) } else { '^' }
|
||||
|
|
Loading…
Reference in New Issue