all: automatically move (some) referenced objects to heap (#9873)
parent
00261afbc1
commit
3c0a368af3
|
@ -400,7 +400,7 @@ fn draw_cube_glsl(app App) {
|
|||
0 /* padding 4 Bytes == 1 f32 */,
|
||||
]!
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &text_res
|
||||
ptr: unsafe { &text_res }
|
||||
size: size_t(4 * 4)
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
||||
|
|
|
@ -302,7 +302,7 @@ fn draw_cube_glsl(app App) {
|
|||
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||
]!
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &tmp_fs_params
|
||||
ptr: unsafe { &tmp_fs_params }
|
||||
size: size_t(sizeof(tmp_fs_params))
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
||||
|
|
|
@ -417,7 +417,7 @@ fn draw_cube_glsl_m(app App) {
|
|||
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||
]!
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &tmp_fs_params
|
||||
ptr: unsafe { &tmp_fs_params }
|
||||
size: size_t(sizeof(tmp_fs_params))
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &fs_uniforms_range)
|
||||
|
@ -469,7 +469,7 @@ fn draw_cube_glsl_p(app App) {
|
|||
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||
]!
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &tmp_fs_params
|
||||
ptr: unsafe { &tmp_fs_params }
|
||||
size: size_t(sizeof(tmp_fs_params))
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params_p, &fs_uniforms_range)
|
||||
|
|
|
@ -331,7 +331,7 @@ fn draw_cube_glsl_i(mut app App){
|
|||
app.inst_pos[index] = m4.Vec4{e:[f32((x - cx - app.camera_x) * cube_size),y ,f32( (z - cz - app.camera_z) * cube_size),spare_param]!}
|
||||
}
|
||||
range := C.sg_range{
|
||||
ptr: &app.inst_pos
|
||||
ptr: unsafe { &app.inst_pos }
|
||||
size: size_t(num_inst * int(sizeof(m4.Vec4)))
|
||||
}
|
||||
gfx.update_buffer(app.bind['inst'].vertex_buffers[1], &range )
|
||||
|
@ -341,7 +341,7 @@ fn draw_cube_glsl_i(mut app App){
|
|||
// passing the view matrix as uniform
|
||||
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
|
||||
vs_uniforms_range := C.sg_range{
|
||||
ptr: &tr_matrix
|
||||
ptr: unsafe { &tr_matrix }
|
||||
size: size_t(4 * 16)
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_i, &vs_uniforms_range)
|
||||
|
@ -359,7 +359,7 @@ fn draw_cube_glsl_i(mut app App){
|
|||
0,0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||
]!
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &tmp_fs_params
|
||||
ptr: unsafe { &tmp_fs_params }
|
||||
size: size_t(sizeof(tmp_fs_params))
|
||||
}
|
||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
||||
|
|
|
@ -235,7 +235,7 @@ pub fn (obj_part ObjPart) bind_and_draw(rend_data_index int, in_data Shader_data
|
|||
size: size_t(in_data.vs_len)
|
||||
}
|
||||
fs_uniforms_range := C.sg_range{
|
||||
ptr: &tmp_fs_params
|
||||
ptr: unsafe { &tmp_fs_params }
|
||||
size: size_t(in_data.fs_len)
|
||||
}
|
||||
|
||||
|
|
|
@ -153,9 +153,9 @@ fn draw_model(app App, model_pos m4.Vec4) u32 {
|
|||
tmp_fs_params.ligth = m4.vec3(x_light, radius_light, z_light)
|
||||
|
||||
sd := obj.Shader_data{
|
||||
vs_data: &tmp_vs_param
|
||||
vs_data: unsafe { &tmp_vs_param }
|
||||
vs_len: int(sizeof(tmp_vs_param))
|
||||
fs_data: &tmp_fs_params
|
||||
fs_data: unsafe { &tmp_fs_params }
|
||||
fs_len: int(sizeof(tmp_fs_params))
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ fn (mut p Player) update() {
|
|||
return
|
||||
}
|
||||
// dt := p.game.app.dt
|
||||
ball := &p.game.ball
|
||||
ball := unsafe { &p.game.ball }
|
||||
// Evil AI that eventually will take over the world
|
||||
p.pos.y = ball.pos.y - int(f32(p.racket_size) * 0.5)
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ mut:
|
|||
}
|
||||
|
||||
fn (mut g Game) move_player(id int, x int, y int) {
|
||||
mut p := &g.players[id]
|
||||
mut p := unsafe { &g.players[id] }
|
||||
if p.ai { // disable AI when moved
|
||||
p.ai = false
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ fn (mut g Game) new_round() {
|
|||
|
||||
fn (mut g Game) update() {
|
||||
dt := g.app.dt
|
||||
mut b := &g.ball
|
||||
mut b := unsafe { &g.ball }
|
||||
for mut p in g.players {
|
||||
p.update()
|
||||
// Keep rackets within the game area
|
||||
|
|
|
@ -53,7 +53,7 @@ fn draw_frame(mut app App_data) {
|
|||
sgl.v2f(510, 400)
|
||||
sgl.end()
|
||||
// update the text
|
||||
mut txt1 := &app.ttf_render[0]
|
||||
mut txt1 := unsafe { &app.ttf_render[0] }
|
||||
if app.frame_c % 2 == 0 {
|
||||
txt1.destroy_texture()
|
||||
txt1.create_text(cframe_txt, 43)
|
||||
|
@ -71,7 +71,7 @@ Frame: $app.frame_c
|
|||
But Vwill prevail for sure, V is the way!!
|
||||
òàèì@ò!£$%&
|
||||
"
|
||||
txt1 = &app.ttf_render[1]
|
||||
txt1 = unsafe { &app.ttf_render[1] }
|
||||
if app.frame_c % 2 == 0 {
|
||||
txt1.bmp.justify = false
|
||||
if (app.frame_c >> 6) % 2 == 0 {
|
||||
|
@ -93,7 +93,7 @@ But Vwill prevail for sure, V is the way!!
|
|||
txt1.draw_text_bmp(app.gg, 30 + (app.frame_c >> 1) & 0xFF, 200)
|
||||
// draw mouse position
|
||||
if app.mouse_x >= 0 {
|
||||
txt1 = &app.ttf_render[2]
|
||||
txt1 = unsafe { &app.ttf_render[2] }
|
||||
txt1.destroy_texture()
|
||||
txt1.create_text('$app.mouse_x,$app.mouse_y', 25)
|
||||
txt1.create_texture()
|
||||
|
|
|
@ -35,7 +35,7 @@ fn print_help_for_command(help_cmd Command) ? {
|
|||
mut found := false
|
||||
for sub_cmd in cmd.commands {
|
||||
if sub_cmd.name == arg {
|
||||
cmd = &sub_cmd
|
||||
cmd = unsafe { &sub_cmd }
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ pub fn (mut ctx CancelContext) err() IError {
|
|||
|
||||
pub fn (ctx CancelContext) value(key string) ?voidptr {
|
||||
if key == cancel_context_key {
|
||||
return voidptr(&ctx)
|
||||
return voidptr(unsafe { &ctx })
|
||||
}
|
||||
return ctx.context.value(key)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ fn (req &Request) ssl_do(port int, method Method, host_name string, path string)
|
|||
C.BIO_puts(web, &char(req_headers.str))
|
||||
mut content := strings.new_builder(100)
|
||||
mut buff := [bufsize]byte{}
|
||||
bp := &buff[0]
|
||||
bp := unsafe { &buff[0] }
|
||||
mut readcounter := 0
|
||||
for {
|
||||
readcounter++
|
||||
|
|
|
@ -571,19 +571,19 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||
mut sem := unsafe { Semaphore{} }
|
||||
sem.init(0)
|
||||
for i, ch in channels {
|
||||
subscr[i].sem = &sem
|
||||
subscr[i].sem = unsafe { &sem }
|
||||
if dir[i] == .push {
|
||||
mut null16 := u16(0)
|
||||
for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) {
|
||||
null16 = u16(0)
|
||||
}
|
||||
subscr[i].prev = &ch.write_subscriber
|
||||
subscr[i].prev = unsafe { &ch.write_subscriber }
|
||||
unsafe {
|
||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
||||
&subscr[i])
|
||||
}
|
||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
||||
subscr[i].nxt.prev = &subscr[i].nxt
|
||||
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
||||
}
|
||||
C.atomic_store_u16(&ch.write_sub_mtx, u16(0))
|
||||
} else {
|
||||
|
@ -591,13 +591,13 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
|||
for !C.atomic_compare_exchange_weak_u16(&ch.read_sub_mtx, &null16, u16(1)) {
|
||||
null16 = u16(0)
|
||||
}
|
||||
subscr[i].prev = &ch.read_subscriber
|
||||
subscr[i].prev = unsafe { &ch.read_subscriber }
|
||||
unsafe {
|
||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.read_subscriber),
|
||||
&subscr[i])
|
||||
}
|
||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
||||
subscr[i].nxt.prev = &subscr[i].nxt
|
||||
subscr[i].nxt.prev = unsafe { &subscr[i].nxt }
|
||||
}
|
||||
C.atomic_store_u16(&ch.read_sub_mtx, u16(0))
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ fn (mut ctx Context) shift(len int) {
|
|||
// TODO: don't actually do this, lmao
|
||||
[inline]
|
||||
fn (mut ctx Context) resize_arr(size int) {
|
||||
mut l := &ctx.read_buf.len
|
||||
mut l := unsafe { &ctx.read_buf.len }
|
||||
unsafe {
|
||||
*l = size
|
||||
_ = l
|
||||
|
|
|
@ -493,8 +493,11 @@ pub mut:
|
|||
is_changed bool // to detect mutable vars that are never changed
|
||||
//
|
||||
// (for setting the position after the or block for autofree)
|
||||
is_or bool // `x := foo() or { ... }`
|
||||
is_tmp bool // for tmp for loop vars, so that autofree can skip them
|
||||
is_or bool // `x := foo() or { ... }`
|
||||
is_tmp bool // for tmp for loop vars, so that autofree can skip them
|
||||
is_auto_heap bool // value whoes address goes out of scope
|
||||
is_heap_ref bool // *known* to be pointer to heap memory (ptr to [heap] struct)
|
||||
is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct)
|
||||
}
|
||||
|
||||
// used for smartcasting only
|
||||
|
|
|
@ -7,6 +7,7 @@ import v.cflag
|
|||
import v.token
|
||||
import v.util
|
||||
|
||||
[heap]
|
||||
pub struct Table {
|
||||
pub mut:
|
||||
type_symbols []TypeSymbol
|
||||
|
|
|
@ -61,6 +61,7 @@ pub mut:
|
|||
inside_const bool
|
||||
inside_anon_fn bool
|
||||
inside_ref_lit bool
|
||||
inside_fn_arg bool // `a`, `b` in `a.f(b)`
|
||||
skip_flags bool // should `#flag` and `#include` be skipped
|
||||
mut:
|
||||
files []ast.File
|
||||
|
@ -1318,7 +1319,10 @@ pub fn (mut c Checker) call_expr(mut call_expr ast.CallExpr) ast.Type {
|
|||
}
|
||||
*/
|
||||
// Now call `method_call` or `fn_call` for specific checks.
|
||||
old_inside_fn_arg := c.inside_fn_arg
|
||||
c.inside_fn_arg = true
|
||||
typ := if call_expr.is_method { c.method_call(mut call_expr) } else { c.fn_call(mut call_expr) }
|
||||
c.inside_fn_arg = old_inside_fn_arg
|
||||
// autofree: mark args that have to be freed (after saving them in tmp exprs)
|
||||
free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && call_expr.args.len > 0
|
||||
&& !call_expr.args[0].typ.has_flag(.optional)
|
||||
|
@ -3564,7 +3568,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
|||
ast.DeferStmt {
|
||||
if node.idx_in_fn < 0 {
|
||||
node.idx_in_fn = c.cur_fn.defer_stmts.len
|
||||
c.cur_fn.defer_stmts << &node
|
||||
c.cur_fn.defer_stmts << unsafe { &node }
|
||||
}
|
||||
c.stmts(node.stmts)
|
||||
}
|
||||
|
@ -4176,7 +4180,7 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
|
|||
ast.AnonFn {
|
||||
c.inside_anon_fn = true
|
||||
keep_fn := c.cur_fn
|
||||
c.cur_fn = &node.decl
|
||||
c.cur_fn = unsafe { &node.decl }
|
||||
c.stmts(node.decl.stmts)
|
||||
c.fn_decl(mut node.decl)
|
||||
c.cur_fn = keep_fn
|
||||
|
@ -5014,6 +5018,24 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
|||
// node.expected_type = c.expected_type
|
||||
// }
|
||||
node.return_type = ret_type
|
||||
cond_var := c.get_base_name(&node.cond)
|
||||
if cond_var != '' {
|
||||
mut cond_is_auto_heap := false
|
||||
for branch in node.branches {
|
||||
if v := branch.scope.find_var(cond_var) {
|
||||
if v.is_auto_heap {
|
||||
cond_is_auto_heap = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if cond_is_auto_heap {
|
||||
for branch in node.branches {
|
||||
mut v := branch.scope.find_var(cond_var) or { continue }
|
||||
v.is_auto_heap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret_type
|
||||
}
|
||||
|
||||
|
@ -5830,6 +5852,53 @@ pub fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
|
|||
return typ
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) {
|
||||
match mut node {
|
||||
ast.Ident {
|
||||
if mut node.obj is ast.Var {
|
||||
mut obj := unsafe { &node.obj }
|
||||
if c.fn_scope != voidptr(0) {
|
||||
obj = c.fn_scope.find_var(node.obj.name) or { unsafe { &node.obj } }
|
||||
}
|
||||
type_sym := c.table.get_type_symbol(obj.typ)
|
||||
if obj.is_stack_obj {
|
||||
c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider declaring `$type_sym.name` as `[heap]`.',
|
||||
node.pos)
|
||||
} else if type_sym.kind == .array_fixed {
|
||||
c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack',
|
||||
node.pos)
|
||||
} else {
|
||||
node.obj.is_auto_heap = true
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
c.mark_as_referenced(mut &node.expr)
|
||||
}
|
||||
ast.IndexExpr {
|
||||
c.mark_as_referenced(mut &node.left)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) get_base_name(node &ast.Expr) string {
|
||||
match node {
|
||||
ast.Ident {
|
||||
return node.name
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
return c.get_base_name(&node.expr)
|
||||
}
|
||||
ast.IndexExpr {
|
||||
return c.get_base_name(&node.left)
|
||||
}
|
||||
else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
||||
old_inside_ref_lit := c.inside_ref_lit
|
||||
c.inside_ref_lit = c.inside_ref_lit || node.op == .amp
|
||||
|
@ -5871,9 +5940,19 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
|||
}
|
||||
}
|
||||
}
|
||||
if !c.inside_fn_arg && !c.inside_unsafe {
|
||||
c.mark_as_referenced(mut &node.right)
|
||||
}
|
||||
return right_type.to_ptr()
|
||||
} else if node.op == .amp && node.right !is ast.CastExpr {
|
||||
return right_type.to_ptr()
|
||||
if !c.inside_fn_arg && !c.inside_unsafe {
|
||||
c.mark_as_referenced(mut &node.right)
|
||||
}
|
||||
if node.right.is_auto_deref_var() {
|
||||
return right_type
|
||||
} else {
|
||||
return right_type.to_ptr()
|
||||
}
|
||||
}
|
||||
if node.op == .mul {
|
||||
if right_type.is_ptr() {
|
||||
|
|
|
@ -3,6 +3,13 @@ vlib/v/checker/tests/function_missing_return_type.vv:1:1: error: missing return
|
|||
| ~~~~~~~~~~
|
||||
2 | }
|
||||
3 |
|
||||
vlib/v/checker/tests/function_missing_return_type.vv:14:11: error: `s` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider declaring `Abc` as `[heap]`.
|
||||
12 | fn (s Abc) abc() &int {
|
||||
13 | if true {
|
||||
14 | return &s.x
|
||||
| ^
|
||||
15 | }
|
||||
16 | s.panic(@FN)
|
||||
vlib/v/checker/tests/function_missing_return_type.vv:12:1: error: missing return at end of function `abc`
|
||||
10 | }
|
||||
11 |
|
||||
|
|
|
@ -147,7 +147,7 @@ pub struct RemoveNewLineConfig {
|
|||
}
|
||||
|
||||
pub fn (mut f Fmt) remove_new_line(cfg RemoveNewLineConfig) {
|
||||
mut buffer := if cfg.imports_buffer { &f.out_imports } else { &f.out }
|
||||
mut buffer := if cfg.imports_buffer { unsafe { &f.out_imports } } else { unsafe { &f.out } }
|
||||
mut i := 0
|
||||
for i = buffer.len - 1; i >= 0; i-- {
|
||||
if !buffer.buf[i].is_space() { // != `\n` {
|
||||
|
|
|
@ -2145,21 +2145,36 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.expr(assign_stmt.right[0])
|
||||
g.writeln(';')
|
||||
for i, lx in assign_stmt.left {
|
||||
mut is_auto_heap := false
|
||||
if lx is ast.Ident {
|
||||
if lx.kind == .blank_ident {
|
||||
continue
|
||||
}
|
||||
if lx.obj is ast.Var {
|
||||
is_auto_heap = lx.obj.is_auto_heap
|
||||
}
|
||||
}
|
||||
styp := g.typ(assign_stmt.left_types[i])
|
||||
if assign_stmt.op == .decl_assign {
|
||||
g.write('$styp ')
|
||||
if is_auto_heap {
|
||||
g.write('*')
|
||||
}
|
||||
}
|
||||
g.expr(lx)
|
||||
if is_opt {
|
||||
mr_base_styp := g.base_type(return_type)
|
||||
g.writeln(' = (*($mr_base_styp*)${mr_var_name}.data).arg$i;')
|
||||
if is_auto_heap {
|
||||
g.writeln(' = HEAP($mr_base_styp, *($mr_base_styp*)${mr_var_name}.data).arg$i);')
|
||||
} else {
|
||||
g.writeln(' = (*($mr_base_styp*)${mr_var_name}.data).arg$i;')
|
||||
}
|
||||
} else {
|
||||
g.writeln(' = ${mr_var_name}.arg$i;')
|
||||
if is_auto_heap {
|
||||
g.writeln(' = HEAP($styp, ${mr_var_name}.arg$i);')
|
||||
} else {
|
||||
g.writeln(' = ${mr_var_name}.arg$i;')
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -2256,6 +2271,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
}
|
||||
// `a := 1` | `a,b := 1,2`
|
||||
for i, left in assign_stmt.left {
|
||||
mut is_auto_heap := false
|
||||
mut var_type := assign_stmt.left_types[i]
|
||||
mut val_type := assign_stmt.right_types[i]
|
||||
val := assign_stmt.right[i]
|
||||
|
@ -2281,6 +2297,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
var_type = var_type.set_flag(.atomic_f)
|
||||
}
|
||||
}
|
||||
if left.obj is ast.Var {
|
||||
is_auto_heap = left.obj.is_auto_heap
|
||||
}
|
||||
}
|
||||
styp := g.typ(var_type)
|
||||
mut is_fixed_array_init := false
|
||||
|
@ -2432,6 +2451,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.out.write_string(util.tabs(g.indent - g.inside_ternary))
|
||||
}
|
||||
g.write('$styp ')
|
||||
if is_auto_heap {
|
||||
g.write('*')
|
||||
}
|
||||
}
|
||||
if left is ast.Ident || left is ast.SelectorExpr {
|
||||
g.prevent_sum_type_unwrapping_once = true
|
||||
|
@ -2511,10 +2533,16 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
g.write('{0}')
|
||||
}
|
||||
} else {
|
||||
if is_auto_heap {
|
||||
g.write('HEAP($styp, (')
|
||||
}
|
||||
if val.is_auto_deref_var() {
|
||||
g.write('*')
|
||||
}
|
||||
g.expr(val)
|
||||
if is_auto_heap {
|
||||
g.write('))')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if assign_stmt.has_cross_var {
|
||||
|
@ -2842,9 +2870,9 @@ fn (mut g Gen) map_fn_ptrs(key_typ ast.TypeSymbol) (string, string, string, stri
|
|||
}
|
||||
.voidptr {
|
||||
ts := if g.pref.m64 {
|
||||
&g.table.type_symbols[ast.u64_type_idx]
|
||||
unsafe { &g.table.type_symbols[ast.u64_type_idx] }
|
||||
} else {
|
||||
&g.table.type_symbols[ast.u32_type_idx]
|
||||
unsafe { &g.table.type_symbols[ast.u32_type_idx] }
|
||||
}
|
||||
return g.map_fn_ptrs(ts)
|
||||
}
|
||||
|
@ -3123,7 +3151,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
}
|
||||
} else {
|
||||
// g.write('/*pref*/')
|
||||
g.write(node.op.str())
|
||||
if !(g.is_amp && node.right.is_auto_deref_var()) {
|
||||
g.write(node.op.str())
|
||||
}
|
||||
// g.write('(')
|
||||
g.expr(node.right)
|
||||
}
|
||||
|
@ -4355,6 +4385,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
mut name := c_name(node.name)
|
||||
// TODO: temporary, remove this
|
||||
node_info := node.info
|
||||
mut is_auto_heap := false
|
||||
if node_info is ast.IdentVar {
|
||||
// x ?int
|
||||
// `x = 10` => `x.data = 10` (g.right_is_opt == false)
|
||||
|
@ -4372,12 +4403,16 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
}
|
||||
scope := g.file.scope.innermost(node.pos.pos)
|
||||
if v := scope.find_var(node.name) {
|
||||
is_auto_heap = v.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign)
|
||||
if is_auto_heap {
|
||||
g.write('(*(')
|
||||
}
|
||||
if v.smartcasts.len > 0 {
|
||||
v_sym := g.table.get_type_symbol(v.typ)
|
||||
if !prevent_sum_type_unwrapping_once {
|
||||
for _ in v.smartcasts {
|
||||
g.write('(')
|
||||
if v_sym.kind == .sum_type {
|
||||
if v_sym.kind == .sum_type && !is_auto_heap {
|
||||
g.write('*')
|
||||
}
|
||||
}
|
||||
|
@ -4390,7 +4425,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
is_ptr = true
|
||||
}
|
||||
}
|
||||
dot := if is_ptr { '->' } else { '.' }
|
||||
dot := if is_ptr || is_auto_heap { '->' } else { '.' }
|
||||
if mut cast_sym.info is ast.Aggregate {
|
||||
sym := g.table.get_type_symbol(cast_sym.info.types[g.aggregate_type_idx])
|
||||
g.write('${dot}_$sym.cname')
|
||||
|
@ -4399,6 +4434,9 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
}
|
||||
g.write(')')
|
||||
}
|
||||
if is_auto_heap {
|
||||
g.write('))')
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -4413,6 +4451,9 @@ fn (mut g Gen) ident(node ast.Ident) {
|
|||
}
|
||||
}
|
||||
g.write(g.get_ternary_name(name))
|
||||
if is_auto_heap {
|
||||
g.write('))')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) cast_expr(node ast.CastExpr) {
|
||||
|
@ -4623,7 +4664,18 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|||
g.expr(branch.cond.expr)
|
||||
g.writeln(';')
|
||||
} else {
|
||||
g.writeln('\t$base_type $branch.cond.var_name = *($base_type*)${var_name}.data;')
|
||||
mut is_auto_heap := false
|
||||
if branch.stmts.len > 0 {
|
||||
scope := g.file.scope.innermost(ast.Node(branch.stmts[branch.stmts.len - 1]).position().pos)
|
||||
if v := scope.find_var(branch.cond.var_name) {
|
||||
is_auto_heap = v.is_auto_heap
|
||||
}
|
||||
}
|
||||
if is_auto_heap {
|
||||
g.writeln('\t$base_type* $branch.cond.var_name = HEAP($base_type, *($base_type*)${var_name}.data);')
|
||||
} else {
|
||||
g.writeln('\t$base_type $branch.cond.var_name = *($base_type*)${var_name}.data;')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,9 @@ fn (mut g Gen) process_fn_decl(node ast.FnDecl) {
|
|||
}
|
||||
}
|
||||
keep_fn_decl := g.fn_decl
|
||||
g.fn_decl = &node
|
||||
unsafe {
|
||||
g.fn_decl = &node
|
||||
}
|
||||
if node.name == 'main.main' {
|
||||
g.has_main = true
|
||||
}
|
||||
|
|
|
@ -387,7 +387,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
|||
g.gen_expr_stmt(node)
|
||||
}
|
||||
ast.FnDecl {
|
||||
g.fn_decl = &node
|
||||
g.fn_decl = unsafe { &node }
|
||||
g.gen_fn_decl(node)
|
||||
}
|
||||
ast.ForCStmt {
|
||||
|
@ -813,7 +813,9 @@ fn fn_has_go(node ast.FnDecl) bool {
|
|||
}
|
||||
|
||||
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||
g.fn_decl = &it
|
||||
unsafe {
|
||||
g.fn_decl = &it
|
||||
}
|
||||
has_go := fn_has_go(it)
|
||||
is_main := it.name == 'main.main'
|
||||
g.gen_attrs(it.attrs)
|
||||
|
|
|
@ -152,6 +152,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
|
|||
share: share
|
||||
is_mut: lx.is_mut || p.inside_for
|
||||
pos: lx.pos
|
||||
is_stack_obj: p.inside_for
|
||||
}
|
||||
if p.pref.autofree {
|
||||
if r0 is ast.CallExpr {
|
||||
|
|
|
@ -291,11 +291,28 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
|||
scope: 0
|
||||
}
|
||||
}
|
||||
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
|
||||
mut is_stack_obj := true
|
||||
nr_muls := param.typ.nr_muls()
|
||||
if nr_muls == 1 { // mut a St, b &St
|
||||
base_type_sym := p.table.get_type_symbol(param.typ.set_nr_muls(0))
|
||||
if base_type_sym.kind == .struct_ {
|
||||
info := base_type_sym.info as ast.Struct
|
||||
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
|
||||
is_stack_obj = !is_heap_ref
|
||||
}
|
||||
}
|
||||
if param.typ.has_flag(.shared_f) {
|
||||
is_heap_ref = true
|
||||
is_stack_obj = false
|
||||
}
|
||||
p.scope.register(ast.Var{
|
||||
name: param.name
|
||||
typ: param.typ
|
||||
is_mut: param.is_mut
|
||||
is_auto_deref: param.is_mut || param.is_auto_rec
|
||||
is_heap_ref: is_heap_ref
|
||||
is_stack_obj: is_stack_obj
|
||||
pos: param.pos
|
||||
is_used: true
|
||||
is_arg: true
|
||||
|
@ -580,6 +597,21 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
|||
if arg.name.len == 0 {
|
||||
p.error_with_pos('use `_` to name an unused parameter', arg.pos)
|
||||
}
|
||||
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
|
||||
mut is_stack_obj := true
|
||||
nr_muls := arg.typ.nr_muls()
|
||||
if nr_muls == 1 { // mut a St, b &St
|
||||
base_type_sym := p.table.get_type_symbol(arg.typ.set_nr_muls(0))
|
||||
if base_type_sym.kind == .struct_ {
|
||||
info := base_type_sym.info as ast.Struct
|
||||
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
|
||||
is_stack_obj = !is_heap_ref
|
||||
}
|
||||
}
|
||||
if arg.typ.has_flag(.shared_f) {
|
||||
is_heap_ref = true
|
||||
is_stack_obj = false
|
||||
}
|
||||
p.scope.register(ast.Var{
|
||||
name: arg.name
|
||||
typ: arg.typ
|
||||
|
@ -587,6 +619,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
|||
pos: arg.pos
|
||||
is_used: true
|
||||
is_arg: true
|
||||
is_heap_ref: is_heap_ref
|
||||
is_stack_obj: is_stack_obj
|
||||
})
|
||||
}
|
||||
mut same_line := p.tok.line_nr == p.prev_tok.line_nr
|
||||
|
|
|
@ -122,6 +122,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
|
|||
typ: ast.int_type
|
||||
pos: key_var_pos
|
||||
is_tmp: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
} else if p.scope.known_var(val_var_name) {
|
||||
return p.error('redefinition of value iteration variable `$val_var_name`')
|
||||
|
@ -146,6 +147,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
|
|||
typ: ast.int_type
|
||||
pos: val_var_pos
|
||||
is_tmp: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
if key_var_name.len > 0 {
|
||||
return p.error_with_pos('cannot declare index variable with range `for`',
|
||||
|
@ -159,6 +161,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
|
|||
is_mut: val_is_mut
|
||||
is_auto_deref: val_is_mut
|
||||
is_tmp: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
}
|
||||
p.inside_for = false
|
||||
|
|
|
@ -54,6 +54,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
|
|||
typ: ast.error_type
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
}
|
||||
branches << ast.IfBranch{
|
||||
|
|
|
@ -2258,6 +2258,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
|||
typ: ast.error_type
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
or_kind = .block
|
||||
or_stmts = p.parse_block_no_scope(false)
|
||||
|
|
|
@ -471,6 +471,7 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
|
|||
typ: ast.error_type
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
or_kind = .block
|
||||
or_stmts = p.parse_block_no_scope(false)
|
||||
|
@ -553,6 +554,7 @@ fn (mut p Parser) prefix_expr() ast.PrefixExpr {
|
|||
typ: ast.error_type
|
||||
pos: p.tok.position()
|
||||
is_used: true
|
||||
is_stack_obj: true
|
||||
})
|
||||
or_kind = .block
|
||||
or_stmts = p.parse_block_no_scope(false)
|
||||
|
|
|
@ -18,7 +18,7 @@ fn (mut p Player) set_position(x int, y int) &Player {
|
|||
// TODO: from the point of view of the V programmer,
|
||||
// `p` has still type &Player.
|
||||
// assert typeof(p).name == 'Player'
|
||||
return &p
|
||||
return unsafe { &p }
|
||||
}
|
||||
|
||||
fn test_mut_receiver() {
|
||||
|
|
|
@ -268,7 +268,7 @@ mut:
|
|||
}
|
||||
|
||||
fn foo4(mut f Foo) {
|
||||
f2 := &f
|
||||
f2 := unsafe { &f }
|
||||
f.foo = 100
|
||||
println(f.foo)
|
||||
println(f2.foo)
|
||||
|
@ -284,7 +284,7 @@ fn test_mut_13() {
|
|||
}
|
||||
|
||||
fn foo5(mut arr []int) {
|
||||
arr2 := &arr
|
||||
arr2 := unsafe { &arr }
|
||||
arr[0] = 0
|
||||
println(arr[0]) // 0
|
||||
assert arr[0] == 0
|
||||
|
@ -300,7 +300,7 @@ fn test_mut_14() {
|
|||
}
|
||||
|
||||
fn foo6(mut arr [3]int) {
|
||||
arr2 := &arr
|
||||
arr2 := unsafe { &arr }
|
||||
arr[0] = 0
|
||||
println(arr[0]) // 0
|
||||
assert arr[0] == 0
|
||||
|
@ -316,7 +316,7 @@ fn test_mut_15() {
|
|||
}
|
||||
|
||||
fn foo7(mut m map[string]int) {
|
||||
m2 := &m
|
||||
m2 := unsafe { &m }
|
||||
m['one'] = 1
|
||||
println(m['one']) // 1
|
||||
assert m['one'] == 1
|
||||
|
|
|
@ -48,8 +48,8 @@ fn test_ptr_arithmetic_over_struct() {
|
|||
a[0].x = 10
|
||||
a[1].x = 100
|
||||
a[2].x = 1000
|
||||
mut pa := &a[0]
|
||||
assert pa == &a[0]
|
||||
mut pa := unsafe { &a[0] }
|
||||
assert pa == unsafe { &a[0] }
|
||||
unsafe {
|
||||
assert pa.x == 10
|
||||
pa++
|
||||
|
@ -66,5 +66,5 @@ fn test_ptr_arithmetic_over_struct() {
|
|||
assert pa.x == 1000
|
||||
pa -= 2
|
||||
}
|
||||
assert pa == &a[0]
|
||||
assert pa == unsafe { &a[0] }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
struct Qwe {
|
||||
mut:
|
||||
a f64
|
||||
}
|
||||
|
||||
fn f() &Qwe {
|
||||
q := Qwe{
|
||||
a: 12.5
|
||||
}
|
||||
return &q
|
||||
}
|
||||
|
||||
fn g() f64 {
|
||||
a := -0.125
|
||||
b := 3
|
||||
c := a * b
|
||||
return c
|
||||
}
|
||||
|
||||
fn test_reference_return() {
|
||||
x := f()
|
||||
y := g()
|
||||
assert x.a == 12.5
|
||||
assert y == -0.375
|
||||
}
|
|
@ -15,7 +15,7 @@ fn memcpy(mut dest voidptr, src voidptr, len u32) voidptr {
|
|||
fn test_mut_voidptr_arg() {
|
||||
mut a := [1, 2]!
|
||||
b := [3, 4]!
|
||||
mut aptr := voidptr(&a[0])
|
||||
mut aptr := voidptr(unsafe { &a[0] })
|
||||
unsafe { memcpy(mut aptr, &b[0], sizeof(int)) }
|
||||
assert a == [3, 2]!
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue