diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 55810c1efe..09d1133cbc 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -32,6 +32,7 @@ mut: in_for_count int // if checker is currently in an for loop // checked_ident string // to avoid infinit checker loops var_decl_name string + returns bool } pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker { @@ -250,6 +251,9 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { } pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { + if call_expr.name == 'panic' { + c.returns = true + } c.stmts(call_expr.or_block.stmts) if call_expr.is_method { left_type := c.expr(call_expr.left) @@ -876,6 +880,11 @@ fn (c mut Checker) stmt(node ast.Stmt) { c.expected_type = table.void_type c.fn_return_type = it.return_type c.stmts(it.stmts) + if !it.is_c && !it.no_body && it.return_type != table.void_type && !c.returns && + !(it.name in ['panic', 'exit']) { + c.error('missing return at end of function `$it.name`', it.pos) + } + c.returns = false } ast.ForStmt { c.in_for_count++ @@ -937,6 +946,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { ast.Import {} // ast.GlobalDecl {} ast.Return { + c.returns = true c.return_stmt(mut it) } // ast.StructDecl {} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 62b41f854e..e9bb340d3c 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -83,6 +83,7 @@ pub fn (p mut Parser) call_args() []ast.CallArg { fn (p mut Parser) fn_decl() ast.FnDecl { // p.table.clear_vars() + pos := p.tok.position() p.open_scope() is_deprecated := p.attr == 'deprecated' is_pub := p.tok.kind == .key_pub @@ -207,7 +208,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { rec_mut: rec_mut is_c: is_c no_body: no_body - pos: p.tok.position() + pos: pos is_builtin: p.builtin_mod || p.mod in ['math', 'strconv', 'strconv.ftoa', 'hash.wyhash', 'math.bits', 'strings'] }