checker: fail if else isn't the last branch of match
parent
0c63f5c80d
commit
86402204a7
|
@ -1355,69 +1355,80 @@ pub fn (c mut Checker) match_expr(node mut ast.MatchExpr) table.Type {
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
if !node.branches[node.branches.len - 1].is_else {
|
mut has_else := node.branches[node.branches.len - 1].is_else
|
||||||
mut used_values_count := 0
|
if !has_else {
|
||||||
for bi, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
used_values_count += branch.exprs.len
|
if branch.is_else && i != node.branches.len - 1 {
|
||||||
for bi_ei, bexpr in branch.exprs {
|
c.error('`else` must be the last branch of `match`', branch.pos)
|
||||||
match bexpr {
|
has_else = true
|
||||||
ast.Type {
|
break
|
||||||
tidx := table.type_idx(it.typ)
|
|
||||||
stidx := tidx.str()
|
|
||||||
all_possible_left_subtypes[stidx] = all_possible_left_subtypes[stidx] +
|
|
||||||
1
|
|
||||||
}
|
|
||||||
ast.EnumVal {
|
|
||||||
all_possible_left_enum_vals[it.val] = all_possible_left_enum_vals[it.val] +
|
|
||||||
1
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut err := false
|
|
||||||
mut err_details := 'match must be exhaustive'
|
if !has_else {
|
||||||
unhandled := []string
|
mut used_values_count := 0
|
||||||
match type_sym.info {
|
for bi, branch in node.branches {
|
||||||
table.SumType {
|
used_values_count += branch.exprs.len
|
||||||
for k, v in all_possible_left_subtypes {
|
for bi_ei, bexpr in branch.exprs {
|
||||||
if v == 0 {
|
match bexpr {
|
||||||
err = true
|
ast.Type {
|
||||||
unhandled << '`' + c.table.type_to_str(table.new_type(k.int())) + '`'
|
tidx := table.type_idx(it.typ)
|
||||||
}
|
stidx := tidx.str()
|
||||||
if v > 1 {
|
all_possible_left_subtypes[stidx] = all_possible_left_subtypes[stidx] +
|
||||||
err = true
|
1
|
||||||
multiple_type_name := '`' + c.table.type_to_str(table.new_type(k.int())) +
|
}
|
||||||
'`'
|
ast.EnumVal {
|
||||||
c.error('a match case for $multiple_type_name is handled more than once',
|
all_possible_left_enum_vals[it.val] = all_possible_left_enum_vals[it.val] +
|
||||||
node.pos)
|
1
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
table.Enum {
|
mut err := false
|
||||||
for k, v in all_possible_left_enum_vals {
|
mut err_details := 'match must be exhaustive'
|
||||||
if v == 0 {
|
unhandled := []string
|
||||||
err = true
|
match type_sym.info {
|
||||||
unhandled << '`.$k`'
|
table.SumType {
|
||||||
}
|
for k, v in all_possible_left_subtypes {
|
||||||
if v > 1 {
|
if v == 0 {
|
||||||
err = true
|
err = true
|
||||||
multiple_enum_val := '`.$k`'
|
unhandled << '`' + c.table.type_to_str(table.new_type(k.int())) + '`'
|
||||||
c.error('a match case for $multiple_enum_val is handled more than once',
|
}
|
||||||
node.pos)
|
if v > 1 {
|
||||||
|
err = true
|
||||||
|
multiple_type_name := '`' + c.table.type_to_str(table.new_type(k.int())) +
|
||||||
|
'`'
|
||||||
|
c.error('a match case for $multiple_type_name is handled more than once',
|
||||||
|
node.pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
table.Enum {
|
||||||
|
for k, v in all_possible_left_enum_vals {
|
||||||
|
if v == 0 {
|
||||||
|
err = true
|
||||||
|
unhandled << '`.$k`'
|
||||||
|
}
|
||||||
|
if v > 1 {
|
||||||
|
err = true
|
||||||
|
multiple_enum_val := '`.$k`'
|
||||||
|
c.error('a match case for $multiple_enum_val is handled more than once',
|
||||||
|
node.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
if err {
|
||||||
err = true
|
if unhandled.len > 0 {
|
||||||
|
err_details += ' (add match branches for: ' + unhandled.join(', ') + ' or an else{} branch)'
|
||||||
|
}
|
||||||
|
c.error(err_details, node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err {
|
|
||||||
if unhandled.len > 0 {
|
|
||||||
err_details += ' (add match branches for: ' + unhandled.join(', ') + ' or an else{} branch)'
|
|
||||||
}
|
|
||||||
c.error(err_details, node.pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
c.expected_type = cond_type
|
c.expected_type = cond_type
|
||||||
mut ret_type := table.void_type
|
mut ret_type := table.void_type
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
vlib/v/checker/tests/inout/match_else_last_expr.v:4:3: error: `else` must be the last branch of `match`
|
||||||
|
2| match 1 {
|
||||||
|
3| 1 { println('1') }
|
||||||
|
4| else { println('else') }
|
||||||
|
~~~~~~
|
||||||
|
5| 4 { println('4') }
|
||||||
|
6| }
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
match 1 {
|
||||||
|
1 { println('1') }
|
||||||
|
else { println('else') }
|
||||||
|
4 { println('4') }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1919,8 +1919,8 @@ fn (p mut Parser) match_expr() ast.MatchExpr {
|
||||||
// p.warn('match block')
|
// p.warn('match block')
|
||||||
stmts := p.parse_block()
|
stmts := p.parse_block()
|
||||||
pos := token.Position{
|
pos := token.Position{
|
||||||
line_nr: match_first_pos.line_nr
|
line_nr: branch_first_pos.line_nr
|
||||||
pos: match_first_pos.pos
|
pos: branch_first_pos.pos
|
||||||
len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len
|
len: branch_last_pos.pos - branch_first_pos.pos + branch_last_pos.len
|
||||||
}
|
}
|
||||||
branches << ast.MatchBranch{
|
branches << ast.MatchBranch{
|
||||||
|
|
Loading…
Reference in New Issue