checker: add error for `type StructAlias = Struct struct Struct { field StructAlias }`
parent
64f1ea6fe9
commit
41e763f79c
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 |
|
|
@ -0,0 +1,11 @@
|
||||||
|
type Foo = Bar
|
||||||
|
|
||||||
|
struct Bar {
|
||||||
|
pfield &Foo = 0
|
||||||
|
field Foo = Bar{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
bar := Bar{}
|
||||||
|
println(bar)
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue