checker: allow for references to fixed array consts inside their initialisation `const a = [ ... &a[0] ...]!`
parent
a8461a900d
commit
4cfff58fdf
|
@ -66,10 +66,10 @@ pub mut:
|
||||||
notices []errors.Notice
|
notices []errors.Notice
|
||||||
error_lines []int // to avoid printing multiple errors for the same line
|
error_lines []int // to avoid printing multiple errors for the same line
|
||||||
expected_type ast.Type
|
expected_type ast.Type
|
||||||
expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type
|
expected_or_type ast.Type // fn() or { 'this type' } eg. string. expected or block type
|
||||||
expected_expr_type ast.Type // if/match is_expr: expected_type
|
expected_expr_type ast.Type // if/match is_expr: expected_type
|
||||||
mod string // current module name
|
mod string // current module name
|
||||||
const_decl string
|
const_var &ast.ConstField = voidptr(0) // the current constant, when checking const declarations
|
||||||
const_deps []string
|
const_deps []string
|
||||||
const_names []string
|
const_names []string
|
||||||
global_names []string
|
global_names []string
|
||||||
|
@ -142,7 +142,7 @@ pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker {
|
||||||
fn (mut c Checker) reset_checker_state_at_start_of_new_file() {
|
fn (mut c Checker) reset_checker_state_at_start_of_new_file() {
|
||||||
c.expected_type = ast.void_type
|
c.expected_type = ast.void_type
|
||||||
c.expected_or_type = ast.void_type
|
c.expected_or_type = ast.void_type
|
||||||
c.const_decl = ''
|
c.const_var = voidptr(0)
|
||||||
c.in_for_count = 0
|
c.in_for_count = 0
|
||||||
c.returns = false
|
c.returns = false
|
||||||
c.scope_returns = false
|
c.scope_returns = false
|
||||||
|
@ -1327,8 +1327,9 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
|
||||||
c.const_names << field.name
|
c.const_names << field.name
|
||||||
}
|
}
|
||||||
for i, mut field in node.fields {
|
for i, mut field in node.fields {
|
||||||
c.const_decl = field.name
|
|
||||||
c.const_deps << field.name
|
c.const_deps << field.name
|
||||||
|
prev_const_var := c.const_var
|
||||||
|
c.const_var = unsafe { field }
|
||||||
mut typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
|
mut typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
|
||||||
if ct_value := c.eval_comptime_const_expr(field.expr, 0) {
|
if ct_value := c.eval_comptime_const_expr(field.expr, 0) {
|
||||||
field.comptime_expr_value = ct_value
|
field.comptime_expr_value = ct_value
|
||||||
|
@ -1338,6 +1339,7 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
|
||||||
}
|
}
|
||||||
node.fields[i].typ = ast.mktyp(typ)
|
node.fields[i].typ = ast.mktyp(typ)
|
||||||
c.const_deps = []
|
c.const_deps = []
|
||||||
|
c.const_var = prev_const_var
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2620,8 +2622,23 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
||||||
if !name.contains('.') && node.mod != 'builtin' {
|
if !name.contains('.') && node.mod != 'builtin' {
|
||||||
name = '${node.mod}.$node.name'
|
name = '${node.mod}.$node.name'
|
||||||
}
|
}
|
||||||
if name == c.const_decl && !c.pref.translated {
|
// detect cycles, while allowing for references to the same constant,
|
||||||
// TODO allow references, do not just check by name
|
// used inside its initialisation like: `struct Abc { x &Abc } ... const a = [ Abc{0}, Abc{unsafe{&a[0]}} ]!`
|
||||||
|
// see vlib/v/tests/const_fixed_array_containing_references_to_itself_test.v
|
||||||
|
if unsafe { c.const_var != 0 } && name == c.const_var.name {
|
||||||
|
if mut c.const_var.expr is ast.ArrayInit {
|
||||||
|
if c.const_var.expr.is_fixed && c.expected_type.nr_muls() > 0 {
|
||||||
|
elem_typ := c.expected_type.deref()
|
||||||
|
node.kind = .constant
|
||||||
|
node.name = c.const_var.name
|
||||||
|
node.info = ast.IdentVar{
|
||||||
|
typ: elem_typ
|
||||||
|
}
|
||||||
|
// c.const_var.typ = elem_typ
|
||||||
|
node.obj = c.const_var
|
||||||
|
return c.expected_type
|
||||||
|
}
|
||||||
|
}
|
||||||
c.error('cycle in constant `$c.const_decl`', node.pos)
|
c.error('cycle in constant `$c.const_decl`', node.pos)
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct Abc {
|
||||||
|
prev &Abc
|
||||||
|
}
|
||||||
|
|
||||||
|
const a = [Abc{voidptr(0)}, Abc{unsafe { &a[0] }}, Abc{unsafe { &a[1] }}]!
|
||||||
|
|
||||||
|
fn test_fixed_array() {
|
||||||
|
dump(a)
|
||||||
|
dump(voidptr(&a[0]))
|
||||||
|
dump(voidptr(&a[1]))
|
||||||
|
dump(voidptr(&a[2]))
|
||||||
|
dump(voidptr(a[0].prev))
|
||||||
|
dump(voidptr(a[1].prev))
|
||||||
|
dump(voidptr(a[2].prev))
|
||||||
|
assert voidptr(&a[0]) == voidptr(a[1].prev)
|
||||||
|
assert voidptr(&a[1]) == voidptr(a[2].prev)
|
||||||
|
}
|
Loading…
Reference in New Issue