diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 829c9fabb0bf9a..1e967199c83599 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2962,6 +2962,20 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type { if !c.is_builtin_mod { c.table.used_features.as_cast = true } + if mut node.expr is ast.Ident { + if mut node.expr.obj is ast.Var { + ident_typ := if node.expr.obj.smartcasts.len > 0 { + node.expr.obj.smartcasts.last() + } else { + node.expr.obj.typ + } + if !node.typ.has_flag(.option) && ident_typ.has_flag(.option) + && node.expr.or_expr.kind == .absent { + c.error('variable `${node.expr.name}` is an Option, it must be unwrapped first', + node.expr.pos) + } + } + } if expr_type_sym.kind == .sum_type { c.ensure_type_exists(node.typ, node.pos) if !c.table.sumtype_has_variant(c.unwrap_generic(node.expr_type), c.unwrap_generic(node.typ), diff --git a/vlib/v/checker/tests/option_as_cast_err.out b/vlib/v/checker/tests/option_as_cast_err.out new file mode 100644 index 00000000000000..e7973ab4ba0ebd --- /dev/null +++ b/vlib/v/checker/tests/option_as_cast_err.out @@ -0,0 +1,5 @@ +vlib/v/checker/tests/option_as_cast_err.vv:12:9: error: variable `b` is an Option, it must be unwrapped first + 10 | println(b) + 11 | println(b? as int) + 12 | println(b as int) + | ^ diff --git a/vlib/v/checker/tests/option_as_cast_err.vv b/vlib/v/checker/tests/option_as_cast_err.vv new file mode 100644 index 00000000000000..c57cd3f7348058 --- /dev/null +++ b/vlib/v/checker/tests/option_as_cast_err.vv @@ -0,0 +1,12 @@ +type Sum = int | string + +fn sum() ?Sum { + return Sum(5) +} + +a := sum()? +println(a as int) +b := sum() +println(b) +println(b? as int) +println(b as int) diff --git a/vlib/v/tests/options/option_concatexpr_test.v b/vlib/v/tests/options/option_concatexpr_test.v index f8b181e073c72b..a19b1488e5b5a1 100644 --- a/vlib/v/tests/options/option_concatexpr_test.v +++ b/vlib/v/tests/options/option_concatexpr_test.v @@ -12,17 +12,17 @@ fn foo(f int) !(int, ?int) { fn test_main() { a, b := foo(-1) or { 2, 2 } - c := b as int + c := b? as int assert a == 2 assert c == 2 a2, b2 := foo(0) or { 2, 2 } - c2 := b2 as int + c2 := b2? as int assert a2 == 0 assert c2 == 0 a3, b3 := foo(1) or { 2, 2 } - c3 := b3 as int + c3 := b3? as int assert a3 == 1 assert c3 == 1 } diff --git a/vlib/v/tests/options/option_unwrap_as_cast_test.v b/vlib/v/tests/options/option_unwrap_as_cast_test.v index 6bf6879a9f74d4..a6353525655b6a 100644 --- a/vlib/v/tests/options/option_unwrap_as_cast_test.v +++ b/vlib/v/tests/options/option_unwrap_as_cast_test.v @@ -15,9 +15,9 @@ fn get_opt_int(a int) ?int { fn test_option_unwrap_as_cast() { x := get_opt(1) d := get_opt_int(12) - dump(d as int == 12) - dump('${x as string}' == 'success') + dump(d? as int == 12) + dump('${x? as string}' == 'success') - assert d as int == 12 - assert x as string == 'success' + assert d? as int == 12 + assert x? as string == 'success' }