all: various fixes for [heap]/auto-heap handling (#10033)
							parent
							
								
									5b4eef8010
								
							
						
					
					
						commit
						d26ac5692e
					
				|  | @ -43,7 +43,7 @@ fn (mut ctx Context) println(s string) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn do_timeout(c &Context) { | fn do_timeout(c &Context) { | ||||||
| 	mut ctx := c | 	mut ctx := unsafe { c } | ||||||
| 	time.sleep(ctx.timeout_ms * time.millisecond) | 	time.sleep(ctx.timeout_ms * time.millisecond) | ||||||
| 	exit(ctx.exitcode) | 	exit(ctx.exitcode) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -171,7 +171,7 @@ fn (mut context Context) get_changed_vfiles() int { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn change_detection_loop(ocontext &Context) { | fn change_detection_loop(ocontext &Context) { | ||||||
| 	mut context := ocontext | 	mut context := unsafe { ocontext } | ||||||
| 	for { | 	for { | ||||||
| 		if context.v_cycles >= max_v_cycles || context.scan_cycles >= max_scan_cycles { | 		if context.v_cycles >= max_v_cycles || context.scan_cycles >= max_scan_cycles { | ||||||
| 			context.is_exiting = true | 			context.is_exiting = true | ||||||
|  |  | ||||||
|  | @ -13,7 +13,7 @@ mut: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut acontext AppState) { | fn my_audio_stream_callback(buffer &f32, num_frames int, num_channels int, mut acontext AppState) { | ||||||
| 	mut soundbuffer := buffer | 	mut soundbuffer := unsafe { buffer } | ||||||
| 	for frame := 0; frame < num_frames; frame++ { | 	for frame := 0; frame < num_frames; frame++ { | ||||||
| 		t := int(f32(acontext.frame_0 + frame) * 0.245) | 		t := int(f32(acontext.frame_0 + frame) * 0.245) | ||||||
| 		// "Techno" by Gabriel Miceli
 | 		// "Techno" by Gabriel Miceli
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ const ( | ||||||
| 	orange     = ui.Color{255, 140, 0} | 	orange     = ui.Color{255, 140, 0} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| struct App { | struct App { | ||||||
| mut: | mut: | ||||||
| 	tui    &ui.Context = 0 | 	tui    &ui.Context = 0 | ||||||
|  | @ -238,6 +239,7 @@ fn (mut b Ball) update(dt f32) { | ||||||
| 	b.pos.y += b.vel.y * b.acc.y * dt | 	b.pos.y += b.vel.y * b.acc.y * dt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| struct Game { | struct Game { | ||||||
| mut: | mut: | ||||||
| 	app     &App = 0 | 	app     &App = 0 | ||||||
|  |  | ||||||
|  | @ -256,6 +256,7 @@ fn (mut r Rat) randomize() { | ||||||
| 		r.app.height - block_size - buffer) | 		r.app.height - block_size - buffer) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| struct App { | struct App { | ||||||
| mut: | mut: | ||||||
| 	termui &termui.Context = 0 | 	termui &termui.Context = 0 | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void { | ||||||
| 			dest_[i] = src_[i] | 			dest_[i] = src_[i] | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return dest | 	return unsafe { dest } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [export: 'malloc'] | [export: 'malloc'] | ||||||
|  | @ -37,7 +37,7 @@ fn realloc(old_area &C.void, new_size size_t) &C.void { | ||||||
| 	} | 	} | ||||||
| 	old_size := unsafe { *(&u64(old_area - sizeof(u64))) } | 	old_size := unsafe { *(&u64(old_area - sizeof(u64))) } | ||||||
| 	if u64(new_size) <= old_size { | 	if u64(new_size) <= old_size { | ||||||
| 		return old_area | 		return unsafe { old_area } | ||||||
| 	} else { | 	} else { | ||||||
| 		new_area := unsafe { malloc(int(new_size)) } | 		new_area := unsafe { malloc(int(new_size)) } | ||||||
| 		unsafe { memmove(new_area, old_area, size_t(old_size)) } | 		unsafe { memmove(new_area, old_area, size_t(old_size)) } | ||||||
|  | @ -54,7 +54,7 @@ fn memset(s &C.void, c int, n size_t) &C.void { | ||||||
| 			s_[i] = char(c) | 			s_[i] = char(c) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return s | 	return unsafe { s } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [unsafe] | [unsafe] | ||||||
|  | @ -74,7 +74,7 @@ fn memmove(dest &C.void, src &C.void, n size_t) &C.void { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	unsafe { free(temp_buf) } | 	unsafe { free(temp_buf) } | ||||||
| 	return dest | 	return unsafe { dest } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [export: 'calloc'] | [export: 'calloc'] | ||||||
|  |  | ||||||
|  | @ -77,7 +77,7 @@ pub fn tos(s &byte, len int) string { | ||||||
| 		panic('tos(): nil string') | 		panic('tos(): nil string') | ||||||
| 	} | 	} | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: s | 		str: unsafe { s } | ||||||
| 		len: len | 		len: len | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -96,7 +96,7 @@ pub fn tos2(s &byte) string { | ||||||
| 		panic('tos2: nil string') | 		panic('tos2: nil string') | ||||||
| 	} | 	} | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: s | 		str: unsafe { s } | ||||||
| 		len: unsafe { vstrlen(s) } | 		len: unsafe { vstrlen(s) } | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -146,7 +146,7 @@ pub fn tos_lit(s &char) string { | ||||||
| [unsafe] | [unsafe] | ||||||
| pub fn (bp &byte) vstring() string { | pub fn (bp &byte) vstring() string { | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: bp | 		str: unsafe { bp } | ||||||
| 		len: unsafe { C.strlen(&char(bp)) } | 		len: unsafe { C.strlen(&char(bp)) } | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -156,7 +156,7 @@ pub fn (bp &byte) vstring() string { | ||||||
| [unsafe] | [unsafe] | ||||||
| pub fn (bp &byte) vstring_with_len(len int) string { | pub fn (bp &byte) vstring_with_len(len int) string { | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: bp | 		str: unsafe { bp } | ||||||
| 		len: len | 		len: len | ||||||
| 		is_lit: 0 | 		is_lit: 0 | ||||||
| 	} | 	} | ||||||
|  | @ -194,7 +194,7 @@ pub fn (cp &char) vstring_with_len(len int) string { | ||||||
| [unsafe] | [unsafe] | ||||||
| pub fn (bp &byte) vstring_literal() string { | pub fn (bp &byte) vstring_literal() string { | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: bp | 		str: unsafe { bp } | ||||||
| 		len: unsafe { C.strlen(&char(bp)) } | 		len: unsafe { C.strlen(&char(bp)) } | ||||||
| 		is_lit: 1 | 		is_lit: 1 | ||||||
| 	} | 	} | ||||||
|  | @ -205,7 +205,7 @@ pub fn (bp &byte) vstring_literal() string { | ||||||
| [unsafe] | [unsafe] | ||||||
| pub fn (bp &byte) vstring_literal_with_len(len int) string { | pub fn (bp &byte) vstring_literal_with_len(len int) string { | ||||||
| 	return string{ | 	return string{ | ||||||
| 		str: bp | 		str: unsafe { bp } | ||||||
| 		len: len | 		len: len | ||||||
| 		is_lit: 1 | 		is_lit: 1 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -94,7 +94,7 @@ pub fn (mut cmd Command) add_command(command Command) { | ||||||
| 		println('Command with the name `$subcmd.name` already exists') | 		println('Command with the name `$subcmd.name` already exists') | ||||||
| 		exit(1) | 		exit(1) | ||||||
| 	} | 	} | ||||||
| 	subcmd.parent = cmd | 	subcmd.parent = unsafe { cmd } | ||||||
| 	cmd.commands << subcmd | 	cmd.commands << subcmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -102,7 +102,7 @@ pub fn (mut cmd Command) add_command(command Command) { | ||||||
| // is linked as a chain.
 | // is linked as a chain.
 | ||||||
| pub fn (mut cmd Command) setup() { | pub fn (mut cmd Command) setup() { | ||||||
| 	for mut subcmd in cmd.commands { | 	for mut subcmd in cmd.commands { | ||||||
| 		subcmd.parent = cmd | 		subcmd.parent = unsafe { cmd } | ||||||
| 		subcmd.setup() | 		subcmd.setup() | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -100,6 +100,7 @@ pub: | ||||||
| 	native_rendering  bool // Cocoa on macOS/iOS, GDI+ on Windows
 | 	native_rendering  bool // Cocoa on macOS/iOS, GDI+ on Windows
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| pub struct Context { | pub struct Context { | ||||||
| 	render_text bool | 	render_text bool | ||||||
| mut: | mut: | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ import sokol | ||||||
| import sokol.sgl | import sokol.sgl | ||||||
| import stbi | import stbi | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| pub struct Image { | pub struct Image { | ||||||
| pub mut: | pub mut: | ||||||
| 	id          int | 	id          int | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ pub fn vec3(x f32, y f32, z f32) Vec3 { | ||||||
| 
 | 
 | ||||||
| fn mat4(f &f32) Mat4 { | fn mat4(f &f32) Mat4 { | ||||||
| 	res := Mat4{ | 	res := Mat4{ | ||||||
| 		data: f | 		data: unsafe { f } | ||||||
| 	} | 	} | ||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ pub fn (mut r Response) write_string(s string) { | ||||||
| [inline] | [inline] | ||||||
| pub fn (mut r Response) http_ok() &Response { | pub fn (mut r Response) http_ok() &Response { | ||||||
| 	r.write_string('HTTP/1.1 200 OK\r\n') | 	r.write_string('HTTP/1.1 200 OK\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
|  | @ -29,7 +29,7 @@ pub fn (mut r Response) header(k string, v string) &Response { | ||||||
| 	r.write_string(': ') | 	r.write_string(': ') | ||||||
| 	r.write_string(v) | 	r.write_string(v) | ||||||
| 	r.write_string('\r\n') | 	r.write_string('\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
|  | @ -39,13 +39,13 @@ pub fn (mut r Response) header_date() &Response { | ||||||
| 		r.buf += cpy(r.buf, r.date, 29) | 		r.buf += cpy(r.buf, r.date, 29) | ||||||
| 	} | 	} | ||||||
| 	r.write_string('\r\n') | 	r.write_string('\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
| pub fn (mut r Response) header_server() &Response { | pub fn (mut r Response) header_server() &Response { | ||||||
| 	r.write_string('Server: V\r\n') | 	r.write_string('Server: V\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
|  | @ -53,25 +53,25 @@ pub fn (mut r Response) content_type(s string) &Response { | ||||||
| 	r.write_string('Content-Type: ') | 	r.write_string('Content-Type: ') | ||||||
| 	r.write_string(s) | 	r.write_string(s) | ||||||
| 	r.write_string('\r\n') | 	r.write_string('\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
| pub fn (mut r Response) html() &Response { | pub fn (mut r Response) html() &Response { | ||||||
| 	r.write_string('Content-Type: text/html\r\n') | 	r.write_string('Content-Type: text/html\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
| pub fn (mut r Response) plain() &Response { | pub fn (mut r Response) plain() &Response { | ||||||
| 	r.write_string('Content-Type: text/plain\r\n') | 	r.write_string('Content-Type: text/plain\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
| pub fn (mut r Response) json() &Response { | pub fn (mut r Response) json() &Response { | ||||||
| 	r.write_string('Content-Type: application/json\r\n') | 	r.write_string('Content-Type: application/json\r\n') | ||||||
| 	return r | 	return unsafe { r } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| [inline] | [inline] | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ pub fn get_current_rng() &PRNG { | ||||||
| // should be restored if work with the custom RNG is complete. It is not necessary to restore if the
 | // should be restored if work with the custom RNG is complete. It is not necessary to restore if the
 | ||||||
| // program terminates soon afterwards.
 | // program terminates soon afterwards.
 | ||||||
| pub fn set_rng(rng &PRNG) { | pub fn set_rng(rng &PRNG) { | ||||||
| 	default_rng = rng | 	default_rng = unsafe { rng } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // seed sets the given array of `u32` values as the seed for the `default_rng`. The default_rng is
 | // seed sets the given array of `u32` values as the seed for the `default_rng`. The default_rng is
 | ||||||
|  |  | ||||||
|  | @ -150,6 +150,7 @@ pub fn (b &C.sg_bindings) append_index_buffer(data voidptr, element_size int, el | ||||||
| 	return C.sg_append_buffer(b.index_buffer, &range) | 	return C.sg_append_buffer(b.index_buffer, &range) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| pub struct C.sg_shader_desc { | pub struct C.sg_shader_desc { | ||||||
| pub mut: | pub mut: | ||||||
| 	_start_canary u32 | 	_start_canary u32 | ||||||
|  |  | ||||||
|  | @ -510,7 +510,6 @@ pub mut: | ||||||
| 	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_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)
 | 	is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct)
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| // that can be found in the LICENSE file.
 | // that can be found in the LICENSE file.
 | ||||||
| module ast | module ast | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| pub struct Scope { | pub struct Scope { | ||||||
| pub mut: | pub mut: | ||||||
| 	// mut:
 | 	// mut:
 | ||||||
|  |  | ||||||
|  | @ -282,7 +282,7 @@ pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool { | ||||||
| // search from current type up through each parent looking for method
 | // search from current type up through each parent looking for method
 | ||||||
| pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn { | pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn { | ||||||
| 	// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
 | 	// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
 | ||||||
| 	mut ts := s | 	mut ts := unsafe { s } | ||||||
| 	for { | 	for { | ||||||
| 		if method := ts.find_method(name) { | 		if method := ts.find_method(name) { | ||||||
| 			return method | 			return method | ||||||
|  | @ -337,7 +337,7 @@ pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool { | ||||||
| // search from current type up through each parent looking for field
 | // search from current type up through each parent looking for field
 | ||||||
| pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField { | pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField { | ||||||
| 	// println('find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
 | 	// println('find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
 | ||||||
| 	mut ts := s | 	mut ts := unsafe { s } | ||||||
| 	for { | 	for { | ||||||
| 		match mut ts.info { | 		match mut ts.info { | ||||||
| 			Struct { | 			Struct { | ||||||
|  | @ -401,7 +401,7 @@ pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) ?St | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (t &Table) resolve_common_sumtype_fields(sym_ &TypeSymbol) { | pub fn (t &Table) resolve_common_sumtype_fields(sym_ &TypeSymbol) { | ||||||
| 	mut sym := sym_ | 	mut sym := unsafe { sym_ } | ||||||
| 	mut info := sym.info as SumType | 	mut info := sym.info as SumType | ||||||
| 	if info.found_fields { | 	if info.found_fields { | ||||||
| 		return | 		return | ||||||
|  |  | ||||||
|  | @ -64,6 +64,7 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language { | ||||||
| // * Table.type_kind(typ) not TypeSymbol.kind.
 | // * Table.type_kind(typ) not TypeSymbol.kind.
 | ||||||
| // Each TypeSymbol is entered into `Table.types`.
 | // Each TypeSymbol is entered into `Table.types`.
 | ||||||
| // See also: Table.get_type_symbol.
 | // See also: Table.get_type_symbol.
 | ||||||
|  | 
 | ||||||
| pub struct TypeSymbol { | pub struct TypeSymbol { | ||||||
| pub: | pub: | ||||||
| 	parent_idx int | 	parent_idx int | ||||||
|  | @ -557,6 +558,15 @@ pub fn (t &TypeSymbol) sumtype_info() SumType { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub fn (t &TypeSymbol) is_heap() bool { | ||||||
|  | 	if t.kind == .struct_ { | ||||||
|  | 		info := t.info as Struct | ||||||
|  | 		return info.is_heap | ||||||
|  | 	} else { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* | /* | ||||||
| pub fn (t TypeSymbol) str() string { | pub fn (t TypeSymbol) str() string { | ||||||
| 	return t.name | 	return t.name | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ pub fn (mut c Checker) check2(ast_file &ast.File) []errors.Error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn (mut c Checker) change_current_file(file &ast.File) { | pub fn (mut c Checker) change_current_file(file &ast.File) { | ||||||
| 	c.file = file | 	c.file = unsafe { file } | ||||||
| 	c.vmod_file_content = '' | 	c.vmod_file_content = '' | ||||||
| 	c.mod = file.mod.name | 	c.mod = file.mod.name | ||||||
| } | } | ||||||
|  | @ -666,11 +666,6 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 			c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' + | 			c.error('struct `$type_sym.name` is declared with a `[noinit]` attribute, so ' + | ||||||
| 				'it cannot be initialized with `$type_sym.name{}`', struct_init.pos) | 				'it cannot be initialized with `$type_sym.name{}`', struct_init.pos) | ||||||
| 		} | 		} | ||||||
| 		if info.is_heap && c.inside_decl_rhs && !c.inside_ref_lit && !c.inside_unsafe |  | ||||||
| 			&& !struct_init.typ.is_ptr() { |  | ||||||
| 			c.error('`$type_sym.name` type can only be used as a reference `&$type_sym.name` or inside a `struct` reference', |  | ||||||
| 				struct_init.pos) |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	if type_sym.name.len == 1 && c.cur_fn.generic_names.len == 0 { | 	if type_sym.name.len == 1 && c.cur_fn.generic_names.len == 0 { | ||||||
| 		c.error('unknown struct `$type_sym.name`', struct_init.pos) | 		c.error('unknown struct `$type_sym.name`', struct_init.pos) | ||||||
|  | @ -754,9 +749,12 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 						continue | 						continue | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 				mut expr_type := ast.Type(0) | ||||||
|  | 				mut expected_type := ast.Type(0) | ||||||
| 				if is_embed { | 				if is_embed { | ||||||
| 					c.expected_type = embed_type | 					expected_type = embed_type | ||||||
| 					expr_type := c.expr(field.expr) | 					c.expected_type = expected_type | ||||||
|  | 					expr_type = c.expr(field.expr) | ||||||
| 					expr_type_sym := c.table.get_type_symbol(expr_type) | 					expr_type_sym := c.table.get_type_symbol(expr_type) | ||||||
| 					if expr_type != ast.void_type && expr_type_sym.kind != .placeholder { | 					if expr_type != ast.void_type && expr_type_sym.kind != .placeholder { | ||||||
| 						c.check_expected(expr_type, embed_type) or { | 						c.check_expected(expr_type, embed_type) or { | ||||||
|  | @ -769,8 +767,9 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 				} else { | 				} else { | ||||||
| 					inited_fields << field_name | 					inited_fields << field_name | ||||||
| 					field_type_sym := c.table.get_type_symbol(info_field.typ) | 					field_type_sym := c.table.get_type_symbol(info_field.typ) | ||||||
| 					c.expected_type = info_field.typ | 					expected_type = info_field.typ | ||||||
| 					mut expr_type := c.expr(field.expr) | 					c.expected_type = expected_type | ||||||
|  | 					expr_type = c.expr(field.expr) | ||||||
| 					if !info_field.typ.has_flag(.optional) { | 					if !info_field.typ.has_flag(.optional) { | ||||||
| 						expr_type = c.check_expr_opt_call(field.expr, expr_type) | 						expr_type = c.check_expr_opt_call(field.expr, expr_type) | ||||||
| 					} | 					} | ||||||
|  | @ -798,6 +797,28 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) ast.Type { | ||||||
| 					struct_init.fields[i].typ = expr_type | 					struct_init.fields[i].typ = expr_type | ||||||
| 					struct_init.fields[i].expected_type = info_field.typ | 					struct_init.fields[i].expected_type = info_field.typ | ||||||
| 				} | 				} | ||||||
|  | 				if expr_type.is_ptr() && expected_type.is_ptr() { | ||||||
|  | 					if mut field.expr is ast.Ident { | ||||||
|  | 						if mut field.expr.obj is ast.Var { | ||||||
|  | 							mut obj := unsafe { &field.expr.obj } | ||||||
|  | 							if c.fn_scope != voidptr(0) { | ||||||
|  | 								obj = c.fn_scope.find_var(obj.name) or { obj } | ||||||
|  | 							} | ||||||
|  | 							if obj.is_stack_obj && !c.inside_unsafe { | ||||||
|  | 								sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0)) | ||||||
|  | 								if !sym.is_heap() { | ||||||
|  | 									suggestion := if sym.kind == .struct_ { | ||||||
|  | 										'declaring `$sym.name` as `[heap]`' | ||||||
|  | 									} else { | ||||||
|  | 										'wrapping the `$sym.name` object in a `struct` declared as `[heap]`' | ||||||
|  | 									} | ||||||
|  | 									c.error('`$field.expr.name` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.', | ||||||
|  | 										field.expr.pos) | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 			// Check uninitialized refs/sum types
 | 			// Check uninitialized refs/sum types
 | ||||||
| 			for field in info.fields { | 			for field in info.fields { | ||||||
|  | @ -2954,6 +2975,29 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { | ||||||
| 			c.error('fn `$c.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | 			c.error('fn `$c.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead', | ||||||
| 				pos) | 				pos) | ||||||
| 		} | 		} | ||||||
|  | 		if exp_type.is_ptr() && got_typ.is_ptr() { | ||||||
|  | 			mut r_expr := &return_stmt.exprs[i] | ||||||
|  | 			if mut r_expr is ast.Ident { | ||||||
|  | 				if mut r_expr.obj is ast.Var { | ||||||
|  | 					mut obj := unsafe { &r_expr.obj } | ||||||
|  | 					if c.fn_scope != voidptr(0) { | ||||||
|  | 						obj = c.fn_scope.find_var(r_expr.obj.name) or { obj } | ||||||
|  | 					} | ||||||
|  | 					if obj.is_stack_obj && !c.inside_unsafe { | ||||||
|  | 						type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0)) | ||||||
|  | 						if !type_sym.is_heap() { | ||||||
|  | 							suggestion := if type_sym.kind == .struct_ { | ||||||
|  | 								'declaring `$type_sym.name` as `[heap]`' | ||||||
|  | 							} else { | ||||||
|  | 								'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`' | ||||||
|  | 							} | ||||||
|  | 							c.error('`$r_expr.name` cannot be returned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.', | ||||||
|  | 								r_expr.pos) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	if exp_is_optional && return_stmt.exprs.len > 0 { | 	if exp_is_optional && return_stmt.exprs.len > 0 { | ||||||
| 		expr0 := return_stmt.exprs[0] | 		expr0 := return_stmt.exprs[0] | ||||||
|  | @ -3176,6 +3220,28 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { | ||||||
| 			c.fail_if_immutable(left) | 			c.fail_if_immutable(left) | ||||||
| 			// left_type = c.expr(left)
 | 			// left_type = c.expr(left)
 | ||||||
| 		} | 		} | ||||||
|  | 		if right_type.is_ptr() && left_type.is_ptr() { | ||||||
|  | 			if mut right is ast.Ident { | ||||||
|  | 				if mut right.obj is ast.Var { | ||||||
|  | 					mut obj := unsafe { &right.obj } | ||||||
|  | 					if c.fn_scope != voidptr(0) { | ||||||
|  | 						obj = c.fn_scope.find_var(right.obj.name) or { obj } | ||||||
|  | 					} | ||||||
|  | 					if obj.is_stack_obj && !c.inside_unsafe { | ||||||
|  | 						type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0)) | ||||||
|  | 						if !type_sym.is_heap() { | ||||||
|  | 							suggestion := if type_sym.kind == .struct_ { | ||||||
|  | 								'declaring `$type_sym.name` as `[heap]`' | ||||||
|  | 							} else { | ||||||
|  | 								'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`' | ||||||
|  | 							} | ||||||
|  | 							c.error('`$right.name` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider ${suggestion}.', | ||||||
|  | 								right.pos) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 		assign_stmt.left_types << left_type | 		assign_stmt.left_types << left_type | ||||||
| 		match mut left { | 		match mut left { | ||||||
| 			ast.Ident { | 			ast.Ident { | ||||||
|  | @ -3216,6 +3282,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { | ||||||
| 								if left.obj.is_auto_deref { | 								if left.obj.is_auto_deref { | ||||||
| 									left.obj.is_used = true | 									left.obj.is_used = true | ||||||
| 								} | 								} | ||||||
|  | 								if !left_type.is_ptr() { | ||||||
|  | 									if c.table.get_type_symbol(left_type).is_heap() { | ||||||
|  | 										left.obj.is_auto_heap = true | ||||||
|  | 									} | ||||||
|  | 								} | ||||||
| 							} | 							} | ||||||
| 							ast.GlobalField { | 							ast.GlobalField { | ||||||
| 								left.obj.typ = left_type | 								left.obj.typ = left_type | ||||||
|  | @ -6046,20 +6117,30 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr) { | ||||||
| 			if mut node.obj is ast.Var { | 			if mut node.obj is ast.Var { | ||||||
| 				mut obj := unsafe { &node.obj } | 				mut obj := unsafe { &node.obj } | ||||||
| 				if c.fn_scope != voidptr(0) { | 				if c.fn_scope != voidptr(0) { | ||||||
| 					obj = c.fn_scope.find_var(node.obj.name) or { unsafe { &node.obj } } | 					obj = c.fn_scope.find_var(node.obj.name) or { obj } | ||||||
| 				} | 				} | ||||||
| 				type_sym := c.table.get_type_symbol(obj.typ) | 				type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0)) | ||||||
| 				if obj.is_stack_obj { | 				if obj.is_stack_obj && !type_sym.is_heap() { | ||||||
| 					c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider declaring `$type_sym.name` as `[heap]`.', | 					suggestion := if type_sym.kind == .struct_ { | ||||||
|  | 						'declaring `$type_sym.name` as `[heap]`' | ||||||
|  | 					} else { | ||||||
|  | 						'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`' | ||||||
|  | 					} | ||||||
|  | 					c.error('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.', | ||||||
| 						node.pos) | 						node.pos) | ||||||
| 				} else if type_sym.kind == .array_fixed { | 				} else if type_sym.kind == .array_fixed { | ||||||
| 					c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack', | 					c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack', | ||||||
| 						node.pos) | 						node.pos) | ||||||
| 				} else { | 				} else { | ||||||
|  | 					if type_sym.kind == .struct_ { | ||||||
|  | 						info := type_sym.info as ast.Struct | ||||||
|  | 						if !info.is_heap { | ||||||
| 							node.obj.is_auto_heap = true | 							node.obj.is_auto_heap = true | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 		ast.SelectorExpr { | 		ast.SelectorExpr { | ||||||
| 			if !node.expr_type.is_ptr() { | 			if !node.expr_type.is_ptr() { | ||||||
| 				c.mark_as_referenced(mut &node.expr) | 				c.mark_as_referenced(mut &node.expr) | ||||||
|  | @ -6930,7 +7011,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	c.expected_type = ast.void_type | 	c.expected_type = ast.void_type | ||||||
| 	c.cur_fn = node | 	c.cur_fn = unsafe { node } | ||||||
| 	// Add return if `fn(...) ? {...}` have no return at end
 | 	// Add return if `fn(...) ? {...}` have no return at end
 | ||||||
| 	if node.return_type != ast.void_type && node.return_type.has_flag(.optional) | 	if node.return_type != ast.void_type && node.return_type.has_flag(.optional) | ||||||
| 		&& (node.stmts.len == 0 || node.stmts[node.stmts.len - 1] !is ast.Return) { | 		&& (node.stmts.len == 0 || node.stmts[node.stmts.len - 1] !is ast.Return) { | ||||||
|  |  | ||||||
|  | @ -1,35 +0,0 @@ | ||||||
| vlib/v/checker/tests/heap_struct.vv:18:7: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference |  | ||||||
|    16 |  |  | ||||||
|    17 | fn main() { |  | ||||||
|    18 |     a := Abc{ n: 3 } |  | ||||||
|       |          ~~~~~~~~~~~ |  | ||||||
|    19 |     b := St{ |  | ||||||
|    20 |         Abc{ n: 7 } |  | ||||||
| vlib/v/checker/tests/heap_struct.vv:19:7: error: `St` type can only be used as a reference `&St` or inside a `struct` reference |  | ||||||
|    17 | fn main() { |  | ||||||
|    18 |     a := Abc{ n: 3 } |  | ||||||
|    19 |     b := St{ |  | ||||||
|       |          ~~~ |  | ||||||
|    20 |         Abc{ n: 7 } |  | ||||||
|    21 |     } |  | ||||||
| vlib/v/checker/tests/heap_struct.vv:20:3: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference |  | ||||||
|    18 |     a := Abc{ n: 3 } |  | ||||||
|    19 |     b := St{ |  | ||||||
|    20 |         Abc{ n: 7 } |  | ||||||
|       |         ~~~~~~~~~~~ |  | ||||||
|    21 |     } |  | ||||||
|    22 |     x := Qwe{ |  | ||||||
| vlib/v/checker/tests/heap_struct.vv:22:7: error: `Qwe` type can only be used as a reference `&Qwe` or inside a `struct` reference |  | ||||||
|    20 |         Abc{ n: 7 } |  | ||||||
|    21 |     } |  | ||||||
|    22 |     x := Qwe{ |  | ||||||
|       |          ~~~~ |  | ||||||
|    23 |         f: 12.25 |  | ||||||
|    24 |         a: Abc{ n: 23 } |  | ||||||
| vlib/v/checker/tests/heap_struct.vv:24:6: error: `Abc` type can only be used as a reference `&Abc` or inside a `struct` reference |  | ||||||
|    22 |     x := Qwe{ |  | ||||||
|    23 |         f: 12.25 |  | ||||||
|    24 |         a: Abc{ n: 23 } |  | ||||||
|       |            ~~~~~~~~~~~~ |  | ||||||
|    25 |     } |  | ||||||
|    26 |     println('$a.n $b.n $x.a.n') |  | ||||||
|  | @ -1,27 +0,0 @@ | ||||||
| [heap] |  | ||||||
| struct Abc { |  | ||||||
| mut: |  | ||||||
| 	n int |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct St { |  | ||||||
| 	Abc |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct Qwe { |  | ||||||
| mut: |  | ||||||
| 	f f64 |  | ||||||
| 	a Abc |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn main() { |  | ||||||
| 	a := Abc{ n: 3 } |  | ||||||
| 	b := St{ |  | ||||||
| 		Abc{ n: 7 } |  | ||||||
| 	} |  | ||||||
| 	x := Qwe{ |  | ||||||
| 		f: 12.25 |  | ||||||
| 		a: Abc{ n: 23 } |  | ||||||
| 	} |  | ||||||
| 	println('$a.n $b.n $x.a.n') |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | vlib/v/checker/tests/no_heap_struct.vv:13:6: error: `x` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`. | ||||||
|  |    11 | fn f(x &Abc) St { | ||||||
|  |    12 |     s := St{ | ||||||
|  |    13 |         a: x | ||||||
|  |       |            ^ | ||||||
|  |    14 |     } | ||||||
|  |    15 |     return s | ||||||
|  | vlib/v/checker/tests/no_heap_struct.vv:19:9: error: `x` cannot be returned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`. | ||||||
|  |    17 |  | ||||||
|  |    18 | fn g(mut x Abc) &Abc { | ||||||
|  |    19 |     return x | ||||||
|  |       |            ^ | ||||||
|  |    20 | } | ||||||
|  |    21 | | ||||||
|  | vlib/v/checker/tests/no_heap_struct.vv:23:7: error: `x` cannot be assigned outside `unsafe` blocks as it might refer to an object stored on stack. Consider declaring `Abc` as `[heap]`. | ||||||
|  |    21 |  | ||||||
|  |    22 | fn h(x &Abc) &Abc { | ||||||
|  |    23 |     y := x | ||||||
|  |       |          ^ | ||||||
|  |    24 |     return y | ||||||
|  |    25 | } | ||||||
|  | @ -0,0 +1,25 @@ | ||||||
|  | struct Abc { | ||||||
|  | mut: | ||||||
|  | 	n int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct St { | ||||||
|  | mut: | ||||||
|  | 	a &Abc | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn f(x &Abc) St { | ||||||
|  | 	s := St{ | ||||||
|  | 		a: x | ||||||
|  | 	} | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn g(mut x Abc) &Abc { | ||||||
|  | 	return x | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn h(x &Abc) &Abc { | ||||||
|  | 	y := x | ||||||
|  | 	return y | ||||||
|  | } | ||||||
|  | @ -32,6 +32,7 @@ mut: | ||||||
| 	methods  map[string][]ast.FnDecl | 	methods  map[string][]ast.FnDecl | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| struct JsGen { | struct JsGen { | ||||||
| 	table &ast.Table | 	table &ast.Table | ||||||
| 	pref  &pref.Preferences | 	pref  &pref.Preferences | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ interface CodeGen { | ||||||
| 	// XXX WHY gen_exit fn (expr ast.Expr)
 | 	// XXX WHY gen_exit fn (expr ast.Expr)
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | [heap] | ||||||
| pub struct Gen { | pub struct Gen { | ||||||
| 	out_name string | 	out_name string | ||||||
| 	pref     &pref.Preferences // Preferences shared from V struct
 | 	pref     &pref.Preferences // Preferences shared from V struct
 | ||||||
|  | @ -67,7 +68,7 @@ fn (g &Gen) get_backend() ?CodeGen { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn gen(files []ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) { | pub fn gen(files []ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) { | ||||||
| 	mut g := Gen{ | 	mut g := &Gen{ | ||||||
| 		table: table | 		table: table | ||||||
| 		sect_header_name_pos: 0 | 		sect_header_name_pos: 0 | ||||||
| 		out_name: out_name | 		out_name: out_name | ||||||
|  |  | ||||||
|  | @ -292,19 +292,8 @@ 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 | 			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) { | 			if param.typ.has_flag(.shared_f) { | ||||||
| 				is_heap_ref = true |  | ||||||
| 				is_stack_obj = false | 				is_stack_obj = false | ||||||
| 			} | 			} | ||||||
| 			p.scope.register(ast.Var{ | 			p.scope.register(ast.Var{ | ||||||
|  | @ -312,7 +301,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl { | ||||||
| 				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 | 				is_stack_obj: is_stack_obj | ||||||
| 				pos: param.pos | 				pos: param.pos | ||||||
| 				is_used: true | 				is_used: true | ||||||
|  | @ -601,19 +589,8 @@ 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 | 		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) { | 		if arg.typ.has_flag(.shared_f) { | ||||||
| 			is_heap_ref = true |  | ||||||
| 			is_stack_obj = false | 			is_stack_obj = false | ||||||
| 		} | 		} | ||||||
| 		p.scope.register(ast.Var{ | 		p.scope.register(ast.Var{ | ||||||
|  | @ -623,7 +600,6 @@ 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 | 			is_stack_obj: is_stack_obj | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1,18 +1,19 @@ | ||||||
| struct Qwe { | [heap] | ||||||
|  | struct Hwe { | ||||||
| mut: | mut: | ||||||
| 	n int | 	n int | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn mut_x(mut x Qwe) &Qwe { | fn mut_x(mut x Hwe) &Hwe { | ||||||
| 	n := x.n | 	n := x.n | ||||||
| 	// defer statement should not have run, yet
 | 	// defer statement should not have run, yet
 | ||||||
| 	assert n == 10 | 	assert n == 10 | ||||||
| 	x.n += 5 | 	x.n += 5 | ||||||
| 	return unsafe { &x } | 	return &x | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn deferer() &Qwe { | fn deferer() &Hwe { | ||||||
| 	mut s := &Qwe{ | 	mut s := &Hwe{ | ||||||
| 		n: 10 | 		n: 10 | ||||||
| 	} | 	} | ||||||
| 	defer { | 	defer { | ||||||
|  | @ -28,6 +29,15 @@ fn test_defer_in_return() { | ||||||
| 	assert q.n == 17 | 	assert q.n == 17 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | struct Qwe { | ||||||
|  | mut: | ||||||
|  | 	n int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn ret_ref(mut x Qwe) &Qwe { | ||||||
|  | 	return unsafe { x } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fn defer_multi_ret(mut a Qwe) (int, f64) { | fn defer_multi_ret(mut a Qwe) (int, f64) { | ||||||
| 	defer { | 	defer { | ||||||
| 		a.n *= 2 | 		a.n *= 2 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ mut: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (mut s MyStruct<T>) add(e &T) bool { | fn (mut s MyStruct<T>) add(e &T) bool { | ||||||
| 	s.buffer[0] = e | 	s.buffer[0] = unsafe { e } | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ pub fn (mut gitstructure GitStructure) repo_get(name string) ?&GitRepo { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn test_opt_ref_return() { | fn test_opt_ref_return() { | ||||||
| 	mut gitstruct := &GitStructure{ | 	mut gitstruct := GitStructure{ | ||||||
| 		root: 'r' | 		root: 'r' | ||||||
| 		repos: [ | 		repos: [ | ||||||
| 			&GitRepo{ | 			&GitRepo{ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,61 @@ | ||||||
|  | [heap] | ||||||
|  | struct Abc { | ||||||
|  | mut: | ||||||
|  | 	n int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct St { | ||||||
|  | 	Abc | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct Qwe { | ||||||
|  | mut: | ||||||
|  | 	f f64 | ||||||
|  | 	a Abc | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn pass_abc(q &Abc) &Abc { | ||||||
|  | 	return q | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn pass_st(q &St) &St { | ||||||
|  | 	return q | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn pass_qwe(q &Qwe) &Qwe { | ||||||
|  | 	return q | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_ref_structs() (&Abc, &St, &Qwe) { | ||||||
|  | 	a := Abc{ | ||||||
|  | 		n: 3 | ||||||
|  | 	} | ||||||
|  | 	b := St{Abc{ | ||||||
|  | 		n: 7 | ||||||
|  | 	}} | ||||||
|  | 	x := Qwe{ | ||||||
|  | 		f: 12.25 | ||||||
|  | 		a: Abc{ | ||||||
|  | 			n: 23 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	aa := pass_abc(&a) | ||||||
|  | 	bb := pass_st(&b) | ||||||
|  | 	xx := pass_qwe(&x) | ||||||
|  | 	return aa, bb, xx | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn owerwrite_stack() f64 { | ||||||
|  | 	a := 12.5 | ||||||
|  | 	b := 3.5 | ||||||
|  | 	c := a + b | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn test_ref_struct() { | ||||||
|  | 	u, v, w := get_ref_structs() | ||||||
|  | 	d := owerwrite_stack() | ||||||
|  | 	assert u.n == 3 | ||||||
|  | 	assert v.n == 7 | ||||||
|  | 	assert w.a.n == 23 | ||||||
|  | } | ||||||
|  | @ -11,17 +11,17 @@ fn new(x int) &Test { | ||||||
| 
 | 
 | ||||||
| fn (mut t Test) inc() &Test { | fn (mut t Test) inc() &Test { | ||||||
| 	t.val++ | 	t.val++ | ||||||
| 	return t | 	return unsafe { t } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (mut t Test) add(x int) &Test { | fn (mut t Test) add(x int) &Test { | ||||||
| 	t.val += x | 	t.val += x | ||||||
| 	return t | 	return unsafe { t } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn (mut t Test) div(x int) &Test { | fn (mut t Test) div(x int) &Test { | ||||||
| 	t.val /= x | 	t.val /= x | ||||||
| 	return t | 	return unsafe { t } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn test_method_call_chains() { | fn test_method_call_chains() { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ mut: | ||||||
| 
 | 
 | ||||||
| fn (mut p Player) set_name(name string) &Player { | fn (mut p Player) set_name(name string) &Player { | ||||||
| 	p.name = name | 	p.name = name | ||||||
| 	return p // because of automatic (de)reference of return values
 | 	return unsafe { p } // because of automatic (de)reference of return values
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NB: `p` is declared as a `mut` parameter,
 | // NB: `p` is declared as a `mut` parameter,
 | ||||||
|  |  | ||||||
|  | @ -231,7 +231,7 @@ fn opt_ptr(a &int) ?&int { | ||||||
| 	if isnil(a) { | 	if isnil(a) { | ||||||
| 		return none | 		return none | ||||||
| 	} | 	} | ||||||
| 	return a | 	return unsafe { a } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn test_opt_ptr() { | fn test_opt_ptr() { | ||||||
|  |  | ||||||
|  | @ -264,7 +264,7 @@ fn bar_config(c Config, def int) { | ||||||
| fn mut_bar_config(mut c Config, def int) &Config { | fn mut_bar_config(mut c Config, def int) &Config { | ||||||
| 	c.n = c.def | 	c.n = c.def | ||||||
| 	assert c.n == def | 	assert c.n == def | ||||||
| 	return c | 	return unsafe { c } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn foo_user(u User) {} | fn foo_user(u User) {} | ||||||
|  |  | ||||||
|  | @ -37,7 +37,7 @@ pub struct SSEMessage { | ||||||
| 
 | 
 | ||||||
| pub fn new_connection(conn &net.TcpConn) &SSEConnection { | pub fn new_connection(conn &net.TcpConn) &SSEConnection { | ||||||
| 	return &SSEConnection{ | 	return &SSEConnection{ | ||||||
| 		conn: conn | 		conn: unsafe { conn } | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -329,7 +329,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) { | ||||||
| 	} | 	} | ||||||
| 	app.Context = Context{ | 	app.Context = Context{ | ||||||
| 		req: req | 		req: req | ||||||
| 		conn: conn | 		conn: unsafe { conn } | ||||||
| 		form: map[string]string{} | 		form: map[string]string{} | ||||||
| 		static_files: app.static_files | 		static_files: app.static_files | ||||||
| 		static_mime_types: app.static_mime_types | 		static_mime_types: app.static_mime_types | ||||||
|  |  | ||||||
|  | @ -98,8 +98,8 @@ fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client) | ||||||
| 	server_client := &ServerClient{ | 	server_client := &ServerClient{ | ||||||
| 		resource_name: get_tokens[1] | 		resource_name: get_tokens[1] | ||||||
| 		client_key: key | 		client_key: key | ||||||
| 		client: c | 		client: unsafe { c } | ||||||
| 		server: s | 		server: unsafe { s } | ||||||
| 	} | 	} | ||||||
| 	unsafe { | 	unsafe { | ||||||
| 		lines.free() | 		lines.free() | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue