1 /// Copyright: Copyright (c) 2017-2019 Andrey Penechko.
2 /// License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
3 /// Authors: Andrey Penechko.
4 module vox.fe.ast.stmt.return_stmt;
5 
6 import vox.all;
7 
8 
9 @(AstType.stmt_return)
10 struct ReturnStmtNode {
11 	mixin AstNodeData!(AstType.stmt_return, 0, AstNodeState.name_register_nested_done);
12 	AstIndex parentFunction;
13 	AstIndex expression; // Nullable
14 }
15 
16 void print_return(ReturnStmtNode* node, ref AstPrintState state)
17 {
18 	state.print("RETURN");
19 	if (node.expression) print_ast(node.expression, state);
20 }
21 
22 void post_clone_return(ReturnStmtNode* node, ref CloneState state)
23 {
24 	state.fixAstIndex(node.parentFunction);
25 	state.fixAstIndex(node.expression);
26 }
27 
28 void name_resolve_return(ReturnStmtNode* node, ref NameResolveState state) {
29 	node.state = AstNodeState.name_resolve;
30 	if (node.expression) require_name_resolve(node.expression, state);
31 	node.state = AstNodeState.name_resolve_done;
32 }
33 
34 // Check return type and function return type
35 void type_check_return(ReturnStmtNode* node, ref TypeCheckState state)
36 {
37 	CompilationContext* c = state.context;
38 
39 	node.state = AstNodeState.type_check;
40 
41 	AstIndex retTypeIndex = node.parentFunction.get!FunctionDeclNode(c).signature.get!FunctionSignatureNode(c).returnType;
42 	bool isVoidFunc = retTypeIndex.isVoidType(c);
43 
44 	if (node.expression)
45 	{
46 		require_type_check_expr(retTypeIndex, node.expression, state);
47 
48 		bool success = autoconvTo(node.expression, retTypeIndex, c);
49 		if (!success)
50 			c.error(node.loc,
51 				"Cannot implicitly convert expression of type `%s` to `%s`",
52 				node.expression.get_expr_type(c).printer(c),
53 				retTypeIndex.printer(c));
54 	}
55 	else
56 	{
57 		if (!isVoidFunc)
58 			c.error(node.loc,
59 				"Cannot return void from non-void function",
60 				node.expression.get_expr(c).type.typeName(c));
61 	}
62 	node.state = AstNodeState.type_check_done;
63 }
64 
65 void ir_gen_return(ref IrGenState gen, IrIndex currentBlock, ref IrLabel nextStmt, ReturnStmtNode* node)
66 {
67 	CompilationContext* c = gen.context;
68 	if (node.expression)
69 	{
70 		IrLabel afterExpr = IrLabel(currentBlock);
71 		ExprValue lval = ir_gen_expr(gen, node.expression, currentBlock, afterExpr);
72 		currentBlock = afterExpr.blockIndex;
73 		if (node.expression.get_expr_type(c).isVoidType(c)) {
74 			gen.builder.addReturn(currentBlock);
75 			return;
76 		}
77 		IrIndex rval = lval.rvalue(gen, node.loc, currentBlock);
78 		gen.builder.addReturn(currentBlock, rval);
79 	}
80 	else gen.builder.addReturn(currentBlock);
81 }