parser: fix panic when single letter receiver parsed (#8381)

pull/8391/head
Daniel Däschle 2021-01-28 10:56:43 +01:00 committed by GitHub
parent 5fc7eadd8b
commit 93b0d8ca64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 44 deletions

View File

@ -5296,7 +5296,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
sym := c.table.get_type_symbol(arg.typ) sym := c.table.get_type_symbol(arg.typ)
if sym.kind == .placeholder if sym.kind == .placeholder
|| (sym.kind in [table.Kind.int_literal, .float_literal] && !c.is_builtin_mod) { || (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)
} }
} }
} }

View File

@ -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() {}
| ~~~

View File

@ -0,0 +1 @@
fn (p A) foo() {}

View File

@ -190,6 +190,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
mut rec_mut := false mut rec_mut := false
mut params := []table.Param{} mut params := []table.Param{}
if p.tok.kind == .lpar { if p.tok.kind == .lpar {
p.is_parsing_receiver = true
lpar_pos := p.tok.position() lpar_pos := p.tok.position()
p.next() // ( p.next() // (
is_method = true is_method = true
@ -246,6 +247,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
typ: rec_type typ: rec_type
} }
p.check(.rpar) p.check(.rpar)
p.is_parsing_receiver = false
} }
mut name := '' mut name := ''
if p.tok.kind == .name { if p.tok.kind == .name {

View File

@ -373,7 +373,7 @@ pub fn (mut p Parser) parse_any_type(language table.Language, is_ptr bool, check
return table.int_literal_type return table.int_literal_type
} }
else { 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) return p.parse_generic_template_type(name)
} }
if p.peek_tok.kind == .lt { if p.peek_tok.kind == .lt {

View File

@ -29,48 +29,49 @@ mut:
scanner &scanner.Scanner scanner &scanner.Scanner
comments_mode scanner.CommentsMode = .skip_comments comments_mode scanner.CommentsMode = .skip_comments
// see comment in parse_file // see comment in parse_file
tok token.Token tok token.Token
prev_tok token.Token prev_tok token.Token
peek_tok token.Token peek_tok token.Token
peek_tok2 token.Token peek_tok2 token.Token
peek_tok3 token.Token peek_tok3 token.Token
table &table.Table table &table.Table
language table.Language language table.Language
inside_if bool inside_if bool
inside_if_expr bool inside_if_expr bool
inside_ct_if_expr bool inside_ct_if_expr bool
inside_or_expr bool inside_or_expr bool
inside_for bool inside_for bool
inside_fn bool // true even with implicit main inside_fn bool // true even with implicit main
inside_str_interp bool inside_str_interp bool
or_is_handled bool // ignore `or` in this expression or_is_handled bool // ignore `or` in this expression
builtin_mod bool // are we in the `builtin` module? builtin_mod bool // are we in the `builtin` module?
mod string // current module name 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 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 attrs []table.Attr // attributes before next decl stmt
expr_mod string // for constructing full type names in parse_type() expr_mod string // for constructing full type names in parse_type()
scope &ast.Scope scope &ast.Scope
global_scope &ast.Scope global_scope &ast.Scope
imports map[string]string // alias => mod_name imports map[string]string // alias => mod_name
ast_imports []ast.Import // mod_names ast_imports []ast.Import // mod_names
used_imports []string // alias used_imports []string // alias
auto_imports []string // imports, the user does not need to specify auto_imports []string // imports, the user does not need to specify
imported_symbols map[string]string imported_symbols map[string]string
is_amp bool // for generating the right code for `&Foo{}` is_amp bool // for generating the right code for `&Foo{}`
returns bool returns bool
inside_match bool // to separate `match A { }` from `Struct{}` inside_match bool // to separate `match A { }` from `Struct{}`
inside_select bool // to allow `ch <- Struct{} {` inside `select` inside_select bool // to allow `ch <- Struct{} {` inside `select`
inside_match_case bool // to separate `match_expr { }` from `Struct{}` inside_match_case bool // to separate `match_expr { }` from `Struct{}`
inside_match_body bool // to fix eval not used TODO inside_match_body bool // to fix eval not used TODO
inside_unsafe bool inside_unsafe bool
is_stmt_ident bool // true while the beginning of a statement is an ident/selector is_stmt_ident bool // true while the beginning of a statement is an ident/selector
expecting_type bool // `is Type`, expecting type expecting_type bool // `is Type`, expecting type
errors []errors.Error errors []errors.Error
warnings []errors.Warning warnings []errors.Warning
vet_errors []vet.Error vet_errors []vet.Error
cur_fn_name string cur_fn_name string
in_generic_params bool // indicates if parsing between `<` and `>` of a method/function 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 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 // for tests