all: various fixes for [heap]/auto-heap handling (#10033)

pull/10046/head
Uwe Krüger 2021-05-07 14:58:48 +02:00 committed by GitHub
parent 5b4eef8010
commit d26ac5692e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 279 additions and 149 deletions

View File

@ -43,7 +43,7 @@ fn (mut ctx Context) println(s string) {
}
fn do_timeout(c &Context) {
mut ctx := c
mut ctx := unsafe { c }
time.sleep(ctx.timeout_ms * time.millisecond)
exit(ctx.exitcode)
}

View File

@ -171,7 +171,7 @@ fn (mut context Context) get_changed_vfiles() int {
}
fn change_detection_loop(ocontext &Context) {
mut context := ocontext
mut context := unsafe { ocontext }
for {
if context.v_cycles >= max_v_cycles || context.scan_cycles >= max_scan_cycles {
context.is_exiting = true

View File

@ -13,7 +13,7 @@ mut:
}
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++ {
t := int(f32(acontext.frame_0 + frame) * 0.245)
// "Techno" by Gabriel Miceli

View File

@ -16,6 +16,7 @@ const (
orange = ui.Color{255, 140, 0}
)
[heap]
struct App {
mut:
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
}
[heap]
struct Game {
mut:
app &App = 0

View File

@ -256,6 +256,7 @@ fn (mut r Rat) randomize() {
r.app.height - block_size - buffer)
}
[heap]
struct App {
mut:
termui &termui.Context = 0

View File

@ -9,7 +9,7 @@ pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void {
dest_[i] = src_[i]
}
}
return dest
return unsafe { dest }
}
[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))) }
if u64(new_size) <= old_size {
return old_area
return unsafe { old_area }
} else {
new_area := unsafe { malloc(int(new_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)
}
}
return s
return unsafe { s }
}
[unsafe]
@ -74,7 +74,7 @@ fn memmove(dest &C.void, src &C.void, n size_t) &C.void {
}
}
unsafe { free(temp_buf) }
return dest
return unsafe { dest }
}
[export: 'calloc']

View File

