checker: avert if else is unnecessary
parent
e0f9c042c1
commit
3e68e429b6
|
@ -21,7 +21,6 @@ fn tag(l Level) string {
|
||||||
.warn { term.yellow('WARN ') }
|
.warn { term.yellow('WARN ') }
|
||||||
.info { term.white('INFO ') }
|
.info { term.white('INFO ') }
|
||||||
.debug { term.blue('DEBUG') }
|
.debug { term.blue('DEBUG') }
|
||||||
else { ' ' }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,8 +150,7 @@ mut res := match fmt_date {
|
||||||
.space{
|
.space{
|
||||||
' '
|
' '
|
||||||
}
|
}
|
||||||
else {
|
})
|
||||||
'unknown enumeration $fmt_dlmtr'}})
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,6 @@ pub fn compile(command string, pref &pref.Preferences) {
|
||||||
.x64 {
|
.x64 {
|
||||||
b.compile_x64()
|
b.compile_x64()
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
eprintln('backend not implemented `$pref.backend`')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if pref.is_stats {
|
if pref.is_stats {
|
||||||
tmark.stop()
|
tmark.stop()
|
||||||
|
|
|
@ -292,22 +292,22 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
||||||
.array {
|
.array {
|
||||||
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
right_sym := c.table.get_type_symbol(right.array_info().elem_type)
|
||||||
if left.kind != right_sym.kind {
|
if left.kind != right_sym.kind {
|
||||||
c.error('the data type on the left of `in` does not match the array item type',
|
c.error('the data type on the left of `in` does not match the array item type',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map {
|
.map {
|
||||||
key_sym := c.table.get_type_symbol(right.map_info().key_type)
|
key_sym := c.table.get_type_symbol(right.map_info().key_type)
|
||||||
if left.kind != key_sym.kind {
|
if left.kind != key_sym.kind {
|
||||||
c.error('the data type on the left of `in` does not match the map key type',
|
c.error('the data type on the left of `in` does not match the map key type',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.string {
|
.string {
|
||||||
if left.kind != .string {
|
if left.kind != .string {
|
||||||
c.error('the data type on the left of `in` must be a string', infix_expr.pos)
|
c.error('the data type on the left of `in` must be a string', infix_expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
c.error('`in` can only be used with an array/map/string', infix_expr.pos)
|
||||||
}
|
}
|
||||||
|
@ -365,10 +365,10 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||||
} else if !left.is_int() && right.is_int() {
|
} else if !left.is_int() && right.is_int() {
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||||
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
} else if left.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||||
!left.has_method(infix_expr.op.str()) {
|
!left.has_method(infix_expr.op.str()) {
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.left.position())
|
||||||
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
} else if right.kind in [.f32, .f64, .string, .array, .array_fixed, .map, .struct_] &&
|
||||||
!right.has_method(infix_expr.op.str()) {
|
!right.has_method(infix_expr.op.str()) {
|
||||||
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
c.error('mismatched types `$left.name` and `$right.name`', infix_expr.right.position())
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
|
||||||
}
|
}
|
||||||
// TODO: Absorb this block into the above single side check block to accelerate.
|
// TODO: Absorb this block into the above single side check block to accelerate.
|
||||||
if left_type == table.bool_type && !(infix_expr.op in [.eq, .ne, .logical_or, .and]) {
|
if left_type == table.bool_type && !(infix_expr.op in [.eq, .ne, .logical_or, .and]) {
|
||||||
c.error('bool types only have the following operators defined: `==`, `!=`, `||`, and `&&`',
|
c.error('bool types only have the following operators defined: `==`, `!=`, `||`, and `&&`',
|
||||||
infix_expr.pos)
|
infix_expr.pos)
|
||||||
} else if left_type == table.string_type && !(infix_expr.op in [.plus, .eq, .ne, .lt, .gt, .le, .ge]) {
|
} else if left_type == table.string_type && !(infix_expr.op in [.plus, .eq, .ne, .lt, .gt, .le, .ge]) {
|
||||||
// TODO broken !in
|
// TODO broken !in
|
||||||
|
@ -1601,46 +1601,57 @@ fn (mut c Checker) match_exprs(node mut ast.MatchExpr, type_sym table.TypeSymbol
|
||||||
// this is achieved either by putting an else
|
// this is achieved either by putting an else
|
||||||
// or, when the match is on a sum type or an enum
|
// or, when the match is on a sum type or an enum
|
||||||
// by listing all variants or values
|
// by listing all variants or values
|
||||||
if !node.branches[node.branches.len - 1].is_else {
|
mut is_exhaustive := true
|
||||||
|
mut unhandled := []string
|
||||||
|
match type_sym.info {
|
||||||
|
table.SumType {
|
||||||
|
for v in it.variants {
|
||||||
|
v_str := c.table.type_to_str(v)
|
||||||
|
if v_str !in branch_exprs {
|
||||||
|
is_exhaustive = false
|
||||||
|
unhandled << '`$v_str`'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.Enum {
|
||||||
|
for v in it.vals {
|
||||||
|
if v !in branch_exprs {
|
||||||
|
is_exhaustive = false
|
||||||
|
unhandled << '`.$v`'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
is_exhaustive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut else_branch := node.branches[node.branches.len - 1]
|
||||||
|
mut has_else := else_branch.is_else
|
||||||
|
if !has_else {
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
if branch.is_else && i != node.branches.len - 1 {
|
if branch.is_else && i != node.branches.len - 1 {
|
||||||
c.error('`else` must be the last branch of `match`', branch.pos)
|
c.error('`else` must be the last branch of `match`', branch.pos)
|
||||||
return
|
else_branch = branch
|
||||||
|
has_else = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut err := false
|
|
||||||
mut err_details := 'match must be exhaustive'
|
|
||||||
unhandled := []string
|
|
||||||
match type_sym.info {
|
|
||||||
table.SumType {
|
|
||||||
for v in it.variants {
|
|
||||||
v_str := c.table.type_to_str(v)
|
|
||||||
if v_str !in branch_exprs {
|
|
||||||
err = true
|
|
||||||
unhandled << '`$v_str`'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
table.Enum {
|
|
||||||
for v in it.vals {
|
|
||||||
if v !in branch_exprs {
|
|
||||||
err = true
|
|
||||||
unhandled << '`.$v`'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println('else')
|
|
||||||
err = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err {
|
|
||||||
if unhandled.len > 0 {
|
|
||||||
err_details += ' (add match branches for: ' + unhandled.join(', ') + ' or `else {}` at the end)'
|
|
||||||
}
|
|
||||||
c.error(err_details, node.pos)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if is_exhaustive {
|
||||||
|
if has_else {
|
||||||
|
c.error('match expression is exhaustive, `else` is unnecessary', else_branch.pos)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if has_else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut err_details := 'match must be exhaustive'
|
||||||
|
if unhandled.len > 0 {
|
||||||
|
err_details += ' (add match branches for: ' + unhandled.join(', ') + ' or `else {}` at the end)'
|
||||||
|
} else {
|
||||||
|
err_details += ' (add `else {}` at the end)'
|
||||||
|
}
|
||||||
|
c.error(err_details, node.pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
|
pub fn (mut c Checker) if_expr(node mut ast.IfExpr) table.Type {
|
||||||
|
|
|
@ -5,3 +5,17 @@ vlib/v/checker/tests/inout/match_expr_else.v:5:6: error: match must be exhaustiv
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
6| int {
|
6| int {
|
||||||
7| 'int'
|
7| 'int'
|
||||||
|
vlib/v/checker/tests/inout/match_expr_else.v:23:3: error: match expression is exhaustive, `else` is unnecessary
|
||||||
|
21| 'f64'
|
||||||
|
22| }
|
||||||
|
23| else {
|
||||||
|
~~~~~~
|
||||||
|
24| 'else'
|
||||||
|
25| }
|
||||||
|
vlib/v/checker/tests/inout/match_expr_else.v:34:3: error: `else` must be the last branch of `match`
|
||||||
|
32| 'string'
|
||||||
|
33| }
|
||||||
|
34| else {
|
||||||
|
~~~~~~
|
||||||
|
35| 'else'
|
||||||
|
36| }
|
||||||
|
|
|
@ -10,4 +10,32 @@ fn main() {
|
||||||
'string'
|
'string'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ := match x {
|
||||||
|
int {
|
||||||
|
'int'
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
'string'
|
||||||
|
}
|
||||||
|
f64 {
|
||||||
|
'f64'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
'else'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ := match x {
|
||||||
|
int {
|
||||||
|
'int'
|
||||||
|
}
|
||||||
|
string {
|
||||||
|
'string'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
'else'
|
||||||
|
}
|
||||||
|
f64 {
|
||||||
|
'f64'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,11 +107,6 @@ pub fn (o OS) str() string {
|
||||||
.haiku {
|
.haiku {
|
||||||
return 'Haiku'
|
return 'Haiku'
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
//TODO Remove when V is smart enough to know that there's no other possibilities
|
|
||||||
//should never be reached as all enum types have been enumerated
|
|
||||||
panic('unknown OS enum type: $o')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,10 +55,6 @@ fn test_match_expression_on_sumtype_full(){
|
||||||
c = 2
|
c = 2
|
||||||
eprintln('hi')
|
eprintln('hi')
|
||||||
'a string'
|
'a string'
|
||||||
}else{
|
|
||||||
c = 3
|
|
||||||
eprintln('hi')
|
|
||||||
'unknown'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert res == 'an integer'
|
assert res == 'an integer'
|
||||||
|
|
Loading…
Reference in New Issue