mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker,cgen: support const y = term.yellow
, then println(y('abc'))
(#16436)
This commit is contained in:
parent
dc81d755e8
commit
ddc1a1fc08
@ -580,7 +580,8 @@ pub mut:
|
|||||||
name string // left.name()
|
name string // left.name()
|
||||||
is_method bool
|
is_method bool
|
||||||
is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
|
is_field bool // temp hack, remove ASAP when re-impl CallExpr / Selector (joe)
|
||||||
is_fn_var bool // fn variable
|
is_fn_var bool // fn variable, `a := fn() {}`, then: `a()`
|
||||||
|
is_fn_a_const bool // fn const, `const c = abc`, where `abc` is a function, then: `c()`
|
||||||
is_keep_alive bool // GC must not free arguments before fn returns
|
is_keep_alive bool // GC must not free arguments before fn returns
|
||||||
is_noreturn bool // whether the function/method is marked as [noreturn]
|
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_ctor_new bool // if JS ctor calls requires `new` before call, marked as `[use_new]` in V
|
||||||
@ -592,7 +593,8 @@ pub mut:
|
|||||||
left_type Type // type of `user`
|
left_type Type // type of `user`
|
||||||
receiver_type Type // User
|
receiver_type Type // User
|
||||||
return_type Type
|
return_type Type
|
||||||
fn_var_type Type // fn variable type
|
fn_var_type Type // the fn type, when `is_fn_a_const` or `is_fn_var` is true
|
||||||
|
const_name string // the fully qualified name of the const, i.e. `main.c`, given `const c = abc`, and callexpr: `c()`
|
||||||
should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
|
should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
|
||||||
concrete_types []Type // concrete types, e.g. <int, string>
|
concrete_types []Type // concrete types, e.g. <int, string>
|
||||||
concrete_list_pos token.Pos
|
concrete_list_pos token.Pos
|
||||||
|
@ -1434,8 +1434,8 @@ pub fn (t &Table) fn_signature_using_aliases(func &Fn, import_aliases map[string
|
|||||||
return sb.str()
|
return sb.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the name of the complete quanlified name of the type
|
// symbol_name_except_generic return the name of the complete qualified name of the type,
|
||||||
// without the generic parts.
|
// but without the generic parts. For example, `main.Abc<int>` -> `main.Abc`
|
||||||
pub fn (t &TypeSymbol) symbol_name_except_generic() string {
|
pub fn (t &TypeSymbol) symbol_name_except_generic() string {
|
||||||
// main.Abc<int>
|
// main.Abc<int>
|
||||||
mut embed_name := t.name
|
mut embed_name := t.name
|
||||||
|
@ -832,12 +832,37 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||||||
if obj.typ != 0 {
|
if obj.typ != 0 {
|
||||||
sym := c.table.sym(obj.typ)
|
sym := c.table.sym(obj.typ)
|
||||||
if sym.kind == .function {
|
if sym.kind == .function {
|
||||||
found = true
|
|
||||||
func = (sym.info as ast.FnType).func
|
func = (sym.info as ast.FnType).func
|
||||||
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// a same module constant?
|
||||||
|
if !found {
|
||||||
|
// allow for `const abc = myfunc`, then calling `abc()`
|
||||||
|
qualified_const_name := if fn_name.contains('.') { fn_name } else { '${c.mod}.${fn_name}' }
|
||||||
|
if mut obj := c.table.global_scope.find_const(qualified_const_name) {
|
||||||
|
if obj.typ == 0 {
|
||||||
|
obj.typ = c.expr(obj.expr)
|
||||||
|
}
|
||||||
|
if obj.typ != 0 {
|
||||||
|
sym := c.table.sym(obj.typ)
|
||||||
|
if sym.kind == .function {
|
||||||
|
// at this point, the const metadata should be already known,
|
||||||
|
// and we are sure that it is just a function
|
||||||
|
c.table.fns[qualified_const_name].usages++
|
||||||
|
c.table.fns[func.name].usages++
|
||||||
|
found = true
|
||||||
|
func = (sym.info as ast.FnType).func
|
||||||
|
node.is_fn_a_const = true
|
||||||
|
node.fn_var_type = obj.typ
|
||||||
|
node.const_name = qualified_const_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
continue_check = false
|
continue_check = false
|
||||||
if dot_index := fn_name.index('.') {
|
if dot_index := fn_name.index('.') {
|
||||||
|
@ -4890,11 +4890,15 @@ fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) c_const_name(name string) string {
|
||||||
|
return if g.pref.translated && !g.is_builtin_mod { name } else { '_const_${name}' }
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ ast.Type, unwrap_option bool) {
|
fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ ast.Type, unwrap_option bool) {
|
||||||
// Initialize more complex consts in `void _vinit/2{}`
|
// Initialize more complex consts in `void _vinit/2{}`
|
||||||
// (C doesn't allow init expressions that can't be resolved at compile time).
|
// (C doesn't allow init expressions that can't be resolved at compile time).
|
||||||
mut styp := g.typ(typ)
|
mut styp := g.typ(typ)
|
||||||
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_${name}' }
|
cname := g.c_const_name(name)
|
||||||
mut init := strings.new_builder(100)
|
mut init := strings.new_builder(100)
|
||||||
if cname == '_const_os__args' {
|
if cname == '_const_os__args' {
|
||||||
if g.pref.os == .windows {
|
if g.pref.os == .windows {
|
||||||
@ -4911,9 +4915,16 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
|
|||||||
init.writeln(g.expr_string_surround('\t${cname} = ', expr, ';'))
|
init.writeln(g.expr_string_surround('\t${cname} = ', expr, ';'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mut def := '${styp} ${cname}'
|
||||||
|
expr_sym := g.table.sym(typ)
|
||||||
|
if expr_sym.kind == .function {
|
||||||
|
// allow for: `const xyz = abc`, where `abc` is `fn abc() {}`
|
||||||
|
func := (expr_sym.info as ast.FnType).func
|
||||||
|
def = g.fn_var_signature(func.return_type, func.params.map(it.typ), cname)
|
||||||
|
}
|
||||||
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
|
||||||
mod: mod
|
mod: mod
|
||||||
def: '${styp} ${cname}; // inited later'
|
def: '${def}; // inited later'
|
||||||
init: init.str().trim_right('\n')
|
init: init.str().trim_right('\n')
|
||||||
dep_names: g.table.dependent_names_in_expr(expr)
|
dep_names: g.table.dependent_names_in_expr(expr)
|
||||||
}
|
}
|
||||||
|
@ -638,6 +638,9 @@ fn (mut g Gen) get_anon_fn_type_name(mut node ast.AnonFn, var_name string) strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) call_expr(node ast.CallExpr) {
|
fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
|
if node.should_be_skipped {
|
||||||
|
return
|
||||||
|
}
|
||||||
// NOTE: everything could be done this way
|
// NOTE: everything could be done this way
|
||||||
// see my comment in parser near anon_fn
|
// see my comment in parser near anon_fn
|
||||||
if node.left is ast.AnonFn {
|
if node.left is ast.AnonFn {
|
||||||
@ -659,9 +662,6 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
|||||||
} else if node.left is ast.CallExpr && node.name == '' {
|
} else if node.left is ast.CallExpr && node.name == '' {
|
||||||
g.expr(node.left)
|
g.expr(node.left)
|
||||||
}
|
}
|
||||||
if node.should_be_skipped {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
old_inside_call := g.inside_call
|
old_inside_call := g.inside_call
|
||||||
g.inside_call = true
|
g.inside_call = true
|
||||||
defer {
|
defer {
|
||||||
@ -1358,6 +1358,9 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if node.is_fn_a_const {
|
||||||
|
name = g.c_const_name(node.const_name.replace('.', '__'))
|
||||||
|
}
|
||||||
// TODO2
|
// TODO2
|
||||||
// cgen shouldn't modify ast nodes, this should be moved
|
// cgen shouldn't modify ast nodes, this should be moved
|
||||||
// g.generate_tmp_autofree_arg_vars(node, name)
|
// g.generate_tmp_autofree_arg_vars(node, name)
|
||||||
|
65
vlib/v/tests/const_name_equals_fn_name_test.v
Normal file
65
vlib/v/tests/const_name_equals_fn_name_test.v
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
import term
|
||||||
|
|
||||||
|
fn abc() {
|
||||||
|
println('xyz')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def() string {
|
||||||
|
return 'xyz'
|
||||||
|
}
|
||||||
|
|
||||||
|
const a_const_that_is_fn = abc
|
||||||
|
|
||||||
|
const a_const_that_is_fn_returning_value = def
|
||||||
|
|
||||||
|
const a_const_same_as_fn_in_another_module = term.yellow
|
||||||
|
|
||||||
|
fn test_simple_fn_assigned_to_const_can_be_called() {
|
||||||
|
a_const_that_is_fn()
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_simple_fn_assigned_to_const_can_be_called_and_returns_value() {
|
||||||
|
assert def == a_const_that_is_fn_returning_value
|
||||||
|
assert def() == 'xyz'
|
||||||
|
assert a_const_that_is_fn_returning_value() == 'xyz'
|
||||||
|
assert def() == a_const_that_is_fn_returning_value()
|
||||||
|
assert a_const_that_is_fn_returning_value() == def()
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
fn test_a_const_that_is_alias_to_fn_from_module() {
|
||||||
|
assert a_const_same_as_fn_in_another_module == term.yellow
|
||||||
|
assert term.yellow('x') == a_const_same_as_fn_in_another_module('x')
|
||||||
|
assert ptr_str(term.yellow) == ptr_str(a_const_same_as_fn_in_another_module)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
const pg = fn_generator()
|
||||||
|
|
||||||
|
const pg2 = main.fn_generator()()
|
||||||
|
|
||||||
|
fn fn_generator() fn () string {
|
||||||
|
return fn () string {
|
||||||
|
println('hello')
|
||||||
|
return 'ok'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_a_const_can_be_assigned_a_fn_produced_by_a_fn_generator_and_the_const_can_be_used() {
|
||||||
|
assert main.fn_generator()() == 'ok'
|
||||||
|
|
||||||
|
x := fn_generator()
|
||||||
|
assert x() == 'ok'
|
||||||
|
|
||||||
|
y := pg
|
||||||
|
assert y() == 'ok'
|
||||||
|
|
||||||
|
assert pg() == 'ok'
|
||||||
|
|
||||||
|
assert pg2 == 'ok'
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user