diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index c6355ad93a..aea8fd9cf4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -155,17 +155,17 @@ pub: pub struct CallExpr { pub: -// tok token.Token - pos token.Position +// tok token.Token + pos token.Position mut: -// func Expr - name string - args []Expr - arg_types []table.Type - is_c bool - muts []bool - or_block OrExpr - typ table.Type +// func Expr + name string + args []Expr + arg_types []table.Type + is_c bool + muts []bool + or_block OrExpr + return_type table.Type } pub struct MethodCallExpr { @@ -180,7 +180,7 @@ pub: mut: expr_type table.Type // type of `user` receiver_type table.Type // User - typ table.Type + return_type table.Type } pub struct Return { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 654ff5fc84..e2c6783860 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -207,7 +207,7 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type { if !found { c.error('unknown fn: $fn_name', call_expr.pos) } - call_expr.typ = f.return_type + call_expr.return_type = f.return_type if f.is_c || call_expr.is_c { for expr in call_expr.args { c.expr(expr) @@ -255,57 +255,39 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) typ_sym := c.table.get_type_symbol(typ) name := method_call_expr.name // println('method call $name $method_call_expr.pos.line_nr') - if typ_sym.kind == .array && name in ['filter', 'clone'] { + if typ_sym.kind == .array && name in ['filter', 'clone', 'repeat'] { if name == 'filter' { array_info := typ_sym.info as table.Array - elem_type_sym := c.table.get_type_symbol(array_info.elem_type) mut scope := c.file.scope.innermost(method_call_expr.pos.pos) scope.override_var(ast.Var{ name: 'it' typ: array_info.elem_type }) } - if method := typ_sym.find_method(name) { - method_call_expr.typ = method.return_type - for i, arg_expr in method_call_expr.args { - c.expected_type = method.args[i].typ - c.expr(arg_expr) - } + else if name == 'repeat' { + c.expr(method_call_expr.args[0]) } + // need to return `array_xxx` instead of `array` + method_call_expr.return_type = typ return typ } else if typ_sym.kind == .array && name in ['first', 'last'] { info := typ_sym.info as table.Array + method_call_expr.return_type = info.elem_type return info.elem_type } - // repeat() returns `array`, need to return `array_xxx` - else if typ_sym.kind == .array && name in ['repeat'] { - c.expr(method_call_expr.args[0]) - return typ - } - if method := typ_sym.find_method(name) { + if method := c.table.type_find_method(typ_sym, name) { // if name == 'clone' { // println('CLONE nr args=$method.args.len') // } - method_call_expr.receiver_type = method.args[0].typ for i, arg_expr in method_call_expr.args { c.expected_type = method.args[i].typ c.expr(arg_expr) } + method_call_expr.receiver_type = method.args[0].typ + method_call_expr.return_type = method.return_type return method.return_type } - // check parent - if typ_sym.parent_idx != 0 { - parent := &c.table.types[typ_sym.parent_idx] - if method := parent.find_method(name) { - // println('got method $name, returning') - for i, arg_expr in method_call_expr.args { - c.expected_type = method.args[i].typ - c.expr(arg_expr) - } - return method.return_type - } - } c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos) return table.void_type } @@ -320,21 +302,14 @@ pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.T // println('sel expr line_nr=$selector_expr.pos.line_nr typ=$selector_expr.expr_type') typ_sym := c.table.get_type_symbol(typ) field_name := selector_expr.field - if field := typ_sym.find_field(field_name) { - return field.typ - } // variadic if table.type_is_variadic(typ) { if field_name == 'len' { return table.int_type } } - // check parent - if typ_sym.parent_idx != 0 { - parent := &c.table.types[typ_sym.parent_idx] - if field := parent.find_field(field_name) { - return field.typ - } + if field := c.table.struct_find_field(typ_sym, field_name) { + return field.typ } if typ_sym.kind != .struct_ { c.error('`$typ_sym.name` is not a struct', selector_expr.pos) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 87f0c8af6f..1dfb4b6b7d 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -291,10 +291,10 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { mut return_type := table.void_type match assign_stmt.right[0] { ast.CallExpr { - return_type = it.typ + return_type = it.return_type } ast.MethodCallExpr { - return_type = it.typ + return_type = it.return_type } else { panic('expected call') diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 0edf3396d5..07971e83b4 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -142,16 +142,13 @@ fn (p mut Parser) fn_decl() ast.FnDecl { } // Register if is_method { - type_sym := p.table.get_type_symbol(rec_type) + mut type_sym := p.table.get_type_symbol(rec_type) // p.warn('reg method $type_sym.name . $name ()') - ok := p.table.register_method(type_sym, table.Fn{ + type_sym.register_method(table.Fn{ name: name args: args return_type: typ }) - if !ok { - p.error('expected Struct') - } } else { if is_c { diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index f7cf5de05f..553ec2586d 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -83,15 +83,8 @@ pub fn (t mut Table) register_fn(new_fn Fn) { t.fns[new_fn.name] = new_fn } -pub fn (t &Table) register_method(typ &TypeSymbol, new_fn Fn) bool { - // println('register method `$new_fn.name` type=$typ.name idx=$typ.idx') - // println('register method `$new_fn.name` type=$typ.name') - // TODO mut << bug - mut t1 := typ - mut methods := typ.methods - methods << new_fn - t1.methods = methods - return true +pub fn (t mut TypeSymbol) register_method(new_fn Fn) { + t.methods << new_fn } pub fn (t &TypeSymbol) has_method(name string) bool { @@ -131,37 +124,50 @@ pub fn (s &TypeSymbol) find_field(name string) ?Field { return none } +pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool { + // println('type_has_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + if _ := t.type_find_method(s, name) { + return true + } + return false +} + +// search from current type up through each parent looking for method +pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn { + // println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + mut ts := s + for { + if method := ts.find_method(name) { + return method + } + if s.parent_idx == 0 { + break + } + ts = &t.types[ts.parent_idx] + } + return none +} + pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool { - if s.parent_idx != 0 { - parent := &t.types[s.parent_idx] - println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=$parent.name') - } - else { - println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent=none') - } + // println('struct_has_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') if _ := t.struct_find_field(s, name) { return true } return false } +// search from current type up through each parent looking for field pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field { - if s.parent_idx != 0 { - parent := &t.types[s.parent_idx] - println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=$parent.name') - } - else { - println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent=none') - } - if field := s.find_field(name) { - return field - } - if s.parent_idx != 0 { - parent := &t.types[s.parent_idx] - if field := parent.find_field(name) { - println('got parent $parent.name') + // println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') + mut ts := s + for { + if field := ts.find_field(name) { return field } + if s.parent_idx == 0 { + break + } + ts = &t.types[ts.parent_idx] } return none }