From 70cbf5665571ade6419fba3d84cf78b7a09655fd Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 30 Oct 2020 20:26:08 +0200 Subject: [PATCH] cgen: show more informative errors, instead of a `invalid type (typ=0 idx=0)` verror panic --- vlib/v/ast/ast.v | 1 + vlib/v/checker/checker.v | 6 ++++-- vlib/v/gen/cgen.v | 27 +++++++++++++++++++++++---- vlib/v/gen/fn.v | 14 +++++++++++++- vlib/v/parser/fn.v | 1 + 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5650fed3f6..f8d4bdd1fa 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -318,6 +318,7 @@ pub: pub mut: typ table.Type is_tmp_autofree bool + pos token.Position // tmp_name string // for autofree } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a391eebccf..3bb9d5eef5 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1057,6 +1057,10 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { left_type := c.expr(call_expr.left) is_generic := left_type.has_flag(.generic) call_expr.left_type = left_type + // Set default values for .return_type & .receiver_type too, + // or there will be hard to diagnose 0 type panics in cgen. + call_expr.return_type = left_type + call_expr.receiver_type = left_type left_type_sym := c.table.get_type_symbol(c.unwrap_generic(left_type)) method_name := call_expr.name mut unknown_method_msg := 'unknown method: `${left_type_sym.source_name}.$method_name`' @@ -1095,8 +1099,6 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type { for arg in call_expr.args { arg_type = c.expr(arg.expr) } - call_expr.return_type = left_type - call_expr.receiver_type = left_type if method_name == 'map' { // check fn c.check_map_and_filter(true, elem_typ, call_expr) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 240fa714d2..509bbf88b7 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -2309,6 +2309,9 @@ fn (mut g Gen) expr(node ast.Expr) { g.typeof_name(left) return } + if node.expr_type == 0 { + g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos) + } sym := g.table.get_type_symbol(node.expr_type) if sym.kind == .array_fixed { assert node.field_name == 'len' @@ -3886,7 +3889,11 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { for i, field in struct_init.fields { inited_fields[field.name] = i if sym.info is table.Struct as struct_info { - tfield := struct_info.fields.filter(it.name == field.name)[0] + equal_fields := struct_info.fields.filter(it.name == field.name) + if equal_fields.len == 0 { + continue + } + tfield := equal_fields[0] if tfield.embed_alias_for.len != 0 { continue } @@ -3894,6 +3901,9 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { if sym.kind != .struct_ { field_name := c_name(field.name) g.write('.$field_name = ') + if field.typ == 0 { + g.checker_bug('struct init, field.typ is 0', field.pos) + } field_type_sym := g.table.get_type_symbol(field.typ) mut cloned := false if g.autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] { @@ -3931,7 +3941,11 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) { // nr_fields = info.fields.len for field in info.fields { if sym.info is table.Struct as struct_info { - tfield := struct_info.fields.filter(it.name == field.name)[0] + equal_fields := struct_info.fields.filter(it.name == field.name) + if equal_fields.len == 0 { + continue + } + tfield := equal_fields[0] if tfield.embed_alias_for.len != 0 { continue } @@ -4132,8 +4146,13 @@ fn verror(s string) { } fn (g &Gen) error(s string, pos token.Position) { - p := if pos.line_nr == 0 { '?' } else { '${pos.line_nr + 1}' } - util.verror('$g.file.path:$p: cgen error', s) + ferror := util.formatted_error('cgen error:', s, g.file.path, pos) + eprintln(ferror) + exit(1) +} + +fn (g &Gen) checker_bug(s string, pos token.Position) { + g.error('checker bug; $s', pos) } fn (mut g Gen) write_init_function() { diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index 139367fb8c..7911fb24f0 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -326,7 +326,10 @@ pub fn (g &Gen) unwrap_generic(typ table.Type) table.Type { fn (mut g Gen) method_call(node ast.CallExpr) { // TODO: there are still due to unchecked exprs (opt/some fn arg) if node.left_type == 0 { - verror('method receiver type is 0, this means there are some uchecked exprs') + g.checker_bug('CallExpr.left_type is 0 in method_call', node.pos) + } + if node.receiver_type == 0 { + g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos) } // mut receiver_type_name := g.cc_type(node.receiver_type) // mut receiver_type_name := g.typ(node.receiver_type) @@ -545,6 +548,9 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { // Handle `print(x)` if is_print && node.args[0].typ != table.string_type { // && !free_tmp_arg_vars { typ := node.args[0].typ + if typ == 0 { + g.checker_bug('print arg.typ is 0', node.pos) + } mut styp := g.typ(typ) sym := g.table.get_type_symbol(typ) if typ.is_ptr() { @@ -831,6 +837,9 @@ fn (mut g Gen) call_args(node ast.CallExpr) { fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { arg_is_ptr := expected_type.is_ptr() || expected_type.idx() in table.pointer_type_idxs expr_is_ptr := arg.typ.is_ptr() || arg.typ.idx() in table.pointer_type_idxs + if expected_type == 0 { + g.checker_bug('ref_or_deref_arg expected_type is 0', arg.pos) + } exp_sym := g.table.get_type_symbol(expected_type) if arg.is_mut && !arg_is_ptr { g.write('&/*mut*/') @@ -851,6 +860,9 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) { } } if !g.is_json_fn { + if arg.typ == 0 { + g.checker_bug('ref_or_deref_arg arg.typ is 0', arg.pos) + } arg_typ_sym := g.table.get_type_symbol(arg.typ) expected_deref_type := if expected_type.is_ptr() { expected_type.deref() } else { expected_type } is_sum_type := g.table.get_type_symbol(expected_deref_type).kind == .sum_type diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index bff633c368..bd8a73af9b 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -140,6 +140,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg { share: table.sharetype_from_flags(is_shared, is_atomic) expr: e comments: comments + pos: p.tok.position() } if p.tok.kind != .rpar { p.check(.comma)