diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 562a157cce..e91574067e 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -259,6 +259,7 @@ pub: pub struct InterfaceDecl { pub: name string + name_pos token.Position field_names []string is_pub bool methods []FnDecl @@ -365,7 +366,6 @@ pub: language Language no_body bool // just a definition `fn C.malloc()` is_builtin bool // this function is defined in builtin/strconv - pos token.Position // function declaration position body_pos token.Position // function bodys position file string generic_params []GenericParam @@ -373,15 +373,17 @@ pub: attrs []Attr skip_gen bool // this function doesn't need to be generated (for example [if foo]) pub mut: - stmts []Stmt - defer_stmts []DeferStmt - return_type Type - has_return bool - comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl - next_comments []Comment // coments that are one line after the decl; used for InterfaceDecl - source_file &File = 0 - scope &Scope - label_names []string + stmts []Stmt + defer_stmts []DeferStmt + return_type Type + return_type_pos token.Position // `string` in `fn (u User) name() string` position + has_return bool + comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl + next_comments []Comment // coments that are one line after the decl; used for InterfaceDecl + source_file &File = 0 + scope &Scope + label_names []string + pos token.Position // function declaration position } pub struct GenericParam { @@ -1603,7 +1605,7 @@ pub fn (node Node) position() token.Position { StructField { return node.pos.extend(node.type_pos) } - MatchBranch, SelectBranch, EnumField, ConstField, StructInitField, GlobalField, Param { + MatchBranch, SelectBranch, EnumField, ConstField, StructInitField, GlobalField, CallArg { return node.pos } IfBranch { @@ -1625,6 +1627,9 @@ pub fn (node Node) position() token.Position { } } } + Param { + return node.pos.extend(node.type_pos) + } File { mut pos := token.Position{} if node.stmts.len > 0 { @@ -1634,9 +1639,6 @@ pub fn (node Node) position() token.Position { } return pos } - CallArg { - return node.pos - } } } @@ -1719,7 +1721,8 @@ pub fn (node Node) children() []Node { children << node.expr } InterfaceDecl { - return node.methods.map(Node(Stmt(it))) + children << node.methods.map(Node(Stmt(it))) + children << node.fields.map(Node(it)) } AssignStmt { children << node.left.map(Node(it)) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index c4086cd39b..ed3fdea7c1 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -353,7 +353,7 @@ pub fn (mut c Checker) interface_decl(decl ast.InterfaceDecl) { for method in decl.methods { c.check_valid_snake_case(method.name, 'method name', method.pos) if method.return_type != ast.Type(0) { - c.ensure_type_exists(method.return_type, method.pos) or { return } + c.ensure_type_exists(method.return_type, method.return_type_pos) or { return } } for param in method.params { c.ensure_type_exists(param.typ, param.pos) or { return } diff --git a/vlib/v/checker/tests/interface_return_parameter_err.out b/vlib/v/checker/tests/interface_return_parameter_err.out index 86236b1c6d..ac3f23dba4 100644 --- a/vlib/v/checker/tests/interface_return_parameter_err.out +++ b/vlib/v/checker/tests/interface_return_parameter_err.out @@ -1,8 +1,8 @@ -vlib/v/checker/tests/interface_return_parameter_err.vv:2:5: error: unknown type `Baz`. +vlib/v/checker/tests/interface_return_parameter_err.vv:2:17: error: unknown type `Baz`. Did you mean `Foo`? 1 | interface Foo { 2 | bar(string) []Baz - | ~~~~~~~~~~~ + | ~~~~~ 3 | bar2(Bax) string 4 | } vlib/v/checker/tests/interface_return_parameter_err.vv:3:10: error: unknown type `Bax`. diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 2524e6eaee..5e2883ffcd 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -293,12 +293,14 @@ fn (mut p Parser) fn_decl() ast.FnDecl { } } // Return type + mut return_type_pos := p.tok.position() mut return_type := ast.void_type // don't confuse token on the next line: fn decl, [attribute] same_line := p.tok.line_nr == p.prev_tok.line_nr if (p.tok.kind.is_start_of_type() && (same_line || p.tok.kind != .lsbr)) || (same_line && p.tok.kind == .key_fn) { return_type = p.parse_type() + return_type_pos = return_type_pos.extend(p.prev_tok.position()) } mut type_sym_method_idx := 0 no_body := p.tok.kind != .lcbr @@ -398,6 +400,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mod: p.mod stmts: stmts return_type: return_type + return_type_pos: return_type_pos params: params is_manualfree: is_manualfree is_deprecated: is_deprecated @@ -574,10 +577,12 @@ fn (mut p Parser) anon_fn() ast.AnonFn { } mut same_line := p.tok.line_nr == p.prev_tok.line_nr mut return_type := ast.void_type + mut return_type_pos := p.tok.position() // lpar: multiple return types if same_line { if p.tok.kind.is_start_of_type() { return_type = p.parse_type() + return_type_pos = return_type_pos.extend(p.tok.position()) } else if p.tok.kind != .lcbr { p.error_with_pos('expected return type, not $p.tok for anonymous function', p.tok.position()) @@ -618,6 +623,7 @@ fn (mut p Parser) anon_fn() ast.AnonFn { mod: p.mod stmts: stmts return_type: return_type + return_type_pos: return_type_pos params: args is_variadic: is_variadic is_method: false diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index 9f45f38edd..87e15664ec 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -518,7 +518,10 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl { scope: p.scope } if p.tok.kind.is_start_of_type() && p.tok.line_nr == line_nr { + method.return_type_pos = p.tok.position() method.return_type = p.parse_type() + method.return_type_pos = method.return_type_pos.extend(p.tok.position()) + method.pos = method.pos.extend(method.return_type_pos) } mcomments := p.eat_comments(same_line: true) mnext_comments := p.eat_comments({}) @@ -577,5 +580,6 @@ fn (mut p Parser) interface_decl() ast.InterfaceDecl { pos: pos pre_comments: pre_comments mut_pos: mut_pos + name_pos: name_pos } }