Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Nov 7, 2024
1 parent dab25ca commit fb2743c
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 53 deletions.
1 change: 1 addition & 0 deletions cmd/tools/vast/vast.v
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,7 @@ fn (t Tree) call_expr(node ast.CallExpr) &Node {
obj.add_terse('is_noreturn', t.bool_node(node.is_noreturn))
obj.add_terse('is_ctor_new', t.bool_node(node.is_ctor_new))
obj.add_terse('is_return_used', t.bool_node(node.is_return_used))
obj.add_terse('is_static_method', t.bool_node(node.is_static_method))
obj.add('should_be_skipped', t.bool_node(node.should_be_skipped))
obj.add_terse('free_receiver', t.bool_node(node.free_receiver))
obj.add('scope', t.number_node(int(node.scope)))
Expand Down
1 change: 1 addition & 0 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ pub mut:
is_noreturn bool // whether the function/method is marked as [noreturn]
is_ctor_new bool // if JS ctor calls requires `new` before call, marked as `[use_new]` in V
is_file_translated bool // true, when the file it resides in is `@[translated]`
is_static_method bool // it is a static method call
args []CallArg
expected_arg_types []Type
comptime_ret_val bool
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/ast/str.v
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn (table &Table) get_anon_fn_name(prefix string, func &Fn, pos int) string

// 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__') {
if f.is_static_method {
return f.name.replace('__static__', '.')
} else {
return f.name
Expand Down Expand Up @@ -474,7 +474,7 @@ pub fn (x &Expr) str() string {
if x.name.contains('.') {
return '${x.get_name()}(${sargs})${propagate_suffix}'
}
if x.name.contains('__static__') {
if x.is_static_method {
return '${x.mod}.${x.get_name()}(${sargs})${propagate_suffix}'
}
if x.mod == 'main' {
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -3613,7 +3613,7 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type {
if c.table.cur_fn == unsafe { nil } {
return ast.void_type
}
if _ := c.table.cur_fn.name.index('__static__') {
if c.table.cur_fn.is_static_type_method {
node.val = c.table.cur_fn.name.all_after_last('__static__')
} else {
node.val = c.table.cur_fn.name.all_after_last('.')
Expand All @@ -3627,7 +3627,7 @@ fn (mut c Checker) at_expr(mut node ast.AtExpr) ast.Type {
if c.table.cur_fn.is_method {
node.val = c.table.type_to_str(c.table.cur_fn.receiver.typ).all_after_last('.') +
'.' + fname
} else if _ := fname.index('__static__') {
} else if c.table.cur_fn.is_static_type_method {
node.val = fname.all_before('__static__') + '.' + fname.all_after('__static__')
} else {
node.val = fname
Expand Down
115 changes: 69 additions & 46 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ 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 node.is_static_type_method {
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)
Expand Down Expand Up @@ -827,9 +827,9 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
is_va_arg := node.name == 'C.va_arg'
is_json_decode := node.name == 'json.decode'
mut fn_name := node.name
if index := node.name.index('__static__') {
if node.is_static_method {
// resolve static call T.name()
if index > 0 && c.table.cur_fn != unsafe { nil } {
if c.table.cur_fn != unsafe { nil } {
fn_name = c.table.convert_generic_static_type_name(fn_name, c.table.cur_fn.generic_names,
c.table.cur_concrete_types)
}
Expand Down Expand Up @@ -1045,10 +1045,12 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
unsafe { c.table.fns[fn_name].usages++ }
}
}
// already imported symbol (static Foo.new() in another module)
if !found && fn_name.len > 0 && fn_name[0].is_capital() {

// static method resolution
if !found && node.is_static_method {
if index := fn_name.index('__static__') {
owner_name := fn_name#[..index]
// already imported symbol (static Foo.new() in another module)
for import_sym in c.file.imports.filter(it.syms.any(it.name == owner_name)) {
qualified_name := '${import_sym.mod}.${fn_name}'
if f := c.table.find_fn(qualified_name) {
Expand All @@ -1059,55 +1061,76 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
break
}
}
}
}
// Enum.from_string, `mod.Enum.from_string('item')`, `Enum.from_string('item')`
if !found && fn_name.ends_with('__static__from_string') {
enum_name := fn_name.all_before('__static__')
mut full_enum_name := if !enum_name.contains('.') {
c.mod + '.' + enum_name
} else {
enum_name
}
mut idx := c.table.type_idxs[full_enum_name]
if idx > 0 {
// is from another mod.
if enum_name.contains('.') {
if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
return ast.void_type
if !found {
// aliased static method on current mod
full_type_name := if !fn_name.contains('.') {
c.mod + '.' + owner_name
} else {
owner_name
}
typ := c.table.find_type(full_type_name)
if typ != 0 {
final_sym := c.table.final_sym(typ)
// try to find the unaliased static method name
orig_name := final_sym.name + fn_name#[index..]
if f := c.table.find_fn(orig_name) {
found = true
func = f
unsafe { c.table.fns[orig_name].usages++ }
node.name = orig_name
node.is_static_method = true
}
}
}
} else if !enum_name.contains('.') {
// find from another mods.
for import_sym in c.file.imports {
full_enum_name = '${import_sym.mod}.${enum_name}'
idx = c.table.type_idxs[full_enum_name]
if idx < 1 {
continue
}
// Enum.from_string, `mod.Enum.from_string('item')`, `Enum.from_string('item')`
if !found && node.is_static_method && fn_name.ends_with('__static__from_string') {
enum_name := fn_name.all_before('__static__')
mut full_enum_name := if !enum_name.contains('.') {
c.mod + '.' + enum_name
} else {
enum_name
}
mut idx := c.table.type_idxs[full_enum_name]
if idx > 0 {
// is from another mod.
if enum_name.contains('.') {
if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
return ast.void_type
}
}
if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
return ast.void_type
} else if !enum_name.contains('.') {
// find from another mods.
for import_sym in c.file.imports {
full_enum_name = '${import_sym.mod}.${enum_name}'
idx = c.table.type_idxs[full_enum_name]
if idx < 1 {
continue
}
if !c.check_type_and_visibility(full_enum_name, idx, .enum, node.pos) {
return ast.void_type
}
break
}
break
}
}
if idx == 0 {
c.error('unknown enum `${enum_name}`', node.pos)
return ast.void_type
}
if idx == 0 {
c.error('unknown enum `${enum_name}`', node.pos)
return ast.void_type
}

ret_typ := ast.idx_to_type(idx).set_flag(.option)
if node.args.len != 1 {
c.error('expected 1 argument, but got ${node.args.len}', node.pos)
} else {
node.args[0].typ = c.expr(mut node.args[0].expr)
if node.args[0].typ != ast.string_type {
styp := c.table.type_to_str(node.args[0].typ)
c.error('expected `string` argument, but got `${styp}`', node.pos)
ret_typ := ast.idx_to_type(idx).set_flag(.option)
if node.args.len != 1 {
c.error('expected 1 argument, but got ${node.args.len}', node.pos)
} else {
node.args[0].typ = c.expr(mut node.args[0].expr)
if node.args[0].typ != ast.string_type {
styp := c.table.type_to_str(node.args[0].typ)
c.error('expected `string` argument, but got `${styp}`', node.pos)
}
}
node.return_type = ret_typ
return ret_typ
}
node.return_type = ret_typ
return ret_typ
}
mut is_native_builtin := false
if !found && c.pref.backend == .native {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/fmt/fmt.v
Original file line number Diff line number Diff line change
Expand Up @@ -2091,7 +2091,7 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
f.write('${node.name.after_char(`.`)}')
} else {
name := f.short_module(node.name)
if node.name.contains('__static__') {
if node.is_static_method {
f.write_static_method(node.name, name)
} else {
f.mark_import_as_used(name)
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -2047,9 +2047,9 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
is_selector_call = true
}
mut name := node.name
if index := node.name.index('__static__') {
if node.is_static_method {
// resolve static call T.name()
if index > 0 && g.cur_fn != unsafe { nil } {
if g.cur_fn != unsafe { nil } {
name = g.table.convert_generic_static_type_name(node.name, g.cur_fn.generic_names,
g.cur_concrete_types)
}
Expand Down
1 change: 1 addition & 0 deletions vlib/v/parser/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
scope: p.scope
comments: comments
is_return_used: p.expecting_value
is_static_method: is_static_type_method
}
}

Expand Down
13 changes: 13 additions & 0 deletions vlib/v/tests/fns/aliased_static_method_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module main

struct MyStruct {}

fn MyStruct.new() {}

type MyAlias = MyStruct

fn test_main() {
MyStruct.new()
MyAlias.new()
assert true
}

0 comments on commit fb2743c

Please sign in to comment.