From 6068777e039605cda880e77b44d595bd835c4518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sat, 31 Jul 2021 15:35:19 +0200 Subject: [PATCH] parser/checker: deduce type of global from initialization expression (#11005) --- vlib/v/ast/scope.v | 10 ++++ vlib/v/checker/checker.v | 33 ++++++++---- .../checker/tests/globals/assign_no_type.out | 3 -- .../v/checker/tests/globals/assign_no_type.vv | 1 - .../checker/tests/globals/assign_no_value.out | 4 +- vlib/v/checker/tests/globals/unknown_typ.out | 4 +- vlib/v/fmt/fmt.v | 3 -- vlib/v/parser/parser.v | 53 +++++++++++++------ vlib/v/tests/init_global_test.v | 36 +++++++++++++ 9 files changed, 111 insertions(+), 36 deletions(-) delete mode 100644 vlib/v/checker/tests/globals/assign_no_type.out delete mode 100644 vlib/v/checker/tests/globals/assign_no_type.vv diff --git a/vlib/v/ast/scope.v b/vlib/v/ast/scope.v index 31bc3d1d72..a02460c90f 100644 --- a/vlib/v/ast/scope.v +++ b/vlib/v/ast/scope.v @@ -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 { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 2c0c327541..6b6b6be6ad 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -134,9 +134,23 @@ pub fn (mut c Checker) check(ast_file &ast.File) { } } } - for stmt in ast_file.stmts { - c.expr_level = 0 - c.stmt(stmt) + 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) diff --git a/vlib/v/checker/tests/globals/assign_no_type.out b/vlib/v/checker/tests/globals/assign_no_type.out deleted file mode 100644 index 5782878412..0000000000 --- a/vlib/v/checker/tests/globals/assign_no_type.out +++ /dev/null @@ -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 ) - | ^ diff --git a/vlib/v/checker/tests/globals/assign_no_type.vv b/vlib/v/checker/tests/globals/assign_no_type.vv deleted file mode 100644 index 235c6527e0..0000000000 --- a/vlib/v/checker/tests/globals/assign_no_type.vv +++ /dev/null @@ -1 +0,0 @@ -__global ( test = 0 ) \ No newline at end of file diff --git a/vlib/v/checker/tests/globals/assign_no_value.out b/vlib/v/checker/tests/globals/assign_no_value.out index 00b93ef683..2c3865e057 100644 --- a/vlib/v/checker/tests/globals/assign_no_value.out +++ b/vlib/v/checker/tests/globals/assign_no_value.out @@ -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 ) - | ^ + | ~~~ diff --git a/vlib/v/checker/tests/globals/unknown_typ.out b/vlib/v/checker/tests/globals/unknown_typ.out index 91d082dd6b..60b44bbbc6 100644 --- a/vlib/v/checker/tests/globals/unknown_typ.out +++ b/vlib/v/checker/tests/globals/unknown_typ.out @@ -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 | ) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index aaad88510c..6de223af56 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -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)}') } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 1234bce4fb..f4575e8986 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 diff --git a/vlib/v/tests/init_global_test.v b/vlib/v/tests/init_global_test.v index a6d47267ca..b94e6b0f69 100644 --- a/vlib/v/tests/init_global_test.v +++ b/vlib/v/tests/init_global_test.v @@ -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() {