Skip to content

Commit

Permalink
Support result<void> to HILTI.
Browse files Browse the repository at this point in the history
This allows to capture errors even if there's no actual result
otherwise. Example (HILTI syntax):

```
function result<void> x(bool b) {
     if ( b )
         return Null; # coerces to a successful result<void>
     else
         return error("trouble...");
 }

assert x(True);
assert x(False).error() == error("trouble...");

```
  • Loading branch information
rsmmr committed Jun 12, 2024
1 parent e0728cc commit ea47943
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 4 deletions.
4 changes: 3 additions & 1 deletion hilti/toolchain/src/compiler/codegen/ctors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ struct Visitor : hilti::visitor::PreOrder {
void operator()(ctor::Result* n) final {
auto t = cg->compile(n->type(), codegen::TypeUsage::Storage);

if ( auto e = n->value() )
if ( n->value()->type()->type()->isA<type::Null>() )
result = fmt("::hilti::rt::Nothing{}");
else if ( auto e = n->value() )
result = fmt("%s(%s)", t, cg->compile(e));
else
result = fmt("%s(%s)", t, cg->compile(n->error()));
Expand Down
8 changes: 6 additions & 2 deletions hilti/toolchain/src/compiler/codegen/types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -706,8 +706,12 @@ struct VisitorStorage : hilti::visitor::PreOrder {
void operator()(type::Result* n) final {
std::string t;

if ( const auto& ct = n->dereferencedType(); ! ct->isWildcard() )
t = fmt("::hilti::rt::Result<%s>", cg->compile(ct, codegen::TypeUsage::Storage));
if ( const auto& ct = n->dereferencedType(); ! ct->isWildcard() ) {
if ( ct->type()->isA<type::Void>() )
t = "::hilti::rt::Result<::hilti::rt::Nothing>";
else
t = fmt("::hilti::rt::Result<%s>", cg->compile(ct, codegen::TypeUsage::Storage));
}
else
t = "*";

Expand Down
7 changes: 7 additions & 0 deletions hilti/toolchain/src/compiler/coercer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ struct VisitorCtor : visitor::PreOrder {
return;
}

if ( auto t = dst->type()->tryAs<type::Result>(); t && t->dereferencedType()->type()->isA<type::Void>() ) {
result = builder->ctorResult(builder->expressionCtor(builder->ctorNull()));
return;
}

if ( auto t = dst->type()->tryAs<type::StrongReference>() ) {
result = builder->ctorStrongReference(t->dereferencedType());
return;
Expand Down Expand Up @@ -462,6 +467,8 @@ struct VisitorType : visitor::PreOrder {
void operator()(type::Null* n) final {
if ( dst->type()->isA<type::Optional>() )
result = dst;
else if ( auto t = dst->type()->tryAs<type::Result>(); t && t->dereferencedType()->type()->isA<type::Void>() )
result = dst;
else if ( dst->type()->isA<type::StrongReference>() )
result = dst;
else if ( dst->type()->isA<type::WeakReference>() )
Expand Down
2 changes: 1 addition & 1 deletion hilti/toolchain/src/compiler/validator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ struct VisitorPost : visitor::PreOrder, public validator::VisitorMixIn {
if ( n->isWildcard() )
return;

if ( const auto& t = n->dereferencedType(); ! t->type()->isAllocable() )
if ( const auto& t = n->dereferencedType(); ! t->type()->isAllocable() && ! t->type()->isA<type::Void>() )
error(fmt("type %s cannot be used inside result", *t), n);
}

Expand Down
19 changes: 19 additions & 0 deletions tests/hilti/types/result/void.hlt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# @TEST-EXEC: hiltic -j %INPUT >output
#
# @TEST-DOC: Test the special-case of `result<void>`.

module Foo {

import hilti;

function result<void> x(bool b) {
if ( b )
return Null;
else
return error("trouble...");
}

assert x(True);
assert x(False).error() == error("trouble...");

}

0 comments on commit ea47943

Please sign in to comment.