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