parser/cgen: interface <<; `any` type

pull/4689/head
Alexander Medvednikov 2020-05-03 18:08:45 +02:00
parent 2a016d03ac
commit de749e9d3b
5 changed files with 39 additions and 5 deletions

View File

@ -391,7 +391,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
// `array << elm` // `array << elm`
c.fail_if_immutable(infix_expr.left) c.fail_if_immutable(infix_expr.left)
// the expressions have different types (array_x and x) // the expressions have different types (array_x and x)
if c.table.check(c.table.value_type(left_type), right_type) { if c.table.check(right_type, c.table.value_type(left_type)) { // , right_type) {
// []T << T // []T << T
return table.void_type return table.void_type
} }
@ -400,7 +400,7 @@ pub fn (mut c Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
return table.void_type return table.void_type
} }
s := left.name.replace('array_', '[]') s := left.name.replace('array_', '[]')
c.error('cannot append `$right.name` to `$s', infix_expr.right.position()) c.error('cannot append `$right.name` to `$s`', infix_expr.right.position())
return table.void_type return table.void_type
} else if !left.is_int() { } else if !left.is_int() {
c.error('cannot shift type $right.name into non-integer type $left.name', infix_expr.left.position()) c.error('cannot shift type $right.name into non-integer type $left.name', infix_expr.left.position())

View File

@ -1470,7 +1470,14 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
g.write('array_push(&') g.write('array_push(&')
g.expr(node.left) g.expr(node.left)
g.write(', &($elem_type_str[]){ ') g.write(', &($elem_type_str[]){ ')
elem_sym := g.table.get_type_symbol(info.elem_type)
if elem_sym.kind == .interface_ {
g.interface_call(node.right_type, info.elem_type)
}
g.expr_with_cast(node.right, node.right_type, info.elem_type) g.expr_with_cast(node.right, node.right_type, info.elem_type)
if elem_sym.kind == .interface_ {
g.write(')')
}
g.write(' })') g.write(' })')
} }
} else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in } else if (node.left_type == node.right_type) && node.left_type.is_float() && node.op in

View File

@ -176,6 +176,7 @@ pub const (
ustring_type_idx = 19 ustring_type_idx = 19
array_type_idx = 20 array_type_idx = 20
map_type_idx = 21 map_type_idx = 21
any_type_idx = 22
) )
pub const ( pub const (
@ -220,6 +221,7 @@ pub const (
ustring_type = new_type(ustring_type_idx) ustring_type = new_type(ustring_type_idx)
array_type = new_type(array_type_idx) array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx) map_type = new_type(map_type_idx)
any_type = new_type(any_type_idx)
) )
pub const ( pub const (
@ -227,7 +229,7 @@ pub const (
'u16', 'u16',
'u32', 'u32',
'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'u64', 'f32', 'f64', 'string', 'ustring', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed',
'map', 'struct', 'map', 'any', 'struct',
'mapnode', 'size_t'] 'mapnode', 'size_t']
) )
@ -270,6 +272,7 @@ pub enum Kind {
array array
array_fixed array_fixed
map map
any
struct_ struct_
multi_return multi_return
sum_type sum_type
@ -427,6 +430,10 @@ pub fn (mut t Table) register_builtin_type_symbols() {
kind: .map kind: .map
name: 'map' name: 'map'
}) })
t.register_type_symbol(TypeSymbol{
kind: .any
name: 'any'
})
t.register_type_symbol(TypeSymbol{ t.register_type_symbol(TypeSymbol{
kind: .size_t kind: .size_t
name: 'size_t' name: 'size_t'
@ -466,6 +473,7 @@ pub fn (t &TypeSymbol) is_number() bool {
return t.is_int() || t.is_float() return t.is_int() || t.is_float()
} }
// for debugging/errors only, perf is not an issue
pub fn (k Kind) str() string { pub fn (k Kind) str() string {
k_str := match k { k_str := match k {
.placeholder { 'placeholder' } .placeholder { 'placeholder' }
@ -496,6 +504,7 @@ pub fn (k Kind) str() string {
.sum_type { 'sum_type' } .sum_type { 'sum_type' }
.alias { 'alias' } .alias { 'alias' }
.enum_ { 'enum' } .enum_ { 'enum' }
.any { 'any' }
else { 'unknown' } else { 'unknown' }
} }
return k_str return k_str
@ -535,7 +544,7 @@ pub:
foo string foo string
} }
// NB: FExpr here is a actually an ast.Expr . // NB: FExpr here is a actually an ast.Expr .
// It should always be used by casting to ast.Expr, using ast.fe2ex()/ast.ex2fe() // It should always be used by casting to ast.Expr, using ast.fe2ex()/ast.ex2fe()
// That hack is needed to break an import cycle between v.ast and v.table . // That hack is needed to break an import cycle between v.ast and v.table .
type FExpr = voidptr | byteptr type FExpr = voidptr | byteptr

View File

@ -469,6 +469,9 @@ pub fn (t &Table) check(got, expected Type) bool {
if exp_idx == voidptr_type_idx || got_idx == voidptr_type_idx { if exp_idx == voidptr_type_idx || got_idx == voidptr_type_idx {
return true return true
} }
if exp_idx == any_type_idx || got_idx == any_type_idx {
return true
}
if (exp_idx in pointer_type_idxs || exp_idx in number_type_idxs) && (got_idx in pointer_type_idxs || if (exp_idx in pointer_type_idxs || exp_idx in number_type_idxs) && (got_idx in pointer_type_idxs ||
got_idx in number_type_idxs) { got_idx in number_type_idxs) {
return true return true
@ -485,7 +488,7 @@ pub fn (t &Table) check(got, expected Type) bool {
// # NOTE: use symbols from this point on for perf // # NOTE: use symbols from this point on for perf
got_type_sym := t.get_type_symbol(got) got_type_sym := t.get_type_symbol(got)
exp_type_sym := t.get_type_symbol(expected) exp_type_sym := t.get_type_symbol(expected)
// // Handle expected interface
if exp_type_sym.kind == .interface_ { if exp_type_sym.kind == .interface_ {
mut info := exp_type_sym.info as Interface mut info := exp_type_sym.info as Interface
// println('gen_types before') // println('gen_types before')
@ -498,6 +501,13 @@ pub fn (t &Table) check(got, expected Type) bool {
// println(info.gen_types) // println(info.gen_types)
return true return true
} }
// Handle expected interface array
/*
if exp_type_sym.kind == .array && t.get_type_symbol(t.value_type(exp_idx)).kind == .interface_ {
return true
}
*/
//
if exp_type_sym.kind == .function && got_type_sym.kind == .int { if exp_type_sym.kind == .function && got_type_sym.kind == .int {
// TODO temporary // TODO temporary
// fn == 0 // fn == 0

View File

@ -91,3 +91,11 @@ interface Speaker {
speak() speak()
} }
fn test_interface_array() {
mut animals := []Speaker{}
animals = [ Cat{}, Dog{} ]
animals << Cat{}
assert true
assert animals.len == 3
}