From 2fc05b814c04e7c9d9e6feeaf73f0c7e905ef017 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 29 Apr 2020 12:20:22 +0200 Subject: [PATCH] all: interface arrays --- vlib/v/ast/ast.v | 25 ++++++----- vlib/v/checker/checker.v | 42 +++++++++++++----- vlib/v/fmt/fmt.v | 7 ++- vlib/v/gen/cgen.v | 84 +++++++++++++++++++---------------- vlib/v/parser/parser.v | 5 +-- vlib/v/table/table.v | 2 +- vlib/v/tests/interface_test.v | 3 +- 7 files changed, 103 insertions(+), 65 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index f32ca89271..cd15891035 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -634,18 +634,21 @@ pub: pub struct ArrayInit { pub: - pos token.Position - exprs []Expr - is_fixed bool - has_val bool - mod string - len_expr Expr - has_len bool - has_cap bool - cap_expr Expr + pos token.Position + exprs []Expr + is_fixed bool + has_val bool + mod string + len_expr Expr + has_len bool + has_cap bool + cap_expr Expr mut: - elem_type table.Type - typ table.Type + is_interface bool // array of interfaces e.g. `[]Animal` `[Dog{}, Cat{}]` + interface_types []table.Type // [Dog, Cat] + interface_type table.Type // Animal + elem_type table.Type + typ table.Type } pub struct MapInit { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index abf226c5ad..d87181a60f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -211,7 +211,7 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) { c.error('struct name must begin with capital letter', pos) } for i, field in decl.fields { - for j in 0..i { + for j in 0 .. i { if field.name == decl.fields[j].name { c.error('field name `$field.name` duplicate', field.pos) } @@ -367,9 +367,8 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type { return table.bool_type } .plus, .minus, .mul, .div { - if infix_expr.op == .div && - (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == '0' || - infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) { + if infix_expr.op == .div && (infix_expr.right is ast.IntegerLiteral && infix_expr.right.str() == + '0' || infix_expr.right is ast.FloatLiteral && infix_expr.right.str().f64() == 0.0) { c.error('division by zero', infix_expr.right.position()) } if left.kind in [.array, .array_fixed, .map, .struct_] && !left.has_method(infix_expr.op.str()) { @@ -743,7 +742,8 @@ pub fn (mut c Checker) call_fn(call_expr mut ast.CallExpr) table.Type { if !found_in_args && call_expr.mod in ['builtin', 'main'] { scope := c.file.scope.innermost(call_expr.pos.pos) if _ := scope.find_var(fn_name) { - c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`', call_expr.pos) + c.error('ambiguous call to: `$fn_name`, may refer to fn `$fn_name` or variable `$fn_name`', + call_expr.pos) } } call_expr.return_type = f.return_type @@ -1117,27 +1117,49 @@ pub fn (mut c Checker) array_init(array_init mut ast.ArrayInit) table.Type { } // [1,2,3] if array_init.exprs.len > 0 && array_init.elem_type == table.void_type { - expecting_interface_array := c.expected_type != 0 && c.table.get_type_symbol(c.table.value_type(c.expected_type)).kind == - .interface_ + mut expected_value_type := table.void_type + mut expecting_interface_array := false + cap := array_init.exprs.len + mut interface_types := []table.Type{cap: cap} + if c.expected_type != 0 { + expected_value_type = c.table.value_type(c.expected_type) + if c.table.get_type_symbol(expected_value_type).kind == .interface_ { + // Array of interfaces? (`[dog, cat]`) Save the interface type (`Animal`) + expecting_interface_array = true + array_init.interface_type = expected_value_type + array_init.is_interface = true + } + } + // expecting_interface_array := c.expected_type != 0 && + // c.table.get_type_symbol(c.table.value_type(c.expected_type)).kind == .interface_ + // // if expecting_interface_array { // println('ex $c.expected_type') // } for i, expr in array_init.exprs { typ := c.expr(expr) + if expecting_interface_array { + if i == 0 { + elem_type = expected_value_type + c.expected_type = elem_type + } + interface_types << typ + continue + } // The first element's type if i == 0 { elem_type = typ c.expected_type = typ continue } - if expecting_interface_array { - continue - } if !c.table.check(elem_type, typ) { elem_type_sym := c.table.get_type_symbol(elem_type) c.error('expected array element with type `$elem_type_sym.name`', array_init.pos) } } + if expecting_interface_array { + array_init.interface_types = interface_types + } if array_init.is_fixed { idx := c.table.find_or_register_array_fixed(elem_type, array_init.exprs.len, 1) array_init.typ = table.new_type(idx) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 6d660d90ab..e21e8d5f1a 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -996,7 +996,12 @@ fn (mut f Fmt) array_init(it ast.ArrayInit) { if it.exprs.len == 0 && it.typ != 0 && it.typ != table.void_type { // `x := []string` f.write(f.type_to_str(it.typ)) - f.write('{}') + f.write('{') + if it.has_cap { + f.write('cap: ') + f.expr(it.cap_expr) + } + f.write('}') return } // `[1,2,3]` diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 5478c1bc37..69be8e8317 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -87,8 +87,8 @@ mut: array_fn_definitions []string // array equality functions that have been defined is_json_fn bool // inside json.encode() pcs []ProfileCounterMeta // -prof profile counter fn_names => fn counter name - attr string - is_builtin_mod bool + attr string + is_builtin_mod bool } const ( @@ -450,7 +450,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { ast.Attr { g.attr = it.name if it.name == 'inline' { - //g.writeln(it.name) + // g.writeln(it.name) } else { g.writeln('//[$it.name]') } @@ -517,14 +517,14 @@ fn (mut g Gen) stmt(node ast.Stmt) { ast.FnDecl { mut skip := false pos := g.out.buf.len - if g.pref.build_mode==.build_module { - if !it.name.starts_with(g.module_built + '.'){ + if g.pref.build_mode == .build_module { + if !it.name.starts_with(g.module_built + '.') { // Skip functions that don't have to be generated // for this module. - skip = true + skip = true } if g.is_builtin_mod && g.module_built == 'builtin' { - skip=false + skip = false } if !skip { println('build module `$g.module_built` fn `$it.name`') @@ -606,7 +606,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.definitions.writeln('} $it.name;') } ast.Module { - g.is_builtin_mod = it.name=='builtin' + g.is_builtin_mod = it.name == 'builtin' } ast.Return { g.write_defer_stmts_when_needed() @@ -1176,7 +1176,7 @@ fn (mut g Gen) expr(node ast.Expr) { g.write('.') } if it.expr_type == 0 { - verror('cgen: SelectorExpr typ=0 field=$it.field') + verror('cgen: SelectorExpr typ=0 field=$it.field $g.file.path $it.pos.line_nr') } g.write(c_name(it.field)) } @@ -3361,35 +3361,7 @@ ${interface_name} I_${cctype}_to_${interface_name}(${cctype} x) { fn (mut g Gen) array_init(it ast.ArrayInit) { type_sym := g.table.get_type_symbol(it.typ) - if type_sym.kind != .array_fixed { - // elem_sym := g.table.get_type_symbol(it.elem_type) - elem_type_str := g.typ(it.elem_type) - if it.exprs.len == 0 { - g.write('__new_array(') - if it.has_len { - g.expr(it.len_expr) - g.write(', ') - } else { - g.write('0, ') - } - if it.has_cap { - g.expr(it.cap_expr) - g.write(', ') - } else { - g.write('0, ') - } - g.write('sizeof($elem_type_str))') - } else { - len := it.exprs.len - g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ') - g.write('($elem_type_str[$len]){\n\t\t') - for expr in it.exprs { - g.expr(expr) - g.write(', ') - } - g.write('\n})') - } - } else { + if type_sym.kind == .array_fixed { g.write('{') for i, expr in it.exprs { g.expr(expr) @@ -3398,5 +3370,41 @@ fn (mut g Gen) array_init(it ast.ArrayInit) { } } g.write('}') + return } + // elem_sym := g.table.get_type_symbol(it.elem_type) + elem_type_str := g.typ(it.elem_type) + if it.exprs.len == 0 { + g.write('__new_array(') + if it.has_len { + g.expr(it.len_expr) + g.write(', ') + } else { + g.write('0, ') + } + if it.has_cap { + g.expr(it.cap_expr) + g.write(', ') + } else { + g.write('0, ') + } + g.write('sizeof($elem_type_str))') + return + } + len := it.exprs.len + g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), ') + g.write('($elem_type_str[$len]){\n\t\t') + for i, expr in it.exprs { + if it.is_interface { + sym := g.table.get_type_symbol(it.interface_types[i]) + isym := g.table.get_type_symbol(it.interface_type) + g.write('I_${sym.name}_to_${isym.name}(') + } + g.expr(expr) + if it.is_interface { + g.write(')') + } + g.write(', ') + } + g.write('\n})') } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index ceec1f6230..00286960a7 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -201,9 +201,9 @@ pub fn (mut p Parser) close_scope() { ast.Var { if !it.is_used && !it.name.starts_with('__') { if p.pref.is_prod { - p.error_with_pos('Unused variable: $it.name', it.pos) + p.error_with_pos('unused variable: `$it.name`', it.pos) } else { - p.warn_with_pos('Unused variable: $it.name', it.pos) + p.warn_with_pos('unused variable: `$it.name`', it.pos) } } } @@ -1249,7 +1249,6 @@ fn (mut p Parser) assoc() ast.Assoc { fields: fields exprs: vals pos: pos - // typ: v.typ } } diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index cc68acf067..aa52be1f78 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -201,7 +201,7 @@ pub fn (t &Table) get_type_symbol(typ Type) &TypeSymbol { return &t.types[idx] } // this should never happen - panic('get_type_symbol: invalid type (typ=$typ idx=${idx}). This should never happen') + panic('get_type_symbol: invalid type (typ=$typ idx=${idx}). Compiler bug. This should never happen') } [inline] diff --git a/vlib/v/tests/interface_test.v b/vlib/v/tests/interface_test.v index cdaf2e4f8a..78358ebcc1 100644 --- a/vlib/v/tests/interface_test.v +++ b/vlib/v/tests/interface_test.v @@ -46,7 +46,7 @@ fn test_perform_speak() { perform_speak(dog) cat := Cat{} perform_speak(cat) - //perform_speakers([dog, cat]) + perform_speakers([dog, cat]) /* f := Foo { speaker: dog @@ -62,6 +62,7 @@ interface Speak2er { speak() } + struct Foo { speaker Speaker speakers []Speaker