Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/daScript/ast/ast_infer_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ namespace das {
ExpressionPtr visit(ExprTryCatch *expr) override;
// ExprReturn
bool inferReturnType(TypeDeclPtr &resType, ExprReturn *expr);
bool isVoidReturnValueSettled(Expression *subexpr) const;
void reportUnresolvedReturnValue(ExprReturn *expr);
virtual void preVisit(ExprReturn *expr) override;
void getDetailsAndSuggests(ExprReturn *expr, string &details, string &suggestions) const;
Expand Down
3 changes: 2 additions & 1 deletion src/ast/ast_infer_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4717,7 +4717,8 @@ namespace das {
TypeDecl::clone(expr->returnType, func->result);
}
}
if (expr->subexpr && expr->subexpr->type && expr->subexpr->type->isVoid() && !expr->moveSemantics) {
if (expr->subexpr && expr->subexpr->type && expr->subexpr->type->isVoid() && !expr->moveSemantics
&& isVoidReturnValueSettled(expr->subexpr)) {
const auto & resT = blocks.size() ? blocks.back()->type : func->result;
if (resT && resT->isVoid()) {
// lower 'return void_expr' to { void_expr; return; } so the backends
Expand Down
20 changes: 20 additions & 0 deletions src/ast/ast_infer_type_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,22 @@ namespace das {
expr->at, CompilationError::not_resolved_yet_expression_type);
}
}
bool InferTypes::isVoidReturnValueSettled(Expression *subexpr) const {
if (!subexpr->rtti_isCallFunc()) {
return true;
}
auto callee = ((ExprCallFunc *)subexpr)->func;
if (!callee) {
return false;
}
if (callee->builtIn || callee->isFullyInferred) {
return true;
}
if (callee->module && callee->module != program->thisModule.get()) {
return true;
}
return callee->hasReturn;
}
bool InferTypes::inferReturnType(TypeDeclPtr &resType, ExprReturn *expr) {
if (expr->subexpr && expr->subexpr->type && expr->subexpr->type->isVoid()) {
// 'return void_expr' is legal when the result is void, or a bare auto which the
Expand All @@ -1061,6 +1077,10 @@ namespace das {
expr->at, CompilationError::invalid_result);
return false;
}
if (!isVoidReturnValueSettled(expr->subexpr)) {
error("subexpression type is not fully resolved yet", "", "", expr->at, CompilationError::not_resolved_yet_expression_type);
return false;
}
if (resType->isVoid()) {
return false;
}
Expand Down
47 changes: 47 additions & 0 deletions tests/language/return_void_expression.das
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
options gen2
require dastest/testing_boost public
require daslib/constant_expression

var g_hits = 0

Expand Down Expand Up @@ -49,6 +50,41 @@ def mixed_result(n : int) : int {
return g_hits + n
}

// until [constant_expression] folds the argument in, the raw instance is an empty void function
[generic, constant_expression(name), unused_argument(name)]
def get_by_name(name : string) {
static_if (!typeinfo is_argument(name)) {
static_if (name == "one") {
return 1
} static_elif (name == "two") {
return 2
}
}
}

def pick_by_name(sel : int) {
if (sel == 1) {
return get_by_name("one")
}
return get_by_name("two")
}

def ping(n : int) : void {
if (n <= 0) {
return
}
g_hits++
return pong(n - 1)
}

def pong(n : int) : void {
if (n <= 0) {
return
}
g_hits++
return ping(n - 1)
}

[test]
def test_return_void_expression(t : T?) {
t |> run("block arrow with void body") @(t : T?) {
Expand Down Expand Up @@ -133,4 +169,15 @@ def test_return_void_forwarding(t : T?) {
g_hits = 0
t |> equal(mixed_result(10), 13)
}

t |> run("transiently-void generic call does not poison a bare-auto result") @(t : T?) {
t |> equal(pick_by_name(1), 1)
t |> equal(pick_by_name(2), 2)
}

t |> run("mutually recursive void functions forward through return") @(t : T?) {
g_hits = 0
ping(5)
t |> equal(g_hits, 5)
}
}
Loading