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 }