Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Oct 14, 2024
1 parent df4c6ac commit 3ef9e09
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 21 deletions.
1 change: 1 addition & 0 deletions vlib/v/ast/ast.v
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ pub struct StructDecl {
pub:
pos token.Pos
name string
scoped_name string
generic_types []Type
is_pub bool
// _pos fields for vfmt
Expand Down
38 changes: 35 additions & 3 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,17 @@ pub fn (t &Table) find_type_idx(name string) int {
return t.type_idxs[name]
}

@[inline]
pub fn (t &Table) find_type_idx_fn_scoped(name string, scope &Scope) int {
if scope != unsafe { nil } {
idx := t.type_idxs['_${name}_${scope.start_pos}']
if idx != 0 {
return idx
}
}
return t.type_idxs[name]
}

@[inline]
pub fn (t &Table) find_sym(name string) ?&TypeSymbol {
idx := t.type_idxs[name]
Expand All @@ -672,6 +683,22 @@ pub fn (t &Table) find_sym_and_type_idx(name string) (&TypeSymbol, int) {
return invalid_type_symbol, idx
}

@[inline]
pub fn (t &Table) find_sym_and_type_idx_fn_scoped(name string) (&TypeSymbol, int) {
if t.cur_fn != unsafe { nil } && t.cur_fn.scope != unsafe { nil } {
sym_name := '_${name}_${t.cur_fn.scope.start_pos}'
idx := t.type_idxs[sym_name]
if idx > 0 {
return t.type_symbols[idx], idx
}
}
idx := t.type_idxs[name]
if idx > 0 {
return t.type_symbols[idx], idx
}
return invalid_type_symbol, idx
}

pub const invalid_type_symbol = &TypeSymbol{
idx: invalid_type_idx
parent_idx: invalid_type_idx
Expand Down Expand Up @@ -791,15 +818,20 @@ pub fn (mut t Table) register_sym(sym TypeSymbol) int {
eprintln('>> register_sym: ${sym.name:-60} | idx: ${idx}')
}
}
mut existing_idx := t.type_idxs[sym.name]
sym_name := if sym.info is Struct && sym.info.scoped_name != '' {
sym.info.scoped_name
} else {
sym.name
}
mut existing_idx := t.type_idxs[sym_name]
if existing_idx > 0 {
idx = t.rewrite_already_registered_symbol(sym, existing_idx)
if idx != -2 {
return idx
}
}
if sym.mod == 'main' {
existing_idx = t.type_idxs[sym.name.trim_string_left('main.')]
existing_idx = t.type_idxs[sym_name.trim_string_left('main.')]
if existing_idx > 0 {
idx = t.rewrite_already_registered_symbol(sym, existing_idx)
if idx != -2 {
Expand All @@ -812,7 +844,7 @@ pub fn (mut t Table) register_sym(sym TypeSymbol) int {
...sym
}
t.type_symbols[idx].idx = idx
t.type_idxs[sym.name] = idx
t.type_idxs[sym_name] = idx
return idx
}

Expand Down
24 changes: 21 additions & 3 deletions vlib/v/ast/types.v
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ pub mut:
@[minify]
pub struct Struct {
pub:
attrs []Attr
scope &Scope = unsafe { nil }
is_local bool
attrs []Attr
scope &Scope = unsafe { nil }
scoped_name string
pub mut:
embeds []Type
fields []StructField
Expand Down Expand Up @@ -416,6 +416,24 @@ pub fn (t Type) has_option_or_result() bool {
return t & 0x0300_0000 != 0
}

@[inline]
pub fn (ts TypeSymbol) scoped_name() string {
return if ts.info is Struct && ts.info.scoped_name != '' {
ts.info.scoped_name
} else {
ts.name
}
}

@[inline]
pub fn (ts TypeSymbol) scoped_cname() string {
return if ts.info is Struct && ts.info.scoped_name != '' {
ts.info.scoped_name.replace('.', '__')
} else {
ts.cname
}
}

// debug returns a verbose representation of the information in ts, useful for tracing/debugging
pub fn (ts TypeSymbol) debug() []string {
mut res := []string{}
Expand Down
7 changes: 1 addition & 6 deletions vlib/v/checker/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
defer {
util.timing_measure_cumulative(@METHOD)
}
mut struct_sym, struct_typ_idx := c.table.find_sym_and_type_idx(node.name)
mut struct_sym, struct_typ_idx := c.table.find_sym_and_type_idx_fn_scoped(node.name)
mut has_generic_types := false
if mut struct_sym.info is ast.Struct {
for mut symfield in struct_sym.info.fields {
Expand Down Expand Up @@ -441,11 +441,6 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
mut old_cur_struct_generic_types := []ast.Type{}
mut old_cur_struct_concrete_types := []ast.Type{}
if struct_sym.info is ast.Struct {
if struct_sym.info.is_local && struct_sym.info.scope != unsafe { nil }
&& !struct_sym.info.scope.contains(node.pos.pos) {
c.error('struct `${struct_sym.name}` was declared in a local scope outside current scope',
node.pos)
}
// check if the generic param types have been defined
for ct in struct_sym.info.concrete_types {
ct_sym := c.table.sym(ct)
Expand Down
12 changes: 7 additions & 5 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ fn (mut g Gen) write_shareds() {
g.shared_functions.writeln('\tsync__RwMutex_init(&dest->mtx);')
g.shared_functions.writeln('\treturn dest;')
g.shared_functions.writeln('}')
g.typedefs.writeln('typedef struct ${sh_typ} ${sh_typ};')
g.typedefs.writeln('typedef struct ${sh_typ} ${sh_typ}; ///shared')
}
}

Expand Down Expand Up @@ -1492,7 +1492,7 @@ static inline ${option_name}_void __Option_${styp}_pushval(${styp} ch, ${el_type
// cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo)
fn (mut g Gen) cc_type(typ ast.Type, is_prefix_struct bool) string {
sym := g.table.sym(g.unwrap_generic(typ))
mut styp := sym.cname
mut styp := sym.scoped_cname()
// TODO: this needs to be removed; cgen shouldn't resolve generic types (job of checker)
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
Expand Down Expand Up @@ -2358,6 +2358,8 @@ fn (mut g Gen) stmt(node ast.Stmt) {
util.no_dots(node.name)
} else if node.name in ['array', 'string'] {
node.name
} else if node.scoped_name != '' {
c_name(node.scoped_name)
} else {
c_name(node.name)
}
Expand Down Expand Up @@ -6734,7 +6736,7 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
g.type_definitions.writeln('};')
g.typedefs.writeln('typedef struct none none;')
}
mut name := sym.cname
mut name := sym.scoped_cname()
match sym.info {
ast.Struct {
if !struct_names[name] {
Expand Down Expand Up @@ -6960,7 +6962,7 @@ fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
// types name list
mut type_names := []string{}
for sym in typesa {
type_names << sym.name
type_names << sym.scoped_name()
}
// loop over types
for sym in typesa {
Expand Down Expand Up @@ -7062,7 +7064,7 @@ fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
else {}
}
// add type and dependent types to graph
dep_graph.add(sym.name, field_deps)
dep_graph.add(sym.scoped_name(), field_deps)
}
// sort graph
dep_graph_sorted := dep_graph.resolve()
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ fn (mut g Gen) struct_decl(s ast.Struct, name string, is_anon bool) {
if s.is_union {
g.typedefs.writeln('typedef union ${name} ${name};')
} else {
g.typedefs.writeln('typedef struct ${name} ${name};')
g.typedefs.writeln('typedef struct ${name} ${name}; // 3')
}
}
// TODO: avoid buffer manip
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/parser/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -635,9 +635,12 @@ run them via `v file.v` instead',
if language != .v && !(language == .js && type_sym.info is ast.Interface) {
p.error_with_pos('interop functions cannot have a body', body_start_pos)
}
last_fn_scope := p.scope
p.inside_fn = true
p.inside_unsafe_fn = is_unsafe
p.cur_fn_scope = p.scope
stmts = p.parse_block_no_scope(true)
p.cur_fn_scope = last_fn_scope
p.inside_unsafe_fn = false
p.inside_fn = false
}
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/parser/parse_type.v
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_dot b

fn (mut p Parser) find_type_or_add_placeholder(name string, language ast.Language) ast.Type {
// struct / enum / placeholder
mut idx := p.table.find_type_idx(name)
mut idx := p.table.find_type_idx_fn_scoped(name, p.cur_fn_scope)
if idx > 0 {
mut typ := ast.new_type(idx)
sym := p.table.sym(typ)
Expand Down
1 change: 1 addition & 0 deletions vlib/v/parser/parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ mut:
is_stmt_ident bool // true while the beginning of a statement is an ident/selector
expecting_type bool // `is Type`, expecting type
cur_fn_name string
cur_fn_scope &ast.Scope = unsafe { nil }
label_names []string
name_error bool // indicates if the token is not a name or the name is on another line
n_asm int // controls assembly labels
Expand Down
5 changes: 3 additions & 2 deletions vlib/v/parser/struct.v
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
p.check(.rcbr)
end_comments = p.eat_comments(same_line: true)
}
scoped_name := if p.inside_fn { '_${name}_${p.cur_fn_scope.start_pos}' } else { '' }
is_minify := attrs.contains('minify')
mut sym := ast.TypeSymbol{
kind: .struct
Expand All @@ -360,6 +361,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
cname: util.no_dots(name)
mod: p.mod
info: ast.Struct{
scoped_name: scoped_name
embeds: embed_types
fields: fields
is_typedef: attrs.contains('typedef')
Expand All @@ -370,8 +372,6 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
generic_types: generic_types
attrs: attrs
is_anon: is_anon
is_local: p.inside_fn
scope: p.scope
}
is_pub: is_pub
}
Expand All @@ -392,6 +392,7 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
p.expr_mod = ''
return ast.StructDecl{
name: name
scoped_name: scoped_name
is_pub: is_pub
fields: ast_fields
pos: start_pos.extend_with_last_line(name_pos, last_line)
Expand Down
21 changes: 21 additions & 0 deletions vlib/v/tests/structs/struct_local_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
fn test_main() {

struct Foobar {
foo int
}

fb := Foobar{5}
assert fb.foo == 5
x()
}

fn x() {

struct Foobar {
baz string
}

fb := Foobar{'hello world!'}
println(fb.baz)
assert true
}

0 comments on commit 3ef9e09

Please sign in to comment.