diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 247dcce3bdea7b..4cfc7e65131ce0 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -36,6 +36,8 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { c.match_exprs(mut node, cond_type_sym) c.expected_type = cond_type mut first_iteration := true + mut infer_cast_type := ast.void_type + mut need_explicit_cast := false mut ret_type := ast.void_type mut nbranches_with_return := 0 mut nbranches_without_return := 0 @@ -87,6 +89,11 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { } } } + infer_cast_type = stmt.typ + if mut stmt.expr is ast.CastExpr { + need_explicit_cast = true + infer_cast_type = stmt.expr.typ + } } else { if node.is_expr && ret_type.idx() != expr_type.idx() { if (node.expected_type.has_flag(.option) @@ -120,6 +127,82 @@ fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { stmt.pos) } } + if !node.is_sum_type { + if mut stmt.expr is ast.CastExpr { + expr_typ_sym := c.table.sym(stmt.expr.typ) + if need_explicit_cast { + if infer_cast_type != stmt.expr.typ + && expr_typ_sym.kind !in [.interface_, .sum_type] { + c.error('the type of the last expression in the first match branch was an explicit `${c.table.type_to_str(infer_cast_type)}`, not `${c.table.type_to_str(stmt.expr.typ)}`', + stmt.pos) + } + } else { + if infer_cast_type != stmt.expr.typ + && expr_typ_sym.kind !in [.interface_, .sum_type] + && c.promote_num(stmt.expr.typ, ast.int_type) != ast.int_type { + c.error('the type of the last expression of the first match branch was `${c.table.type_to_str(infer_cast_type)}`, which is not compatible with `${c.table.type_to_str(stmt.expr.typ)}`', + stmt.pos) + } + } + } else { + if mut stmt.expr is ast.IntegerLiteral { + cast_type_sym := c.table.sym(infer_cast_type) + num := stmt.expr.val.i64() + mut needs_explicit_cast := false + + match cast_type_sym.kind { + .u8 { + if !(num >= min_u8 && num <= max_u8) { + needs_explicit_cast = true + } + } + .u16 { + if !(num >= min_u16 && num <= max_u16) { + needs_explicit_cast = true + } + } + .u32 { + if !(num >= min_u32 && num <= max_u32) { + needs_explicit_cast = true + } + } + .u64 { + if !(num >= min_u64 && num <= max_u64) { + needs_explicit_cast = true + } + } + .i8 { + if !(num >= min_i32 && num <= max_i32) { + needs_explicit_cast = true + } + } + .i16 { + if !(num >= min_i16 && num <= max_i16) { + needs_explicit_cast = true + } + } + .i32, .int { + if !(num >= min_i32 && num <= max_i32) { + needs_explicit_cast = true + } + } + .i64 { + if !(num >= min_i64 && num <= max_i64) { + needs_explicit_cast = true + } + } + .int_literal { + needs_explicit_cast = false + } + else {} + } + if needs_explicit_cast { + c.error('${num} does not fit the range of `${c.table.type_to_str(infer_cast_type)}`', + stmt.pos) + } + } + } + } } } else if stmt !in [ast.Return, ast.BranchStmt] { if node.is_expr && ret_type != ast.void_type { diff --git a/vlib/v/checker/tests/match_incorrect_cast_branch_err.out b/vlib/v/checker/tests/match_incorrect_cast_branch_err.out new file mode 100644 index 00000000000000..312d8e33d48c70 --- /dev/null +++ b/vlib/v/checker/tests/match_incorrect_cast_branch_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/match_incorrect_cast_branch_err.vv:5:9: error: the type of the last expression in the first match branch was an explicit `u8`, not `u16` + 3 | nb := match name { + 4 | 'a' { u8(10) } + 5 | 'b' { u16(500) } + | ~~~~~~~~ + 6 | else { u8(0) } + 7 | } diff --git a/vlib/v/checker/tests/match_incorrect_cast_branch_err.vv b/vlib/v/checker/tests/match_incorrect_cast_branch_err.vv new file mode 100644 index 00000000000000..6aa81763ec83e0 --- /dev/null +++ b/vlib/v/checker/tests/match_incorrect_cast_branch_err.vv @@ -0,0 +1,10 @@ +fn main () { + name := 'b' + nb := match name { + 'a' { u8(10) } + 'b' { u16(500) } + else { u8(0) } + } + + println(nb) +} diff --git a/vlib/v/checker/tests/match_last_branch_only_casted.out b/vlib/v/checker/tests/match_last_branch_only_casted.out new file mode 100644 index 00000000000000..2ad959d5b59754 --- /dev/null +++ b/vlib/v/checker/tests/match_last_branch_only_casted.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/match_last_branch_only_casted.vv:6:10: error: the type of the last expression of the first match branch was `int literal`, which is not compatible with `u64` + 4 | 'a' { 10 } + 5 | 'b' { 500 } + 6 | else { u64(345454) } + | ~~~~~~~~~~~ + 7 | } + 8 | diff --git a/vlib/v/checker/tests/match_last_branch_only_casted.vv b/vlib/v/checker/tests/match_last_branch_only_casted.vv new file mode 100644 index 00000000000000..98160040a9ffab --- /dev/null +++ b/vlib/v/checker/tests/match_last_branch_only_casted.vv @@ -0,0 +1,10 @@ +fn main () { + name := 'b' + nb := match name { + 'a' { 10 } + 'b' { 500 } + else { u64(345454) } + } + + println(nb) +} diff --git a/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.out b/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.out new file mode 100644 index 00000000000000..7db28f080f8f4f --- /dev/null +++ b/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.vv:5:9: error: 345 does not fit the range of `u8` + 3 | nb := match name { + 4 | 'a' { u8(10) } + 5 | 'b' { 345 } + | ~~~ + 6 | else { 0 } + 7 | } diff --git a/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.vv b/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.vv new file mode 100644 index 00000000000000..a3d3f8d5a84988 --- /dev/null +++ b/vlib/v/checker/tests/match_no_branch_cast_rest_casted_err.vv @@ -0,0 +1,10 @@ +fn main () { + name := 'b' + nb := match name { + 'a' { u8(10) } + 'b' { 345 } + else { 0 } + } + + println(nb) +}