Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix top-level mutually-recursive functions #167

Merged
merged 4 commits into from
Jun 5, 2023
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
14 changes: 13 additions & 1 deletion shared/src/main/scala/mlscript/JSBackend.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,15 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {
(zeroWidthSpace + JSIdent("e") + zeroWidthSpace).log() :: Nil
)

otherStmts.foreach {
case fd @ NuFunDef(isLetRec, Var(nme), _, L(body)) if (isLetRec.isEmpty || isLetRec.getOrElse(false)) =>
val isByname = isLetRec.isEmpty
val isByvalueRecIn = if (isByname) None else Some(true)
val bodyIsLam = body match { case _: Lam => true case _ => false }
scope.declareValue(nme, isByvalueRecIn, bodyIsLam)
case _ => ()
}

// Generate statements.
val queries = otherStmts.map {
case NuFunDef(isLetRec, nme @ Var(name), tys, rhs @ L(body)) =>
Expand All @@ -1338,7 +1347,10 @@ class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {
val bodyIsLam = body match { case _: Lam => true case _ => false }
(if (recursive) {
val isByvalueRecIn = if (isByname) None else Some(true)
val sym = scope.declareValue(name, isByvalueRecIn, bodyIsLam)
val sym = scope.resolveValue(name) match {
case Some(s: ValueSymbol) => s
case _ => scope.declareValue(name, isByvalueRecIn, bodyIsLam)
}
try {
val translated = translateTerm(body)
scope.unregisterSymbol(sym)
Expand Down
55 changes: 47 additions & 8 deletions shared/src/test/diff/nu/MutualRec.mls
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,17 @@ fun fooo(x) =



:ge // FIXME; + re-enable JS in tests below
fun foo = bar
fun bar = foo
//│ fun foo: nothing
//│ fun bar: nothing
//│ Code generation encountered an error:
//│ unresolved symbol bar

:NoJS // TODO

:re
foo(bar)
//│ nothing
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded


fun foo = {x: foo}
Expand All @@ -55,26 +54,42 @@ fun bar = {y: foo}
//│ where
//│ 'foo :> {x: {y: 'foo}}

:re
foo
//│ forall 'foo. 'foo
//│ where
//│ 'foo :> {x: {y: 'foo}}
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded

:ns
:re
foo
//│ forall 'foo. {x: {y: 'foo}}
//│ where
//│ 'foo :> {x: {y: 'foo}}
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded

:re
foo.x
//│ 'x
//│ where
//│ 'x :> {y: {x: 'x}}
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded

:re
foo.x.y
//│ 'foo
//│ where
//│ 'foo :> {x: {y: 'foo}}
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded


fun foo(a) = {h: a, t: bar(a)}
Expand All @@ -91,6 +106,8 @@ foo
//│ 'c :> {h: 'a, t: 'c}
//│ 'a <: 'b
//│ 'b <: 'a
//│ res
//│ = [Function: foo3]


fun foo(a) = {h1: a, t1: bar(a)}
Expand Down Expand Up @@ -118,6 +135,8 @@ module Test0_2 {

Test0_1.a
//│ 123
//│ res
//│ = 123

class Test0_1 {
fun a = Test0_2().b
Expand All @@ -141,7 +160,7 @@ module Test1_2 {
fun b = Test1_1.a
}
//│ ╔══[ERROR] Indirectly-recursive member should have type annotation
//│ ║ l.141: fun b = Test1_1.a
//│ ║ l.160: fun b = Test1_1.a
//│ ╙── ^^
//│ module Test1_1 {
//│ fun a: error
Expand All @@ -150,8 +169,12 @@ module Test1_2 {
//│ fun b: error
//│ }

:re
Test1_1.a
//│ error
//│ res
//│ Runtime error:
//│ RangeError: Maximum call stack size exceeded


:e
Expand All @@ -162,7 +185,7 @@ class Test1_2 {
fun b = Test1_1().a
}
//│ ╔══[ERROR] Indirectly-recursive member should have type annotation
//│ ║ l.162: fun b = Test1_1().a
//│ ║ l.185: fun b = Test1_1().a
//│ ╙── ^^
//│ class Test1_1 {
//│ fun a: error
Expand All @@ -185,7 +208,7 @@ module Test2_2 {
fun e = Test2_1.n
}
//│ ╔══[ERROR] Indirectly-recursive member should have type annotation
//│ ║ l.184: fun c = Test2_1.a
//│ ║ l.207: fun c = Test2_1.a
//│ ╙── ^^
//│ module Test2_1 {
//│ fun a: 123 | error
Expand All @@ -201,15 +224,23 @@ module Test2_2 {

Test2_1.t2.b
//│ 123
//│ res
//│ = 123

Test2_1.a
//│ 123 | error
//│ res
//│ = 123

Test2_1.d
//│ error
//│ res
//│ = 456

Test2_1.n
//│ 456
//│ res
//│ = 456

module Test2_1 {
fun t2 = Test2_2
Expand Down Expand Up @@ -238,15 +269,23 @@ module Test2_2 {

Test2_1.t2.b
//│ 123
//│ res
//│ = 123

Test2_1.a
//│ int
//│ res
//│ = 123

Test2_1.d
//│ int
//│ res
//│ = 456

Test2_1.n
//│ int
//│ res
//│ = 456


class Test2(n: int) {
Expand Down