From 485983ebd2881efb00f60a6bede9ee413d8d5277 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Thu, 1 Aug 2024 18:03:25 +0530 Subject: [PATCH] checker: disallow static fn call when receiver type is unknown (#21970) --- vlib/v/ast/ast.v | 1 + vlib/v/checker/fn.v | 7 +++++++ vlib/v/checker/tests/static_fn_call_no_struct_decl_err.out | 7 +++++++ vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv | 7 +++++++ vlib/v/parser/fn.v | 3 +++ 5 files changed, 25 insertions(+) create mode 100644 vlib/v/checker/tests/static_fn_call_no_struct_decl_err.out create mode 100644 vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index b43cb419d..76f374cdb 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -558,6 +558,7 @@ pub: receiver_pos token.Pos // `(u User)` in `fn (u User) name()` position is_method bool is_static_type_method bool // true for `fn Foo.bar() {}` + static_type_pos token.Pos // `Foo` in `fn Foo.bar() {}` method_type_pos token.Pos // `User` in ` fn (u User)` position method_idx int rec_mut bool // is receiver mutable diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 9d5413188..352eef48e 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -312,6 +312,13 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { && node.name.after_char(`.`) in reserved_type_names { c.error('top level declaration cannot shadow builtin type', node.pos) } + if _ := node.name.index('__static__') { + if sym := c.table.find_sym(node.name.all_before('__static__')) { + if sym.kind == .placeholder { + c.error('unknown type `${sym.name}`', node.static_type_pos) + } + } + } } } if node.return_type != ast.Type(0) { diff --git a/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.out b/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.out new file mode 100644 index 000000000..e5d116f5c --- /dev/null +++ b/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv:5:4: error: unknown type `Mystery` + 3 | } + 4 | + 5 | fn Mystery.hey() { + | ~~~~~~~ + 6 | println('hey') + 7 | } diff --git a/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv b/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv new file mode 100644 index 000000000..fc58b092e --- /dev/null +++ b/vlib/v/checker/tests/static_fn_call_no_struct_decl_err.vv @@ -0,0 +1,7 @@ +fn main() { + Mystery.hey() +} + +fn Mystery.hey() { + println('hey') +} diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index e92d590ed..e7b7b10b8 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -308,6 +308,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut name := '' mut type_sym := p.table.sym(rec.typ) mut name_pos := p.tok.pos() + mut static_type_pos := p.tok.pos() if p.tok.kind == .name { mut check_name := '' // TODO: high order fn @@ -315,6 +316,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { && p.peek_tok.kind == .dot && language == .v // `fn Foo.bar() {}` if is_static_type_method { type_name := p.tok.lit // "Foo" + static_type_pos = p.tok.pos() rec.typ = p.parse_type() p.check(.dot) check_name = p.check_name() @@ -647,6 +649,7 @@ run them via `v file.v` instead', receiver_pos: rec.pos is_method: is_method is_static_type_method: is_static_type_method + static_type_pos: static_type_pos method_type_pos: rec.type_pos method_idx: type_sym_method_idx rec_mut: rec.is_mut -- 2.39.5