Skip to content

Commit

Permalink
jule: add return forwarding support for multi-ret functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mertcandav committed Aug 25, 2024
1 parent 2e28ce1 commit cf8b709
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 21 deletions.
25 changes: 17 additions & 8 deletions src/julec/obj/cxx/scope.jule
Original file line number Diff line number Diff line change
Expand Up @@ -775,14 +775,23 @@ impl scopeCoder {
self.oc.indent()
ret
}
mut datas := (&TupleExprModel)(r.Expr).Datas
for i, data in datas {
self.oc.write(resultName + "." + resultArgName)
self.oc.write(conv::Itoa(i))
self.oc.write(" = ")
self.oc.ec.possibleRefExpr(data.Model)
self.oc.write(";\n")
self.oc.indent()
match type r.Expr {
| &TupleExprModel:
mut datas := (&TupleExprModel)(r.Expr).Datas
for i, data in datas {
self.oc.write(resultName + "." + resultArgName)
self.oc.write(conv::Itoa(i))
self.oc.write(" = ")
self.oc.ec.possibleRefExpr(data.Model)
self.oc.write(";\n")
self.oc.indent()
}
| &FnCallExprModel:
self.oc.write(resultName + " = std::move(")
self.oc.ec.model(r.Expr)
self.oc.write(");\n")
|:
panic("implementation mistake, this panic call should be unreachable")
}
}

Expand Down
1 change: 1 addition & 0 deletions std/jule/build/log.jule
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ enum LogMsg: str {
InvalidTypeForComptimeIter: `type @ is not supports comptime iterations`,
InvalidComptimeIter: `comptime iterations can only be range iteration`,
InvalidComptimeTypeMatchExpr: `comptime type-match expressions can take only type declarations`,
WrongRetForward: "function return forwaring is wrong\n want (@)\n have (@)",

// Suggestions.
ExpectedIdentifier: `write an identifier because identifier expected`,
Expand Down
72 changes: 59 additions & 13 deletions std/jule/sema/type2.jule
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use ast for std::jule::ast::{
SliceExpr,
VariadicExpr,
TupleExpr,
FnCallExpr,
}
use std::jule::build::{LogMsg, Logf}
use lit for std::jule::constant::lit
Expand Down Expand Up @@ -711,7 +712,7 @@ impl fnCallArgChecker {
}
mut err := StrBuilder.New(1 << 5)
err.WriteStr(self.f.Decl.Ident)
err.WriteStr("\n wanted (")
err.WriteStr("\n want (")
for i, p in params {
err.WriteStr(p.Kind.Str())
if len(params)-i > 1 {
Expand Down Expand Up @@ -1338,30 +1339,75 @@ impl retTypeChecker {
}
}

// Assumes len(self.exprs) == 0 and kind is [&FnCallExpr].
fn tryFuncMultiRetForward(mut self): bool {
mut eval := self.sc.s.eval(self.sc)
mut d := eval.evalExpr(self.exprs[0])
if d == nil {
// Return true to skip following "false" handling errors.
// Evaluation error is enough for developer for now.
ret true
}
mut tup := d.Kind.Tup()
if tup == nil {
ret false
}
if len(tup.Types) != len(self.types) {
goto err
}
self.model = d.Model
for i in self.types {
if !self.sc.s._checkTypeCompatibility(self.types[i], tup.Types[i], self.errorToken) {
goto err
}
}
ret true
err:
mut wanted := StrBuilder.New(1 << 5)
for i, t in self.types {
wanted.WriteStr(t.Str())
if len(self.types)-i > 1 {
wanted.WriteStr(", ")
}
}
mut given := StrBuilder.New(1 << 5)
for i, t in tup.Types {
given.WriteStr(t.Str())
if len(self.types)-i > 1 {
given.WriteStr(", ")
}
}
self.sc.s.pushErr(self.errorToken, LogMsg.WrongRetForward, wanted.Str(), given.Str())
ret false
}

fn check(mut self, mut &e: &Expr): bool {
self.prepareTypes()
self.prepareExprs(e)

n := len(self.exprs)
if n == 0 && len(self.types) > 0 {
match {
| len(self.exprs) == 0 && len(self.types) > 0:
if !self.f.Decl.AnyVar() {
self.sc.s.pushErr(self.errorToken, LogMsg.RequireRetExpr)
ret false
}
ret true
}

if n > 0 && self.f != nil && self.f.Decl.IsVoid() {
| len(self.exprs) > 0 && self.f != nil && self.f.Decl.IsVoid():
self.sc.s.pushErr(self.errorToken, LogMsg.VoidFnRetExpr)
ret false
}

if n > len(self.types) {
self.sc.s.pushErr(self.errorToken, LogMsg.OverflowRet)
} else if n < len(self.types) {
| len(self.exprs) == 1 && len(self.types) > 1:
match type self.exprs[0].Kind {
| &FnCallExpr:
if self.tryFuncMultiRetForward() {
ret true
}
}
self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet)
ret false
| len(self.exprs) < len(self.types):
self.sc.s.pushErr(self.errorToken, LogMsg.MissingMultiRet)
| len(self.exprs) > len(self.types):
self.sc.s.pushErr(self.errorToken, LogMsg.OverflowRet)
}

self.checkExprs()
ret true
}
Expand Down

0 comments on commit cf8b709

Please sign in to comment.