cgen: optionals/autofree fixes
parent
970bb09eca
commit
d39866d4f7
|
@ -295,9 +295,10 @@ jobs:
|
||||||
run: ./v -cc gcc -cflags "-Werror" test-self
|
run: ./v -cc gcc -cflags "-Werror" test-self
|
||||||
- name: Build examples
|
- name: Build examples
|
||||||
run: ./v build-examples
|
run: ./v build-examples
|
||||||
- name: Build examples with -autofree
|
- name: Build examples/certain tests with -autofree
|
||||||
run: |
|
run: |
|
||||||
./v -autofree -experimental -o tetris examples/tetris/tetris.v
|
./v -autofree -experimental -o tetris examples/tetris/tetris.v
|
||||||
|
./v -autofree vlib/v/tests/option_test.v
|
||||||
- name: Build modules
|
- name: Build modules
|
||||||
run: |
|
run: |
|
||||||
./v build-module vlib/os
|
./v build-module vlib/os
|
||||||
|
|
|
@ -16,7 +16,7 @@ const (
|
||||||
==================
|
==================
|
||||||
C error. This should never happen.
|
C error. This should never happen.
|
||||||
|
|
||||||
If you were not working with C interop, please raise an issue on GitHub:
|
If you were not working with C interop, this is a compiler bug, please raise an issue on GitHub:
|
||||||
|
|
||||||
https://github.com/vlang/v/issues/new/choose
|
https://github.com/vlang/v/issues/new/choose
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module c
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import v.table
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
||||||
|
mut node := original_assert_statement
|
||||||
|
g.writeln('// assert')
|
||||||
|
if mut node.expr is ast.InfixExpr {
|
||||||
|
if mut node.expr.left is ast.CallExpr {
|
||||||
|
node.expr.left = g.new_ctemp_var_then_gen(node.expr.left, node.expr.left_type)
|
||||||
|
}
|
||||||
|
if mut node.expr.right is ast.CallExpr {
|
||||||
|
node.expr.right = g.new_ctemp_var_then_gen(node.expr.right, node.expr.right_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.inside_ternary++
|
||||||
|
if g.is_test {
|
||||||
|
g.write('if (')
|
||||||
|
g.expr(node.expr)
|
||||||
|
g.write(')')
|
||||||
|
g.decrement_inside_ternary()
|
||||||
|
g.writeln(' {')
|
||||||
|
g.writeln('\tg_test_oks++;')
|
||||||
|
metaname_ok := g.gen_assert_metainfo(node)
|
||||||
|
g.writeln('\tmain__cb_assertion_ok(&$metaname_ok);')
|
||||||
|
g.writeln('} else {')
|
||||||
|
g.writeln('\tg_test_fails++;')
|
||||||
|
metaname_fail := g.gen_assert_metainfo(node)
|
||||||
|
g.writeln('\tmain__cb_assertion_failed(&$metaname_fail);')
|
||||||
|
g.writeln('\tlongjmp(g_jump_buffer, 1);')
|
||||||
|
g.writeln('\t// TODO')
|
||||||
|
g.writeln('\t// Maybe print all vars in a test function if it fails?')
|
||||||
|
g.writeln('}')
|
||||||
|
} else {
|
||||||
|
g.write('if (!(')
|
||||||
|
g.expr(node.expr)
|
||||||
|
g.write('))')
|
||||||
|
g.decrement_inside_ternary()
|
||||||
|
g.writeln(' {')
|
||||||
|
metaname_panic := g.gen_assert_metainfo(node)
|
||||||
|
g.writeln('\t__print_assert_failure(&$metaname_panic);')
|
||||||
|
g.writeln('\tv_panic(_SLIT("Assertion failed..."));')
|
||||||
|
g.writeln('}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt) string {
|
||||||
|
mod_path := cestring(g.file.path)
|
||||||
|
fn_name := g.fn_decl.name
|
||||||
|
line_nr := node.pos.line_nr
|
||||||
|
src := cestring(node.expr.str())
|
||||||
|
metaname := 'v_assert_meta_info_$g.new_tmp_var()'
|
||||||
|
g.writeln('\tVAssertMetaInfo $metaname = {0};')
|
||||||
|
g.writeln('\t${metaname}.fpath = ${ctoslit(mod_path)};')
|
||||||
|
g.writeln('\t${metaname}.line_nr = $line_nr;')
|
||||||
|
g.writeln('\t${metaname}.fn_name = ${ctoslit(fn_name)};')
|
||||||
|
g.writeln('\t${metaname}.src = ${cnewlines(ctoslit(src))};')
|
||||||
|
match mut node.expr {
|
||||||
|
ast.InfixExpr {
|
||||||
|
g.writeln('\t${metaname}.op = ${ctoslit(node.expr.op.str())};')
|
||||||
|
g.writeln('\t${metaname}.llabel = ${cnewlines(ctoslit(node.expr.left.str()))};')
|
||||||
|
g.writeln('\t${metaname}.rlabel = ${cnewlines(ctoslit(node.expr.right.str()))};')
|
||||||
|
g.write('\t${metaname}.lvalue = ')
|
||||||
|
g.gen_assert_single_expr(node.expr.left, node.expr.left_type)
|
||||||
|
g.writeln(';')
|
||||||
|
//
|
||||||
|
g.write('\t${metaname}.rvalue = ')
|
||||||
|
g.gen_assert_single_expr(node.expr.right, node.expr.right_type)
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
|
ast.CallExpr {
|
||||||
|
g.writeln('\t${metaname}.op = _SLIT("call");')
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
return metaname
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ table.Type) {
|
||||||
|
unknown_value := '*unknown value*'
|
||||||
|
match expr {
|
||||||
|
ast.CastExpr, ast.IndexExpr, ast.MatchExpr {
|
||||||
|
g.write(ctoslit(unknown_value))
|
||||||
|
}
|
||||||
|
ast.PrefixExpr {
|
||||||
|
if expr.right is ast.CastExpr {
|
||||||
|
// TODO: remove this check;
|
||||||
|
// vlib/builtin/map_test.v (a map of &int, set to &int(0)) fails
|
||||||
|
// without special casing ast.CastExpr here
|
||||||
|
g.write(ctoslit(unknown_value))
|
||||||
|
} else {
|
||||||
|
g.gen_expr_to_string(expr, typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Type {
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
g.write(ctoslit('$sym.name'))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.gen_expr_to_string(expr, typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ')
|
||||||
|
}
|
|
@ -1637,111 +1637,10 @@ fn (mut g Gen) gen_attrs(attrs []table.Attr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_assert_stmt(original_assert_statement ast.AssertStmt) {
|
|
||||||
mut node := original_assert_statement
|
|
||||||
g.writeln('// assert')
|
|
||||||
if mut node.expr is ast.InfixExpr {
|
|
||||||
if mut node.expr.left is ast.CallExpr {
|
|
||||||
node.expr.left = g.new_ctemp_var_then_gen(node.expr.left, node.expr.left_type)
|
|
||||||
}
|
|
||||||
if mut node.expr.right is ast.CallExpr {
|
|
||||||
node.expr.right = g.new_ctemp_var_then_gen(node.expr.right, node.expr.right_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.inside_ternary++
|
|
||||||
if g.is_test {
|
|
||||||
g.write('if (')
|
|
||||||
g.expr(node.expr)
|
|
||||||
g.write(')')
|
|
||||||
g.decrement_inside_ternary()
|
|
||||||
g.writeln(' {')
|
|
||||||
g.writeln('\tg_test_oks++;')
|
|
||||||
metaname_ok := g.gen_assert_metainfo(node)
|
|
||||||
g.writeln('\tmain__cb_assertion_ok(&$metaname_ok);')
|
|
||||||
g.writeln('} else {')
|
|
||||||
g.writeln('\tg_test_fails++;')
|
|
||||||
metaname_fail := g.gen_assert_metainfo(node)
|
|
||||||
g.writeln('\tmain__cb_assertion_failed(&$metaname_fail);')
|
|
||||||
g.writeln('\tlongjmp(g_jump_buffer, 1);')
|
|
||||||
g.writeln('\t// TODO')
|
|
||||||
g.writeln('\t// Maybe print all vars in a test function if it fails?')
|
|
||||||
g.writeln('}')
|
|
||||||
} else {
|
|
||||||
g.write('if (!(')
|
|
||||||
g.expr(node.expr)
|
|
||||||
g.write('))')
|
|
||||||
g.decrement_inside_ternary()
|
|
||||||
g.writeln(' {')
|
|
||||||
metaname_panic := g.gen_assert_metainfo(node)
|
|
||||||
g.writeln('\t__print_assert_failure(&$metaname_panic);')
|
|
||||||
g.writeln('\tv_panic(_SLIT("Assertion failed..."));')
|
|
||||||
g.writeln('}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cnewlines(s string) string {
|
fn cnewlines(s string) string {
|
||||||
return s.replace('\n', r'\n')
|
return s.replace('\n', r'\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_assert_metainfo(node ast.AssertStmt) string {
|
|
||||||
mod_path := cestring(g.file.path)
|
|
||||||
fn_name := g.fn_decl.name
|
|
||||||
line_nr := node.pos.line_nr
|
|
||||||
src := cestring(node.expr.str())
|
|
||||||
metaname := 'v_assert_meta_info_$g.new_tmp_var()'
|
|
||||||
g.writeln('\tVAssertMetaInfo $metaname = {0};')
|
|
||||||
g.writeln('\t${metaname}.fpath = ${ctoslit(mod_path)};')
|
|
||||||
g.writeln('\t${metaname}.line_nr = $line_nr;')
|
|
||||||
g.writeln('\t${metaname}.fn_name = ${ctoslit(fn_name)};')
|
|
||||||
g.writeln('\t${metaname}.src = ${cnewlines(ctoslit(src))};')
|
|
||||||
match mut node.expr {
|
|
||||||
ast.InfixExpr {
|
|
||||||
g.writeln('\t${metaname}.op = ${ctoslit(node.expr.op.str())};')
|
|
||||||
g.writeln('\t${metaname}.llabel = ${cnewlines(ctoslit(node.expr.left.str()))};')
|
|
||||||
g.writeln('\t${metaname}.rlabel = ${cnewlines(ctoslit(node.expr.right.str()))};')
|
|
||||||
g.write('\t${metaname}.lvalue = ')
|
|
||||||
g.gen_assert_single_expr(node.expr.left, node.expr.left_type)
|
|
||||||
g.writeln(';')
|
|
||||||
//
|
|
||||||
g.write('\t${metaname}.rvalue = ')
|
|
||||||
g.gen_assert_single_expr(node.expr.right, node.expr.right_type)
|
|
||||||
g.writeln(';')
|
|
||||||
}
|
|
||||||
ast.CallExpr {
|
|
||||||
g.writeln('\t${metaname}.op = _SLIT("call");')
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
return metaname
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_assert_single_expr(expr ast.Expr, typ table.Type) {
|
|
||||||
unknown_value := '*unknown value*'
|
|
||||||
match expr {
|
|
||||||
ast.CastExpr, ast.IndexExpr, ast.MatchExpr {
|
|
||||||
g.write(ctoslit(unknown_value))
|
|
||||||
}
|
|
||||||
ast.PrefixExpr {
|
|
||||||
if expr.right is ast.CastExpr {
|
|
||||||
// TODO: remove this check;
|
|
||||||
// vlib/builtin/map_test.v (a map of &int, set to &int(0)) fails
|
|
||||||
// without special casing ast.CastExpr here
|
|
||||||
g.write(ctoslit(unknown_value))
|
|
||||||
} else {
|
|
||||||
g.gen_expr_to_string(expr, typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Type {
|
|
||||||
sym := g.table.get_type_symbol(typ)
|
|
||||||
g.write(ctoslit('$sym.name'))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.gen_expr_to_string(expr, typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.write(' /* typeof: ' + expr.type_name() + ' type: ' + typ.str() + ' */ ')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) write_fn_ptr_decl(func &table.FnType, ptr_name string) {
|
fn (mut g Gen) write_fn_ptr_decl(func &table.FnType, ptr_name string) {
|
||||||
ret_styp := g.typ(func.func.return_type)
|
ret_styp := g.typ(func.func.return_type)
|
||||||
g.write('$ret_styp (*$ptr_name) (')
|
g.write('$ret_styp (*$ptr_name) (')
|
||||||
|
@ -1830,8 +1729,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
// int pos = *(int*)_t190.data;
|
// int pos = *(int*)_t190.data;
|
||||||
mut tmp_opt := ''
|
// mut tmp_opt := ''
|
||||||
is_optional := g.is_autofree && (assign_stmt.op in [.decl_assign, .assign])
|
/*
|
||||||
|
is_optional := false && g.is_autofree && (assign_stmt.op in [.decl_assign, .assign])
|
||||||
&& assign_stmt.left_types.len == 1 && assign_stmt.right[0] is ast.CallExpr
|
&& assign_stmt.left_types.len == 1 && assign_stmt.right[0] is ast.CallExpr
|
||||||
if is_optional {
|
if is_optional {
|
||||||
// g.write('/* optional assignment */')
|
// g.write('/* optional assignment */')
|
||||||
|
@ -1849,6 +1749,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// return
|
// return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// json_test failed w/o this check
|
// json_test failed w/o this check
|
||||||
if return_type != table.void_type && return_type != 0 {
|
if return_type != table.void_type && return_type != 0 {
|
||||||
sym := g.table.get_type_symbol(return_type)
|
sym := g.table.get_type_symbol(return_type)
|
||||||
|
@ -2175,7 +2076,9 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// Unwrap the optional now that the testing code has been prepended.
|
// Unwrap the optional now that the testing code has been prepended.
|
||||||
// `pos := s.index(...
|
// `pos := s.index(...
|
||||||
// `int pos = *(int)_t10.data;`
|
// `int pos = *(int)_t10.data;`
|
||||||
if g.is_autofree {
|
// if g.is_autofree {
|
||||||
|
/*
|
||||||
|
if is_optional {
|
||||||
g.write('*($styp*)')
|
g.write('*($styp*)')
|
||||||
g.write(tmp_opt + '.data/*FFz*/')
|
g.write(tmp_opt + '.data/*FFz*/')
|
||||||
g.right_is_opt = false
|
g.right_is_opt = false
|
||||||
|
@ -2185,6 +2088,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
g.is_shared = var_type.has_flag(.shared_f)
|
g.is_shared = var_type.has_flag(.shared_f)
|
||||||
if !cloned {
|
if !cloned {
|
||||||
|
@ -5619,7 +5523,7 @@ fn (mut g Gen) or_block(var_name string, or_block ast.OrExpr, return_type table.
|
||||||
if is_none_ok {
|
if is_none_ok {
|
||||||
g.writeln('if (!${cvar_name}.ok && !${cvar_name}.is_none) {')
|
g.writeln('if (!${cvar_name}.ok && !${cvar_name}.is_none) {')
|
||||||
} else {
|
} else {
|
||||||
g.writeln('if (!${cvar_name}.ok) {')
|
g.writeln('if (!${cvar_name}.ok) { /*or block*/ ')
|
||||||
}
|
}
|
||||||
if or_block.kind == .block {
|
if or_block.kind == .block {
|
||||||
if g.inside_or_block {
|
if g.inside_or_block {
|
||||||
|
|
|
@ -391,6 +391,7 @@ fn (mut g Gen) fn_args(args []table.Param, is_variadic bool) ([]string, []string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) call_expr(node ast.CallExpr) {
|
fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
|
// g.write('/*call expr*/')
|
||||||
// NOTE: everything could be done this way
|
// NOTE: everything could be done this way
|
||||||
// see my comment in parser near anon_fn
|
// see my comment in parser near anon_fn
|
||||||
if node.left is ast.AnonFn {
|
if node.left is ast.AnonFn {
|
||||||
|
@ -408,20 +409,25 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
defer {
|
defer {
|
||||||
g.inside_call = false
|
g.inside_call = false
|
||||||
}
|
}
|
||||||
gen_or := node.or_block.kind != .absent && !g.is_autofree
|
gen_or := node.or_block.kind != .absent // && !g.is_autofree
|
||||||
// if gen_or {
|
|
||||||
// g.writeln('/*start*/')
|
|
||||||
// }
|
|
||||||
is_gen_or_and_assign_rhs := gen_or && g.is_assign_rhs
|
is_gen_or_and_assign_rhs := gen_or && g.is_assign_rhs
|
||||||
cur_line := if is_gen_or_and_assign_rhs && !g.is_autofree {
|
cur_line := if is_gen_or_and_assign_rhs { // && !g.is_autofree {
|
||||||
|
// `x := foo() or { ...}`
|
||||||
|
// cut everything that has been generated to prepend optional variable creation
|
||||||
line := g.go_before_stmt(0)
|
line := g.go_before_stmt(0)
|
||||||
g.out.write_string(tabs[g.indent])
|
g.out.write_string(tabs[g.indent])
|
||||||
|
// g.write('/*is_gen_or_and_assign_rhs*/')
|
||||||
line
|
line
|
||||||
} else {
|
} else {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
|
if gen_or && g.pref.autofree && g.inside_return {
|
||||||
|
// TODO optional return af hack (tmp_count gets increased in .return_statement())
|
||||||
|
g.tmp_count--
|
||||||
|
}
|
||||||
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
||||||
if gen_or {
|
if gen_or && !g.inside_return {
|
||||||
|
// if is_gen_or_and_assign_rhs {
|
||||||
styp := g.typ(node.return_type.set_flag(.optional))
|
styp := g.typ(node.return_type.set_flag(.optional))
|
||||||
g.write('$styp $tmp_opt = ')
|
g.write('$styp $tmp_opt = ')
|
||||||
}
|
}
|
||||||
|
@ -437,16 +443,16 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
g.fn_call(node)
|
g.fn_call(node)
|
||||||
}
|
}
|
||||||
if gen_or { // && !g.autofree {
|
if gen_or { // && !g.autofree {
|
||||||
if !g.is_autofree {
|
// if !g.is_autofree {
|
||||||
g.or_block(tmp_opt, node.or_block, node.return_type)
|
g.or_block(tmp_opt, node.or_block, node.return_type)
|
||||||
}
|
//}
|
||||||
if is_gen_or_and_assign_rhs {
|
if is_gen_or_and_assign_rhs {
|
||||||
unwrapped_typ := node.return_type.clear_flag(.optional)
|
unwrapped_typ := node.return_type.clear_flag(.optional)
|
||||||
unwrapped_styp := g.typ(unwrapped_typ)
|
unwrapped_styp := g.typ(unwrapped_typ)
|
||||||
if unwrapped_typ == table.void_type {
|
if unwrapped_typ == table.void_type {
|
||||||
g.write('\n $cur_line')
|
g.write('\n $cur_line')
|
||||||
} else if g.table.get_type_symbol(node.return_type).kind == .multi_return {
|
} else if g.table.get_type_symbol(node.return_type).kind == .multi_return {
|
||||||
g.write('\n $cur_line $tmp_opt')
|
g.write('\n $cur_line $tmp_opt /*U*/')
|
||||||
} else {
|
} else {
|
||||||
g.write('\n $cur_line *($unwrapped_styp*)${tmp_opt}.data')
|
g.write('\n $cur_line *($unwrapped_styp*)${tmp_opt}.data')
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,7 @@ fn test_option_for_base_type_without_variable() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
assert val == 42
|
assert val == 42
|
||||||
val = ret_none() or {
|
val = ret_none() or { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
assert false
|
assert false
|
||||||
// This is invalid:
|
// This is invalid:
|
||||||
// x := 5 or {
|
// x := 5 or {
|
||||||
|
@ -101,30 +99,32 @@ fn foo_str() ?string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_optional(b bool) ?int {
|
fn propagate_optional(b bool) ?int {
|
||||||
a := err_call(b)?
|
a := err_call(b) ?
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_different_type(b bool) ?bool {
|
fn propagate_different_type(b bool) ?bool {
|
||||||
err_call(b)?
|
err_call(b) ?
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_propagation() {
|
fn test_propagation() {
|
||||||
a := propagate_optional(true) or {
|
println(1)
|
||||||
0
|
a := propagate_optional(true) or { 0 }
|
||||||
}
|
println(2)
|
||||||
assert a == 42
|
assert a == 42
|
||||||
|
println(3)
|
||||||
if _ := propagate_optional(false) {
|
if _ := propagate_optional(false) {
|
||||||
assert false
|
assert false
|
||||||
}
|
}
|
||||||
b := propagate_different_type(true) or {
|
println(4)
|
||||||
false
|
b := propagate_different_type(true) or { false }
|
||||||
}
|
|
||||||
assert b == true
|
assert b == true
|
||||||
|
println(5)
|
||||||
if _ := propagate_different_type(false) {
|
if _ := propagate_different_type(false) {
|
||||||
assert false
|
assert false
|
||||||
}
|
}
|
||||||
|
println(6)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_q() {
|
fn test_q() {
|
||||||
|
@ -132,23 +132,17 @@ fn test_q() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn or_return_val() int {
|
fn or_return_val() int {
|
||||||
a := ret_none() or {
|
a := ret_none() or { return 1 }
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
fn or_return_error() ?int {
|
fn or_return_error() ?int {
|
||||||
a := ret_none() or {
|
a := ret_none() or { return error('Nope') }
|
||||||
return error('Nope')
|
|
||||||
}
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
fn or_return_none() ?int {
|
fn or_return_none() ?int {
|
||||||
a := ret_none() or {
|
a := ret_none() or { return none }
|
||||||
return none
|
|
||||||
}
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,9 +187,7 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_field_or() {
|
fn test_field_or() {
|
||||||
name := foo_str() or {
|
name := foo_str() or { 'nada' }
|
||||||
'nada'
|
|
||||||
}
|
|
||||||
assert name == 'something'
|
assert name == 'something'
|
||||||
/*
|
/*
|
||||||
QTODO
|
QTODO
|
||||||
|
@ -225,8 +217,6 @@ mut:
|
||||||
opt ?Thing
|
opt ?Thing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn test_opt_field() {
|
fn test_opt_field() {
|
||||||
/*
|
/*
|
||||||
QTODO
|
QTODO
|
||||||
|
@ -251,13 +241,9 @@ fn test_opt_ptr() {
|
||||||
else {
|
else {
|
||||||
}
|
}
|
||||||
a := 3
|
a := 3
|
||||||
mut r := opt_ptr(&a) or {
|
mut r := opt_ptr(&a) or { &int(0) }
|
||||||
&int(0)
|
|
||||||
}
|
|
||||||
assert r == &a
|
assert r == &a
|
||||||
r = opt_ptr(&int(0)) or {
|
r = opt_ptr(&int(0)) or { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
assert false
|
assert false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,34 +269,34 @@ fn test_multi_return_opt() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn test_optional_val_with_empty_or() {
|
fn test_optional_val_with_empty_or() {
|
||||||
ret_none() or {}
|
ret_none() or { }
|
||||||
assert true
|
assert true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_optional_void_return_types_of_anon_fn() {
|
fn test_optional_void_return_types_of_anon_fn() {
|
||||||
f := fn(i int) ? {
|
f := fn (i int) ? {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return error("0")
|
return error('0')
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f(0) or {
|
f(0) or {
|
||||||
assert err == "0"
|
assert err == '0'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
f fn(int) ?
|
f fn (int) ?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_option_void_return_types_of_anon_fn_in_struct() {
|
fn test_option_void_return_types_of_anon_fn_in_struct() {
|
||||||
foo := Foo {
|
foo := Foo{
|
||||||
f: fn(i int) ? {
|
f: fn (i int) ? {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return error("0")
|
return error('0')
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -318,7 +304,7 @@ fn test_option_void_return_types_of_anon_fn_in_struct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
foo.f(0) or {
|
foo.f(0) or {
|
||||||
assert err == "0"
|
assert err == '0'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,3 +363,21 @@ struct MultiOptionalFieldTest {
|
||||||
a ?int
|
a ?int
|
||||||
b ?int
|
b ?int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn foo() ?int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo2() ?int {
|
||||||
|
for _ in 0 .. 5 {
|
||||||
|
return foo() or { continue }
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_return_or() {
|
||||||
|
x := foo2() or { return }
|
||||||
|
assert x == 0
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -210,15 +210,11 @@ fn if_expr() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_if_expr() string {
|
fn return_if_expr() string {
|
||||||
return if true {
|
return if true { get_string('a' + 'b') } else { get_string('c' + 'd') }
|
||||||
get_string('a' + 'b')
|
|
||||||
} else {
|
|
||||||
get_string('c' + 'd')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_map() {
|
fn loop_map() {
|
||||||
m := {
|
m := map{
|
||||||
'UK': 'London'
|
'UK': 'London'
|
||||||
'France': 'Paris'
|
'France': 'Paris'
|
||||||
}
|
}
|
||||||
|
@ -337,6 +333,9 @@ fn comp_if() {
|
||||||
println(s)
|
println(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn anon_fn() {
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println('start')
|
println('start')
|
||||||
simple()
|
simple()
|
||||||
|
|
Loading…
Reference in New Issue