From 93b0d8ca64f7eeec3543b9397860e350241a8075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20D=C3=A4schle?= Date: Thu, 28 Jan 2021 10:56:43 +0100 Subject: [PATCH] parser: fix panic when single letter receiver parsed (#8381) --- vlib/v/checker/checker.v | 2 +- .../receiver_unknown_type_single_letter.out | 3 + .../receiver_unknown_type_single_letter.vv | 1 + vlib/v/parser/fn.v | 2 + vlib/v/parser/parse_type.v | 2 +- vlib/v/parser/parser.v | 85 ++++++++++--------- 6 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 vlib/v/checker/tests/receiver_unknown_type_single_letter.out create mode 100644 vlib/v/checker/tests/receiver_unknown_type_single_letter.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 4eefbee119..1f52502d20 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5296,7 +5296,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { sym := c.table.get_type_symbol(arg.typ) if sym.kind == .placeholder || (sym.kind in [table.Kind.int_literal, .float_literal] && !c.is_builtin_mod) { - c.error('unknown type `$sym.name`', node.pos) + c.error('unknown type `$sym.name`', node.receiver_pos) } } } diff --git a/vlib/v/checker/tests/receiver_unknown_type_single_letter.out b/vlib/v/checker/tests/receiver_unknown_type_single_letter.out new file mode 100644 index 0000000000..bd78937087 --- /dev/null +++ b/vlib/v/checker/tests/receiver_unknown_type_single_letter.out @@ -0,0 +1,3 @@ +vlib/v/checker/tests/receiver_unknown_type_single_letter.vv:1:5: error: unknown type `A` + 1 | fn (p A) foo() {} + | ~~~ diff --git a/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv b/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv new file mode 100644 index 0000000000..0cd62232fc --- /dev/null +++ b/vlib/v/checker/tests/receiver_unknown_type_single_letter.vv @@ -0,0 +1 @@ +fn (p A) foo() {} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index df1b06a1e1..458fbdd1e4 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -190,6 +190,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut rec_mut := false mut params := []table.Param{} if p.tok.kind == .lpar { + p.is_parsing_receiver = true lpar_pos := p.tok.position() p.next() // ( is_method = true @@ -246,6 +247,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { typ: rec_type } p.check(.rpar) + p.is_parsing_receiver = false } mut name := '' if p.tok.kind == .name { diff --git a/vlib/v/parser/parse_type.v b/vlib/v/parser/parse_type.v index fd2338f782..db5276085a 100644 --- a/vlib/v/parser/parse_type.v +++ b/vlib/v/parser/parse_type.v @@ -373,7 +373,7 @@ pub fn (mut p Parser) parse_any_type(language table.Language, is_ptr bool, check return table.int_literal_type } else { - if name.len == 1 && name[0].is_capital() { + if name.len == 1 && name[0].is_capital() && !p.is_parsing_receiver { return p.parse_generic_template_type(name) } if p.peek_tok.kind == .lt { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 39f3dede9e..7b5da0cdf5 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -29,48 +29,49 @@ mut: scanner &scanner.Scanner comments_mode scanner.CommentsMode = .skip_comments // see comment in parse_file - tok token.Token - prev_tok token.Token - peek_tok token.Token - peek_tok2 token.Token - peek_tok3 token.Token - table &table.Table - language table.Language - inside_if bool - inside_if_expr bool - inside_ct_if_expr bool - inside_or_expr bool - inside_for bool - inside_fn bool // true even with implicit main - inside_str_interp bool - or_is_handled bool // ignore `or` in this expression - builtin_mod bool // are we in the `builtin` module? - mod string // current module name - is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree - attrs []table.Attr // attributes before next decl stmt - expr_mod string // for constructing full type names in parse_type() - scope &ast.Scope - global_scope &ast.Scope - imports map[string]string // alias => mod_name - ast_imports []ast.Import // mod_names - used_imports []string // alias - auto_imports []string // imports, the user does not need to specify - imported_symbols map[string]string - is_amp bool // for generating the right code for `&Foo{}` - returns bool - inside_match bool // to separate `match A { }` from `Struct{}` - inside_select bool // to allow `ch <- Struct{} {` inside `select` - inside_match_case bool // to separate `match_expr { }` from `Struct{}` - inside_match_body bool // to fix eval not used TODO - inside_unsafe bool - is_stmt_ident bool // true while the beginning of a statement is an ident/selector - expecting_type bool // `is Type`, expecting type - errors []errors.Error - warnings []errors.Warning - vet_errors []vet.Error - cur_fn_name string - in_generic_params bool // indicates if parsing between `<` and `>` of a method/function - name_error bool // indicates if the token is not a name or the name is on another line + tok token.Token + prev_tok token.Token + peek_tok token.Token + peek_tok2 token.Token + peek_tok3 token.Token + table &table.Table + language table.Language + inside_if bool + inside_if_expr bool + inside_ct_if_expr bool + inside_or_expr bool + inside_for bool + inside_fn bool // true even with implicit main + inside_str_interp bool + or_is_handled bool // ignore `or` in this expression + builtin_mod bool // are we in the `builtin` module? + mod string // current module name + is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree + attrs []table.Attr // attributes before next decl stmt + expr_mod string // for constructing full type names in parse_type() + scope &ast.Scope + global_scope &ast.Scope + imports map[string]string // alias => mod_name + ast_imports []ast.Import // mod_names + used_imports []string // alias + auto_imports []string // imports, the user does not need to specify + imported_symbols map[string]string + is_amp bool // for generating the right code for `&Foo{}` + returns bool + inside_match bool // to separate `match A { }` from `Struct{}` + inside_select bool // to allow `ch <- Struct{} {` inside `select` + inside_match_case bool // to separate `match_expr { }` from `Struct{}` + inside_match_body bool // to fix eval not used TODO + inside_unsafe bool + is_stmt_ident bool // true while the beginning of a statement is an ident/selector + expecting_type bool // `is Type`, expecting type + errors []errors.Error + warnings []errors.Warning + vet_errors []vet.Error + cur_fn_name string + in_generic_params bool // indicates if parsing between `<` and `>` of a method/function + name_error bool // indicates if the token is not a name or the name is on another line + is_parsing_receiver bool // indicates if parser is parsing receiver fn (x Xxx) } // for tests