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 */,
|
0 /* padding 4 Bytes == 1 f32 */,
|
||||||
]!
|
]!
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &text_res
|
ptr: unsafe { &text_res }
|
||||||
size: size_t(4 * 4)
|
size: size_t(4 * 4)
|
||||||
}
|
}
|
||||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
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
|
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||||
]!
|
]!
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &tmp_fs_params
|
ptr: unsafe { &tmp_fs_params }
|
||||||
size: size_t(sizeof(tmp_fs_params))
|
size: size_t(sizeof(tmp_fs_params))
|
||||||
}
|
}
|
||||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
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
|
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||||
]!
|
]!
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &tmp_fs_params
|
ptr: unsafe { &tmp_fs_params }
|
||||||
size: size_t(sizeof(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)
|
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
|
0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||||
]!
|
]!
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &tmp_fs_params
|
ptr: unsafe { &tmp_fs_params }
|
||||||
size: size_t(sizeof(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)
|
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]!}
|
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{
|
range := C.sg_range{
|
||||||
ptr: &app.inst_pos
|
ptr: unsafe { &app.inst_pos }
|
||||||
size: size_t(num_inst * int(sizeof(m4.Vec4)))
|
size: size_t(num_inst * int(sizeof(m4.Vec4)))
|
||||||
}
|
}
|
||||||
gfx.update_buffer(app.bind['inst'].vertex_buffers[1], &range )
|
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
|
// passing the view matrix as uniform
|
||||||
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
|
// res is a 4x4 matrix of f32 thus: 4*16 byte of size
|
||||||
vs_uniforms_range := C.sg_range{
|
vs_uniforms_range := C.sg_range{
|
||||||
ptr: &tr_matrix
|
ptr: unsafe { &tr_matrix }
|
||||||
size: size_t(4 * 16)
|
size: size_t(4 * 16)
|
||||||
}
|
}
|
||||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_VS, C.SLOT_vs_params_i, &vs_uniforms_range)
|
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
|
0,0 // padding bytes , see "fs_params" struct paddings in rt_glsl.h
|
||||||
]!
|
]!
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &tmp_fs_params
|
ptr: unsafe { &tmp_fs_params }
|
||||||
size: size_t(sizeof(tmp_fs_params))
|
size: size_t(sizeof(tmp_fs_params))
|
||||||
}
|
}
|
||||||
gfx.apply_uniforms(C.SG_SHADERSTAGE_FS, C.SLOT_fs_params, &fs_uniforms_range)
|
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)
|
size: size_t(in_data.vs_len)
|
||||||
}
|
}
|
||||||
fs_uniforms_range := C.sg_range{
|
fs_uniforms_range := C.sg_range{
|
||||||
ptr: &tmp_fs_params
|
ptr: unsafe { &tmp_fs_params }
|
||||||
size: size_t(in_data.fs_len)
|
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)
|
tmp_fs_params.ligth = m4.vec3(x_light, radius_light, z_light)
|
||||||
|
|
||||||
sd := obj.Shader_data{
|
sd := obj.Shader_data{
|
||||||
vs_data: &tmp_vs_param
|
vs_data: unsafe { &tmp_vs_param }
|
||||||
vs_len: int(sizeof(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))
|
fs_len: int(sizeof(tmp_fs_params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ fn (mut p Player) update() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// dt := p.game.app.dt
|
// dt := p.game.app.dt
|
||||||
ball := &p.game.ball
|
ball := unsafe { &p.game.ball }
|
||||||
// Evil AI that eventually will take over the world
|
// Evil AI that eventually will take over the world
|
||||||
p.pos.y = ball.pos.y - int(f32(p.racket_size) * 0.5)
|
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) {
|
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
|
if p.ai { // disable AI when moved
|
||||||
p.ai = false
|
p.ai = false
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,7 @@ fn (mut g Game) new_round() {
|
||||||
|
|
||||||
fn (mut g Game) update() {
|
fn (mut g Game) update() {
|
||||||
dt := g.app.dt
|
dt := g.app.dt
|
||||||
mut b := &g.ball
|
mut b := unsafe { &g.ball }
|
||||||
for mut p in g.players {
|
for mut p in g.players {
|
||||||
p.update()
|
p.update()
|
||||||
// Keep rackets within the game area
|
// Keep rackets within the game area
|
||||||
|
|
|
@ -53,7 +53,7 @@ fn draw_frame(mut app App_data) {
|
||||||
sgl.v2f(510, 400)
|
sgl.v2f(510, 400)
|
||||||
sgl.end()
|
sgl.end()
|
||||||
// update the text
|
// update the text
|
||||||
mut txt1 := &app.ttf_render[0]
|
mut txt1 := unsafe { &app.ttf_render[0] }
|
||||||
if app.frame_c % 2 == 0 {
|
if app.frame_c % 2 == 0 {
|
||||||
txt1.destroy_texture()
|
txt1.destroy_texture()
|
||||||
txt1.create_text(cframe_txt, 43)
|
txt1.create_text(cframe_txt, 43)
|
||||||
|
@ -71,7 +71,7 @@ Frame: $app.frame_c
|
||||||
But Vwill prevail for sure, V is the way!!
|
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 {
|
if app.frame_c % 2 == 0 {
|
||||||
txt1.bmp.justify = false
|
txt1.bmp.justify = false
|
||||||
if (app.frame_c >> 6) % 2 == 0 {
|
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)
|
txt1.draw_text_bmp(app.gg, 30 + (app.frame_c >> 1) & 0xFF, 200)
|
||||||
// draw mouse position
|
// draw mouse position
|
||||||
if app.mouse_x >= 0 {
|
if app.mouse_x >= 0 {
|
||||||
txt1 = &app.ttf_render[2]
|
txt1 = unsafe { &app.ttf_render[2] }
|
||||||
txt1.destroy_texture()
|
txt1.destroy_texture()
|
||||||
txt1.create_text('$app.mouse_x,$app.mouse_y', 25)
|
txt1.create_text('$app.mouse_x,$app.mouse_y', 25)
|
||||||
txt1.create_texture()
|
txt1.create_texture()
|
||||||
|
|
|
@ -35,7 +35,7 @@ fn print_help_for_command(help_cmd Command) ? {
|
||||||
mut found := false
|
mut found := false
|
||||||
for sub_cmd in cmd.commands {
|
for sub_cmd in cmd.commands {
|
||||||
if sub_cmd.name == arg {
|
if sub_cmd.name == arg {
|
||||||
cmd = &sub_cmd
|
cmd = unsafe { &sub_cmd }
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub fn (mut ctx CancelContext) err() IError {
|
||||||
|
|
||||||
pub fn (ctx CancelContext) value(key string) ?voidptr {
|
pub fn (ctx CancelContext) value(key string) ?voidptr {
|
||||||
if key == cancel_context_key {
|
if key == cancel_context_key {
|
||||||
return voidptr(&ctx)
|
return voidptr(unsafe { &ctx })
|
||||||
}
|
}
|
||||||
return ctx.context.value(key)
|
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))
|
C.BIO_puts(web, &char(req_headers.str))
|
||||||
mut content := strings.new_builder(100)
|
mut content := strings.new_builder(100)
|
||||||
mut buff := [bufsize]byte{}
|
mut buff := [bufsize]byte{}
|
||||||
bp := &buff[0]
|
bp := unsafe { &buff[0] }
|
||||||
mut readcounter := 0
|
mut readcounter := 0
|
||||||
for {
|
for {
|
||||||
readcounter++
|
readcounter++
|
||||||
|
|
|
@ -571,19 +571,19 @@ pub fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []vo
|
||||||
mut sem := unsafe { Semaphore{} }
|
mut sem := unsafe { Semaphore{} }
|
||||||
sem.init(0)
|
sem.init(0)
|
||||||
for i, ch in channels {
|
for i, ch in channels {
|
||||||
subscr[i].sem = &sem
|
subscr[i].sem = unsafe { &sem }
|
||||||
if dir[i] == .push {
|
if dir[i] == .push {
|
||||||
mut null16 := u16(0)
|
mut null16 := u16(0)
|
||||||
for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) {
|
for !C.atomic_compare_exchange_weak_u16(&ch.write_sub_mtx, &null16, u16(1)) {
|
||||||
null16 = u16(0)
|
null16 = u16(0)
|
||||||
}
|
}
|
||||||
subscr[i].prev = &ch.write_subscriber
|
subscr[i].prev = unsafe { &ch.write_subscriber }
|
||||||
unsafe {
|
unsafe {
|
||||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.write_subscriber),
|
||||||
&subscr[i])
|
&subscr[i])
|
||||||
}
|
}
|
||||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
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))
|
C.atomic_store_u16(&ch.write_sub_mtx, u16(0))
|
||||||
} else {
|
} 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)) {
|
for !C.atomic_compare_exchange_weak_u16(&ch.read_sub_mtx, &null16, u16(1)) {
|
||||||
null16 = u16(0)
|
null16 = u16(0)
|
||||||
}
|
}
|
||||||
subscr[i].prev = &ch.read_subscriber
|
subscr[i].prev = unsafe { &ch.read_subscriber }
|
||||||
unsafe {
|
unsafe {
|
||||||
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.read_subscriber),
|
subscr[i].nxt = C.atomic_exchange_ptr(&voidptr(&ch.read_subscriber),
|
||||||
&subscr[i])
|
&subscr[i])
|
||||||
}
|
}
|
||||||
if voidptr(subscr[i].nxt) != voidptr(0) {
|
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))
|
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
|
// TODO: don't actually do this, lmao
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut ctx Context) resize_arr(size int) {
|
fn (mut ctx Context) resize_arr(size int) {
|
||||||
mut l := &ctx.read_buf.len
|
mut l := unsafe { &ctx.read_buf.len }
|
||||||
unsafe {
|
unsafe {
|
||||||
*l = size
|
*l = size
|
||||||
_ = l
|
_ = l
|
||||||
|
|
|
@ -495,6 +495,9 @@ pub mut:
|
||||||
// (for setting the position after the or block for autofree)
|
// (for setting the position after the or block for autofree)
|
||||||
is_or bool // `x := foo() or { ... }`
|
is_or bool // `x := foo() or { ... }`
|
||||||
is_tmp bool // for tmp for loop vars, so that autofree can skip them
|
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
|
// used for smartcasting only
|
||||||
|
|
|
@ -7,6 +7,7 @@ import v.cflag
|
||||||
import v.token
|
import v.token
|
||||||
import v.util
|
import v.util
|
||||||
|
|
||||||
|
[heap]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
pub mut:
|
pub mut:
|
||||||
type_symbols []TypeSymbol
|
type_symbols []TypeSymbol
|
||||||
|
|
|
@ -61,6 +61,7 @@ pub mut:
|
||||||
inside_const bool
|
inside_const bool
|
||||||
inside_anon_fn bool
|
inside_anon_fn bool
|
||||||
inside_ref_lit bool
|
inside_ref_lit bool
|
||||||
|
inside_fn_arg bool // `a`, `b` in `a.f(b)`
|
||||||
skip_flags bool // should `#flag` and `#include` be skipped
|
skip_flags bool // should `#flag` and `#include` be skipped
|
||||||
mut:
|
mut:
|
||||||
files []ast.File
|
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.
|
// 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) }
|
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)
|
// 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
|
free_tmp_arg_vars := c.pref.autofree && !c.is_builtin_mod && call_expr.args.len > 0
|
||||||
&& !call_expr.args[0].typ.has_flag(.optional)
|
&& !call_expr.args[0].typ.has_flag(.optional)
|
||||||
|
@ -3564,7 +3568,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
ast.DeferStmt {
|
ast.DeferStmt {
|
||||||
if node.idx_in_fn < 0 {
|
if node.idx_in_fn < 0 {
|
||||||
node.idx_in_fn = c.cur_fn.defer_stmts.len
|
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)
|
c.stmts(node.stmts)
|
||||||
}
|
}
|
||||||
|
@ -4176,7 +4180,7 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
|
||||||
ast.AnonFn {
|
ast.AnonFn {
|
||||||
c.inside_anon_fn = true
|
c.inside_anon_fn = true
|
||||||
keep_fn := c.cur_fn
|
keep_fn := c.cur_fn
|
||||||
c.cur_fn = &node.decl
|
c.cur_fn = unsafe { &node.decl }
|
||||||
c.stmts(node.decl.stmts)
|
c.stmts(node.decl.stmts)
|
||||||
c.fn_decl(mut node.decl)
|
c.fn_decl(mut node.decl)
|
||||||
c.cur_fn = keep_fn
|
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.expected_type = c.expected_type
|
||||||
// }
|
// }
|
||||||
node.return_type = ret_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
|
return ret_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5830,6 +5852,53 @@ 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) {
|
||||||
|
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 {
|
pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
||||||
old_inside_ref_lit := c.inside_ref_lit
|
old_inside_ref_lit := c.inside_ref_lit
|
||||||
c.inside_ref_lit = c.inside_ref_lit || node.op == .amp
|
c.inside_ref_lit = c.inside_ref_lit || node.op == .amp
|
||||||
|
@ -5871,10 +5940,20 @@ 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()
|
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 {
|
||||||
|
c.mark_as_referenced(mut &node.right)
|
||||||
|
}
|
||||||
|
if node.right.is_auto_deref_var() {
|
||||||
|
return right_type
|
||||||
|
} else {
|
||||||
return right_type.to_ptr()
|
return right_type.to_ptr()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if node.op == .mul {
|
if node.op == .mul {
|
||||||
if right_type.is_ptr() {
|
if right_type.is_ptr() {
|
||||||
return right_type.deref()
|
return right_type.deref()
|
||||||
|
|
|
@ -3,6 +3,13 @@ vlib/v/checker/tests/function_missing_return_type.vv:1:1: error: missing return
|
||||||
| ~~~~~~~~~~
|
| ~~~~~~~~~~
|
||||||
2 | }
|
2 | }
|
||||||
3 |
|
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`
|
vlib/v/checker/tests/function_missing_return_type.vv:12:1: error: missing return at end of function `abc`
|
||||||
10 | }
|
10 | }
|
||||||
11 |
|
11 |
|
||||||
|
|
|
@ -147,7 +147,7 @@ pub struct RemoveNewLineConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut f Fmt) remove_new_line(cfg 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
|
mut i := 0
|
||||||
for i = buffer.len - 1; i >= 0; i-- {
|
for i = buffer.len - 1; i >= 0; i-- {
|
||||||
if !buffer.buf[i].is_space() { // != `\n` {
|
if !buffer.buf[i].is_space() { // != `\n` {
|
||||||
|
|
|
@ -2145,23 +2145,38 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.expr(assign_stmt.right[0])
|
g.expr(assign_stmt.right[0])
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
for i, lx in assign_stmt.left {
|
for i, lx in assign_stmt.left {
|
||||||
|
mut is_auto_heap := false
|
||||||
if lx is ast.Ident {
|
if lx is ast.Ident {
|
||||||
if lx.kind == .blank_ident {
|
if lx.kind == .blank_ident {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if lx.obj is ast.Var {
|
||||||
|
is_auto_heap = lx.obj.is_auto_heap
|
||||||
|
}
|
||||||
}
|
}
|
||||||
styp := g.typ(assign_stmt.left_types[i])
|
styp := g.typ(assign_stmt.left_types[i])
|
||||||
if assign_stmt.op == .decl_assign {
|
if assign_stmt.op == .decl_assign {
|
||||||
g.write('$styp ')
|
g.write('$styp ')
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.expr(lx)
|
g.expr(lx)
|
||||||
if is_opt {
|
if is_opt {
|
||||||
mr_base_styp := g.base_type(return_type)
|
mr_base_styp := g.base_type(return_type)
|
||||||
|
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;')
|
g.writeln(' = (*($mr_base_styp*)${mr_var_name}.data).arg$i;')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if is_auto_heap {
|
||||||
|
g.writeln(' = HEAP($styp, ${mr_var_name}.arg$i);')
|
||||||
} else {
|
} else {
|
||||||
g.writeln(' = ${mr_var_name}.arg$i;')
|
g.writeln(' = ${mr_var_name}.arg$i;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2256,6 +2271,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
for i, left in assign_stmt.left {
|
for i, left in assign_stmt.left {
|
||||||
|
mut is_auto_heap := false
|
||||||
mut var_type := assign_stmt.left_types[i]
|
mut var_type := assign_stmt.left_types[i]
|
||||||
mut val_type := assign_stmt.right_types[i]
|
mut val_type := assign_stmt.right_types[i]
|
||||||
val := assign_stmt.right[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)
|
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)
|
styp := g.typ(var_type)
|
||||||
mut is_fixed_array_init := false
|
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.out.write_string(util.tabs(g.indent - g.inside_ternary))
|
||||||
}
|
}
|
||||||
g.write('$styp ')
|
g.write('$styp ')
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if left is ast.Ident || left is ast.SelectorExpr {
|
if left is ast.Ident || left is ast.SelectorExpr {
|
||||||
g.prevent_sum_type_unwrapping_once = true
|
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}')
|
g.write('{0}')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('HEAP($styp, (')
|
||||||
|
}
|
||||||
if val.is_auto_deref_var() {
|
if val.is_auto_deref_var() {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('))')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assign_stmt.has_cross_var {
|
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 {
|
.voidptr {
|
||||||
ts := if g.pref.m64 {
|
ts := if g.pref.m64 {
|
||||||
&g.table.type_symbols[ast.u64_type_idx]
|
unsafe { &g.table.type_symbols[ast.u64_type_idx] }
|
||||||
} else {
|
} else {
|
||||||
&g.table.type_symbols[ast.u32_type_idx]
|
unsafe { &g.table.type_symbols[ast.u32_type_idx] }
|
||||||
}
|
}
|
||||||
return g.map_fn_ptrs(ts)
|
return g.map_fn_ptrs(ts)
|
||||||
}
|
}
|
||||||
|
@ -3123,7 +3151,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// g.write('/*pref*/')
|
// g.write('/*pref*/')
|
||||||
|
if !(g.is_amp && node.right.is_auto_deref_var()) {
|
||||||
g.write(node.op.str())
|
g.write(node.op.str())
|
||||||
|
}
|
||||||
// g.write('(')
|
// g.write('(')
|
||||||
g.expr(node.right)
|
g.expr(node.right)
|
||||||
}
|
}
|
||||||
|
@ -4355,6 +4385,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
mut name := c_name(node.name)
|
mut name := c_name(node.name)
|
||||||
// TODO: temporary, remove this
|
// TODO: temporary, remove this
|
||||||
node_info := node.info
|
node_info := node.info
|
||||||
|
mut is_auto_heap := false
|
||||||
if node_info is ast.IdentVar {
|
if node_info is ast.IdentVar {
|
||||||
// x ?int
|
// x ?int
|
||||||
// `x = 10` => `x.data = 10` (g.right_is_opt == false)
|
// `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)
|
scope := g.file.scope.innermost(node.pos.pos)
|
||||||
if v := scope.find_var(node.name) {
|
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 {
|
if v.smartcasts.len > 0 {
|
||||||
v_sym := g.table.get_type_symbol(v.typ)
|
v_sym := g.table.get_type_symbol(v.typ)
|
||||||
if !prevent_sum_type_unwrapping_once {
|
if !prevent_sum_type_unwrapping_once {
|
||||||
for _ in v.smartcasts {
|
for _ in v.smartcasts {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
if v_sym.kind == .sum_type {
|
if v_sym.kind == .sum_type && !is_auto_heap {
|
||||||
g.write('*')
|
g.write('*')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4390,7 +4425,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
is_ptr = true
|
is_ptr = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dot := if is_ptr { '->' } else { '.' }
|
dot := if is_ptr || is_auto_heap { '->' } else { '.' }
|
||||||
if mut cast_sym.info is ast.Aggregate {
|
if mut cast_sym.info is ast.Aggregate {
|
||||||
sym := g.table.get_type_symbol(cast_sym.info.types[g.aggregate_type_idx])
|
sym := g.table.get_type_symbol(cast_sym.info.types[g.aggregate_type_idx])
|
||||||
g.write('${dot}_$sym.cname')
|
g.write('${dot}_$sym.cname')
|
||||||
|
@ -4399,6 +4434,9 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('))')
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4413,6 +4451,9 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.write(g.get_ternary_name(name))
|
g.write(g.get_ternary_name(name))
|
||||||
|
if is_auto_heap {
|
||||||
|
g.write('))')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) cast_expr(node ast.CastExpr) {
|
fn (mut g Gen) cast_expr(node ast.CastExpr) {
|
||||||
|
@ -4622,11 +4663,22 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
g.write('\t$base_type $cond_var_name = ')
|
g.write('\t$base_type $cond_var_name = ')
|
||||||
g.expr(branch.cond.expr)
|
g.expr(branch.cond.expr)
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
g.writeln('\t$base_type $branch.cond.var_name = *($base_type*)${var_name}.data;')
|
g.writeln('\t$base_type $branch.cond.var_name = *($base_type*)${var_name}.data;')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
g.expr(branch.cond)
|
g.expr(branch.cond)
|
||||||
|
|
|
@ -69,7 +69,9 @@ fn (mut g Gen) process_fn_decl(node ast.FnDecl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keep_fn_decl := g.fn_decl
|
keep_fn_decl := g.fn_decl
|
||||||
|
unsafe {
|
||||||
g.fn_decl = &node
|
g.fn_decl = &node
|
||||||
|
}
|
||||||
if node.name == 'main.main' {
|
if node.name == 'main.main' {
|
||||||
g.has_main = true
|
g.has_main = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
|
||||||
g.gen_expr_stmt(node)
|
g.gen_expr_stmt(node)
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
g.fn_decl = &node
|
g.fn_decl = unsafe { &node }
|
||||||
g.gen_fn_decl(node)
|
g.gen_fn_decl(node)
|
||||||
}
|
}
|
||||||
ast.ForCStmt {
|
ast.ForCStmt {
|
||||||
|
@ -813,7 +813,9 @@ fn fn_has_go(node ast.FnDecl) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
fn (mut g JsGen) gen_method_decl(it ast.FnDecl) {
|
||||||
|
unsafe {
|
||||||
g.fn_decl = &it
|
g.fn_decl = &it
|
||||||
|
}
|
||||||
has_go := fn_has_go(it)
|
has_go := fn_has_go(it)
|
||||||
is_main := it.name == 'main.main'
|
is_main := it.name == 'main.main'
|
||||||
g.gen_attrs(it.attrs)
|
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
|
share: share
|
||||||
is_mut: lx.is_mut || p.inside_for
|
is_mut: lx.is_mut || p.inside_for
|
||||||
pos: lx.pos
|
pos: lx.pos
|
||||||
|
is_stack_obj: p.inside_for
|
||||||
}
|
}
|
||||||
if p.pref.autofree {
|
if p.pref.autofree {
|
||||||
if r0 is ast.CallExpr {
|
if r0 is ast.CallExpr {
|
||||||
|
|
|
@ -291,11 +291,28 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
scope: 0
|
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{
|
p.scope.register(ast.Var{
|
||||||
name: param.name
|
name: param.name
|
||||||
typ: param.typ
|
typ: param.typ
|
||||||
is_mut: param.is_mut
|
is_mut: param.is_mut
|
||||||
is_auto_deref: param.is_mut || param.is_auto_rec
|
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
|
pos: param.pos
|
||||||
is_used: true
|
is_used: true
|
||||||
is_arg: true
|
is_arg: true
|
||||||
|
@ -580,6 +597,21 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||||
if arg.name.len == 0 {
|
if arg.name.len == 0 {
|
||||||
p.error_with_pos('use `_` to name an unused parameter', arg.pos)
|
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{
|
p.scope.register(ast.Var{
|
||||||
name: arg.name
|
name: arg.name
|
||||||
typ: arg.typ
|
typ: arg.typ
|
||||||
|
@ -587,6 +619,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
|
||||||
pos: arg.pos
|
pos: arg.pos
|
||||||
is_used: true
|
is_used: true
|
||||||
is_arg: 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
|
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
|
typ: ast.int_type
|
||||||
pos: key_var_pos
|
pos: key_var_pos
|
||||||
is_tmp: true
|
is_tmp: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
} else if p.scope.known_var(val_var_name) {
|
} else if p.scope.known_var(val_var_name) {
|
||||||
return p.error('redefinition of value iteration variable `$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
|
typ: ast.int_type
|
||||||
pos: val_var_pos
|
pos: val_var_pos
|
||||||
is_tmp: true
|
is_tmp: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
if key_var_name.len > 0 {
|
if key_var_name.len > 0 {
|
||||||
return p.error_with_pos('cannot declare index variable with range `for`',
|
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_mut: val_is_mut
|
||||||
is_auto_deref: val_is_mut
|
is_auto_deref: val_is_mut
|
||||||
is_tmp: true
|
is_tmp: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
p.inside_for = false
|
p.inside_for = false
|
||||||
|
|
|
@ -54,6 +54,7 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
|
||||||
typ: ast.error_type
|
typ: ast.error_type
|
||||||
pos: p.tok.position()
|
pos: p.tok.position()
|
||||||
is_used: true
|
is_used: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
branches << ast.IfBranch{
|
branches << ast.IfBranch{
|
||||||
|
|
|
@ -2258,6 +2258,7 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
typ: ast.error_type
|
typ: ast.error_type
|
||||||
pos: p.tok.position()
|
pos: p.tok.position()
|
||||||
is_used: true
|
is_used: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
or_kind = .block
|
or_kind = .block
|
||||||
or_stmts = p.parse_block_no_scope(false)
|
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
|
typ: ast.error_type
|
||||||
pos: p.tok.position()
|
pos: p.tok.position()
|
||||||
is_used: true
|
is_used: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
or_kind = .block
|
or_kind = .block
|
||||||
or_stmts = p.parse_block_no_scope(false)
|
or_stmts = p.parse_block_no_scope(false)
|
||||||
|
@ -553,6 +554,7 @@ fn (mut p Parser) prefix_expr() ast.PrefixExpr {
|
||||||
typ: ast.error_type
|
typ: ast.error_type
|
||||||
pos: p.tok.position()
|
pos: p.tok.position()
|
||||||
is_used: true
|
is_used: true
|
||||||
|
is_stack_obj: true
|
||||||
})
|
})
|
||||||
or_kind = .block
|
or_kind = .block
|
||||||
or_stmts = p.parse_block_no_scope(false)
|
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,
|
// TODO: from the point of view of the V programmer,
|
||||||
// `p` has still type &Player.
|
// `p` has still type &Player.
|
||||||
// assert typeof(p).name == 'Player'
|
// assert typeof(p).name == 'Player'
|
||||||
return &p
|
return unsafe { &p }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_mut_receiver() {
|
fn test_mut_receiver() {
|
||||||
|
|
|
@ -268,7 +268,7 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo4(mut f Foo) {
|
fn foo4(mut f Foo) {
|
||||||
f2 := &f
|
f2 := unsafe { &f }
|
||||||
f.foo = 100
|
f.foo = 100
|
||||||
println(f.foo)
|
println(f.foo)
|
||||||
println(f2.foo)
|
println(f2.foo)
|
||||||
|
@ -284,7 +284,7 @@ fn test_mut_13() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo5(mut arr []int) {
|
fn foo5(mut arr []int) {
|
||||||
arr2 := &arr
|
arr2 := unsafe { &arr }
|
||||||
arr[0] = 0
|
arr[0] = 0
|
||||||
println(arr[0]) // 0
|
println(arr[0]) // 0
|
||||||
assert arr[0] == 0
|
assert arr[0] == 0
|
||||||
|
@ -300,7 +300,7 @@ fn test_mut_14() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo6(mut arr [3]int) {
|
fn foo6(mut arr [3]int) {
|
||||||
arr2 := &arr
|
arr2 := unsafe { &arr }
|
||||||
arr[0] = 0
|
arr[0] = 0
|
||||||
println(arr[0]) // 0
|
println(arr[0]) // 0
|
||||||
assert arr[0] == 0
|
assert arr[0] == 0
|
||||||
|
@ -316,7 +316,7 @@ fn test_mut_15() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo7(mut m map[string]int) {
|
fn foo7(mut m map[string]int) {
|
||||||
m2 := &m
|
m2 := unsafe { &m }
|
||||||
m['one'] = 1
|
m['one'] = 1
|
||||||
println(m['one']) // 1
|
println(m['one']) // 1
|
||||||
assert m['one'] == 1
|
assert m['one'] == 1
|
||||||
|
|
|
@ -48,8 +48,8 @@ fn test_ptr_arithmetic_over_struct() {
|
||||||
a[0].x = 10
|
a[0].x = 10
|
||||||
a[1].x = 100
|
a[1].x = 100
|
||||||
a[2].x = 1000
|
a[2].x = 1000
|
||||||
mut pa := &a[0]
|
mut pa := unsafe { &a[0] }
|
||||||
assert pa == &a[0]
|
assert pa == unsafe { &a[0] }
|
||||||
unsafe {
|
unsafe {
|
||||||
assert pa.x == 10
|
assert pa.x == 10
|
||||||
pa++
|
pa++
|
||||||
|
@ -66,5 +66,5 @@ fn test_ptr_arithmetic_over_struct() {
|
||||||
assert pa.x == 1000
|
assert pa.x == 1000
|
||||||
pa -= 2
|
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() {
|
fn test_mut_voidptr_arg() {
|
||||||
mut a := [1, 2]!
|
mut a := [1, 2]!
|
||||||
b := [3, 4]!
|
b := [3, 4]!
|
||||||
mut aptr := voidptr(&a[0])
|
mut aptr := voidptr(unsafe { &a[0] })
|
||||||
unsafe { memcpy(mut aptr, &b[0], sizeof(int)) }
|
unsafe { memcpy(mut aptr, &b[0], sizeof(int)) }
|
||||||
assert a == [3, 2]!
|
assert a == [3, 2]!
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue