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