Skip to content

Commit

Permalink
checker, cgen: fix the static from_string method of Enum across mods(fix
Browse files Browse the repository at this point in the history
  • Loading branch information
shove70 committed Dec 3, 2023
1 parent d1dcffa commit da25b8d
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 22 deletions.
83 changes: 66 additions & 17 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -883,27 +883,76 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
}
}
}
if fn_name.ends_with('from_string') {
enum_name := fn_name.all_before('__static__')
full_enum_name := if !enum_name.contains('.') {
c.mod + '.' + enum_name
} else {
enum_name
}
// 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('.') {
mut t_sym := c.table.sym_by_idx(idx)
if t_sym.kind == .alias {
parent_type := (t_sym.info as ast.Alias).parent_type
t_sym = c.table.sym(parent_type)
}
if t_sym.kind != .enum_ {
c.error('expected enum, but `${full_enum_name}` is ${t_sym.kind}',
node.pos)
return ast.void_type
}
if !t_sym.is_pub {
c.error('module `${t_sym.mod}` type `${t_sym.name}` is private', node.pos)
return ast.void_type
}
}
idx := c.table.type_idxs[full_enum_name]
ret_typ := ast.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)
} 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
}
mut t_sym := c.table.sym_by_idx(idx)
if t_sym.kind == .alias {
parent_type := (t_sym.info as ast.Alias).parent_type
t_sym = c.table.sym(parent_type)
}
if t_sym.kind != .enum_ {
c.error('expected enum, but `${full_enum_name}` is ${t_sym.kind}',
node.pos)
return ast.void_type
}
if !t_sym.is_pub {
c.error('module `${t_sym.mod}` type `${t_sym.name}` is private', node.pos)
return ast.void_type
}
break
}
}
if idx == 0 {
c.error('unknown enum `${enum_name}`', node.pos)
return ast.void_type
}

ret_typ := ast.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
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
main.v:3:15: error: module `amod` type `MyEnum` is private
1 | module main
2 |
3 | import amod { MyEnum }
| ~~~~~~
4 |
5 | fn main() {
main.v:6:6: error: module `amod` type `amod.MyEnum` is private
4 |
5 | fn main() {
6 | _ = MyEnum.from_string('item1')
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 | _ = amod.MyEnum.from_string('item1')
8 | _ = amod.MyStruct.from_string('item1')
main.v:6:4: error: assignment mismatch: 1 variable(s) but `MyEnum.from_string()` returns 0 value(s)
4 |
5 | fn main() {
6 | _ = MyEnum.from_string('item1')
| ^
7 | _ = amod.MyEnum.from_string('item1')
8 | _ = amod.MyStruct.from_string('item1')
main.v:7:11: error: module `amod` type `amod.MyEnum` is private
5 | fn main() {
6 | _ = MyEnum.from_string('item1')
7 | _ = amod.MyEnum.from_string('item1')
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 | _ = amod.MyStruct.from_string('item1')
9 | }
main.v:7:4: error: assignment mismatch: 1 variable(s) but `amod.MyEnum.from_string()` returns 0 value(s)
5 | fn main() {
6 | _ = MyEnum.from_string('item1')
7 | _ = amod.MyEnum.from_string('item1')
| ^
8 | _ = amod.MyStruct.from_string('item1')
9 | }
main.v:8:11: error: expected enum, but `amod.MyStruct` is struct
6 | _ = MyEnum.from_string('item1')
7 | _ = amod.MyEnum.from_string('item1')
8 | _ = amod.MyStruct.from_string('item1')
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 | }
main.v:8:4: error: assignment mismatch: 1 variable(s) but `amod.MyStruct.from_string()` returns 0 value(s)
6 | _ = MyEnum.from_string('item1')
7 | _ = amod.MyEnum.from_string('item1')
8 | _ = amod.MyStruct.from_string('item1')
| ^
9 | }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module amod

enum MyEnum {
item1
item2
}

pub struct MyStruct {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module main

import amod { MyEnum }

fn main() {
_ = MyEnum.from_string('item1')
_ = amod.MyEnum.from_string('item1')
_ = amod.MyStruct.from_string('item1')
}
19 changes: 15 additions & 4 deletions vlib/v/gen/c/auto_str_methods.v
Original file line number Diff line number Diff line change
Expand Up @@ -1150,12 +1150,22 @@ fn should_use_indent_func(kind ast.Kind) bool {

fn (mut g Gen) gen_enum_static_from_string(fn_name string) {
enum_name := fn_name.all_before('__static__')
mod_enum_name := if !enum_name.contains('.') {
mut mod_enum_name := if !enum_name.contains('.') {
g.cur_mod.name + '.' + enum_name
} else {
enum_name
}
idx := g.table.type_idxs[mod_enum_name]
mut idx := g.table.type_idxs[mod_enum_name]
if idx == 0 && (enum_name.contains('.') || enum_name[0].is_capital()) {
// no cur mod, find from another mods.
for import_sym in g.file.imports {
mod_enum_name = '${import_sym.mod}.${enum_name}'
idx = g.table.type_idxs[mod_enum_name]
if idx > 0 {
break
}
}
}
enum_typ := ast.Type(idx)
enum_styp := g.typ(enum_typ)
option_enum_typ := ast.Type(idx).set_flag(.option)
Expand All @@ -1164,9 +1174,10 @@ fn (mut g Gen) gen_enum_static_from_string(fn_name string) {
enum_field_vals := g.table.get_enum_field_vals(mod_enum_name)

mut fn_builder := strings.new_builder(512)
g.definitions.writeln('static ${option_enum_styp} ${fn_name}(string name); // auto')
fn_name_no_dots := util.no_dots(fn_name)
g.definitions.writeln('static ${option_enum_styp} ${fn_name_no_dots}(string name); // auto')

fn_builder.writeln('static ${option_enum_styp} ${fn_name}(string name) {')
fn_builder.writeln('static ${option_enum_styp} ${fn_name_no_dots}(string name) {')
fn_builder.writeln('\t${option_enum_styp} t1;')
fn_builder.writeln('\tbool exists = false;')
fn_builder.writeln('\tint inx = 0;')
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -1803,7 +1803,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
g.gen_enum_static_from_string(node.name)
g.str_fn_names << node.name
}
g.write('${node.name}(')
g.write('${util.no_dots(node.name)}(')
g.call_args(node)
g.write(')')
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module amod

pub enum MyEnum {
item1
item2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module main

import amod { MyEnum }

fn test_main() {
item1 := MyEnum.from_string('item1')?
assert item1 == MyEnum.item1
item2 := amod.MyEnum.from_string('item2')?
assert item2 == MyEnum.item2
}

0 comments on commit da25b8d

Please sign in to comment.