@ -77,7 +77,7 @@ pub fn tos(s &byte, len int) string {
panic('tos(): nil string')
}
return string{
str: s
str: unsafe { s }
len: len
}
}
@ -96,7 +96,7 @@ pub fn tos2(s &byte) string {
panic('tos2: nil string')
}
return string{
str: s
str: unsafe { s }
len: unsafe { vstrlen(s) }
}
}
@ -146,7 +146,7 @@ pub fn tos_lit(s &char) string {
[unsafe]
pub fn (bp &byte) vstring() string {
return string{
str: bp
str: unsafe { bp }
len: unsafe { C.strlen(&char(bp)) }
}
}
@ -156,7 +156,7 @@ pub fn (bp &byte) vstring() string {
[unsafe]
pub fn (bp &byte) vstring_with_len(len int) string {
return string{
str: bp
str: unsafe { bp }
len: len
is_lit: 0
}
@ -194,7 +194,7 @@ pub fn (cp &char) vstring_with_len(len int) string {
[unsafe]
pub fn (bp &byte) vstring_literal() string {
return string{
str: bp
str: unsafe { bp }
len: unsafe { C.strlen(&char(bp)) }
is_lit: 1
}
@ -205,7 +205,7 @@ pub fn (bp &byte) vstring_literal() string {
[unsafe]
pub fn (bp &byte) vstring_literal_with_len(len int) string {
return string{
str: bp
str: unsafe { bp }
len: len
is_lit: 1
}

View File

@ -94,7 +94,7 @@ pub fn (mut cmd Command) add_command(command Command) {
println('Command with the name `$subcmd.name` already exists')
exit(1)
}
subcmd.parent = cmd
subcmd.parent = unsafe { cmd }
cmd.commands << subcmd
}
@ -102,7 +102,7 @@ pub fn (mut cmd Command) add_command(command Command) {
// is linked as a chain.
pub fn (mut cmd Command) setup() {
for mut subcmd in cmd.commands {
subcmd.parent = cmd
subcmd.parent = unsafe { cmd }
subcmd.setup()
}
}

View File

@ -100,6 +100,7 @@ pub:
native_rendering bool // Cocoa on macOS/iOS, GDI+ on Windows
}
[heap]
pub struct Context {
render_text bool
mut:

View File

@ -10,6 +10,7 @@ import sokol
import sokol.sgl
import stbi
[heap]
pub struct Image {
pub mut:
id int

View File

@ -43,7 +43,7 @@ pub fn vec3(x f32, y f32, z f32) Vec3 {
fn mat4(f &f32) Mat4 {
res := Mat4{
data: f
data: unsafe { f }
}
return res
}

View File

@ -20,7 +20,7 @@ pub fn (mut r Response) write_string(s string) {
[inline]
pub fn (mut r Response) http_ok() &Response {
r.write_string('HTTP/1.1 200 OK\r\n')
return r
return unsafe { r }
}
[inline]
@ -29,7 +29,7 @@ pub fn (mut r Response) header(k string, v string) &Response {
r.write_string(': ')
r.write_string(v)
r.write_string('\r\n')
return r
return unsafe { r }
}
[inline]
@ -39,13 +39,13 @@ pub fn (mut r Response) header_date() &Response {
r.buf += cpy(r.buf, r.date, 29)
}
r.write_string('\r\n')
return r
return unsafe { r }
}
[inline]
pub fn (mut r Response) header_server() &Response {
r.write_string('Server: V\r\n')
return r
return unsafe { r }
}
[inline]
@ -53,25 +53,25 @@ pub fn (mut r Response) content_type(s string) &Response {
r.write_string('Content-Type: ')
r.write_string(s)
r.write_string('\r\n')
return r
return unsafe { r }
}
[inline]
pub fn (mut r Response) html() &Response {
r.write_string('Content-Type: text/html\r\n')
return r
return unsafe { r }
}
[inline]
pub fn (mut r Response) plain() &Response {
r.write_string('Content-Type: text/plain\r\n')
return r
return unsafe { r }
}
[inline]
pub fn (mut r Response) json() &Response {
r.write_string('Content-Type: application/json\r\n')
return r
return unsafe { r }
}
[inline]

View File

@ -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
// program terminates soon afterwards.
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

View File

@ -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)
}
[heap]
pub struct C.sg_shader_desc {
pub mut:
_start_canary u32

View File

@ -510,7 +510,6 @@ pub mut:
is_or bool // `x := foo() or { ... }`
is_tmp bool // for tmp for loop vars, so that autofree can skip them
is_auto_heap bool // value whoes address goes out of scope
is_heap_ref bool // *known* to be pointer to heap memory (ptr to [heap] struct)
is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct)
}

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file.
module ast
[heap]
pub struct Scope {
pub mut:
// mut:

View File

@ -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
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')
mut ts := s
mut ts := unsafe { s }
for {
if method := ts.find_method(name) {
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
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')
mut ts := s
mut ts := unsafe { s }
for {
match mut ts.info {
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) {
mut sym := sym_
mut sym := unsafe { sym_ }
mut info := sym.info as SumType
if info.found_fields {
return

View File

@ -64,6 +64,7 @@ pub fn pref_arch_to_table_language(pref_arch pref.Arch) Language {
// * Table.type_kind(typ) not TypeSymbol.kind.
// Each TypeSymbol is entered into `Table.types`.
// See also: Table.get_type_symbol.
pub struct TypeSymbol {
pub:
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 {
return t.name

View File

@ -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) {
c.file = file
c.file = unsafe { file }
c.vmod_file_content = ''
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 ' +
'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 {
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
}
}
mut expr_type := ast.Type(0)
mut expected_type := ast.Type(0)
if is_embed {
c.expected_type = embed_type
expr_type := c.expr(field.expr)
expected_type = embed_type
c.expected_type = expected_type
expr_type = c.expr(field.expr)
expr_type_sym := c.table.get_type_symbol(expr_type)
if expr_type != ast.void_type && expr_type_sym.kind != .placeholder {
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 {
inited_fields << field_name
field_type_sym := c.table.get_type_symbol(info_field.typ)
c.expected_type = info_field.typ
mut expr_type := c.expr(field.expr)
expected_type = info_field.typ
c.expected_type = expected_type
expr_type = c.expr(field.expr)
if !info_field.typ.has_flag(.optional) {
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].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
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',
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 {
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)
// 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
match mut left {
ast.Ident {
@ -3216,6 +3282,11 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
if left.obj.is_auto_deref {
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 {
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 {
mut obj := unsafe { &node.obj }
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)
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]`.',
type_sym := c.table.get_type_symbol(obj.typ.set_nr_muls(0))
if obj.is_stack_obj && !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('`$node.name` cannot be referenced outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
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 {
if type_sym.kind == .struct_ {
info := type_sym.info as ast.Struct
if !info.is_heap {
node.obj.is_auto_heap = true
}
}
}
}
}
ast.SelectorExpr {
if !node.expr_type.is_ptr() {
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.cur_fn = node
c.cur_fn = unsafe { node }
// Add return if `fn(...) ? {...}` have no return at end
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) {

View File

@ -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')

View File

@ -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')
}

View File

@ -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 | }

View File

@ -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
}

View File

@ -32,6 +32,7 @@ mut:
methods map[string][]ast.FnDecl
}
[heap]
struct JsGen {
table &ast.Table
pref &pref.Preferences

View File

@ -20,6 +20,7 @@ interface CodeGen {
// XXX WHY gen_exit fn (expr ast.Expr)
}
[heap]
pub struct Gen {
out_name string
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) {
mut g := Gen{
mut g := &Gen{
table: table
sect_header_name_pos: 0
out_name: out_name

View File

@ -292,19 +292,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
scope: 0
}
}
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
mut is_stack_obj := true
nr_muls := param.typ.nr_muls()
if nr_muls == 1 { // mut a St, b &St
base_type_sym := p.table.get_type_symbol(param.typ.set_nr_muls(0))
if base_type_sym.kind == .struct_ {
info := base_type_sym.info as ast.Struct
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
is_stack_obj = !is_heap_ref
}
}
if param.typ.has_flag(.shared_f) {
is_heap_ref = true
is_stack_obj = false
}
p.scope.register(ast.Var{
@ -312,7 +301,6 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
typ: param.typ
is_mut: param.is_mut
is_auto_deref: param.is_mut || param.is_auto_rec
is_heap_ref: is_heap_ref
is_stack_obj: is_stack_obj
pos: param.pos
is_used: true
@ -601,19 +589,8 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
if arg.name.len == 0 {
p.error_with_pos('use `_` to name an unused parameter', arg.pos)
}
mut is_heap_ref := false // args are only borrowed, so assume maybe on stack
mut is_stack_obj := true
nr_muls := arg.typ.nr_muls()
if nr_muls == 1 { // mut a St, b &St
base_type_sym := p.table.get_type_symbol(arg.typ.set_nr_muls(0))
if base_type_sym.kind == .struct_ {
info := base_type_sym.info as ast.Struct
is_heap_ref = info.is_heap // if type is declared as [heap] we can assume this, too
is_stack_obj = !is_heap_ref
}
}
if arg.typ.has_flag(.shared_f) {
is_heap_ref = true
is_stack_obj = false
}
p.scope.register(ast.Var{
@ -623,7 +600,6 @@ fn (mut p Parser) anon_fn() ast.AnonFn {
pos: arg.pos
is_used: true
is_arg: true
is_heap_ref: is_heap_ref
is_stack_obj: is_stack_obj
})
}

View File

@ -1,18 +1,19 @@
struct Qwe {
[heap]
struct Hwe {
mut:
n int
}
fn mut_x(mut x Qwe) &Qwe {
fn mut_x(mut x Hwe) &Hwe {
n := x.n
// defer statement should not have run, yet
assert n == 10
x.n += 5
return unsafe { &x }
return &x
}
fn deferer() &Qwe {
mut s := &Qwe{
fn deferer() &Hwe {
mut s := &Hwe{
n: 10
}
defer {
@ -28,6 +29,15 @@ fn test_defer_in_return() {
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) {
defer {
a.n *= 2

View File

@ -5,7 +5,7 @@ mut:
}
fn (mut s MyStruct<T>) add(e &T) bool {
s.buffer[0] = e
s.buffer[0] = unsafe { e }
return true
}

View File

@ -26,7 +26,7 @@ pub fn (mut gitstructure GitStructure) repo_get(name string) ?&GitRepo {
}
fn test_opt_ref_return() {
mut gitstruct := &GitStructure{
mut gitstruct := GitStructure{
root: 'r'
repos: [
&GitRepo{

View File

@ -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
}

View File

@ -11,17 +11,17 @@ fn new(x int) &Test {
fn (mut t Test) inc() &Test {
t.val++
return t
return unsafe { t }
}
fn (mut t Test) add(x int) &Test {
t.val += x
return t
return unsafe { t }
}
fn (mut t Test) div(x int) &Test {
t.val /= x
return t
return unsafe { t }
}
fn test_method_call_chains() {

View File

@ -7,7 +7,7 @@ mut:
fn (mut p Player) set_name(name string) &Player {
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,

View File

@ -231,7 +231,7 @@ fn opt_ptr(a &int) ?&int {
if isnil(a) {
return none
}
return a
return unsafe { a }
}
fn test_opt_ptr() {

View File

@ -264,7 +264,7 @@ fn bar_config(c Config, def int) {
fn mut_bar_config(mut c Config, def int) &Config {
c.n = c.def
assert c.n == def
return c
return unsafe { c }
}
fn foo_user(u User) {}

View File

@ -37,7 +37,7 @@ pub struct SSEMessage {
pub fn new_connection(conn &net.TcpConn) &SSEConnection {
return &SSEConnection{
conn: conn
conn: unsafe { conn }
}
}

View File

@ -329,7 +329,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T) {
}
app.Context = Context{
req: req
conn: conn
conn: unsafe { conn }
form: map[string]string{}
static_files: app.static_files
static_mime_types: app.static_mime_types

View File

@ -98,8 +98,8 @@ fn (mut s Server) parse_client_handshake(client_handshake string, mut c Client)
server_client := &ServerClient{
resource_name: get_tokens[1]
client_key: key
client: c
server: s
client: unsafe { c }
server: unsafe { s }
}
unsafe {
lines.free()