checker/cgen: interface match

pull/5142/head
Alexander Medvednikov 2020-05-31 10:22:18 +02:00
parent c4241f90e6
commit f87e872fa2
5 changed files with 42 additions and 15 deletions

View File

@ -439,6 +439,7 @@ pub mut:
cond_type table.Type // type of `x` in `match x {`
expected_type table.Type // for debugging only
is_sum_type bool
is_interface bool
}
pub struct MatchBranch {
@ -657,7 +658,7 @@ pub:
pub struct ArrayInit {
pub:
pos token.Position
elem_type_pos token.Position
elem_type_pos token.Position
exprs []Expr
is_fixed bool
has_val bool

View File

@ -1039,7 +1039,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
return f.return_type
}
fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position) {
fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position) bool {
typ_sym := c.table.get_type_symbol(typ)
inter_sym := c.table.get_type_symbol(inter_typ)
styp := c.table.type_to_str(typ)
@ -1048,6 +1048,7 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
if !imethod.is_same_method_as(method) {
c.error('`$styp` incorrectly implements method `$imethod.name` of interface `$inter_sym.name`, expected `${c.table.fn_to_str(imethod)}`',
pos)
return false
}
continue
}
@ -1057,6 +1058,7 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
if typ !in inter_info.types && typ_sym.kind != .interface_ {
inter_info.types << typ
}
return true
}
// return the actual type of the expression, once the optional is handled
@ -2037,11 +2039,11 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
if cond_type == 0 {
c.error('match 0 cond type', node.pos)
}
type_sym := c.table.get_type_symbol(cond_type)
if type_sym.kind != .sum_type {
cond_type_sym := c.table.get_type_symbol(cond_type)
if cond_type_sym.kind !in [.sum_type, .interface_] {
node.is_sum_type = false
}
c.match_exprs(mut node, type_sym)
c.match_exprs(mut node, cond_type_sym)
c.expected_type = cond_type
mut ret_type := table.void_type
for branch in node.branches {
@ -2049,12 +2051,17 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
c.expected_type = cond_type
typ := c.expr(expr)
typ_sym := c.table.get_type_symbol(typ)
if !node.is_sum_type && !c.check_types(typ, cond_type) {
exp_sym := c.table.get_type_symbol(cond_type)
c.error('cannot use `$typ_sym.name` as `$exp_sym.name` in `match`', node.pos)
}
// TODO:
if typ_sym.kind == .sum_type {
if node.is_sum_type || node.is_interface {
ok := if cond_type_sym.kind == .sum_type {
// TODO verify sum type
true // c.check_types(typ, cond_type)
} else {
c.type_implements(typ, cond_type, node.pos)
}
if !ok {
c.error('cannot use `$typ_sym.name` as `$cond_type_sym.name` in `match`',
node.pos)
}
}
}
c.stmts(branch.stmts)

View File

@ -1888,9 +1888,14 @@ fn (mut g Gen) match_expr(node ast.MatchExpr) {
for i, expr in branch.exprs {
if node.is_sum_type {
g.expr(node.cond)
g.write('.typ == ')
// g.write('${tmp}.typ == ')
// sum_type_str
sym := g.table.get_type_symbol(node.cond_type)
// branch_sym := g.table.get_type_symbol(branch.typ)
if sym.kind == .sum_type {
g.write('.typ == ')
} else if sym.kind == .interface_ {
// g.write('._interface_idx == _${sym.name}_${branch_sym} ')
g.write('._interface_idx == ')
}
} else if type_sym.kind == .string {
g.write('string_eq(')
//

View File

@ -12,7 +12,7 @@ import v.util
import v.errors
import os
import runtime
import sync
//import sync
import time
pub struct Parser {
@ -140,6 +140,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme
}
}
/*
struct Queue {
mut:
idx int
@ -171,10 +172,12 @@ fn (mut q Queue) run() {
println('run done(idx=$idx)')
}
}
*/
pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, global_scope &ast.Scope) []ast.File {
// println('nr_cpus= $nr_cpus')
$if macos {
/*
if pref.is_parallel && paths[0].contains('/array.v') {
println('\n\n\nparse_files() nr_files=$paths.len')
println(paths)
@ -194,6 +197,7 @@ pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences, g
println('all done')
return q.parsed_ast_files
}
*/
}
if false {
// TODO: remove this; it just prevents warnings about unused time and runtime

View File

@ -247,3 +247,13 @@ fn new_animal() Animal {
fn new_animal2() Animal {
return new_animal()
}
/*
fn animal_match(a Animal) {
match a {
Dog { println('(dog)') }
Cat { println('(cat)') }
else {}
}
}
*/