checker: add error for `type StructAlias = Struct struct Struct { field StructAlias }`

pull/13251/head
Delyan Angelov 2022-01-02 15:47:58 +02:00
parent 64f1ea6fe9
commit 41e763f79c
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
7 changed files with 40 additions and 5 deletions

View File

@ -610,7 +610,7 @@ pub fn (t &Table) find_type_idx(name string) int {
} }
[inline] [inline]
pub fn (t &Table) find_type(name string) ?&TypeSymbol { pub fn (t &Table) find_sym(name string) ?&TypeSymbol {
idx := t.type_idxs[name] idx := t.type_idxs[name]
if idx > 0 { if idx > 0 {
return t.type_symbols[idx] return t.type_symbols[idx]
@ -618,6 +618,15 @@ pub fn (t &Table) find_type(name string) ?&TypeSymbol {
return none return none
} }
[inline]
pub fn (t &Table) find_sym_and_type_idx(name string) (&TypeSymbol, int) {
idx := t.type_idxs[name]
if idx > 0 {
return t.type_symbols[idx], idx
}
return ast.invalid_type_symbol, idx
}
pub const invalid_type_symbol = &TypeSymbol{ pub const invalid_type_symbol = &TypeSymbol{
idx: -1 idx: -1
parent_idx: -1 parent_idx: -1

View File

@ -2224,7 +2224,7 @@ fn (mut c Checker) import_stmt(node ast.Import) {
for sym in node.syms { for sym in node.syms {
name := '${node.mod}.$sym.name' name := '${node.mod}.$sym.name'
if sym.name[0].is_capital() { if sym.name[0].is_capital() {
if type_sym := c.table.find_type(name) { if type_sym := c.table.find_sym(name) {
if type_sym.kind != .placeholder { if type_sym.kind != .placeholder {
if !type_sym.is_public { if !type_sym.is_public {
c.error('module `$node.mod` type `$sym.name` is private', sym.pos) c.error('module `$node.mod` type `$sym.name` is private', sym.pos)

View File

@ -8,7 +8,7 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
if node.language == .v && !c.is_builtin_mod { if node.language == .v && !c.is_builtin_mod {
c.check_valid_pascal_case(node.name, 'struct name', node.pos) c.check_valid_pascal_case(node.name, 'struct name', node.pos)
} }
mut struct_sym := c.table.find_type(node.name) or { ast.invalid_type_symbol } mut struct_sym, struct_typ_idx := c.table.find_sym_and_type_idx(node.name)
mut has_generic_types := false mut has_generic_types := false
if mut struct_sym.info is ast.Struct { if mut struct_sym.info is ast.Struct {
for embed in node.embeds { for embed in node.embeds {
@ -48,6 +48,14 @@ pub fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
c.error('field name `$field.name` duplicate', field.pos) c.error('field name `$field.name` duplicate', field.pos)
} }
} }
if field.typ != 0 {
if !field.typ.is_ptr() {
if c.table.unaliased_type(field.typ) == struct_typ_idx {
c.error('Field `$field.name` is part of `$node.name`, they can not both have the same type',
field.type_pos)
}
}
}
if sym.kind == .struct_ { if sym.kind == .struct_ {
info := sym.info as ast.Struct info := sym.info as ast.Struct
if info.is_heap && !field.typ.is_ptr() { if info.is_heap && !field.typ.is_ptr() {

View File

@ -0,0 +1,7 @@
vlib/v/checker/tests/field_can_not_be_from_the_same_type_as_containing_struct.vv:5:9: error: Field `field` is part of `Bar`, they can not both have the same type
3 | struct Bar {
4 | pfield &Foo = 0
5 | field Foo = Bar{}
| ~~~
6 | }
7 |

View File

@ -0,0 +1,11 @@
type Foo = Bar
struct Bar {
pfield &Foo = 0
field Foo = Bar{}
}
fn main() {
bar := Bar{}
println(bar)
}

View File

@ -175,7 +175,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
g.enter_namespace('main') g.enter_namespace('main')
// generate JS methods for interface methods // generate JS methods for interface methods
for iface_name, iface_types in g.table.iface_types { for iface_name, iface_types in g.table.iface_types {
iface := g.table.find_type(iface_name) or { panic('unreachable: interface must exist') } iface := g.table.find_sym(iface_name) or { panic('unreachable: interface must exist') }
for ty in iface_types { for ty in iface_types {
sym := g.table.sym(ty) sym := g.table.sym(ty)
for method in iface.methods { for method in iface.methods {

View File

@ -249,7 +249,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
if pref.is_test { if pref.is_test {
all_fn_root_names << 'main.cb_assertion_ok' all_fn_root_names << 'main.cb_assertion_ok'
all_fn_root_names << 'main.cb_assertion_failed' all_fn_root_names << 'main.cb_assertion_failed'
if benched_tests_sym := table.find_type('main.BenchedTests') { if benched_tests_sym := table.find_sym('main.BenchedTests') {
bts_type := benched_tests_sym.methods[0].params[0].typ bts_type := benched_tests_sym.methods[0].params[0].typ
all_fn_root_names << '${bts_type}.testing_step_start' all_fn_root_names << '${bts_type}.testing_step_start'
all_fn_root_names << '${bts_type}.testing_step_end' all_fn_root_names << '${bts_type}.testing_step_end'