v.checker,v.gen.c: extend auto heap mechanism to objects used as interfaces (#10529)
parent
5d138768e9
commit
8f2f377cb1
|
@ -179,7 +179,6 @@ pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
type_pos token.Position
|
type_pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
default_expr Expr
|
|
||||||
has_default_expr bool
|
has_default_expr bool
|
||||||
attrs []Attr
|
attrs []Attr
|
||||||
is_pub bool
|
is_pub bool
|
||||||
|
@ -187,6 +186,7 @@ pub:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
is_global bool
|
is_global bool
|
||||||
pub mut:
|
pub mut:
|
||||||
|
default_expr Expr
|
||||||
default_expr_typ Type
|
default_expr_typ Type
|
||||||
name string
|
name string
|
||||||
typ Type
|
typ Type
|
||||||
|
@ -283,12 +283,12 @@ pub mut:
|
||||||
|
|
||||||
pub struct StructInitField {
|
pub struct StructInitField {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
name_pos token.Position
|
name_pos token.Position
|
||||||
comments []Comment
|
comments []Comment
|
||||||
next_comments []Comment
|
next_comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
name string
|
name string
|
||||||
typ Type
|
typ Type
|
||||||
expected_type Type
|
expected_type Type
|
||||||
|
@ -449,9 +449,9 @@ pub struct CallArg {
|
||||||
pub:
|
pub:
|
||||||
is_mut bool
|
is_mut bool
|
||||||
share ShareType
|
share ShareType
|
||||||
expr Expr
|
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr
|
||||||
typ Type
|
typ Type
|
||||||
is_tmp_autofree bool // this tells cgen that a tmp variable has to be used for the arg expression in order to free it after the call
|
is_tmp_autofree bool // this tells cgen that a tmp variable has to be used for the arg expression in order to free it after the call
|
||||||
pos token.Position
|
pos token.Position
|
||||||
|
@ -462,9 +462,9 @@ pub mut:
|
||||||
pub struct Return {
|
pub struct Return {
|
||||||
pub:
|
pub:
|
||||||
pos token.Position
|
pos token.Position
|
||||||
exprs []Expr
|
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
|
exprs []Expr
|
||||||
types []Type
|
types []Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,13 +769,13 @@ pub mut:
|
||||||
|
|
||||||
pub struct MatchBranch {
|
pub struct MatchBranch {
|
||||||
pub:
|
pub:
|
||||||
exprs []Expr // left side
|
|
||||||
ecmnts [][]Comment // inline comments for each left side expr
|
ecmnts [][]Comment // inline comments for each left side expr
|
||||||
stmts []Stmt // right side
|
stmts []Stmt // right side
|
||||||
pos token.Position
|
pos token.Position
|
||||||
is_else bool
|
is_else bool
|
||||||
post_comments []Comment // comments below ´... }´
|
post_comments []Comment // comments below ´... }´
|
||||||
pub mut:
|
pub mut:
|
||||||
|
exprs []Expr // left side
|
||||||
scope &Scope
|
scope &Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,11 +1093,11 @@ pub:
|
||||||
// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
|
// `string(x,y)`, while skipping the real pointer casts like `&string(x)`.
|
||||||
pub struct CastExpr {
|
pub struct CastExpr {
|
||||||
pub:
|
pub:
|
||||||
expr Expr // `buf` in `string(buf, n)`
|
arg Expr // `n` in `string(buf, n)`
|
||||||
arg Expr // `n` in `string(buf, n)`
|
typ Type // `string` TODO rename to `type_to_cast_to`
|
||||||
typ Type // `string` TODO rename to `type_to_cast_to`
|
pos token.Position
|
||||||
pos token.Position
|
|
||||||
pub mut:
|
pub mut:
|
||||||
|
expr Expr // `buf` in `string(buf, n)`
|
||||||
typname string // TypeSymbol.name
|
typname string // TypeSymbol.name
|
||||||
expr_type Type // `byteptr`
|
expr_type Type // `byteptr`
|
||||||
has_arg bool
|
has_arg bool
|
||||||
|
|
|
@ -585,8 +585,17 @@ pub fn (mut c Checker) struct_decl(mut decl ast.StructDecl) {
|
||||||
}
|
}
|
||||||
struct_sym.info.fields[i].default_expr_typ = field_expr_type
|
struct_sym.info.fields[i].default_expr_typ = field_expr_type
|
||||||
c.check_expected(field_expr_type, field.typ) or {
|
c.check_expected(field_expr_type, field.typ) or {
|
||||||
if !(sym.kind == .interface_
|
if sym.kind == .interface_
|
||||||
&& c.type_implements(field_expr_type, field.typ, field.pos)) {
|
&& c.type_implements(field_expr_type, field.typ, field.pos) {
|
||||||
|
if !field_expr_type.is_ptr() && !field_expr_type.is_pointer()
|
||||||
|
&& !c.inside_unsafe {
|
||||||
|
field_expr_type_sym := c.table.get_type_symbol(field_expr_type)
|
||||||
|
if field_expr_type_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &decl.fields[i].default_expr,
|
||||||
|
true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
c.error('incompatible initializer for field `$field.name`: $err.msg',
|
c.error('incompatible initializer for field `$field.name`: $err.msg',
|
||||||
field.default_expr.position())
|
field.default_expr.position())
|
||||||
}
|
}
|
||||||
|
@ -793,7 +802,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut inited_fields := []string{}
|
mut inited_fields := []string{}
|
||||||
for i, field in node.fields {
|
for i, mut field in node.fields {
|
||||||
mut info_field := ast.StructField{}
|
mut info_field := ast.StructField{}
|
||||||
mut embed_type := ast.Type(0)
|
mut embed_type := ast.Type(0)
|
||||||
mut is_embed := false
|
mut is_embed := false
|
||||||
|
@ -865,7 +874,12 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||||
}
|
}
|
||||||
expr_type_sym := c.table.get_type_symbol(expr_type)
|
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||||
if field_type_sym.kind == .interface_ {
|
if field_type_sym.kind == .interface_ {
|
||||||
c.type_implements(expr_type, info_field.typ, field.pos)
|
if c.type_implements(expr_type, info_field.typ, field.pos) {
|
||||||
|
if !expr_type.is_ptr() && !expr_type.is_pointer()
|
||||||
|
&& expr_type_sym.kind != .interface_ && !c.inside_unsafe {
|
||||||
|
c.mark_as_referenced(mut &field.expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
} else if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
|
||||||
c.check_expected(expr_type, info_field.typ) or {
|
c.check_expected(expr_type, info_field.typ) or {
|
||||||
c.error('cannot assign to field `$info_field.name`: $err.msg',
|
c.error('cannot assign to field `$info_field.name`: $err.msg',
|
||||||
|
@ -1255,7 +1269,12 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
if left_value_sym.kind == .interface_ {
|
if left_value_sym.kind == .interface_ {
|
||||||
if right_final.kind != .array {
|
if right_final.kind != .array {
|
||||||
// []Animal << Cat
|
// []Animal << Cat
|
||||||
c.type_implements(right_type, left_value_type, right_pos)
|
if c.type_implements(right_type, left_value_type, right_pos) {
|
||||||
|
if !right_type.is_ptr() && !right_type.is_pointer() && !c.inside_unsafe
|
||||||
|
&& right_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &node.right, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// []Animal << []Cat
|
// []Animal << []Cat
|
||||||
c.type_implements(c.table.value_type(right_type), left_value_type,
|
c.type_implements(c.table.value_type(right_type), left_value_type,
|
||||||
|
@ -1903,7 +1922,7 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
// }
|
// }
|
||||||
// call_expr.args << method.args[0].typ
|
// call_expr.args << method.args[0].typ
|
||||||
// call_expr.exp_arg_types << method.args[0].typ
|
// call_expr.exp_arg_types << method.args[0].typ
|
||||||
for i, arg in call_expr.args {
|
for i, mut arg in call_expr.args {
|
||||||
if i > 0 || exp_arg_typ == ast.Type(0) {
|
if i > 0 || exp_arg_typ == ast.Type(0) {
|
||||||
exp_arg_typ = if method.is_variadic && i >= method.params.len - 1 {
|
exp_arg_typ = if method.is_variadic && i >= method.params.len - 1 {
|
||||||
method.params[method.params.len - 1].typ
|
method.params[method.params.len - 1].typ
|
||||||
|
@ -1933,7 +1952,14 @@ pub fn (mut c Checker) method_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
if final_arg_sym.kind == .interface_ {
|
if final_arg_sym.kind == .interface_ {
|
||||||
c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position())
|
if c.type_implements(got_arg_typ, exp_arg_typ, arg.expr.position()) {
|
||||||
|
if !got_arg_typ.is_ptr() && !got_arg_typ.is_pointer() && !c.inside_unsafe {
|
||||||
|
got_arg_typ_sym := c.table.get_type_symbol(got_arg_typ)
|
||||||
|
if got_arg_typ_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &arg.expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if method.generic_names.len > 0 {
|
if method.generic_names.len > 0 {
|
||||||
|
@ -2466,7 +2492,7 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
call_expr.expected_arg_types << param.typ
|
call_expr.expected_arg_types << param.typ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, call_arg in call_expr.args {
|
for i, mut call_arg in call_expr.args {
|
||||||
param := if func.is_variadic && i >= func.params.len - 1 {
|
param := if func.is_variadic && i >= func.params.len - 1 {
|
||||||
func.params[func.params.len - 1]
|
func.params[func.params.len - 1]
|
||||||
} else {
|
} else {
|
||||||
|
@ -2521,7 +2547,12 @@ pub fn (mut c Checker) fn_call(mut call_expr ast.CallExpr) ast.Type {
|
||||||
}
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
if final_param_sym.kind == .interface_ {
|
if final_param_sym.kind == .interface_ {
|
||||||
c.type_implements(typ, param.typ, call_arg.expr.position())
|
if c.type_implements(typ, param.typ, call_arg.expr.position()) {
|
||||||
|
if !typ.is_ptr() && !typ.is_pointer() && !c.inside_unsafe
|
||||||
|
&& typ_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &call_arg.expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.check_expected_call_arg(typ, c.unwrap_generic(param.typ), call_expr.language) or {
|
c.check_expected_call_arg(typ, c.unwrap_generic(param.typ), call_expr.language) or {
|
||||||
|
@ -3086,7 +3117,12 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if exp_typ_sym.kind == .interface_ {
|
if exp_typ_sym.kind == .interface_ {
|
||||||
c.type_implements(got_typ, exp_type, node.pos)
|
if c.type_implements(got_typ, exp_type, node.pos) {
|
||||||
|
if !got_typ.is_ptr() && !got_typ.is_pointer() && got_typ_sym.kind != .interface_
|
||||||
|
&& !c.inside_unsafe {
|
||||||
|
c.mark_as_referenced(mut &node.exprs[i], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
|
c.error('cannot use `$got_typ_sym.name` as type `${c.table.type_to_str(exp_type)}` in return argument',
|
||||||
|
@ -3653,7 +3689,12 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if left_sym.kind == .interface_ {
|
if left_sym.kind == .interface_ {
|
||||||
c.type_implements(right_type, left_type, right.position())
|
if c.type_implements(right_type, left_type, right.position()) {
|
||||||
|
if !right_type.is_ptr() && !right_type.is_pointer() && right_sym.kind != .interface_
|
||||||
|
&& !c.inside_unsafe {
|
||||||
|
c.mark_as_referenced(mut &node.right[i], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this needs to run after the assign stmt left exprs have been run through checker
|
// this needs to run after the assign stmt left exprs have been run through checker
|
||||||
|
@ -3812,7 +3853,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
// if expecting_interface_array {
|
// if expecting_interface_array {
|
||||||
// println('ex $c.expected_type')
|
// println('ex $c.expected_type')
|
||||||
// }
|
// }
|
||||||
for i, expr in array_init.exprs {
|
for i, mut expr in array_init.exprs {
|
||||||
typ := c.check_expr_opt_call(expr, c.expr(expr))
|
typ := c.check_expr_opt_call(expr, c.expr(expr))
|
||||||
array_init.expr_types << typ
|
array_init.expr_types << typ
|
||||||
// The first element's type
|
// The first element's type
|
||||||
|
@ -3822,6 +3863,12 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) ast.Type {
|
||||||
c.expected_type = elem_type
|
c.expected_type = elem_type
|
||||||
c.type_implements(typ, elem_type, expr.position())
|
c.type_implements(typ, elem_type, expr.position())
|
||||||
}
|
}
|
||||||
|
if !typ.is_ptr() && !typ.is_pointer() && !c.inside_unsafe {
|
||||||
|
typ_sym := c.table.get_type_symbol(typ)
|
||||||
|
if typ_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// The first element's type
|
// The first element's type
|
||||||
|
@ -5014,7 +5061,12 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
c.error('cannot cast `$type_name` to struct', node.pos)
|
c.error('cannot cast `$type_name` to struct', node.pos)
|
||||||
}
|
}
|
||||||
} else if to_type_sym.kind == .interface_ {
|
} else if to_type_sym.kind == .interface_ {
|
||||||
c.type_implements(node.expr_type, node.typ, node.pos)
|
if c.type_implements(node.expr_type, node.typ, node.pos) {
|
||||||
|
if !node.expr_type.is_ptr() && !node.expr_type.is_pointer()
|
||||||
|
&& from_type_sym.kind != .interface_ && !c.inside_unsafe {
|
||||||
|
c.mark_as_referenced(mut &node.expr, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if node.typ == ast.bool_type && !c.inside_unsafe {
|
} else if node.typ == ast.bool_type && !c.inside_unsafe {
|
||||||
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
||||||
} else if node.expr_type == ast.none_type && !node.typ.has_flag(.optional) {
|
} else if node.expr_type == ast.none_type && !node.typ.has_flag(.optional) {
|
||||||
|
@ -5529,7 +5581,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
||||||
for branch_i, _ in node.branches {
|
for branch_i, _ in node.branches {
|
||||||
mut branch := node.branches[branch_i]
|
mut branch := node.branches[branch_i]
|
||||||
mut expr_types := []ast.TypeNode{}
|
mut expr_types := []ast.TypeNode{}
|
||||||
for expr in branch.exprs {
|
for k, expr in branch.exprs {
|
||||||
mut key := ''
|
mut key := ''
|
||||||
if expr is ast.RangeExpr {
|
if expr is ast.RangeExpr {
|
||||||
mut low := i64(0)
|
mut low := i64(0)
|
||||||
|
@ -5599,7 +5651,14 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
||||||
// Current solution is to move expr.position() to its own statement
|
// Current solution is to move expr.position() to its own statement
|
||||||
// c.type_implements(expr_type, c.expected_type, expr.position())
|
// c.type_implements(expr_type, c.expected_type, expr.position())
|
||||||
expr_pos := expr.position()
|
expr_pos := expr.position()
|
||||||
c.type_implements(expr_type, c.expected_type, expr_pos)
|
if c.type_implements(expr_type, c.expected_type, expr_pos) {
|
||||||
|
if !expr_type.is_ptr() && !expr_type.is_pointer() && !c.inside_unsafe {
|
||||||
|
expr_type_sym := c.table.get_type_symbol(expr_type)
|
||||||
|
if expr_type_sym.kind != .interface_ {
|
||||||
|
c.mark_as_referenced(mut &branch.exprs[k], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if mut cond_type_sym.info is ast.SumType {
|
} else if mut cond_type_sym.info is ast.SumType {
|
||||||
if expr_type !in cond_type_sym.info.variants {
|
if expr_type !in cond_type_sym.info.variants {
|
||||||
expr_str := c.table.type_to_str(expr_type)
|
expr_str := c.table.type_to_str(expr_type)
|
||||||
|
@ -6388,7 +6447,7 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
|
pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr, as_interface bool) {
|
||||||
match mut node {
|
match mut node {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
if mut node.obj is ast.Var {
|
if mut node.obj is ast.Var {
|
||||||
|
@ -6404,7 +6463,12 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
|
||||||
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
||||||
}
|
}
|
||||||
if !c.pref.translated {
|
if !c.pref.translated {
|
||||||
c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
|
mischief := if as_interface {
|
||||||
|
'used as interface object'
|
||||||
|
} else {
|
||||||
|
'referenced'
|
||||||
|
}
|
||||||
|
c.error('`$node.name` cannot be $mischief outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
} else if type_sym.kind == .array_fixed {
|
} else if type_sym.kind == .array_fixed {
|
||||||
|
@ -6427,11 +6491,11 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
if !node.expr_type.is_ptr() {
|
if !node.expr_type.is_ptr() {
|
||||||
c.mark_as_referenced(mut &node.expr)
|
c.mark_as_referenced(mut &node.expr, as_interface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
c.mark_as_referenced(mut &node.left)
|
c.mark_as_referenced(mut &node.left, as_interface)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
|
@ -6496,12 +6560,12 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !c.inside_fn_arg && !c.inside_unsafe {
|
if !c.inside_fn_arg && !c.inside_unsafe {
|
||||||
c.mark_as_referenced(mut &node.right)
|
c.mark_as_referenced(mut &node.right, false)
|
||||||
}
|
}
|
||||||
return right_type.to_ptr()
|
return right_type.to_ptr()
|
||||||
} else if node.op == .amp && node.right !is ast.CastExpr {
|
} else if node.op == .amp && node.right !is ast.CastExpr {
|
||||||
if !c.inside_fn_arg && !c.inside_unsafe {
|
if !c.inside_fn_arg && !c.inside_unsafe {
|
||||||
c.mark_as_referenced(mut &node.right)
|
c.mark_as_referenced(mut &node.right, false)
|
||||||
}
|
}
|
||||||
if node.right.is_auto_deref_var() {
|
if node.right.is_auto_deref_var() {
|
||||||
return right_type
|
return right_type
|
||||||
|
|
|
@ -2422,7 +2422,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
is_auto_heap = left.obj.is_auto_heap
|
is_auto_heap = left.obj.is_auto_heap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
styp := if ident.name in g.defer_vars { '' } else { g.typ(var_type) }
|
styp := g.typ(var_type)
|
||||||
mut is_fixed_array_init := false
|
mut is_fixed_array_init := false
|
||||||
mut has_val := false
|
mut has_val := false
|
||||||
match val {
|
match val {
|
||||||
|
@ -2580,9 +2580,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
if is_inside_ternary {
|
if is_inside_ternary {
|
||||||
g.out.write_string(util.tabs(g.indent - g.inside_ternary))
|
g.out.write_string(util.tabs(g.indent - g.inside_ternary))
|
||||||
}
|
}
|
||||||
g.write('$styp ')
|
if ident.name !in g.defer_vars {
|
||||||
if is_auto_heap {
|
g.write('$styp ')
|
||||||
g.write('*')
|
if is_auto_heap {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if left is ast.Ident || left is ast.SelectorExpr {
|
if left is ast.Ident || left is ast.SelectorExpr {
|
||||||
|
|
|
@ -286,11 +286,17 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
|
||||||
if var.name in fargs || var.kind == .constant {
|
if var.name in fargs || var.kind == .constant {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if var.info is ast.IdentVar {
|
if var.kind == .variable {
|
||||||
info := var.info
|
|
||||||
if var.name !in g.defer_vars {
|
if var.name !in g.defer_vars {
|
||||||
g.defer_vars << var.name
|
g.defer_vars << var.name
|
||||||
g.writeln('${g.typ(info.typ)} $var.name;')
|
mut deref := ''
|
||||||
|
if v := var.scope.find_var(var.name) {
|
||||||
|
if v.is_auto_heap {
|
||||||
|
deref = '*'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info := var.obj as ast.Var
|
||||||
|
g.writeln('${g.typ(info.typ)}$deref $var.name;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
// declare interface
|
||||||
|
interface MyInterface {
|
||||||
|
val() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// define struct type
|
||||||
|
struct St {
|
||||||
|
mut:
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
// make the struct type implement the interface
|
||||||
|
fn (x St) val() int {
|
||||||
|
return x.n
|
||||||
|
}
|
||||||
|
|
||||||
|
fn owerwrite_stack() f64 {
|
||||||
|
a := 12.5
|
||||||
|
b := 3.5
|
||||||
|
c := a + b
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing special so far, but now some functions that return an interfaces
|
||||||
|
// these used to cause memory corruptions, but work with this PR:
|
||||||
|
fn gen_interface() MyInterface {
|
||||||
|
x := St{
|
||||||
|
n: -123
|
||||||
|
} // `x`will be allocated on heap
|
||||||
|
return x // because an interface object is returned here that contains the address of x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_interface(x St) MyInterface {
|
||||||
|
// x will be copied to stack (requires #10528)
|
||||||
|
return x // because it's address is returned inside the interface
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_gen_interface() {
|
||||||
|
i1 := gen_interface()
|
||||||
|
d := owerwrite_stack()
|
||||||
|
assert i1.val() == -123
|
||||||
|
assert d == 16.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_convert_to_interface() {
|
||||||
|
x := St{
|
||||||
|
n: 5
|
||||||
|
}
|
||||||
|
i2 := return_interface(x)
|
||||||
|
d := owerwrite_stack()
|
||||||
|
assert i2.val() == 5
|
||||||
|
assert d == 16.0
|
||||||
|
}
|
Loading…
Reference in New Issue