diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 496fdbfaa5..c678d499e5 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -189,6 +189,8 @@ pub struct Return { pub: pos token.Position exprs []Expr +mut: + types []table.Type } /* @@ -416,10 +418,13 @@ pub: pub struct AssignStmt { pub: - left []Ident - right []Expr - op token.Kind - pos token.Position + left []Ident + right []Expr + op token.Kind + pos token.Position +mut: + left_types []table.Type + right_types []table.Type } pub struct AsCast { @@ -490,12 +495,13 @@ pub: pub struct AssignExpr { pub: - op token.Kind - pos token.Position - left Expr - val Expr + op token.Kind + pos token.Position + left Expr + val Expr mut: - left_type table.Type + left_type table.Type + right_type table.Type } pub struct GotoLabel { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 9238ad876f..d33911a410 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -169,6 +169,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) { // t := c.table.get_type_symbol(left_type) // println('setting exp type to $c.expected_type $t.name') right_type := c.expr(assign_expr.val) + assign_expr.right_type = right_type if !c.table.check(right_type, left_type) { left_type_sym := c.table.get_type_symbol(left_type) right_type_sym := c.table.get_type_symbol(right_type) @@ -352,7 +353,7 @@ pub fn (c mut Checker) selector_expr(selector_expr mut ast.SelectorExpr) table.T } // TODO: non deferred -pub fn (c mut Checker) return_stmt(return_stmt ast.Return) { +pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) { c.expected_type = c.fn_return_type if return_stmt.exprs.len == 0 { return @@ -370,6 +371,7 @@ pub fn (c mut Checker) return_stmt(return_stmt ast.Return) { typ := c.expr(expr) got_types << typ } + return_stmt.types = got_types // allow `none` & `error (Option)` return types for function that returns optional if exp_is_optional && table.type_idx(got_types[0]) in [table.none_type_idx, c.table.type_idxs['Option']] { return @@ -406,12 +408,14 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { assign_stmt.left[i] = ident if assign_stmt.op == .assign { var_type := c.expr(ident) + assign_stmt.left_types << var_type if !c.table.check(val_type, var_type) { val_type_sym := c.table.get_type_symbol(val_type) var_type_sym := c.table.get_type_symbol(var_type) c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos) } } + assign_stmt.right_types << val_type scope.override_var(ast.Var{ name: ident.name typ: mr_info.types[i] @@ -426,16 +430,18 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) { mut scope := c.file.scope.innermost(assign_stmt.pos.pos) for i, _ in assign_stmt.left { mut ident := assign_stmt.left[i] + mut ident_var_info := ident.var_info() val_type := c.expr(assign_stmt.right[i]) if assign_stmt.op == .assign { var_type := c.expr(ident) + assign_stmt.left_types << var_type if !c.table.check(val_type, var_type) { val_type_sym := c.table.get_type_symbol(val_type) var_type_sym := c.table.get_type_symbol(var_type) c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos) } } - mut ident_var_info := ident.var_info() + assign_stmt.right_types << val_type ident_var_info.typ = val_type ident.info = ident_var_info assign_stmt.left[i] = ident @@ -556,7 +562,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { // ast.HashStmt {} ast.Import {} ast.Return { - c.return_stmt(it) + c.return_stmt(mut it) } // ast.StructDecl {} ast.UnsafeStmt { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 85ec29d593..848edcb1cb 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -326,6 +326,29 @@ fn (g mut Gen) stmt(node ast.Stmt) { } } +fn (g &Gen) is_sum_cast(got_type table.Type, exp_type table.Type) bool { + if exp_type != table.void_type && exp_type != 0 && got_type != 0{ + exp_sym := g.table.get_type_symbol(exp_type) + // got_sym := g.table.get_type_symbol(got_type) + if exp_sym.kind == .sum_type { + sum_info := exp_sym.info as table.SumType + if got_type in sum_info.variants { + return true + } + } + } + return false +} + +fn (g mut Gen) sum_cast(got_type table.Type, exp_type table.Type, expr ast.Expr) { + got_styp := g.typ(got_type) + exp_styp := g.typ(exp_type) + got_idx := table.type_idx(got_type) + g.write('/* SUM TYPE CAST */ ($exp_styp) {.obj = memdup(&(${got_styp}[]) {') + g.expr(expr) + g.writeln('}, sizeof($got_styp)), .typ = $got_idx};') +} + fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { // multi return // g.write('/*assign*/') @@ -394,13 +417,20 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { } else {} } + mut is_sum_cast := false if assign_stmt.op == .decl_assign { g.write('$styp ') + } else { + is_sum_cast = g.is_sum_cast(assign_stmt.right_types[i], assign_stmt.left_types[i]) } g.expr(ident) if !is_fixed_array_init { g.write(' = ') - g.expr(val) + if is_sum_cast { + g.sum_cast(ident_var_info.typ, assign_stmt.left_types[i], val) + } else { + g.expr(val) + } } } g.writeln(';') @@ -549,7 +579,11 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(', ') } g.is_assign_expr = false - g.expr(it.val) + if g.is_sum_cast(it.left_type, it.right_type) { + g.sum_cast(it.left_type, it.right_type, it.val) + } else { + g.expr(it.val) + } if g.is_array_set { g.write(' })') g.is_array_set = false @@ -1135,6 +1169,8 @@ fn (g mut Gen) return_statement(it ast.Return) { g.write('return') // multiple returns if it.exprs.len > 1 { + typ_sym := g.table.get_type_symbol(g.fn_decl.return_type) + mr_info := typ_sym.info as table.MultiReturn styp := g.typ(g.fn_decl.return_type) g.write(' ($styp){') for i, expr in it.exprs { @@ -1171,7 +1207,12 @@ fn (g mut Gen) return_statement(it ast.Return) { } // g.write('/*OPTIONAL*/') } - g.expr(it.exprs[0]) + if g.is_sum_cast(it.types[0], g.fn_decl.return_type) { + g.sum_cast(it.types[0], g.fn_decl.return_type, it.exprs[0]) + } + else { + g.expr(it.exprs[0]) + } } g.writeln(';') }