parser/checker: deduce type of global from initialization expression (#11005)
parent
c1f3eb6014
commit
6068777e03
|
@ -100,6 +100,16 @@ pub fn (s &Scope) find_var(name string) ?&Var {
|
|||
return none
|
||||
}
|
||||
|
||||
pub fn (s &Scope) find_global(name string) ?&GlobalField {
|
||||
if obj := s.find(name) {
|
||||
match obj {
|
||||
GlobalField { return &obj }
|
||||
else {}
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
pub fn (s &Scope) find_const(name string) ?&ConstField {
|
||||
if obj := s.find(name) {
|
||||
match obj {
|
||||
|
|
|
@ -134,10 +134,24 @@ pub fn (mut c Checker) check(ast_file &ast.File) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for stmt in ast_file.stmts {
|
||||
for mut stmt in ast_file.stmts {
|
||||
if stmt is ast.ConstDecl || stmt is ast.ExprStmt {
|
||||
c.expr_level = 0
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
for mut stmt in ast_file.stmts {
|
||||
if stmt is ast.GlobalDecl {
|
||||
c.expr_level = 0
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
for mut stmt in ast_file.stmts {
|
||||
if stmt !is ast.ConstDecl && stmt !is ast.GlobalDecl && stmt !is ast.ExprStmt {
|
||||
c.expr_level = 0
|
||||
c.stmt(stmt)
|
||||
}
|
||||
}
|
||||
c.check_scope_vars(c.file.scope)
|
||||
}
|
||||
|
||||
|
@ -4831,13 +4845,12 @@ fn (mut c Checker) global_decl(mut node ast.GlobalDecl) {
|
|||
if sym.kind == .placeholder {
|
||||
c.error('unknown type `$sym.name`', field.typ_pos)
|
||||
}
|
||||
if field.expr !is ast.EmptyExpr {
|
||||
expr_typ := c.expr(field.expr)
|
||||
if !c.check_types(expr_typ, field.typ) {
|
||||
got_sym := c.table.get_type_symbol(expr_typ)
|
||||
c.error('cannot initialize global variable `$field.name` of type `$sym.name` with expression of type `$got_sym.name`',
|
||||
field.expr.position())
|
||||
if field.has_expr {
|
||||
field.typ = c.expr(field.expr)
|
||||
mut v := c.file.global_scope.find_global(field.name) or {
|
||||
panic('internal compiler error - could not find global in scope')
|
||||
}
|
||||
v.typ = c.table.mktyp(field.typ)
|
||||
}
|
||||
c.global_names << field.name
|
||||
}
|
||||
|
@ -5569,7 +5582,7 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
|||
c.mark_as_referenced(mut &node.expr, true)
|
||||
}
|
||||
}
|
||||
} else if node.typ == ast.bool_type && !c.inside_unsafe {
|
||||
} else if node.typ == ast.bool_type && node.expr_type != ast.bool_type && !c.inside_unsafe {
|
||||
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
||||
} else if node.expr_type == ast.none_type && !node.typ.has_flag(.optional) {
|
||||
type_name := c.table.type_to_str(node.typ)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
vlib/v/checker/tests/globals/assign_no_type.vv:1:21: error: global assign must have a type and value, use `name = type(value)` or `name type`
|
||||
1 | __global ( test = 0 )
|
||||
| ^
|
|
@ -1 +0,0 @@
|
|||
__global ( test = 0 )
|
|
@ -1,3 +1,3 @@
|
|||
vlib/v/checker/tests/globals/assign_no_value.vv:1:23: error: global assign must have a type and value, use `name = type(value)` or `name type`
|
||||
vlib/v/checker/tests/globals/assign_no_value.vv:1:19: error: undefined ident: `int`
|
||||
1 | __global ( test = int )
|
||||
| ^
|
||||
| ~~~
|
||||
|
|
|
@ -3,9 +3,9 @@ vlib/v/checker/tests/globals/unknown_typ.vv:1:12: error: unknown type `foo`
|
|||
| ~~~
|
||||
2 | __global (
|
||||
3 | y = float(5.0)
|
||||
vlib/v/checker/tests/globals/unknown_typ.vv:3:6: error: unknown type `float`
|
||||
vlib/v/checker/tests/globals/unknown_typ.vv:3:6: error: unknown function: float
|
||||
1 | __global x foo
|
||||
2 | __global (
|
||||
3 | y = float(5.0)
|
||||
| ~~~~~
|
||||
| ~~~~~~~~~~
|
||||
4 | )
|
||||
|
|
|
@ -983,10 +983,7 @@ pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
|
|||
f.write(strings.repeat(` `, max - field.name.len))
|
||||
if field.has_expr {
|
||||
f.write('= ')
|
||||
f.write(f.table.type_to_str_using_aliases(field.typ, f.mod2alias))
|
||||
f.write('(')
|
||||
f.expr(field.expr)
|
||||
f.write(')')
|
||||
} else {
|
||||
f.write('${f.table.type_to_str_using_aliases(field.typ, f.mod2alias)}')
|
||||
}
|
||||
|
|
|
@ -2937,24 +2937,47 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||
pos := p.tok.position()
|
||||
name := p.check_name()
|
||||
has_expr := p.tok.kind == .assign
|
||||
mut expr := ast.empty_expr()
|
||||
mut typ := ast.void_type
|
||||
mut typ_pos := token.Position{}
|
||||
if has_expr {
|
||||
p.next() // =
|
||||
}
|
||||
typ_pos := p.tok.position()
|
||||
typ := p.parse_type()
|
||||
if p.tok.kind == .assign {
|
||||
p.error('global assign must have the type around the value, use `name = type(value)`')
|
||||
return ast.GlobalDecl{}
|
||||
}
|
||||
mut expr := ast.empty_expr()
|
||||
if has_expr {
|
||||
if p.tok.kind != .lpar {
|
||||
p.error('global assign must have a type and value, use `name = type(value)` or `name type`')
|
||||
return ast.GlobalDecl{}
|
||||
}
|
||||
p.next() // (
|
||||
expr = p.expr(0)
|
||||
p.check(.rpar)
|
||||
match expr {
|
||||
ast.CastExpr {
|
||||
typ = (expr as ast.CastExpr).typ
|
||||
}
|
||||
ast.StructInit {
|
||||
typ = (expr as ast.StructInit).typ
|
||||
}
|
||||
ast.ArrayInit {
|
||||
typ = (expr as ast.ArrayInit).typ
|
||||
}
|
||||
ast.ChanInit {
|
||||
typ = (expr as ast.ChanInit).typ
|
||||
}
|
||||
ast.BoolLiteral, ast.IsRefType {
|
||||
typ = ast.bool_type
|
||||
}
|
||||
ast.CharLiteral {
|
||||
typ = ast.char_type
|
||||
}
|
||||
ast.FloatLiteral {
|
||||
typ = ast.f64_type
|
||||
}
|
||||
ast.IntegerLiteral, ast.SizeOf {
|
||||
typ = ast.int_type
|
||||
}
|
||||
ast.StringLiteral, ast.StringInterLiteral {
|
||||
typ = ast.string_type
|
||||
}
|
||||
else {
|
||||
// type will be deduced by checker
|
||||
}
|
||||
}
|
||||
} else {
|
||||
typ_pos = p.tok.position()
|
||||
typ = p.parse_type()
|
||||
}
|
||||
field := ast.GlobalField{
|
||||
name: name
|
||||
|
|
|
@ -28,6 +28,30 @@ fn test_global_init() {
|
|||
assert true
|
||||
}
|
||||
|
||||
fn get_u64() u64 {
|
||||
return 27
|
||||
}
|
||||
|
||||
fn test_no_type() {
|
||||
assert test == 0
|
||||
assert typeof(test).name == 'int'
|
||||
assert testf == 1.25
|
||||
assert typeof(testf).name == 'f64'
|
||||
assert testneg == -2
|
||||
assert typeof(testneg).name == 'int'
|
||||
assert testnegf == -1250000
|
||||
assert typeof(testnegf).name == 'f64'
|
||||
assert testexpl == 7
|
||||
assert typeof(testexpl).name == 'f32'
|
||||
assert testfn == 27
|
||||
assert typeof(testfn).name == 'u64'
|
||||
assert typeof(testarr).name == '[]f64'
|
||||
assert testarr.len == 10
|
||||
assert testarr[9] == 2.75
|
||||
assert typeof(testmap).name == 'map[string]f64'
|
||||
assert testmap['asd'] == -7.25
|
||||
}
|
||||
|
||||
__global (
|
||||
intmap map[string]int
|
||||
numberfns map[string]fn () int
|
||||
|
@ -38,6 +62,18 @@ __global (
|
|||
mtx sync.RwMutex
|
||||
f1 = f64(545 / (sizeof(f64) + f32(8))) // directly initialized
|
||||
f2 f64
|
||||
test = 0 // int
|
||||
testf = 1.25 // f64
|
||||
testneg = -2 // int
|
||||
testnegf = -1.25e06 // f64
|
||||
testexpl = f32(7)
|
||||
testfn = get_u64()
|
||||
testarr = []f64{len: 10, init: 2.75}
|
||||
testmap = map{
|
||||
'qwe': 2.5
|
||||
'asd': -7.25
|
||||
'yxc': 3.125
|
||||
}
|
||||
)
|
||||
|
||||
fn init() {
|
||||
|
|
Loading…
Reference in New Issue