mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser, checker: fix static method naming and generic call (#18694)
This commit is contained in:
parent
83ee2827d4
commit
89c56fb5ee
@ -6,6 +6,24 @@ module ast
|
||||
import v.util
|
||||
import strings
|
||||
|
||||
// get_name returns the real name for the function declaration
|
||||
pub fn (f &FnDecl) get_name() string {
|
||||
if f.is_static_type_method {
|
||||
return f.name.all_after_last('__static__')
|
||||
} else {
|
||||
return f.name
|
||||
}
|
||||
}
|
||||
|
||||
// get_name returns the real name for the function calling
|
||||
pub fn (f &CallExpr) get_name() string {
|
||||
if f.name != '' && f.name.all_after_last('.')[0].is_capital() && f.name.contains('__static__') {
|
||||
return f.name.replace('__static__', '.')
|
||||
} else {
|
||||
return f.name
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (node &FnDecl) modname() string {
|
||||
if node.mod != '' {
|
||||
return node.mod
|
||||
@ -373,18 +391,18 @@ pub fn (x Expr) str() string {
|
||||
return '${x.left.str()}.${x.name}(${sargs})${propagate_suffix}'
|
||||
}
|
||||
if x.name.starts_with('${x.mod}.') {
|
||||
return util.strip_main_name('${x.name}(${sargs})${propagate_suffix}')
|
||||
return util.strip_main_name('${x.get_name()}(${sargs})${propagate_suffix}')
|
||||
}
|
||||
if x.mod == '' && x.name == '' {
|
||||
return x.left.str() + '(${sargs})${propagate_suffix}'
|
||||
}
|
||||
if x.name.contains('.') {
|
||||
return '${x.name}(${sargs})${propagate_suffix}'
|
||||
return '${x.get_name()}(${sargs})${propagate_suffix}'
|
||||
}
|
||||
if x.name.contains('__static__') {
|
||||
return '${x.mod}.${x.name}(${sargs})${propagate_suffix}'
|
||||
return '${x.mod}.${x.get_name()}(${sargs})${propagate_suffix}'
|
||||
}
|
||||
return '${x.mod}.${x.name}(${sargs})${propagate_suffix}'
|
||||
return '${x.mod}.${x.get_name()}(${sargs})${propagate_suffix}'
|
||||
}
|
||||
CharLiteral {
|
||||
return '`${x.val}`'
|
||||
|
@ -87,14 +87,14 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||
// If it's a void type, it's an unknown variable, already had an error earlier.
|
||||
return
|
||||
}
|
||||
c.error('assignment mismatch: ${node.left.len} variable(s) but `${right_first.name}()` returns ${right_len} value(s)',
|
||||
c.error('assignment mismatch: ${node.left.len} variable(s) but `${right_first.get_name()}()` returns ${right_len} value(s)',
|
||||
node.pos)
|
||||
} else if right_first is ast.ParExpr {
|
||||
mut right_next := right_first
|
||||
for {
|
||||
if mut right_next.expr is ast.CallExpr {
|
||||
if right_next.expr.return_type == ast.void_type {
|
||||
c.error('assignment mismatch: expected ${node.left.len} value(s) but `${right_next.expr.name}()` returns ${right_len} value(s)',
|
||||
c.error('assignment mismatch: expected ${node.left.len} value(s) but `${right_next.expr.get_name()}()` returns ${right_len} value(s)',
|
||||
node.pos)
|
||||
}
|
||||
break
|
||||
|
@ -87,7 +87,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
if node.language == .v && !c.is_builtin_mod && !node.is_anon {
|
||||
c.check_valid_snake_case(node.name, 'function name', node.pos)
|
||||
c.check_valid_snake_case(node.get_name(), 'function name', node.pos)
|
||||
if !node.is_method && node.mod == 'main' && node.short_name in c.table.builtin_pub_fns {
|
||||
c.error('cannot redefine builtin public function `${node.short_name}`', node.pos)
|
||||
}
|
||||
@ -944,7 +944,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
|
||||
return ast.void_type
|
||||
}
|
||||
}
|
||||
c.error('unknown function: ${fn_name}', node.pos)
|
||||
c.error('unknown function: ${node.get_name()}', node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
node.is_file_translated = func.is_file_translated
|
||||
|
12
vlib/v/checker/tests/func_with_static_keyword_err.out
Normal file
12
vlib/v/checker/tests/func_with_static_keyword_err.out
Normal file
@ -0,0 +1,12 @@
|
||||
vlib/v/checker/tests/func_with_static_keyword_err.vv:6:2: warning: unused variable: `a`
|
||||
4 |
|
||||
5 | fn main() {
|
||||
6 | a := a__static__b()
|
||||
| ^
|
||||
7 | }
|
||||
vlib/v/checker/tests/func_with_static_keyword_err.vv:6:4: error: assignment mismatch: 1 variable(s) but `a__static__b()` returns 2 value(s)
|
||||
4 |
|
||||
5 | fn main() {
|
||||
6 | a := a__static__b()
|
||||
| ~~
|
||||
7 | }
|
7
vlib/v/checker/tests/func_with_static_keyword_err.vv
Normal file
7
vlib/v/checker/tests/func_with_static_keyword_err.vv
Normal file
@ -0,0 +1,7 @@
|
||||
fn a__static__b() (int,int) {
|
||||
return 1,2
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := a__static__b()
|
||||
}
|
7
vlib/v/checker/tests/static_method_multi_return_err.out
Normal file
7
vlib/v/checker/tests/static_method_multi_return_err.out
Normal file
@ -0,0 +1,7 @@
|
||||
vlib/v/checker/tests/static_method_multi_return_err.vv:10:6: error: assignment mismatch: 1 variable(s) but `SomeStruct.static_method()` returns 2 value(s)
|
||||
8 |
|
||||
9 | fn main() {
|
||||
10 | val := SomeStruct.static_method()
|
||||
| ~~
|
||||
11 | println(val)
|
||||
12 | }
|
12
vlib/v/checker/tests/static_method_multi_return_err.vv
Normal file
12
vlib/v/checker/tests/static_method_multi_return_err.vv
Normal file
@ -0,0 +1,12 @@
|
||||
struct SomeStruct {
|
||||
name string
|
||||
}
|
||||
|
||||
fn SomeStruct.static_method() (string, int) {
|
||||
return 'hello', 100
|
||||
}
|
||||
|
||||
fn main() {
|
||||
val := SomeStruct.static_method()
|
||||
println(val)
|
||||
}
|
13
vlib/v/checker/tests/static_method_not_found_err.out
Normal file
13
vlib/v/checker/tests/static_method_not_found_err.out
Normal file
@ -0,0 +1,13 @@
|
||||
vlib/v/checker/tests/static_method_not_found_err.vv:10:9: error: unknown function: TestStruct.static_method
|
||||
8 |
|
||||
9 | fn main() {
|
||||
10 | val := TestStruct.static_method()
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
11 | println(val)
|
||||
12 | }
|
||||
vlib/v/checker/tests/static_method_not_found_err.vv:11:2: error: `println` can not print void expressions
|
||||
9 | fn main() {
|
||||
10 | val := TestStruct.static_method()
|
||||
11 | println(val)
|
||||
| ~~~~~~~~~~~~
|
||||
12 | }
|
12
vlib/v/checker/tests/static_method_not_found_err.vv
Normal file
12
vlib/v/checker/tests/static_method_not_found_err.vv
Normal file
@ -0,0 +1,12 @@
|
||||
struct TestStruct {
|
||||
name string
|
||||
}
|
||||
|
||||
fn (f TestStruct) static_method() string {
|
||||
return 'hello'
|
||||
}
|
||||
|
||||
fn main() {
|
||||
val := TestStruct.static_method()
|
||||
println(val)
|
||||
}
|
@ -14,7 +14,7 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
|
||||
mut is_static_type_method := language == .v && name[0].is_capital() && p.tok.kind == .dot
|
||||
if is_static_type_method {
|
||||
p.check(.dot)
|
||||
name = name.to_lower() + '__static__' + p.check_name()
|
||||
name = name + '__static__' + p.check_name()
|
||||
}
|
||||
mut fn_name := if language == .c {
|
||||
'C.${name}'
|
||||
@ -294,6 +294,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
mut type_sym := p.table.sym(rec.typ)
|
||||
name_pos := p.tok.pos()
|
||||
if p.tok.kind == .name {
|
||||
mut check_name := ''
|
||||
// TODO high order fn
|
||||
is_static_type_method = p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
|
||||
&& p.peek_tok.kind == .dot && language == .v // `fn Foo.bar() {}`
|
||||
@ -301,12 +302,14 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
type_name := p.tok.lit // "Foo"
|
||||
rec.typ = p.parse_type()
|
||||
p.check(.dot)
|
||||
name = type_name.to_lower() + '__static__' + p.check_name() // "foo__bar"
|
||||
check_name = p.check_name()
|
||||
name = type_name + '__static__' + check_name // "foo__bar"
|
||||
} else {
|
||||
name = if language == .js { p.check_js_name() } else { p.check_name() }
|
||||
check_name = if language == .js { p.check_js_name() } else { p.check_name() }
|
||||
name = check_name
|
||||
}
|
||||
if language == .v && !p.pref.translated && !p.is_translated && util.contains_capital(name)
|
||||
&& !p.builtin_mod {
|
||||
if language == .v && !p.pref.translated && !p.is_translated
|
||||
&& util.contains_capital(check_name) && !p.builtin_mod {
|
||||
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
||||
name_pos)
|
||||
return ast.FnDecl{
|
||||
|
@ -2630,11 +2630,12 @@ fn (mut p Parser) name_expr() ast.Expr {
|
||||
// type cast. TODO: finish
|
||||
// if name in ast.builtin_type_names_to_idx {
|
||||
// handle the easy cases first, then check for an already known V typename, not shadowed by a local variable
|
||||
if is_mod_cast || is_c_pointer_cast || is_c_type_cast || is_js_cast
|
||||
|| is_generic_cast || (language == .v && name.len > 0 && (name[0].is_capital()
|
||||
if (is_option || p.peek_tok.kind in [.lsbr, .lt, .lpar]) && (is_mod_cast
|
||||
|| is_c_pointer_cast || is_c_type_cast || is_js_cast || is_generic_cast
|
||||
|| (language == .v && name.len > 0 && (name[0].is_capital()
|
||||
|| (!known_var && (name in p.table.type_idxs
|
||||
|| name_w_mod in p.table.type_idxs))
|
||||
|| name.all_after_last('.')[0].is_capital())) {
|
||||
|| name.all_after_last('.')[0].is_capital()))) {
|
||||
// MainLetter(x) is *always* a cast, as long as it is not `C.`
|
||||
// TODO handle C.stat()
|
||||
start_pos := p.tok.pos()
|
||||
@ -2673,7 +2674,6 @@ fn (mut p Parser) name_expr() ast.Expr {
|
||||
p.expr_mod = ''
|
||||
return node
|
||||
} else {
|
||||
// fn call
|
||||
// fn_call
|
||||
if is_option {
|
||||
p.unexpected_with_pos(p.prev_tok.pos(),
|
||||
|
@ -12,7 +12,7 @@ vlib/v/parser/tests/method_call_receiver_err.vv:8:7: warning: unused variable: `
|
||||
| ~~~~~~
|
||||
9 | println(S1.method_hello('yo'))
|
||||
10 | }
|
||||
vlib/v/parser/tests/method_call_receiver_err.vv:9:11: error: unknown function: s1__static__method_hello
|
||||
vlib/v/parser/tests/method_call_receiver_err.vv:9:11: error: unknown function: S1.method_hello
|
||||
7 |
|
||||
8 | $for method in S1.methods {
|
||||
9 | println(S1.method_hello('yo'))
|
||||
|
12
vlib/v/tests/generic_static_method_test.v
Normal file
12
vlib/v/tests/generic_static_method_test.v
Normal file
@ -0,0 +1,12 @@
|
||||
struct SomeStruct {
|
||||
name string
|
||||
}
|
||||
|
||||
fn SomeStruct.static_method[T]() string {
|
||||
return 'hello'
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
val := SomeStruct.static_method[string]()
|
||||
assert val == 'hello'
|
||||
}
|
Loading…
Reference in New Issue
Block a user