all: interface arrays

pull/4645/head
Alexander Medvednikov 2020-04-29 12:20:22 +02:00
parent 3d8853af2b
commit 2fc05b814c
7 changed files with 103 additions and 65 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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]`

View File

@ -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})')
}

View File

@ -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
}
}

View File

@ -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]

View File

@ -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