diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 8f6285fbd9..240c102fb7 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -262,6 +262,7 @@ pub mut: return_type table.Type } +// break, continue pub struct BranchStmt { pub: tok token.Token diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b9cb4c5121..cf4330f83d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1509,12 +1509,6 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type } mut last_stmt := or_expr.stmts[stmts_len - 1] if ret_type != table.void_type { - if !(last_stmt is ast.Return || last_stmt is ast.BranchStmt || last_stmt is ast.ExprStmt) { - expected_type_name := c.table.get_type_symbol(ret_type).name - c.error('last statement in the `or {}` block should return `$expected_type_name`', - or_expr.pos) - return - } match mut last_stmt { ast.ExprStmt { last_stmt.typ = c.expr(last_stmt.expr) @@ -1523,8 +1517,8 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type if type_fits || is_panic_or_exit { return } - type_name := c.table.get_type_symbol(last_stmt.typ).name - expected_type_name := c.table.get_type_symbol(ret_type).name + type_name := c.table.type_to_str(last_stmt.typ) + expected_type_name := c.table.type_to_str(ret_type.clear_flag(.optional)) c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`', last_stmt.pos) return @@ -1536,9 +1530,14 @@ pub fn (mut c Checker) check_or_expr(mut or_expr ast.OrExpr, ret_type table.Type return } } - else {} + ast.Return {} + else { + expected_type_name := c.table.type_to_str(ret_type.clear_flag(.optional)) + c.error('last statement in the `or {}` block should be an expression of type `$expected_type_name` or exit parent scope', + or_expr.pos) + return + } } - return } } diff --git a/vlib/v/checker/tests/or_err.out b/vlib/v/checker/tests/or_err.out new file mode 100644 index 0000000000..dadafc1cb3 --- /dev/null +++ b/vlib/v/checker/tests/or_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/or_err.vv:4:6: error: last statement in the `or {}` block should be an expression of type `&int` or exit parent scope + 2 | return none + 3 | } + 4 | a := f() or { + | ~~~ + 5 | {} + 6 | } +vlib/v/checker/tests/or_err.vv:11:2: error: wrong return type `rune` in the `or {}` block, expected `&int` + 9 | } + 10 | _ = f() or { + 11 | `.` + | ~~~ + 12 | } + 13 | diff --git a/vlib/v/checker/tests/or_err.vv b/vlib/v/checker/tests/or_err.vv new file mode 100644 index 0000000000..035b87eeb8 --- /dev/null +++ b/vlib/v/checker/tests/or_err.vv @@ -0,0 +1,13 @@ +fn f() ?&int { + return none +} +a := f() or { + {} +} +_ = f() or { + a +} +_ = f() or { + `.` +} + diff --git a/vlib/v/table/atypes.v b/vlib/v/table/atypes.v index 57f04abfe2..6670afa3bd 100644 --- a/vlib/v/table/atypes.v +++ b/vlib/v/table/atypes.v @@ -24,14 +24,19 @@ pub enum Language { js } +// Represents a type that only needs an identifier, e.g. int, array_int. +// A pointer type `&T` would have a TypeSymbol `T`. +// Note: For a Type, use Table.type_to_str(typ) not TypeSymbol.name. +// Each TypeSymbol is entered into `Table.types`. +// See also: Table.get_type_symbol. pub struct TypeSymbol { pub: parent_idx int pub mut: info TypeInfo kind Kind - name string // the internal name of the type, i.e. `array_fixed_int_5`. See also .source_name below. - source_name string // the original source name of the type, i.e. `[5]int`. Do not use this for logic, but just for formatting/errors. + name string // the internal name of the type or underlying type, i.e. `array_fixed_int_5`. See also .source_name below. + source_name string // the original source name of the type, i.e. `[5]int`. methods []Fn mod string is_public bool