From ed08423d61931f93c2fd7e8e4e2d3509c6d05718 Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Wed, 11 Oct 2023 12:30:46 +0800 Subject: [PATCH 1/6] Fix unary minus behaviour (#188) --- shared/src/main/scala/mlscript/NewLexer.scala | 19 ++-- .../src/main/scala/mlscript/NewParser.scala | 17 +++- shared/src/test/diff/nu/UnaryMinus.mls | 93 +++++++++++++++++++ shared/src/test/diff/parser/NegativeLits.mls | 4 +- 4 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 shared/src/test/diff/nu/UnaryMinus.mls diff --git a/shared/src/main/scala/mlscript/NewLexer.scala b/shared/src/main/scala/mlscript/NewLexer.scala index 7fd8f324f..2bd9f0e61 100644 --- a/shared/src/main/scala/mlscript/NewLexer.scala +++ b/shared/src/main/scala/mlscript/NewLexer.scala @@ -168,19 +168,14 @@ class NewLexer(origin: Origin, raise: Diagnostic => Unit, dbg: Bool) { // go(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n))) lex(j, ind, next(j, if (keywords.contains(n)) KEYWORD(n) else IDENT(n, isAlphaOp(n)))) case _ if isOpChar(c) => - if (c === '-' && isDigit(bytes(i + 1))) { - val (str, j) = takeWhile(i + 1)(isDigit) - lex(j, ind, next(j, LITVAL(IntLit(-BigInt(str))))) - } else { - val (n, j) = takeWhile(i)(isOpChar) - if (n === "." && j < length && isIdentFirstChar(bytes(j))) { - val (name, k) = takeWhile(j)(isIdentChar) - // go(k, SELECT(name)) - lex(k, ind, next(k, SELECT(name))) - } - // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) - else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) + val (n, j) = takeWhile(i)(isOpChar) + if (n === "." && j < length && isIdentFirstChar(bytes(j))) { + val (name, k) = takeWhile(j)(isIdentChar) + // go(k, SELECT(name)) + lex(k, ind, next(k, SELECT(name))) } + // else go(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true)) + else lex(j, ind, next(j, if (isSymKeyword.contains(n)) KEYWORD(n) else IDENT(n, true))) case _ if isDigit(c) => val (str, j) = takeWhile(i)(isDigit) // go(j, LITVAL(IntLit(BigInt(str)))) diff --git a/shared/src/main/scala/mlscript/NewParser.scala b/shared/src/main/scala/mlscript/NewParser.scala index 8445d82f9..22be9ea17 100644 --- a/shared/src/main/scala/mlscript/NewParser.scala +++ b/shared/src/main/scala/mlscript/NewParser.scala @@ -787,6 +787,18 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case ((KEYWORD(";;") /* | NEWLINE */ /* | BRACKETS(Curly, _) */, l0) :: _) => R(UnitLit(true).withLoc(S(l0))) // R(errExpr) // TODO + case (IDENT("-", true), l0) :: _ /*if opPrec("-")._1 > prec*/ => // Unary minus + consume + val v = Var("-").withLoc(S(l0)) + expr(opPrec("-")._2) match { + case IntLit(i) => // Special case for negative literals + exprCont(IntLit(-i), prec, false) + case rhs: Term => // General case + exprCont( + if (newDefs) App(v, PlainTup(IntLit(BigInt(0)), rhs)) + else App(App(v, PlainTup(IntLit(BigInt(0)))), PlainTup(rhs)) + , prec, false) + } case (tk, l0) :: _ => err(msg"Unexpected ${tk.describe} in expression position" -> S(l0) :: Nil) consume @@ -1128,7 +1140,10 @@ abstract class NewParser(origin: Origin, tokens: Ls[Stroken -> Loc], newDefs: Bo case (SPACE, _) :: _ => consume argsOrIf(acc, seqAcc, allowNewlines, prec) - case (NEWLINE | IDENT(_, true), _) :: _ => // TODO: | ... + case (NEWLINE, _) :: _ => // TODO: | ... + assert(seqAcc.isEmpty) + acc.reverse + case (IDENT(nme, true), _) :: _ if nme =/= "-" => // TODO: | ... assert(seqAcc.isEmpty) acc.reverse case _ => diff --git a/shared/src/test/diff/nu/UnaryMinus.mls b/shared/src/test/diff/nu/UnaryMinus.mls new file mode 100644 index 000000000..389426bfe --- /dev/null +++ b/shared/src/test/diff/nu/UnaryMinus.mls @@ -0,0 +1,93 @@ +:NewDefs + +-1 +//│ -1 +//│ res +//│ = -1 + +- 1 +//│ -1 +//│ res +//│ = -1 + +1+1 +//│ Int +//│ res +//│ = 2 + +1-3 +//│ Int +//│ res +//│ = -2 + +3-1 +//│ Int +//│ res +//│ = 2 + +1 - (3 - 5) +//│ Int +//│ res +//│ = -7 + +3 - 1 +//│ Int +//│ res +//│ = 2 + +1 -1 +//│ Int +//│ res +//│ = 0 + +1-1 +//│ Int +//│ res +//│ = 0 + +1+ -1 +//│ Int +//│ res +//│ = 0 + +1 - (1 - 1) +//│ Int +//│ res +//│ = -1 + +1 - 1 +//│ Int +//│ res +//│ = 0 + +1 - - 1 +//│ Int +//│ res +//│ = 2 + +1 - - - - 1 +//│ Int +//│ res +//│ = 2 + +fun f() = 6 +-f() +//│ fun f: () -> 6 +//│ Int +//│ res +//│ = -6 + +fun inv(x: Int) = -x +inv(15) +inv(inv(15)) +//│ fun inv: (x: Int) -> Int +//│ Int +//│ res +//│ = -15 +//│ res +//│ = 15 + +inv(f()) +//│ Int +//│ res +//│ = -6 diff --git a/shared/src/test/diff/parser/NegativeLits.mls b/shared/src/test/diff/parser/NegativeLits.mls index 6dbcfff44..4290b760b 100644 --- a/shared/src/test/diff/parser/NegativeLits.mls +++ b/shared/src/test/diff/parser/NegativeLits.mls @@ -2,7 +2,7 @@ :ParseOnly type MinusOne = -1 -//│ |#type| |MinusOne| |#=| |-1| +//│ |#type| |MinusOne| |#=| |-|1| //│ Parsed: {type alias MinusOne: -1 {}} fun f(x: MinusOne) = x @@ -10,5 +10,5 @@ fun f(x: MinusOne) = x //│ Parsed: {fun f = (x: MinusOne,) => x} f(-1) -//│ |f|(|-1|)| +//│ |f|(|-|1|)| //│ Parsed: {f(-1,)} From f13624f4d97883246d08d12e6f8e321342a5930f Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:37:03 +0800 Subject: [PATCH 2/6] Approximate overloads less + add tests and notes --- .../main/scala/mlscript/TyperDatatypes.scala | 5 +- shared/src/test/diff/basics/Intersections.fun | 112 ++----- .../diff/ecoop23/SimpleRegionDSL_annot.mls | 2 +- shared/src/test/diff/fcp/Overloads.mls | 71 +--- shared/src/test/diff/mlscript/BadPolym.mls | 30 +- shared/src/test/diff/nu/ArrayProg.mls | 15 +- shared/src/test/diff/nu/HeungTung.mls | 316 ++++++++++++++++++ shared/src/test/diff/nu/WeirdUnions.mls | 27 +- 8 files changed, 385 insertions(+), 193 deletions(-) create mode 100644 shared/src/test/diff/nu/HeungTung.mls diff --git a/shared/src/main/scala/mlscript/TyperDatatypes.scala b/shared/src/main/scala/mlscript/TyperDatatypes.scala index 45da2dc7a..fae7992dc 100644 --- a/shared/src/main/scala/mlscript/TyperDatatypes.scala +++ b/shared/src/main/scala/mlscript/TyperDatatypes.scala @@ -200,7 +200,10 @@ abstract class TyperDatatypes extends TyperHelpers { Typer: Typer => Overload(alts.map(ft => FunctionType(f(pol.contravar, ft.lhs), f(pol, ft.rhs))(ft.prov)))(prov) def approximatePos: FunctionType = { val (lhss, rhss) = alts.map(ft => ft.lhs -> ft.rhs).unzip - FunctionType(lhss.reduce(_ & _), rhss.reduce(_ | _))(prov) + FunctionType(lhss.reduce(_ | _), rhss.reduce(_ | _))(prov) + // * Note: technically the following is another valid (but probably less useful) + // * approximation of the same function type: + // FunctionType(lhss.reduce(_ & _), rhss.reduce(_ & _))(prov) } lazy val level: Level = levelBelow(MaxLevel)(MutSet.empty) def levelBelow(ub: Level)(implicit cache: MutSet[TV]): Level = diff --git a/shared/src/test/diff/basics/Intersections.fun b/shared/src/test/diff/basics/Intersections.fun index 0c2144396..95d264faf 100644 --- a/shared/src/test/diff/basics/Intersections.fun +++ b/shared/src/test/diff/basics/Intersections.fun @@ -31,31 +31,7 @@ foo(1) // returns int & bool, equivalent to nothing succ / foo(1) foo(true) not / foo(true) -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.30: foo(1) // returns int & bool, equivalent to nothing -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ -//│ res: bool | error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.31: succ / foo(1) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.31: succ / foo(1) -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.31: succ / foo(1) -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ +//│ res: bool | int //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.31: succ / foo(1) //│ ║ ^^^^^^^^^^^^^ @@ -66,31 +42,7 @@ not / foo(true) //│ ║ l.31: succ / foo(1) //│ ╙── ^^^^^^ //│ res: error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.32: foo(true) -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.32: foo(true) -//│ ║ ^^^^ -//│ ╟── but it flows into argument with expected type `int` -//│ ║ l.32: foo(true) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^ -//│ res: bool | error | int -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^^^^^^ -//│ ╟── reference of type `true` is not an instance of type `int` -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^ -//│ ╟── but it flows into argument with expected type `int` -//│ ║ l.33: not / foo(true) -//│ ║ ^^^^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^ +//│ res: bool | int //│ ╔══[ERROR] Type mismatch in application: //│ ║ l.33: not / foo(true) //│ ║ ^^^^^^^^^^^^^^^ @@ -106,76 +58,52 @@ not / foo(true) not / foo(1) foo(1) as Nothing //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.106: not / foo(1) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.106: not / foo(1) -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.106: not / foo(1) -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.106: not / foo(1) -//│ ║ ^^^^^^^^^^^^ +//│ ║ l.58: not / foo(1) +//│ ║ ^^^^^^^^^^^^ //│ ╟── reference of type `int` is not an instance of type `bool` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `bool` -//│ ║ l.106: not / foo(1) -//│ ╙── ^^^^^^ +//│ ║ l.58: not / foo(1) +//│ ╙── ^^^^^^ //│ res: bool | error -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `bool` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^ -//│ ╟── but it flows into argument with expected type `bool` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^ -//│ ╟── Note: constraint arises from reference: -//│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) -//│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^^^^^^^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ║ ^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `int` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^ //│ ╟── but it flows into application with expected type `nothing` -//│ ║ l.107: foo(1) as Nothing -//│ ║ ^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ║ ^^^^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.107: foo(1) as Nothing -//│ ╙── ^^^^^^^ +//│ ║ l.59: foo(1) as Nothing +//│ ╙── ^^^^^^^ //│ res: nothing :e foo as Nothing //│ ╔══[ERROR] Type mismatch in 'as' binding: -//│ ║ l.157: foo as Nothing -//│ ║ ^^^^^^^^^^^^^^ +//│ ║ l.85: foo as Nothing +//│ ║ ^^^^^^^^^^^^^^ //│ ╟── type intersection of type `int -> int & bool -> bool` does not match type `nothing` //│ ║ l.26: let foo = (Int => Int) & (Bool => Bool) //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╟── but it flows into reference with expected type `nothing` -//│ ║ l.157: foo as Nothing -//│ ║ ^^^ +//│ ║ l.85: foo as Nothing +//│ ║ ^^^ //│ ╟── Note: constraint arises from reference: -//│ ║ l.157: foo as Nothing -//│ ╙── ^^^^^^^ +//│ ║ l.85: foo as Nothing +//│ ╙── ^^^^^^^ //│ res: nothing :e let oops = (&) //│ ╔══[ERROR] Illegal use of reserved operator: & -//│ ║ l.173: let oops = (&) +//│ ║ l.101: let oops = (&) //│ ╙── ^^^ //│ ╔══[ERROR] identifier not found: & -//│ ║ l.173: let oops = (&) +//│ ║ l.101: let oops = (&) //│ ╙── ^^^ //│ oops: error diff --git a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls index d2b54c679..ae9192d9d 100644 --- a/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls +++ b/shared/src/test/diff/ecoop23/SimpleRegionDSL_annot.mls @@ -348,7 +348,7 @@ fun mk(n) = if n is _ then Scale(Vector(0, 0), mk(n)) //│ fun mk: forall 'a. Object -> 'a //│ where -//│ 'a :> Outside['a] | Scale['a] | Union['a] | Intersect['a] | Translate['a] +//│ 'a :> Outside['a] | Translate['a] | Scale['a] | Union['a] | Intersect['a] :re TestElim.eliminate(mk(100)) diff --git a/shared/src/test/diff/fcp/Overloads.mls b/shared/src/test/diff/fcp/Overloads.mls index 5a713da7a..71a328bb5 100644 --- a/shared/src/test/diff/fcp/Overloads.mls +++ b/shared/src/test/diff/fcp/Overloads.mls @@ -31,12 +31,12 @@ IISS : ZZII //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.30: IISS : ZZII //│ ║ ^^^^ -//│ ╟── type `0` is not an instance of type `string` -//│ ║ l.7: type ZZII = 0 -> 0 & int -> int -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: +//│ ╟── type `int` does not match type `0` //│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ +//│ ║ ^^^ +//│ ╟── Note: constraint arises from literal type: +//│ ║ l.7: type ZZII = 0 -> 0 & int -> int +//│ ╙── ^ //│ res: ZZII :e @@ -44,12 +44,9 @@ IISS : BBNN //│ ╔══[ERROR] Type mismatch in type ascription: //│ ║ l.43: IISS : BBNN //│ ║ ^^^^ -//│ ╟── type `bool` is not an instance of type `int` +//│ ╟── type `bool` does not match type `int | string` //│ ║ l.6: type BBNN = bool -> bool & number -> number -//│ ║ ^^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^ +//│ ╙── ^^^^ //│ res: BBNN @@ -61,53 +58,20 @@ IISS : int -> int IISS : (0 | 1) -> number //│ res: (0 | 1) -> number -:e IISS : 'a -> 'a -//│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.65: IISS : 'a -> 'a -//│ ║ ^^^^ -//│ ╟── type `int` is not an instance of type `string` -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ║ ^^^^^^ -//│ ╟── from type variable: -//│ ║ l.65: IISS : 'a -> 'a -//│ ╙── ^^ -//│ res: nothing -> (error | int | string) +//│ res: ('a & (int | string)) -> (int | string | 'a) -:e IISS 0 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.81: IISS 0 -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `string` -//│ ║ l.81: IISS 0 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ -//│ res: error | int | string +//│ res: int | string (IISS : int -> int) 0 //│ res: int -:e (if true then IISS else BBNN) 0 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.97: (if true then IISS else BBNN) 0 -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `string` -//│ ║ l.97: (if true then IISS else BBNN) 0 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ -//│ res: bool | error | number | string +//│ res: bool | number | string fun x -> (if true then IISS else BBNN) x -//│ res: nothing -> (bool | number | string) +//│ res: int -> (bool | number | string) if true then IISS else BBNN //│ res: bool -> bool & number -> number | int -> int & string -> string @@ -121,14 +85,11 @@ if true then IISS else BBNN :e (if true then IISS else BBNN) : (0 | 1 | true) -> number //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.122: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -//│ ╟── type `0` is not an instance of type `string` -//│ ║ l.122: (if true then IISS else BBNN) : (0 | 1 | true) -> number -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.12: def IISS: int -> int & string -> string -//│ ╙── ^^^^^^ +//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ║ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╟── type `true` does not match type `int | string` +//│ ║ l.86: (if true then IISS else BBNN) : (0 | 1 | true) -> number +//│ ╙── ^^^^ //│ res: (0 | 1 | true) -> number diff --git a/shared/src/test/diff/mlscript/BadPolym.mls b/shared/src/test/diff/mlscript/BadPolym.mls index 44dbedef4..d8695bb76 100644 --- a/shared/src/test/diff/mlscript/BadPolym.mls +++ b/shared/src/test/diff/mlscript/BadPolym.mls @@ -22,12 +22,12 @@ foo = fooImpl //│ ╔══[ERROR] Type mismatch in def definition: //│ ║ l.18: foo = fooImpl //│ ║ ^^^^^^^^^^^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` -//│ ║ l.13: fooImpl f = f 1 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: +//│ ╟── type `int` is not a 0-element tuple //│ ║ l.9: def foo: (int -> int & string -> string) -> () -//│ ╙── ^^^^^^ +//│ ║ ^^^ +//│ ╟── Note: constraint arises from tuple type: +//│ ║ l.9: def foo: (int -> int & string -> string) -> () +//│ ╙── ^^ //│ = [Function: fooImpl] foo id @@ -39,35 +39,25 @@ fooImpl id //│ = 1 -:e fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ║ ^^^ -//│ ╟── integer literal of type `1` is not an instance of type `string` -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ║ ^ -//│ ╟── Note: constraint arises from type reference: -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 -//│ ╙── ^^^^^^ -//│ fooImpl2: (int -> int & string -> string) -> (error | int | string) +//│ fooImpl2: (int -> int & string -> string) -> (int | string) //│ = [Function: fooImpl2] fooImpl2 id -//│ res: error | int | string +//│ res: int | string //│ = 1 :e :re res "oops" //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.62: res "oops" +//│ ║ l.52: res "oops" //│ ║ ^^^^^^^^^^ //│ ╟── type `int` is not a function -//│ ║ l.43: fooImpl2 (f: int -> int & string -> string) = f 1 +//│ ║ l.42: fooImpl2 (f: int -> int & string -> string) = f 1 //│ ║ ^^^ //│ ╟── but it flows into reference with expected type `"oops" -> ?a` -//│ ║ l.62: res "oops" +//│ ║ l.52: res "oops" //│ ╙── ^^^ //│ res: error //│ Runtime error: diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls index d8b1402fd..b33cb35fa 100644 --- a/shared/src/test/diff/nu/ArrayProg.mls +++ b/shared/src/test/diff/nu/ArrayProg.mls @@ -154,6 +154,11 @@ module A { //│ fun g: Int -> Int & Str -> Str //│ } +A.g(0) +//│ Int | Str +//│ res +//│ = 0 + @@ -176,17 +181,7 @@ s([Numbr(0),Numbr(0)]) //│ ║ l.136: fun s: ([Numbr,Numbr] -> Int) & ([Vectr,Vectr] -> Int) //│ ╙── ^^^^^^^^^^^^^ //│ Int | error - -:e -A.g(0) // g <: 0 -> 'a -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.+1: A.g(0) -//│ ║ ^^^^^^ -//│ ╟── integer literal of type `0` is not an instance of type `Str` -//│ ║ l.+1: A.g(0) -//│ ╙── ^ -//│ Int | Str | error :e fun add(e) = diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls new file mode 100644 index 000000000..091301565 --- /dev/null +++ b/shared/src/test/diff/nu/HeungTung.mls @@ -0,0 +1,316 @@ +:NewDefs + + + +trait A +trait B +//│ trait A +//│ trait B + +module AA extends A, B +//│ module AA extends A, B + +fun x: A & B +fun x = AA +//│ fun x: AA +//│ fun x: A & B + +x : A +//│ A +//│ res +//│ = AA { class: [class AA extends Object] } + + + +abstract class Foo[A, B] { fun x: A & B } +//│ abstract class Foo[A, B] { +//│ fun x: A & B +//│ } + +module Bar extends Foo[Int, Bool] { fun x = x } +//│ module Bar extends Foo { +//│ fun x: nothing +//│ } + +module Bar extends Foo { fun x = () } +//│ module Bar extends Foo { +//│ fun x: () +//│ } + +Bar : Foo['a, 'b] +//│ Foo['a, 'b] +//│ where +//│ 'b :> () +//│ 'a :> () +//│ res +//│ = Bar { class: [class Bar extends Foo] } + + +// * An overloaded function type +fun f: (Int -> Int) & (Bool -> Bool) +fun f = id +//│ fun f: forall 'a. 'a -> 'a +//│ fun f: Int -> Int & Bool -> Bool + + +// * Widen the results +fun h: (Int -> (Int | Bool)) & (Bool -> (Int | Bool)) +fun h = f +//│ fun h: Int -> Int & Bool -> Bool +//│ fun h: (Bool | Int) -> (Int | false | true) + +// * Merge intersected functions with same domain +fun g: (Int | Bool) -> (Int | Bool) +fun g = h +//│ fun g: (Bool | Int) -> (Int | false | true) +//│ fun g: (Bool | Int) -> (Int | false | true) + +// * In one step +fun g: (Int | Bool) -> (Int | Bool) +fun g = f +//│ fun g: Int -> Int & Bool -> Bool +//│ fun g: (Bool | Int) -> (Int | false | true) + + +// * Can also widen into intersection +fun i: ((Int & Bool) -> Int) & ((Int & Bool) -> Bool) +fun i = f +//│ fun i: Int -> Int & Bool -> Bool +//│ fun i: nothing -> nothing + +// * Merge intersected functions with same codomain +fun j: (Int & Bool) -> (Int & Bool) +fun j = i +//│ fun j: nothing -> nothing +//│ fun j: nothing -> nothing + +:e // * Note: currently it doesn't work when done in a single step +fun j: (Int & Bool) -> (Int & Bool) +fun j = f +//│ ╔══[ERROR] Type mismatch in definition: +//│ ║ l.89: fun j = f +//│ ║ ^^^^^ +//│ ╙── expression of type `Int` does not match type `nothing` +//│ fun j: Int -> Int & Bool -> Bool +//│ fun j: nothing -> nothing + + +// * Or widen even further with both an intersection and a union, into this +fun g: (Int & Bool) -> (Int | Bool) +fun g = f +//│ fun g: Int -> Int & Bool -> Bool +//│ fun g: nothing -> (Int | false | true) + + +// * Note: we currently approximate uses of overloaded function types! +// * With match-type-based constraint solving, we could return Int here + +f(0) +//│ Int | false | true +//│ res +//│ = 0 + +// f(0) : case 0 of { Int => Int; Bool => Bool } == Int + + +x => f(x) +//│ (Bool | Int) -> (Int | false | true) +//│ res +//│ = [Function: res] + +// : forall 'a: 'a -> case 'a of { Int => Int; Bool => Bool } where 'a <: Int | Bool + + +f(if true then 0 else false) +//│ Int | false | true +//│ res +//│ = 0 + +// * With match-type-based constraint solving, we could *also* return Int here + +:e // TODO implement this syntax +:w +f(refined if true then 0 else false) // this one can be precise again! +//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword +//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: refined +//│ ║ l.133: f(refined if true then 0 else false) // this one can be precise again! +//│ ╙── ^^^^^^^ +//│ Int | false | true +//│ Code generation encountered an error: +//│ unresolved symbol refined + + + +// * Notes on constraint solving + + +// * Easy: + +// ?a -> ?b <: (Int -> Int) & (Bool -> Bool) +// to: +// ?a -> ?b <: (Int -> Int) AND ?a -> ?b <: (Bool -> Bool) + +// * Hard; but can solve with match types: + +// (Int -> Int) & (Bool -> Bool) <: ?a -> ?b +// to: +// ?a <: Int | Bool AND (case ?a of { Int => Int; Bool => Bool }) <: ?b + +// We can still widen if needed; consider: +// ?a := Int | Bool +// then: +// (case (Int | Bool) of { Int => Int; Bool => Bool }) <: ?b +// to: +// Int <: ?b AND Bool <: ?b + +// An simple match-type constraint example: +// (case ?a of { Int => Int; Bool => Bool }) <: Int +// to: +// ?a <: Int + +// A more complicated match-type constraint example: +// (case ?a of { Int => ?b; Bool => ?c }) <: T +// to: +// ?b <: (case ?a of { Int => T; Bool => Top }) AND ?c <: (case ?a of { Int => Top; Bool => T }) + + + +class List[A] +//│ class List[A] { +//│ constructor() +//│ } + +// * Note: match type `T match { case List[t] => ... t ... }` could be encoded as: + +type M = (forall 't: List['t] => 't) +//│ type M = forall 't. List['t] -> 't + +type T = List[Int] +//│ type T = List[Int] + +:e // TODO application types +type Res = M(T) +//│ ╔══[ERROR] Wrong number of type arguments – expected 0, found 1 +//│ ║ l.194: type Res = M(T) +//│ ╙── ^^^^ +//│ type Res = M + + + +let f = x => [x, x] +//│ let f: forall 'a. 'a -> ['a, 'a] +//│ f +//│ = [Function: f2] + +[f(1), f(true)] +//│ [[1, 1], [true, true]] +//│ res +//│ = [ [ 1, 1 ], [ true, true ] ] + + + +:e // TODO support +fun f: Int -> Int +fun f: Bool -> Bool +fun f = id +//│ ╔══[ERROR] A type signature for 'f' was already given +//│ ║ l.216: fun f: Bool -> Bool +//│ ╙── ^^^^^^^^^^^^^^^^^^^ +//│ fun f: forall 'a. 'a -> 'a +//│ fun f: Int -> Int + +:e // TODO support +f: (Int -> Int) & (Bool -> Bool) +//│ ╔══[ERROR] Type mismatch in type ascription: +//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^ +//│ ╟── type `Bool` is not an instance of `Int` +//│ ║ l.225: f: (Int -> Int) & (Bool -> Bool) +//│ ║ ^^^^ +//│ ╟── Note: constraint arises from type reference: +//│ ║ l.215: fun f: Int -> Int +//│ ╙── ^^^ +//│ Int -> Int & Bool -> Bool +//│ res +//│ = [Function: id] + +// t: S t: T +// ------------- +// t: S & T + + + +// * Weird MLstruct rule (only sound when we don't have FCP): +// forall 'a: 'a -> 'a <: (Int -> Int) & (Bool -> Bool) == (Int | Bool) -> (Int & Bool) +// ~{ a: Int } <: Str -> Str + +// * Notice: in positive position, this is equivalent to Bottom +fun x: ~{ a: Int } +//│ fun x: nothing + + +class A() +class B() +//│ class A() +//│ class B() + +A() : ~B +//│ ~B +//│ res +//│ = A {} + +// A <: ~B +// <=> +// A <: ~B | Bot +// <=> +// A & B <: Bot + +fun x: A & B +//│ fun x: nothing + + +fun test(x) = if x is + A then 0 + _ then x +//│ fun test: forall 'a. (A | Object & 'a & ~#A) -> (0 | 'a) + +test(B()) +//│ 0 | B +//│ res +//│ = B {} + +test(A()) +//│ 0 +//│ res +//│ = 0 + +// A <: A | Object & 'a & ~A +// A & ~A <: Object & 'a & ~A +// Bot <: Object & 'a & ~A + + +:e // TODO implement this syntax +:w +fun test(x) = refined if x is + A then 0 + B then 1 +//│ ╔══[WARNING] Paren-less applications should use the 'of' keyword +//│ ║ l.296: fun test(x) = refined if x is +//│ ║ ^^^^^^^^^^^^^^^ +//│ ║ l.297: A then 0 +//│ ║ ^^^^^^^^^^ +//│ ║ l.298: B then 1 +//│ ╙── ^^^^^^^^^^ +//│ ╔══[ERROR] identifier not found: refined +//│ ║ l.296: fun test(x) = refined if x is +//│ ╙── ^^^^^^^ +//│ fun test: (A | B) -> error +//│ Code generation encountered an error: +//│ unresolved symbol refined + +// forall 'a: 'a -> (case 'a of A -> 0, B & ~A -> 1) + + + diff --git a/shared/src/test/diff/nu/WeirdUnions.mls b/shared/src/test/diff/nu/WeirdUnions.mls index 31c87b4a4..0b4e81c38 100644 --- a/shared/src/test/diff/nu/WeirdUnions.mls +++ b/shared/src/test/diff/nu/WeirdUnions.mls @@ -47,15 +47,14 @@ fun f: (Str => Str) & ((Str, Int) => Int) //│ fun f: Str -> Str & (Str, Int) -> Int // * ...resulting in approximation at call sites (we don't handle overloading) -:e f("abc", "abc") -//│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.51: f("abc", "abc") -//│ ║ ^^^^^^^^^^^^^^^ -//│ ╟── argument list of type `["abc", "abc"]` does not match type `nothing` -//│ ║ l.51: f("abc", "abc") -//│ ╙── ^^^^^^^^^^^^^^ -//│ Int | Str | error +//│ Int | Str +//│ res +//│ = +//│ f is not implemented + +f("abcabc") +//│ Int | Str //│ res //│ = //│ f is not implemented @@ -72,19 +71,19 @@ let r = if true then id else (x, y) => [y, x] r(error) r(error, error) //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.72: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^^ //│ ╟── argument of type `[nothing]` does not match type `[?a, ?b]` -//│ ║ l.72: r(error) +//│ ║ l.71: r(error) //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from tuple literal: -//│ ║ l.66: let r = if true then id else (x, y) => [y, x] +//│ ║ l.65: let r = if true then id else (x, y) => [y, x] //│ ╙── ^^^^ //│ ╔══[ERROR] Type mismatch in application: -//│ ║ l.73: r(error, error) +//│ ║ l.72: r(error, error) //│ ║ ^^^^^^^^^^^^^^^ //│ ╟── argument list of type `[nothing, nothing]` does not match type `[?a]` -//│ ║ l.73: r(error, error) +//│ ║ l.72: r(error, error) //│ ╙── ^^^^^^^^^^^^^^ //│ error | [nothing, nothing] //│ res @@ -107,7 +106,7 @@ r of [0, 1] // Also currently parses the same: let r = if true then id else [x, y] => [y, x] -//│ let r: forall 'a 'b 'c. (['a, 'b] & 'c) -> (['b, 'a] | 'c) +//│ let r: forall 'a 'b 'c. (['b, 'c] & 'a) -> (['c, 'b] | 'a) //│ r //│ = [Function: id] From 9d91cdecfbef3ddfba924123451ae3f76662205c Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:53:17 +0800 Subject: [PATCH 3/6] Add various tests --- shared/src/test/diff/nu/CallByName.mls | 39 ++++++++++ shared/src/test/diff/nu/CtorSubtraction.mls | 37 +++++++++ .../test/diff/nu/PrivateMemberOverriding.mls | 63 +++++++++++++++ shared/src/test/diff/ucs/AppSplits.mls | 76 +++++++++++++++++++ shared/src/test/diff/ucs/ThenIndent.mls | 31 ++++++++ 5 files changed, 246 insertions(+) create mode 100644 shared/src/test/diff/nu/CallByName.mls create mode 100644 shared/src/test/diff/nu/CtorSubtraction.mls create mode 100644 shared/src/test/diff/nu/PrivateMemberOverriding.mls create mode 100644 shared/src/test/diff/ucs/AppSplits.mls create mode 100644 shared/src/test/diff/ucs/ThenIndent.mls diff --git a/shared/src/test/diff/nu/CallByName.mls b/shared/src/test/diff/nu/CallByName.mls new file mode 100644 index 000000000..6258b1952 --- /dev/null +++ b/shared/src/test/diff/nu/CallByName.mls @@ -0,0 +1,39 @@ +:NewDefs + + +let x = log("ok") +//│ let x: () +//│ x +//│ = undefined +//│ // Output +//│ ok + +x +//│ () +//│ res +//│ = undefined + +x +//│ () +//│ res +//│ = undefined + + +fun x = log("ok") +//│ fun x: () + +x +//│ () +//│ res +//│ = undefined +//│ // Output +//│ ok + +x +//│ () +//│ res +//│ = undefined +//│ // Output +//│ ok + + diff --git a/shared/src/test/diff/nu/CtorSubtraction.mls b/shared/src/test/diff/nu/CtorSubtraction.mls new file mode 100644 index 000000000..38d37eaaa --- /dev/null +++ b/shared/src/test/diff/nu/CtorSubtraction.mls @@ -0,0 +1,37 @@ +:NewDefs + + +class Cls +//│ class Cls { +//│ constructor() +//│ } + +fun x: ('a & Object) -> ('a \ Cls) +fun x = case + Cls then error + y then y +//│ fun x: forall 'b. (Cls | Object & 'b & ~#Cls) -> 'b +//│ fun x: forall 'a. (Object & 'a) -> ('a & ~Cls) + +x : Int -> Int +//│ Int -> Int +//│ res +//│ = [Function: x1] + +x : Cls -> nothing +//│ Cls -> nothing +//│ res +//│ = [Function: x1] + + +fun x: (Int | Str | Cls) \ Cls +fun x = 42 +//│ fun x: 42 +//│ fun x: Int & ~Cls | Str & ~Cls + +x : Int | Str +//│ Int | Str +//│ res +//│ = 42 + + diff --git a/shared/src/test/diff/nu/PrivateMemberOverriding.mls b/shared/src/test/diff/nu/PrivateMemberOverriding.mls new file mode 100644 index 000000000..3b1fc703a --- /dev/null +++ b/shared/src/test/diff/nu/PrivateMemberOverriding.mls @@ -0,0 +1,63 @@ +:NewDefs + + +class Foo(x: Int) +//│ class Foo(x: Int) + +:e // FIXME this should be allowed +class Bar() extends Foo(123) { fun x = true } +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.8: class Bar() extends Foo(123) { fun x = true } +//│ ║ ^^^^^^^^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar() extends Foo { +//│ fun x: true +//│ } + +Bar().x +//│ true +//│ res +//│ = true + + +:e // FIXME this should be allowed +class Bar(val x: Bool) extends Foo(123) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.26: class Bar(val x: Bool) extends Foo(123) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar(x: Bool) extends Foo + +Bar(true).x +//│ Bool +//│ res +//│ = true + + +:e // FIXME this should be allowed +class Bar(x: Bool) extends Foo(123) +//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden +//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ║ ^ +//│ ╟── Originally declared here: +//│ ║ l.4: class Foo(x: Int) +//│ ╙── ^ +//│ class Bar(x: Bool) extends Foo + +:e // * Expected +Bar(true).x +//│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field +//│ ║ l.52: Bar(true).x +//│ ║ ^^ +//│ ╟── Either make the parameter a `val` or access it through destructuring +//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ╙── ^ +//│ error | false | true +//│ res +//│ = undefined + + diff --git a/shared/src/test/diff/ucs/AppSplits.mls b/shared/src/test/diff/ucs/AppSplits.mls new file mode 100644 index 000000000..f6f81f173 --- /dev/null +++ b/shared/src/test/diff/ucs/AppSplits.mls @@ -0,0 +1,76 @@ +:NewDefs + + +fun foo(x) = x > 1 +//│ fun foo: Num -> Bool + +:pe // TODO +:e +if foo of + 0 then "a" + 1 then "b" +//│ ╔══[PARSE ERROR] Unexpected 'then' keyword here +//│ ║ l.10: 0 then "a" +//│ ╙── ^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead +//│ ║ l.9: if foo of +//│ ║ ^^^^^^ +//│ ║ l.10: 0 then "a" +//│ ║ ^^^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.9: if foo of +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(0,) +//│ ║ l.9: if foo of +//│ ║ ^^^^^^ +//│ ║ l.10: 0 then "a" +//│ ╙── ^^^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:pe // TODO +:e +if foo of 1, + 0 then "a" + 1 then "b" +//│ ╔══[PARSE ERROR] Unexpected 'then'/'else' clause +//│ ║ l.35: 0 then "a" +//│ ║ ^^^^^^^^^^ +//│ ║ l.36: 1 then "b" +//│ ╙── ^^^^^^^^^^^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found application instead +//│ ║ l.34: if foo of 1, +//│ ║ ^^^^^^^^^ +//│ ║ l.35: 0 then "a" +//│ ║ ^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.34: if foo of 1, +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(1, undefined,) +//│ ║ l.34: if foo of 1, +//│ ║ ^^^^^^^^^ +//│ ║ l.35: 0 then "a" +//│ ╙── ^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + +:pe // TODO +:e +if foo + (0) then "a" + (1) then "b" +//│ ╔══[PARSE ERROR] Unexpected parenthesis section here +//│ ║ l.63: (1) then "b" +//│ ╙── ^^^ +//│ ╔══[ERROR] The case when this is false is not handled: foo(0,) +//│ ║ l.61: if foo +//│ ║ ^^^ +//│ ║ l.62: (0) then "a" +//│ ╙── ^^^^^ +//│ error +//│ Code generation encountered an error: +//│ if expression was not desugared + + diff --git a/shared/src/test/diff/ucs/ThenIndent.mls b/shared/src/test/diff/ucs/ThenIndent.mls new file mode 100644 index 000000000..1ca90defc --- /dev/null +++ b/shared/src/test/diff/ucs/ThenIndent.mls @@ -0,0 +1,31 @@ +:NewDefs + + +// FIXME +x => if x == + 0 + then "a" + _ then "b" +//│ ╔══[PARSE ERROR] Unexpected indented block here +//│ ║ l.7: then "a" +//│ ║ ^^^^^^^^^^^^ +//│ ║ l.8: _ then "b" +//│ ╙── ^^ +//│ ╔══[PARSE ERROR] Expected 'then'/'else' clause after 'if'; found operator application instead +//│ ║ l.5: x => if x == +//│ ║ ^^^^ +//│ ║ l.6: 0 +//│ ║ ^^^ +//│ ╟── Note: 'if' expression starts here: +//│ ║ l.5: x => if x == +//│ ╙── ^^ +//│ ╔══[ERROR] The case when this is false is not handled: ==(x, {0},) +//│ ║ l.5: x => if x == +//│ ║ ^^^^ +//│ ║ l.6: 0 +//│ ╙── ^^^ +//│ anything -> error +//│ Code generation encountered an error: +//│ if expression was not desugared + + From 27752e93a45b0b163fab7f37518ed6b354371410 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 12 Oct 2023 14:58:57 +0800 Subject: [PATCH 4/6] Allow 'overriding' private members --- .../src/main/scala/mlscript/NuTypeDefs.scala | 2 + shared/src/test/diff/nu/BadClassInherit.mls | 62 ++++++------- shared/src/test/diff/nu/Interfaces.mls | 87 +++++++------------ shared/src/test/diff/nu/ParamPassing.mls | 49 +++++------ .../test/diff/nu/PrivateMemberOverriding.mls | 40 ++++----- 5 files changed, 101 insertions(+), 139 deletions(-) diff --git a/shared/src/main/scala/mlscript/NuTypeDefs.scala b/shared/src/main/scala/mlscript/NuTypeDefs.scala index 7d3de8263..033964e0a 100644 --- a/shared/src/main/scala/mlscript/NuTypeDefs.scala +++ b/shared/src/main/scala/mlscript/NuTypeDefs.scala @@ -29,6 +29,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => def level: Level def isImplemented: Bool def isPublic: Bool + def isPrivate: Bool = !isPublic // * We currently don't support `protected` def isValueParam: Bool = this match { case p: NuParam => !p.isType @@ -1267,6 +1268,7 @@ class NuTypeDefs extends ConstraintSolver { self: Typer => case (m: TypedNuTermDef, S(fun: TypedNuTermDef)) => fun match { // * If the implementation and the declaration are in the same class, // * it does not require to be virtual. + case _ if fun.isPrivate => () // * Private members are not actually inherited case td: TypedNuFun if (!td.fd.isVirtual && !clsSigns.contains(fun)) => err(msg"${m.kind.str.capitalize} member `${m.name }` is not virtual and cannot be overridden" -> m.toLoc :: diff --git a/shared/src/test/diff/nu/BadClassInherit.mls b/shared/src/test/diff/nu/BadClassInherit.mls index cb696fc26..0d1240eb5 100644 --- a/shared/src/test/diff/nu/BadClassInherit.mls +++ b/shared/src/test/diff/nu/BadClassInherit.mls @@ -11,12 +11,6 @@ class C2(x: Int) extends C1(y) { //│ ╔══[ERROR] identifier not found: y //│ ║ l.8: class C2(x: Int) extends C1(y) { //│ ╙── ^ -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.8: class C2(x: Int) extends C1(y) { -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class C1(x: Int) -//│ ╙── ^ //│ class C2(x: Int) extends C1 { //│ val y: Int //│ } @@ -28,7 +22,7 @@ abstract class C2 extends C1(y) { val y: Int } //│ ╔══[ERROR] identifier not found: y -//│ ║ l.27: abstract class C2 extends C1(y) { +//│ ║ l.21: abstract class C2 extends C1(y) { //│ ╙── ^ //│ abstract class C2 extends C1 { //│ val y: Int @@ -41,7 +35,7 @@ abstract class C2 extends C1(this.y) { val y: Int } //│ ╔══[ERROR] identifier not found: this -//│ ║ l.40: abstract class C2 extends C1(this.y) { +//│ ║ l.34: abstract class C2 extends C1(this.y) { //│ ╙── ^^^^ //│ abstract class C2 extends C1 { //│ val y: Int @@ -54,7 +48,7 @@ class C1(x: C1) :e class C2 extends C1(this) //│ ╔══[ERROR] identifier not found: this -//│ ║ l.55: class C2 extends C1(this) +//│ ║ l.49: class C2 extends C1(this) //│ ╙── ^^^^ //│ class C2 extends C1 { //│ constructor() @@ -70,19 +64,19 @@ class Foo { virtual fun x: Int = 1 } :e class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.71: class Bar extends Foo { fun x = false } +//│ ║ l.65: class Bar extends Foo { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -95,19 +89,19 @@ class Bar extends Foo { fun x = false } //│ ╔══[ERROR] Type mismatch in signature of member `x`: -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── type `Bool` is not an instance of `Int` -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^ //│ ╟── but it flows into signature of member `x` with expected type `Int` -//│ ║ l.94: fun x: Bool +//│ ║ l.88: fun x: Bool //│ ║ ^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -122,19 +116,19 @@ mixin M { fun x = false } :e class Bar extends Foo, M //│ ╔══[ERROR] Type mismatch in definition of method x: -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── reference of type `false` is not an instance of type `Int` -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^ //│ ╟── but it flows into definition of method x with expected type `Int` -//│ ║ l.117: mixin M { fun x = false } +//│ ║ l.111: mixin M { fun x = false } //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from type reference: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ║ ^^^ //│ ╟── from definition of method x: -//│ ║ l.64: class Foo { virtual fun x: Int = 1 } +//│ ║ l.58: class Foo { virtual fun x: Int = 1 } //│ ╙── ^^^^^^^^^^ //│ class Bar extends Foo { //│ constructor() @@ -162,19 +156,19 @@ trait B { class X { fun g = 1 } } :e class C extends A, B //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.163: class C extends A, B +//│ ║ l.157: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.147: trait B { class X { fun g = 1 } } +//│ ║ l.141: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Intersection of class member and class members currently unsupported -//│ ║ l.163: class C extends A, B +//│ ║ l.157: class C extends A, B //│ ║ ^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.146: class A { class X { fun f = 1 } } +//│ ║ l.140: class A { class X { fun f = 1 } } //│ ║ ^^^^^^^^^^^^^^^^^^^^^ //│ ╟── The class member is defined here: -//│ ║ l.147: trait B { class X { fun g = 1 } } +//│ ║ l.141: trait B { class X { fun g = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A, B { //│ constructor() @@ -189,14 +183,14 @@ class C extends A { class X { fun g = 1 } } //│ ╔══[ERROR] Class member `X` cannot override class member of the same name declared in parent -//│ ║ l.188: class C extends A { +//│ ║ l.182: class C extends A { //│ ║ ^^^^^^^^^^^^^^^^^^^ -//│ ║ l.189: class X { fun g = 1 } +//│ ║ l.183: class X { fun g = 1 } //│ ║ ^^^^^^^^^^^^^^^^^^^^^^^ -//│ ║ l.190: } +//│ ║ l.184: } //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.146: class A { class X { fun f = 1 } } +//│ ║ l.140: class A { class X { fun f = 1 } } //│ ╙── ^^^^^^^^^^^^^^^^^^^^^ //│ class C extends A { //│ constructor() @@ -211,7 +205,7 @@ class C extends A { :e class Foo2 extends Foo2 //│ ╔══[ERROR] Unhandled cyclic definition -//│ ║ l.212: class Foo2 extends Foo2 +//│ ║ l.206: class Foo2 extends Foo2 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^ //│ class Foo2 extends Foo2 { //│ constructor() diff --git a/shared/src/test/diff/nu/Interfaces.mls b/shared/src/test/diff/nu/Interfaces.mls index 2d7d8a421..34ab4936b 100644 --- a/shared/src/test/diff/nu/Interfaces.mls +++ b/shared/src/test/diff/nu/Interfaces.mls @@ -796,14 +796,7 @@ class Cx(a2: 1 | 2, val b: Bool) extends Ca(a2) //│ fun foo: 1 //│ } -:e class Cx(a: 1 | 2, val b: Bool) extends Ca(a) -//│ ╔══[ERROR] Inherited parameter named `a` is not virtual and cannot be overridden -//│ ║ l.800: class Cx(a: 1 | 2, val b: Bool) extends Ca(a) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.781: class Ca(a: Int) extends Oth { -//│ ╙── ^ //│ class Cx(a: 1 | 2, b: Bool) extends Ca, Oth, Test { //│ fun bar: forall 'a. 'a -> 'a //│ fun cool: anything -> false @@ -844,22 +837,15 @@ abstract class Bc3 { :e class Bc12() extends Bc1(1), Bc2(true) //│ ╔══[ERROR] Cannot inherit from more than one base class: Bc1 and Bc2 -//│ ║ l.845: class Bc12() extends Bc1(1), Bc2(true) +//│ ║ l.838: class Bc12() extends Bc1(1), Bc2(true) //│ ╙── ^^^^^^^^^ //│ class Bc12() extends Bc1, Bc2 //│ Code generation encountered an error: //│ unexpected parent symbol new class Bc2. -:e class Bc02() extends Bc1(1:Int) { val foo = 2 } -//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.855: val foo = 2 -//│ ║ ^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.833: class Bc1(foo: Int) -//│ ╙── ^^^ //│ class Bc02() extends Bc1 { //│ val foo: 2 //│ } @@ -872,27 +858,20 @@ Bc02().foo :e class Bc31(baz: Bool) extends Bc3 //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.873: class Bc31(baz: Bool) extends Bc3 +//│ ║ l.859: class Bc31(baz: Bool) extends Bc3 //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.836: let baz : Int +//│ ║ l.829: let baz : Int //│ ║ ^^^ //│ ╟── from signature of member `baz`: -//│ ║ l.836: let baz : Int +//│ ║ l.829: let baz : Int //│ ╙── ^^^^^^^^^ //│ class Bc31(baz: Bool) extends Bc3 -:e class Bc11 extends Bc1(1) { let foo = true } -//│ ╔══[ERROR] Inherited parameter named `foo` is not virtual and cannot be overridden -//│ ║ l.888: let foo = true -//│ ║ ^^^^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.833: class Bc1(foo: Int) -//│ ╙── ^^^ //│ class Bc11 extends Bc1 { //│ constructor() //│ let foo: true @@ -921,7 +900,7 @@ trait BInt extends Base[Int] { fun f = error } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.921: fun f = error +//│ ║ l.900: fun f = error //│ ╙── ^^^^^^^^^^^^^ //│ trait BInt extends Base { //│ fun f: nothing @@ -952,7 +931,7 @@ bp: Base[[Int, Bool]] :e bp: Base[[Int, Int]] //│ ╔══[ERROR] Type mismatch in type ascription: -//│ ║ l.953: bp: Base[[Int, Int]] +//│ ║ l.932: bp: Base[[Int, Int]] //│ ║ ^^ //│ ╙── expression of type `true` is not an instance of type `Int` //│ Base[[Int, Int]] @@ -1013,13 +992,13 @@ trait BInfer2 extends Base { :e class DerBad1 extends Base[Int, Int] //│ ╔══[ERROR] trait Base expects 1 type parameter(s); got 2 -//│ ║ l.1014: class DerBad1 extends Base[Int, Int] -//│ ╙── ^^^^^^^^^^^^^ +//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ╙── ^^^^^^^^^^^^^ //│ ╔══[ERROR] Member `f` is declared (or its declaration is inherited) but is not implemented in `DerBad1` -//│ ║ l.1014: class DerBad1 extends Base[Int, Int] -//│ ║ ^^^^^^^ +//│ ║ l.993: class DerBad1 extends Base[Int, Int] +//│ ║ ^^^^^^^ //│ ╟── Declared here: -//│ ║ l.902: trait Base[A] { fun f: A -> A } +//│ ║ l.881: trait Base[A] { fun f: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ class DerBad1 extends Base { //│ constructor() @@ -1031,28 +1010,28 @@ class DerBad1 extends Base[Int, Int] :e class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `B` does not match type `A` -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter B is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method f: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── reference of type `A` does not match type `B` -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: constraint arises from type parameter: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ║ ^ //│ ╟── Note: type parameter A is defined at: -//│ ║ l.1032: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } +//│ ║ l.1011: class Der2[A, B] extends Base[[A, B]] { fun f([x, y]) = [y, x] } //│ ╙── ^ //│ class Der2[A, B] extends Base { //│ constructor() @@ -1104,7 +1083,7 @@ trait Tb extends Ta[Int] { virtual val p = false } //│ ╔══[ERROR] Method implementations in traits are not yet supported -//│ ║ l.1104: virtual val p = false +//│ ║ l.1083: virtual val p = false //│ ╙── ^^^^^^^^^^^^^ //│ trait Tb extends Ta { //│ val g: 'T @@ -1139,14 +1118,14 @@ trait Oz { :e class Fischl(age: Bool) extends Oz //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1140: class Fischl(age: Bool) extends Oz +//│ ║ l.1119: class Fischl(age: Bool) extends Oz //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1133: let age: Int +//│ ║ l.1112: let age: Int //│ ║ ^^^ //│ ╟── from signature of member `age`: -//│ ║ l.1133: let age: Int +//│ ║ l.1112: let age: Int //│ ╙── ^^^^^^^^ //│ class Fischl(age: Bool) extends Oz @@ -1166,29 +1145,29 @@ class Go extends Fate { fun foo(x) = x && true } //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── expression of type `Int & ?a` is not an instance of type `Bool` //│ ╟── Note: constraint arises from reference: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ╙── ^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1157: virtual fun foo(x) = x + 1 +//│ ║ l.1136: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ ╔══[ERROR] Type mismatch in definition of method foo: -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^^^^^^^^^^ //│ ╟── operator application of type `Bool` does not match type `Int | ?a` -//│ ║ l.1166: fun foo(x) = x && true +//│ ║ l.1145: fun foo(x) = x && true //│ ║ ^^^^^^^^^ //│ ╟── Note: constraint arises from operator application: -//│ ║ l.1157: virtual fun foo(x) = x + 1 +//│ ║ l.1136: virtual fun foo(x) = x + 1 //│ ╙── ^^^^^ //│ class Go extends Fate { //│ constructor() @@ -1207,11 +1186,11 @@ class Haha(x: 1 | 2) extends Ha :e class Ohhh(x: Bool) extends Ha //│ ╔══[ERROR] Type mismatch in type reference: -//│ ║ l.1208: class Ohhh(x: Bool) extends Ha +//│ ║ l.1187: class Ohhh(x: Bool) extends Ha //│ ║ ^^^^ //│ ╟── type `Bool` is not an instance of `Int` //│ ╟── Note: constraint arises from type reference: -//│ ║ l.1198: class Ha { virtual val x: Int = 1 } +//│ ║ l.1177: class Ha { virtual val x: Int = 1 } //│ ╙── ^^^ //│ class Ohhh(x: Bool) extends Ha diff --git a/shared/src/test/diff/nu/ParamPassing.mls b/shared/src/test/diff/nu/ParamPassing.mls index 57cbf7b8e..4eacce0f2 100644 --- a/shared/src/test/diff/nu/ParamPassing.mls +++ b/shared/src/test/diff/nu/ParamPassing.mls @@ -7,14 +7,7 @@ class Foo(x: Int) class Bar(z: Int, y: Int) extends Foo(z + y) //│ class Bar(z: Int, y: Int) extends Foo -:e class Bar(x: Int, y: Int) extends Foo(x + y) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.11: class Bar(x: Int, y: Int) extends Foo(x + y) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Int, y: Int) extends Foo @@ -31,7 +24,7 @@ Bar.x :e // FIXME module Bar extends Foo(11) { fun get = this.x } //│ ╔══[ERROR] Indirectly-recursive member should have type annotation -//│ ║ l.32: module Bar extends Foo(11) { fun get = this.x } +//│ ║ l.25: module Bar extends Foo(11) { fun get = this.x } //│ ╙── ^^ //│ module Bar extends Foo { //│ fun get: error @@ -62,10 +55,10 @@ class Foo(x: Int) :e Foo(1).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.63: Foo(1).x +//│ ║ l.56: Foo(1).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.59: class Foo(x: Int) +//│ ║ l.52: class Foo(x: Int) //│ ╙── ^ //│ Int | error //│ res @@ -74,10 +67,10 @@ Foo(1).x :e Foo(1).#x //│ ╔══[ERROR] identifier not found: .# -//│ ║ l.75: Foo(1).#x +//│ ║ l.68: Foo(1).#x //│ ╙── ^^ //│ ╔══[ERROR] identifier not found: x -//│ ║ l.75: Foo(1).#x +//│ ║ l.68: Foo(1).#x //│ ╙── ^ //│ error //│ Code generation encountered an error: @@ -106,20 +99,20 @@ if Foo(1) is Foo(x) then x :e class Bar(x: Int) extends Foo(x) //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ║ l.100: class Bar(x: Int) extends Foo(x) //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar(x: Int) extends Foo :e Bar(11).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.117: Bar(11).x +//│ ║ l.110: Bar(11).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.107: class Bar(x: Int) extends Foo(x) +//│ ║ l.100: class Bar(x: Int) extends Foo(x) //│ ╙── ^ //│ Int | error //│ res @@ -129,10 +122,10 @@ Bar(11).x :e class Bar(val x: Int) extends Foo(x + 1) //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.130: class Bar(val x: Int) extends Foo(x + 1) +//│ ║ l.123: class Bar(val x: Int) extends Foo(x + 1) //│ ║ ^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar(x: Int) extends Foo @@ -144,10 +137,10 @@ Bar(11).x :e class Bar extends Foo(1) { val x: 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.145: class Bar extends Foo(1) { val x: 2 } +//│ ║ l.138: class Bar extends Foo(1) { val x: 2 } //│ ║ ^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ class Bar extends Foo { //│ constructor() @@ -157,10 +150,10 @@ class Bar extends Foo(1) { val x: 2 } :e module Bar extends Foo(1) { fun x = 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.158: module Bar extends Foo(1) { fun x = 2 } +//│ ║ l.151: module Bar extends Foo(1) { fun x = 2 } //│ ║ ^^^^^ //│ ╟── Originally declared here: -//│ ║ l.92: class Foo(val x: Int) +//│ ║ l.85: class Foo(val x: Int) //│ ╙── ^ //│ module Bar extends Foo { //│ fun x: 2 @@ -188,10 +181,10 @@ module B extends A(42) :e B.x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.189: B.x +//│ ║ l.182: B.x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.182: class A(x: Int) +//│ ║ l.175: class A(x: Int) //│ ╙── ^ //│ Int | error //│ res @@ -230,16 +223,16 @@ module Bazz extends Foo(0) { val x: 2 } //│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.230: val x: 2 +//│ ║ l.223: val x: 2 //│ ║ ^^^^^^^^ //│ ╟── Originally declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^ //│ ╔══[ERROR] Member `i` is declared (or its declaration is inherited) but is not implemented in `Bazz` -//│ ║ l.229: module Bazz extends Foo(0) { +//│ ║ l.222: module Bazz extends Foo(0) { //│ ║ ^^^^ //│ ╟── Declared here: -//│ ║ l.202: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } +//│ ║ l.195: abstract class Foo[A](val x: A) { fun y = x;; fun i: A -> A } //│ ╙── ^^^^^^^^^^^^^ //│ module Bazz extends Foo { //│ fun i: 'A -> 'A diff --git a/shared/src/test/diff/nu/PrivateMemberOverriding.mls b/shared/src/test/diff/nu/PrivateMemberOverriding.mls index 3b1fc703a..e7977a41d 100644 --- a/shared/src/test/diff/nu/PrivateMemberOverriding.mls +++ b/shared/src/test/diff/nu/PrivateMemberOverriding.mls @@ -4,14 +4,7 @@ class Foo(x: Int) //│ class Foo(x: Int) -:e // FIXME this should be allowed class Bar() extends Foo(123) { fun x = true } -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.8: class Bar() extends Foo(123) { fun x = true } -//│ ║ ^^^^^^^^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar() extends Foo { //│ fun x: true //│ } @@ -21,15 +14,13 @@ Bar().x //│ res //│ = true +if Bar() is Foo(a) then a +//│ Int +//│ res +//│ = 123 + -:e // FIXME this should be allowed class Bar(val x: Bool) extends Foo(123) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.26: class Bar(val x: Bool) extends Foo(123) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Bool) extends Foo Bar(true).x @@ -37,27 +28,30 @@ Bar(true).x //│ res //│ = true +if Bar(true) is Foo(a) then a +//│ Int +//│ res +//│ = 123 + -:e // FIXME this should be allowed class Bar(x: Bool) extends Foo(123) -//│ ╔══[ERROR] Inherited parameter named `x` is not virtual and cannot be overridden -//│ ║ l.42: class Bar(x: Bool) extends Foo(123) -//│ ║ ^ -//│ ╟── Originally declared here: -//│ ║ l.4: class Foo(x: Int) -//│ ╙── ^ //│ class Bar(x: Bool) extends Foo :e // * Expected Bar(true).x //│ ╔══[ERROR] Parameter 'x' cannot tbe accessed as a field -//│ ║ l.52: Bar(true).x +//│ ║ l.41: Bar(true).x //│ ║ ^^ //│ ╟── Either make the parameter a `val` or access it through destructuring -//│ ║ l.42: class Bar(x: Bool) extends Foo(123) +//│ ║ l.37: class Bar(x: Bool) extends Foo(123) //│ ╙── ^ //│ error | false | true //│ res //│ = undefined +if Bar(true) is Foo(a) then a +//│ Int +//│ res +//│ = 123 + From 38bf8fcba649d78bcba94ac23a8e7136979f6736 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 10 Oct 2023 15:04:42 +0800 Subject: [PATCH 5/6] Update NodeTest --- shared/src/test/scala/mlscript/NodeTest.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/test/scala/mlscript/NodeTest.scala b/shared/src/test/scala/mlscript/NodeTest.scala index e9628619f..1d23160af 100644 --- a/shared/src/test/scala/mlscript/NodeTest.scala +++ b/shared/src/test/scala/mlscript/NodeTest.scala @@ -16,6 +16,7 @@ class NodeTests extends org.scalatest.funsuite.AnyFunSuite { || v.startsWith("v17") || v.startsWith("v18") || v.startsWith("v19") + || v.startsWith("v20") ) } From f5e98264664fbd30490f6c5e21337aa9671a2fb3 Mon Sep 17 00:00:00 2001 From: HarrisL2 Date: Thu, 12 Oct 2023 17:52:51 +0800 Subject: [PATCH 6/6] Add defunctionalizer prototype (#185) Co-authored-by: YKY --- .../scala/mlscript/compiler/ClassLifter.scala | 256 ++-- .../scala/mlscript/compiler/DataType.scala | 36 + .../mlscript/compiler/DataTypeInferer.scala | 18 + .../scala/mlscript/compiler/Helpers.scala | 196 +++ .../mlscript/compiler/mono/Monomorph.scala | 334 +++++ .../compiler/mono/MonomorphContext.scala | 33 + .../compiler/mono/MonomorphError.scala | 3 + .../mono/specializer/BoundedExpr.scala | 226 ++++ .../compiler/mono/specializer/Builtin.scala | 95 ++ .../compiler/mono/specializer/Context.scala | 21 + .../mono/specializer/Predicates.scala | 6 + .../mono/specializer/Specializer.scala | 228 ++++ .../compiler/printer/ExprPrinter.scala | 73 + .../main/scala/mlscript/compiler/syntax.scala | 271 ++++ compiler/shared/test/diff/LambLift.mls | 87 ++ compiler/shared/test/diff/LiftType.mls | 14 +- compiler/shared/test/diff/Lifter.mls | 161 +-- compiler/shared/test/diff/LifterBlks.mls | 130 +- compiler/shared/test/diff/mono.mls | 1204 +++++++++++++++++ .../test/scala/mlscript/compiler/Test.scala | 29 +- .../main/scala/mlscript/codegen/Helpers.scala | 2 +- .../src/test/scala/mlscript/DiffTests.scala | 5 +- 22 files changed, 3204 insertions(+), 224 deletions(-) create mode 100644 compiler/shared/main/scala/mlscript/compiler/DataType.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/Helpers.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala create mode 100644 compiler/shared/main/scala/mlscript/compiler/syntax.scala create mode 100644 compiler/shared/test/diff/LambLift.mls create mode 100644 compiler/shared/test/diff/mono.mls diff --git a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala index e54df8e06..5c0c8da40 100644 --- a/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala +++ b/compiler/shared/main/scala/mlscript/compiler/ClassLifter.scala @@ -6,8 +6,10 @@ import mlscript.utils.shorthands.* import scala.collection.mutable.StringBuilder as StringBuilder import scala.collection.mutable.Map as MutMap import scala.collection.mutable.Set as MutSet +import scala.collection.mutable.ArrayBuffer as ArrayBuffer import mlscript.codegen.Helpers.inspect as showStructure import mlscript.codegen.CodeGenError +import mlscript.compiler.mono.MonomorphError class ClassLifter(logDebugMsg: Boolean = false) { type ClassName = String @@ -28,6 +30,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { LocalContext(vSet ++ inters.map(x => Var(x.name)), tSet -- inters) } def intersect(rst: LocalContext) = LocalContext(vSet intersect rst.vSet, tSet intersect rst.tSet) + def intersectV(rst: Set[Var]) = LocalContext(vSet.intersect(rst), tSet) def contains(v: Var) = vSet.contains(v) || tSet.contains(TypeName(v.name)) def contains(tv: TypeName) = vSet.contains(Var(tv.name)) || tSet.contains(tv) override def toString(): String = "(" ++ vSet.mkString(", ") ++ "; " ++ tSet.mkString(", ") ++ ")" @@ -37,6 +40,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { private def asContext(t: TypeName) = LocalContext(Set(), Set(t)) private def asContextT(tS: IterableOnce[TypeName]) = LocalContext(Set(), tS.iterator.toSet) private def emptyCtx = LocalContext(Set(), Set()) + private def emptyCtxObj = LocalContext(Set(Var("this")), Set()) case class ClassInfoCache( originNm: TypeName, @@ -55,6 +59,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { type NamePath = List[String] var retSeq: List[NuTypeDef] = Nil + val globalFunctions: ArrayBuffer[NuFunDef] = ArrayBuffer() var anonymCnt: Int = 0 var clsCnt: Int = 0 val logOutput: StringBuilder = new StringBuilder @@ -144,7 +149,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { (tmp._1.flatten, tmp._2.flatten, tmp._3.flatten) } - private def genClassNm(orgNm: String)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): TypeName = { + private def genClassNm(orgNm: String)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): TypeName = { TypeName(outer match{ case None => clsCnt = clsCnt+1 @@ -153,11 +158,15 @@ class ClassLifter(logDebugMsg: Boolean = false) { }) } - private def getFreeVars(stmt: Located)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): LocalContext = stmt match{ - case v:Var => - log(s"get free var find $v: ${ctx.vSet.contains(v)}/${buildPathToVar(v).isDefined}/${cache.contains(TypeName(v.name))}/${v.name.equals("this")}") - if(ctx.vSet.contains(v) || buildPathToVar(v).isDefined || cache.contains(TypeName(v.name)) || v.name.equals("this") || primiTypes.contains(v.name)) then emptyCtx else asContext(v) - case t: NamedType => + private def getFreeVars(stmt: Located)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): LocalContext = stmt match{ + case v:Var => + val caseEmpty = ctx.vSet.contains(v) || cache.contains(TypeName(v.name)) || globFuncs.contains(v) || primiTypes.contains(v.name) + val caseThis = buildPathToVar(v).isDefined && !ctx.vSet.contains(Var("this")) + log(s"get free var find $v: $caseEmpty/$caseThis") + if(caseEmpty) then emptyCtx + else if(caseThis) asContext(Var("this")) + else asContext(v) + case t: NamedType => log(s"get type $t under $ctx, $cache, $outer") asContextT(t.collectTypeNames.map(TypeName(_)).filterNot(x => ctx.contains(x) || cache.contains(x) || primiTypes.contains(x.name))) case Lam(lhs, rhs) => @@ -181,7 +190,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case TyApp(trm, tpLst) => getFreeVars(trm).addT(tpLst.flatMap(_.collectTypeNames.map(TypeName(_)))) case NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) => - val prmVs = getFreeVars(param.getOrElse(Tup(Nil)))(using emptyCtx, Map(), None) + val prmVs = getFreeVars(param.getOrElse(Tup(Nil)))(using emptyCtx, Map(), globFuncs, None) val newVs = prmVs.vSet ++ getFields(body.entities) + Var(nm.name) val nCtx = ctx.addV(newVs).addT(nm).addT(tps.map(_._2)) val parVs = pars.map(getFreeVars(_)(using nCtx)).fold(emptyCtx)(_ ++ _) @@ -196,20 +205,20 @@ class ClassLifter(logDebugMsg: Boolean = false) { others.children.map(getFreeVars).fold(emptyCtx)(_ ++ _) } - private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): ClassInfoCache = { + private def collectClassInfo(cls: NuTypeDef, preClss: Set[TypeName])(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): ClassInfoCache = { val NuTypeDef(_, nm, tps, param, _, _, pars, _, _, body) = cls - log(s"grep context of ${cls.nme.name} under {\n$ctx\n$cache\n$outer\n}\n") + log(s"grep context of ${cls.nme.name} under $ctx # $cache # $globFuncs # $outer ") val (clses, funcs, trms) = splitEntities(cls.body.entities) val (supNms, rcdFlds) = pars.map(getSupClsInfoByTerm).unzip val flds = rcdFlds.flatten.map{ - case (v, Fld(_, trm)) => - val tmp = getFreeVars(trm)(using emptyCtx) + case (v, Fld(_, trm)) => + val tmp = getFreeVars(trm)(using emptyCtxObj) val ret = tmp.tSet ++ tmp.vSet.map(x => TypeName(x.name)) (v, ret) }.unzip log(s"par record: ${flds._2.flatten}") val fields = (param.fold(Nil)(t => t.fields).flatMap(tupleEntityToVar) ++ funcs.map(_.nme) ++ clses.map(x => Var(x.nme.name)) ++ trms.flatMap(grepFieldsInTrm) ++ flds._1).toSet - val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)) + val nCtx = ctx.addV(fields).addV(flds._1).extT(tps.map(_._2)).addV(Var("this")) val tmpCtx = ((body.entities.map(getFreeVars(_)(using nCtx)) ++ pars.map(getFreeVars(_)(using nCtx))).fold(emptyCtx)(_ ++ _).moveT2V(preClss) ).addT(flds._2.flatten.toSet).extV(supNms.flatten.map(x => Var(x.name))) @@ -218,8 +227,8 @@ class ClassLifter(logDebugMsg: Boolean = false) { ret } - private def liftCaseBranch(brn: CaseBranches)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (CaseBranches, LocalContext) = brn match{ - case Case(v: Var, body, rest) => + private def liftCaseBranch(brn: CaseBranches)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (CaseBranches, LocalContext) = brn match{ + case Case(v: Var, body, rest) => val nTrm = liftTerm(body)(using ctx.addV(v)) val nRest = liftCaseBranch(rest) (Case(v, nTrm._1, nRest._1), nTrm._2 ++ nRest._2) @@ -233,18 +242,18 @@ class ClassLifter(logDebugMsg: Boolean = false) { case NoCases => (brn, emptyCtx) } - private def liftIf(body: IfBody)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (IfBody, LocalContext) = body match{ - case IfElse(expr) => + private def liftIf(body: IfBody)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (IfBody, LocalContext) = body match{ + case IfElse(expr) => val ret = liftTerm(expr) (IfElse(ret._1), ret._2) case IfThen(expr, rhs) => val nE = liftTerm(expr) val nR = liftTerm(rhs) (IfThen(nE._1, nR._1), nE._2 ++ nR._2) - case _ => ??? + case _ => throw MonomorphError(s"Unknown IfBody: ${body}") } - private def liftTuple(tup: Tup)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Tup, LocalContext) = { + private def liftTuple(tup: Tup)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Tup, LocalContext) = { val ret = tup.fields.map{ case (None, Fld(flags, trm)) => val tmp = liftTerm(trm) @@ -256,7 +265,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { (Tup(ret._1), ret._2.fold(emptyCtx)(_ ++ _)) } - private def liftConstr(tp: TypeName, prm: Tup)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (TypeName, Tup, LocalContext) = { + private def liftConstr(tp: TypeName, prm: Tup)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (TypeName, Tup, LocalContext) = { def findAncestor(crt: ClassInfoCache, target: Option[ClassInfoCache]): Option[(List[String], Option[String])] = { (crt.outerCls, target) match{ case (None, None) => None @@ -290,8 +299,13 @@ class ClassLifter(logDebugMsg: Boolean = false) { } } - private def liftTerm(target: Term)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Term, LocalContext) = target match { - case v: Var => + private def newLambObj(lhs: Term, rhs: Term) = + New(None, TypingUnit(List(NuFunDef(None, Var("apply"), None, Nil, Left(Lam(lhs, rhs)))(N, N, N, N, false)))) //TODO: Use Proper Arguments + + private def liftTerm(target: Term)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Term, LocalContext) = + log(s"liftTermNew $target in $ctx, $cache, $globFuncs, $outer") + target match{ + case v: Var => if(ctx.contains(v) || v.name.equals("this") || primiTypes.contains(v.name)) (v, emptyCtx) else if(cache.contains(TypeName(v.name))){ val ret = liftConstr(TypeName(v.name), Tup(Nil)) @@ -303,12 +317,16 @@ class ClassLifter(logDebugMsg: Boolean = false) { case None => (v, asContext(v)) } } - case Lam(lhs, rhs) => - val lctx = getFreeVars(lhs)(using emptyCtx, cache, None) - val (ltrm, _) = liftTerm(lhs)(using ctx.addV(lctx.vSet)) - val (rtrm, rctx) = liftTerm(rhs)(using ctx.addV(lctx.vSet)) - (Lam(ltrm, rtrm), rctx -+ lctx) - case t: Tup => + case Lam(lhs, rhs) => + val prmCnt = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None).vSet.size + val nTpNm = TypeName(genAnoName("Lambda"+prmCnt)) + val anoCls = NuTypeDef( + Cls, nTpNm, Nil, S(Tup(Nil)), N, N, Nil, N, N, + TypingUnit(List(NuFunDef(None, Var("apply"), N, Nil, Left(Lam(lhs, rhs)))(N, N, N, N, false))))(N, N) //TODO: Use Proper Arguments + val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) + val ret = liftEntities(List(anoCls, nSta)) + (Blk(ret._1), ret._2) + case t: Tup => liftTuple(t) case Rcd(fields) => val ret = fields.map{ @@ -324,7 +342,12 @@ class ClassLifter(logDebugMsg: Boolean = false) { case App(v: Var, prm: Tup) if cache.contains(TypeName(v.name)) => val ret = liftConstr(TypeName(v.name), prm) (App(Var(ret._1.name), ret._2), ret._3) - case App(lhs, rhs) => + case App(v: Var, prm: Tup) if globFuncs.contains(v) => + val (nFuncName, nCtxs) = globFuncs.get(v).get + val addiArgs = nCtxs.vSet.toList.map(toFldsEle(_)) + val nPrm = liftTuple(prm) + (App(nFuncName, Tup(nPrm._1.fields ++ addiArgs)), nPrm._2) + case App(lhs, rhs) => val (ltrm, lctx) = liftTerm(lhs) val (rtrm, rctx) = liftTerm(rhs) (App(ltrm, rtrm), lctx ++ rctx) @@ -357,7 +380,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { case Sel(receiver, fieldName) => val nRec = liftTerm(receiver) (Sel(nRec._1, fieldName), nRec._2) - case Splc(fields) => ??? + case Splc(fields) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case Subs(arr, idx) => val (ltrm, lctx) = liftTerm(arr) val (rtrm, rctx) = liftTerm(idx) @@ -370,7 +393,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val ret = liftTerm(lhs) val nTs = targs.map(liftType).unzip (TyApp(ret._1, nTs._1), nTs._2.fold(ret._2)(_ ++ _)) - case With(trm, fields) => ??? + case With(trm, fields) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case New(Some((t: TypeName, prm: Tup)), TypingUnit(Nil)) => val ret = liftConstr(t, prm) (New(Some((ret._1, ret._2)), TypingUnit(Nil)), ret._3) @@ -390,7 +413,7 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nSta = New(Some((nTpNm, Tup(Nil))), TypingUnit(Nil)) val ret = liftEntities(List(anoCls, nSta)) (Blk(ret._1), ret._2) - case New(head, body) => ??? + case New(head, body) => throw MonomorphError(s"Unimplemented liftTerm: ${target}") case Blk(stmts) => val ret = liftEntities(stmts) (Blk(ret._1), ret._2) @@ -405,12 +428,12 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (bod2, ctx) = liftTerm(bod) val (sts2, ctx2) = liftEntities(sts) (Where(bod2, sts2), ctx2) - case _: Eqn | _: Super => ??? // TODO - case patmat: AdtMatchWith => lastWords(s"Cannot liftTerm ${patmat}") + case _: Eqn | _: Super => throw MonomorphError(s"Unimplemented liftTerm: ${target}") // TODO + case patmat: AdtMatchWith => lastWords(s"Cannot liftTermNew ${patmat}") } //serves for lifting Tup(Some(_), Fld(_, _, trm)), where trm refers to a type - private def liftTermAsType(target: Term)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Term, LocalContext) = + private def liftTermAsType(target: Term)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Term, LocalContext) = log(s"liftTermAsType $target in $ctx, $cache") target match{ case v: Var => @@ -442,24 +465,24 @@ class ClassLifter(logDebugMsg: Boolean = false) { ((v, Fld(flags, tmp._1)), tmp._2) }.unzip (Rcd(ret._1), ret._2.fold(emptyCtx)(_ ++ _)) - case _ => ??? + case _ => throw MonomorphError(s"Unimplemented liftTermAsType: ${target}") } - private def liftTypeName(target: TypeName)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (TypeName, LocalContext) = { + private def liftTypeName(target: TypeName)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (TypeName, LocalContext) = { if(ctx.contains(target) || primiTypes.contains(target.name)) { target -> emptyCtx } else { cache.get(target).map(x => (x.liftedNm -> emptyCtx)).getOrElse(target -> asContext(target)) } } - private def liftTypeField(target: Field)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Field, LocalContext) = { + private def liftTypeField(target: Field)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Field, LocalContext) = { val (inT, iCtx) = target.in.map(liftType).unzip val (outT, oCtx) = liftType(target.out) Field(inT, outT) -> (iCtx.getOrElse(emptyCtx) ++ oCtx) } - private def liftType(target: Type)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (Type, LocalContext) = target match{ - case AppliedType(base, targs) => + private def liftType(target: Type)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (Type, LocalContext) = target match{ + case AppliedType(base, targs) => val (nTargs, nCtx) = targs.map(liftType).unzip val (nBase, bCtx) = liftTypeName(base) AppliedType(nBase, nTargs) -> (nCtx.fold(emptyCtx)(_ ++ _) ++ bCtx) @@ -536,18 +559,24 @@ class ClassLifter(logDebugMsg: Boolean = false) { val (body2, ctx) = liftType(body) PolyType(targs, body2) -> ctx case Top | Bot | _: Literal | _: TypeTag | _: TypeVar => target.asInstanceOf[Type] -> emptyCtx - case _: Selection => ??? // TODO + case _: Selection => throw MonomorphError(s"Unimplemented liftType: ${target}") // TODO } - private def liftFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (NuFunDef, LocalContext) = { - log(s"liftFunc $func under $ctx # $cache # $outer") + private def liftMemberFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (NuFunDef, LocalContext) = { + log(s"liftMemberFunc $func under $ctx # $cache # $globFuncs # $outer") val NuFunDef(rec, nm, sn, tpVs, body) = func - body match { - case Left(value) => - val ret = liftTerm(value)(using ctx.addV(nm).addT(tpVs)) - (func.copy(rhs = Left(ret._1))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2) - case Right(PolyType(targs, body)) => + body match{ + case Left(Lam(lhs@Tup(etts), rhs)) => + val lctx = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None) + val lret = liftTuple(lhs)(using ctx.addV(lctx.vSet)) + val ret = liftTerm(rhs)(using ctx.addV(lctx.vSet).addT(tpVs)) + (func.copy(rhs = Left(Lam(lret._1, ret._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2 -+ lret._2) //TODO: Check correctness + case Left(value) => + // will be treated as Lam(Tup(Nil), rhs) + val ret = liftTerm(value)(using ctx.addT(tpVs)) + (func.copy(rhs = Left(Lam(Tup(Nil), ret._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), ret._2) //TODO: Check correctness + case Right(PolyType(targs, body)) => val nBody = liftType(body)(using ctx.addT(tpVs)) val nTargs = targs.map { case L(tp) => liftTypeName(tp)(using ctx.addT(tpVs)).mapFirst(Left.apply) @@ -555,9 +584,39 @@ class ClassLifter(logDebugMsg: Boolean = false) { }.unzip (func.copy(rhs = Right(PolyType(nTargs._1, nBody._1)))(func.declareLoc, func.virtualLoc, func.signature, func.outer, func.genField), nTargs._2.fold(nBody._2)(_ ++ _)) - case _ => ??? // TODO + case _ => throw MonomorphError(s"Unimplemented liftMemberFunc: ${func}") // TODO } } + + private def liftGlobalFunc(func: NuFunDef)(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): Unit = { + log(s"liftGlobalFunc $func under $ctx # $cache # $globFuncs # $outer") + val NuFunDef(rec, nm, _, tpVs, body) = func + val nTpVs = tpVs ++ globFuncs.get(nm).get._2.tSet.toList + globalFunctions.addOne(body match{ + case Left(Lam(lhs@Tup(etts), rhs)) => + val tmp = globFuncs.get(nm).get._2.vSet.toList.map(toFldsEle) + val lctx = getFreeVars(lhs)(using emptyCtx, cache, globFuncs, None) + val lret = liftTuple(lhs)(using ctx.addV(lctx.vSet) ++ globFuncs.get(nm).get._2, cache, globFuncs) + val ret = liftTerm(rhs)(using ctx.addV(lctx.vSet) ++ globFuncs.get(nm).get._2, cache, globFuncs) + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Left(Lam(Tup(lret._1.fields ++ tmp), ret._1)))(N, N, N, N, true) //TODO: Use proper arguments + case Left(rhs) => + // will be treated as Lam(Tup(Nil), rhs) + val tmp = globFuncs.get(nm).get._2.vSet.toList.map(toFldsEle) + val ret = liftTerm(rhs)(using ctx ++ globFuncs.get(nm).get._2, cache, globFuncs) + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Left(Lam(Tup(tmp), ret._1)))(N, N, N, N, true) //TODO: Use proper arguments + // val ret = liftTermNew(value)(using ctx.addV(nm) ++ globFuncs.get(nm).get._2, cache, globFuncs) + // NuFunDef(rec, globFuncs.get(nm).get._1, nTpVs, Left(ret._1)) + case Right(PolyType(targs, body)) => + val nBody = liftType(body)(using ctx ++ globFuncs.get(nm).get._2, cache, globFuncs, None) + val nTargs = targs.map({ + case L(tn) => + liftTypeName(tn)(using ctx.addT(nTpVs), cache, globFuncs, None) match + case (tn, ctx) => (L(tn), ctx) + case R(tv) => R(tv) -> emptyCtx}).unzip + NuFunDef(rec, globFuncs.get(nm).get._1, N, nTpVs, Right(PolyType(nTargs._1, nBody._1)))(N, N, N, N, true) //TODO: Use proper arguments + case _ => throw MonomorphError(s"Unimplemented liftGlobalFunc: ${func}") + }) + } private def grepFieldsInTrm(trm: Term): Option[Var] = trm match{ @@ -565,35 +624,48 @@ class ClassLifter(logDebugMsg: Boolean = false) { case _ => None } - private def mixClsInfos(clsInfos: Map[TypeName, ClassInfoCache], newClsNms: Set[Var])(using cache: ClassCache): Map[TypeName, ClassInfoCache] = { - val nameInfoMap: MutMap[TypeName, ClassInfoCache] = MutMap(clsInfos.toSeq: _*) - log(s"mix cls infos $nameInfoMap") + private def mixClsInfos(clsInfos: Map[String, ClassInfoCache], funcInfos: Map[String, LocalContext])(using cache: ClassCache): (Map[String, ClassInfoCache], Map[String, LocalContext]) = { + val nameInfoMap: MutMap[String, ClassInfoCache] = MutMap(clsInfos.toSeq: _*) + val nameFuncMap: MutMap[String, LocalContext] = MutMap(funcInfos.toSeq: _*) + log(s"mix cls infos $nameInfoMap, $nameFuncMap") // val fullMp = cache ++ nameInfoMap - val clsNmsAsTypeNm = newClsNms.map(x => TypeName(x.name)) - val len = clsInfos.size - for(_ <- 1 to len){ - val tmp = nameInfoMap.toList - tmp.foreach{case (nmOfCls, infoOfCls@ClassInfoCache(_, _, ctx, flds, inners, sups, _, _, _)) => { - val usedClsNmList = ctx.vSet.map(x => TypeName(x.name)).intersect(clsNmsAsTypeNm) - val newCtxForCls = usedClsNmList.foldLeft(ctx)((c1, c2) => c1 ++ nameInfoMap.get(c2).get.capturedParams) + val clsNmsAsTypeNm = clsInfos.keySet.map(x => TypeName(x)) + val len = clsInfos.size + nameFuncMap.size + for(_ <- 0 to len){ + nameInfoMap.toList.foreach{case (nmOfCls, infoOfCls@ClassInfoCache(_, _, ctx, flds, inners, sups, _, _, _)) => { + val usedClsNmList = ctx.vSet.map(_.name).intersect(clsInfos.keySet) + val newCtxForCls_tmp = usedClsNmList.foldLeft(ctx)((c1, c2) => c1 ++ nameInfoMap.get(c2).get.capturedParams) + + val usedFuncNmList = ctx.vSet.map(_.name).intersect(funcInfos.keySet) + val newCtxForCls = usedFuncNmList.foldLeft(newCtxForCls_tmp)((c, x) => c ++ nameFuncMap.get(x).get) + val supClsNmList = infoOfCls.supClses - val newFields = supClsNmList.foreach(c2 => flds.addAll( - nameInfoMap.get(c2).map(_.fields).getOrElse(cache.get(c2).map(_.fields).getOrElse(Nil)) + supClsNmList.foreach(c2 => flds.addAll( + nameInfoMap.get(c2.name).map(_.fields).getOrElse(cache.get(c2).map(_.fields).getOrElse(Nil)) )) - val newInners = supClsNmList.foreach(c2 => inners.addAll( - nameInfoMap.get(c2).map(_.innerClses).getOrElse(cache.get(c2).map(_.innerClses).getOrElse(Nil)) + supClsNmList.foreach(c2 => inners.addAll( + nameInfoMap.get(c2.name).map(_.innerClses).getOrElse(cache.get(c2).map(_.innerClses).getOrElse(Nil)) )) - val newCtxFromSup = supClsNmList.map(c2 => - nameInfoMap.get(c2).map(_.capturedParams).getOrElse(cache.get(c2).map(_.capturedParams).getOrElse(emptyCtx)) + val newCtxFromSup = supClsNmList.map(c2 => + nameInfoMap.get(c2.name).map(_.capturedParams).getOrElse(cache.get(c2).map(_.capturedParams).getOrElse(emptyCtx)) ).fold(emptyCtx)(_ ++ _) infoOfCls.capturedParams = newCtxForCls ++ newCtxFromSup }} + nameFuncMap.toList.foreach((nm, ctx) => { + val usedClsNmList = ctx.vSet.map(_.name).intersect(clsInfos.keySet) + val usedFuncNmList = ctx.vSet.map(_.name).intersect(funcInfos.keySet) + val nCtx = (usedClsNmList.map(x => nameInfoMap.get(x).get.capturedParams) ++ usedFuncNmList.map(x => nameFuncMap.get(x).get)).foldLeft(ctx)(_ ++ _) + nameFuncMap.update(nm, nCtx) + }) } - nameInfoMap.foreach((x1, x2) => x2.capturedParams = (x2.capturedParams extV newClsNms).extT(x2.innerClses.keySet)) - nameInfoMap.toMap + nameInfoMap.foreach((x1, x2) => x2.capturedParams = (x2.capturedParams.extV(clsInfos.keySet.map(Var(_)))).extV(funcInfos.keySet.map(Var(_))).extT(x2.innerClses.keySet)) + nameFuncMap.toList.foreach((x, c) => nameFuncMap.update(x, c.extV(clsInfos.keySet.map(Var(_))).extV(funcInfos.keySet.map(Var(_))))) + log(s"mix result: $nameInfoMap, $nameFuncMap") + nameInfoMap.toMap -> nameFuncMap.toMap } + - private def liftEntities(etts: List[Statement])(using ctx: LocalContext, cache: ClassCache, outer: Option[ClassInfoCache]): (List[Statement], LocalContext) = { + private def liftEntities(etts: List[Statement])(using ctx: LocalContext, cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): (List[Statement], LocalContext) = { log("liftEntities: " ++ etts.headOption.map(_.toString()).getOrElse("")) val (newCls, newFuncs, rstTrms) = splitEntities(etts) val newClsNms = newCls.map(x => Var(x.nme.name)).toSet @@ -601,30 +673,39 @@ class ClassLifter(logDebugMsg: Boolean = false) { val nmsInTrm = rstTrms.flatMap(grepFieldsInTrm) val clsInfos = newCls.map(x => { val infos = collectClassInfo(x, newCls.map(_.nme).toSet)(using emptyCtx) - infos.capturedParams = infos.capturedParams.copy(vSet = infos.capturedParams.vSet.intersect(ctx.vSet ++ newClsNms ++ newFuncNms ++ nmsInTrm)) - x.nme -> infos}).toMap + infos.capturedParams = infos.capturedParams.intersect(ctx.addT(infos.capturedParams.tSet).addV(newClsNms ++ newFuncNms ++ nmsInTrm -- globFuncs.keySet ++ outer.map(_ => Var("this")))) + x.nme.name -> infos}).toMap + val funcInfos = + newFuncs.map(x => x.nme.name -> (x.rhs match { + case Left(trm) => getFreeVars(trm)(using emptyCtx) + .intersect(ctx.addV(newClsNms ++ newFuncNms ++ nmsInTrm -- globFuncs.keySet ++ outer.map(_ => Var("this")))) + .extT(x.tparams) + case _ => emptyCtx}) + ).toMap log("captured cls infos: \n" ++ clsInfos.toString()) - val refinedInfo = mixClsInfos(clsInfos, newClsNms) - val newCache = cache ++ refinedInfo - refinedInfo.foreach((_, clsi) => completeClsInfo(clsi)(using newCache)) - - newCls.foreach(x => liftTypeDefNew(x)(using newCache)) - val (liftedFuns, funVs) = newFuncs.map(liftFunc(_)(using ctx.addV(newFuncNms), newCache)).unzip - val (liftedTerms, termVs) = rstTrms.map(liftTerm(_)(using ctx.addV(newFuncNms), newCache)).unzip - (liftedFuns ++ liftedTerms, (funVs ++ termVs).fold(emptyCtx)(_ ++ _)) + log("captured func infos: \n" ++ funcInfos.toString()) + val (refinedClsInfo, refinedFuncInfo) = mixClsInfos(clsInfos, funcInfos) + val newCache = cache ++ refinedClsInfo.map(x => (TypeName(x._1) -> x._2)) + refinedClsInfo.foreach((_, clsi) => completeClsInfo(clsi)(using newCache)) + val newGlobalFuncs = refinedFuncInfo.map((nm, vs) => (Var(nm) -> (Var(genAnoName(nm)), vs))) + + newCls.foreach(x => liftTypeDef(x)(using newCache, globFuncs ++ newGlobalFuncs)) + (newFuncs zip refinedFuncInfo).foreach((f, c) => liftGlobalFunc(f)(using ctx, newCache, globFuncs ++ newGlobalFuncs)) + val (liftedTerms, termVs) = rstTrms.map(liftTerm(_)(using ctx.addV(newFuncNms), newCache, globFuncs ++ newGlobalFuncs)).unzip + (liftedTerms, (termVs).fold(emptyCtx)(_ ++ _)) } - private def completeClsInfo(clsInfo: ClassInfoCache)(using cache: ClassCache): Unit = { + private def completeClsInfo(clsInfo: ClassInfoCache)(using cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)]): Unit = { val ClassInfoCache(_, nName, freeVs, flds, inners, _, _, cls, _) = clsInfo val (clsList, _, _) = splitEntities(cls.body.entities) val innerClsNmSet = clsList.map(_.nme).toSet - val innerClsInfos = clsList.map(x => x.nme -> collectClassInfo(x, innerClsNmSet)(using asContextV(freeVs.vSet ++ flds), cache, Some(clsInfo))).toMap - val refinedInfos = mixClsInfos(innerClsInfos, innerClsNmSet.map(x => Var(x.name))) + val innerClsInfos = clsList.map(x => x.nme.name -> collectClassInfo(x, innerClsNmSet)(using asContextV(freeVs.vSet ++ flds), cache, globFuncs, Some(clsInfo))).toMap + val refinedInfos = mixClsInfos(innerClsInfos, Map())._1.map(x => (TypeName(x._1) -> x._2)) refinedInfos.foreach((_, info) => completeClsInfo(info)(using cache ++ refinedInfos)) inners.addAll(refinedInfos) } - private def liftTypeDefNew(target: NuTypeDef)(using cache: ClassCache, outer: Option[ClassInfoCache]): Unit = { + private def liftTypeDef(target: NuTypeDef)(using cache: ClassCache, globFuncs: Map[Var, (Var, LocalContext)], outer: Option[ClassInfoCache]): Unit = { def getAllInners(sups: Set[TypeName]): ClassCache = { sups.flatMap( t => cache.get(t).map(x => getAllInners(x.supClses) ++ x.innerClses) @@ -644,10 +725,10 @@ class ClassLifter(logDebugMsg: Boolean = false) { outer.map(x => List(toFldsEle(Var(genParName(x.liftedNm.name))))).getOrElse(Nil) ++ params.fold(Nil)(t => t.fields) ++ freeVs.vSet.map(toFldsEle) - val nPars = pars.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip - val nFuncs = funcList.map(liftFunc(_)(using emptyCtx, nCache, nOuter)).unzip - val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, nOuter)).unzip - clsList.foreach(x => liftTypeDefNew(x)(using nCache, nOuter)) + val nPars = pars.map(liftTerm(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + val nFuncs = funcList.map(liftMemberFunc(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + val nTerms = termList.map(liftTerm(_)(using emptyCtx, nCache, globFuncs, nOuter)).unzip + clsList.foreach(x => liftTypeDef(x)(using nCache, globFuncs, nOuter)) retSeq = retSeq.appended(NuTypeDef( kind, nName, nTps.map((None, _)), S(Tup(nParams)), None, None, nPars._1, None, None, TypingUnit(nFuncs._1 ++ nTerms._1))(None, None)) @@ -657,9 +738,10 @@ class ClassLifter(logDebugMsg: Boolean = false) { log("=========================\n") log(s"lifting: \n${showStructure(rawUnit)}\n") retSeq = Nil - val re = liftEntities(rawUnit.entities)(using emptyCtx, Map(), None) + globalFunctions.clear() + val re = liftEntities(rawUnit.entities)(using emptyCtx, Map(), Map(), None) log(s"freeVars: ${re._2}") // println(logOutput.toString()) - TypingUnit(retSeq.toList++re._1) + TypingUnit(retSeq.toList ++ globalFunctions.toList ++ re._1) } } diff --git a/compiler/shared/main/scala/mlscript/compiler/DataType.scala b/compiler/shared/main/scala/mlscript/compiler/DataType.scala new file mode 100644 index 000000000..ca3ba27b0 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/DataType.scala @@ -0,0 +1,36 @@ +package mlscript.compiler + +abstract class DataType + +object DataType: + sealed class Singleton(value: Expr.Literal, dataType: DataType) extends DataType: + override def toString(): String = value.toString() + + enum Primitive(name: String) extends DataType: + case Integer extends Primitive("int") + case Decimal extends Primitive("real") + case Boolean extends Primitive("bool") + case String extends Primitive("str") + override def toString(): String = this.name + end Primitive + + sealed case class Tuple(elementTypes: List[DataType]) extends DataType: + override def toString(): String = elementTypes.mkString("(", ", ", ")") + + sealed case class Class(declaration: Item.TypeDecl) extends DataType: + override def toString(): String = s"class ${declaration.name.name}" + + sealed case class Function(parameterTypes: List[DataType], returnType: DataType) extends DataType: + def this(returnType: DataType, parameterTypes: DataType*) = + this(parameterTypes.toList, returnType) + override def toString(): String = + val parameterList = parameterTypes.mkString("(", ", ", ")") + s"$parameterList -> $returnType" + + sealed case class Record(fields: Map[String, DataType]) extends DataType: + def this(fields: (String, DataType)*) = this(Map.from(fields)) + override def toString(): String = + fields.iterator.map { (name, ty) => s"$name: $ty" }.mkString("{", ", ", "}") + + case object Unknown extends DataType: + override def toString(): String = "unknown" diff --git a/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala b/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala new file mode 100644 index 000000000..117a8a3b7 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/DataTypeInferer.scala @@ -0,0 +1,18 @@ +package mlscript.compiler +import mlscript.compiler.mono.MonomorphError + +trait DataTypeInferer: + import DataType._ + + def findClassByName(name: String): Option[Item.TypeDecl] + + def infer(expr: Expr, compatiableType: Option[DataType]): DataType = + expr match + case Expr.Tuple(elements) => DataType.Tuple(elements.map(infer(_, None))) + case lit @ Expr.Literal(value: BigInt) => Singleton(lit, Primitive.Integer) + case lit @ Expr.Literal(value: BigDecimal) => Singleton(lit, Primitive.Decimal) + case lit @ Expr.Literal(value: String) => Singleton(lit, Primitive.String) + case lit @ Expr.Literal(value: Boolean) => Singleton(lit, Primitive.Boolean) + case Expr.Apply(Expr.Ref(name), args) => + findClassByName(name).fold(DataType.Unknown)(DataType.Class(_)) + case _ => throw MonomorphError(s"I can't infer the type of $expr now") \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/Helpers.scala b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala new file mode 100644 index 000000000..a49bd85bd --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/Helpers.scala @@ -0,0 +1,196 @@ +package mlscript.compiler + +import mlscript.{App, Asc, Assign, Bind, Blk, Bra, CaseOf, Lam, Let, Lit, + New, Rcd, Sel, Subs, Term, Test, Tup, With, Var, Fld, FldFlags, If, PolyType} +import mlscript.{IfBody, IfThen, IfElse, IfLet, IfOpApp, IfOpsApp, IfBlock} +import mlscript.UnitLit +import mlscript.codegen.Helpers.inspect as showStructure +import mlscript.compiler.mono.MonomorphError +import mlscript.NuTypeDef +import mlscript.NuFunDef +import scala.collection.mutable.ArrayBuffer +import mlscript.CaseBranches +import mlscript.Case +import mlscript.NoCases +import mlscript.Wildcard +import mlscript.DecLit +import mlscript.IntLit +import mlscript.StrLit +import mlscript.AppliedType +import mlscript.TypeName +import mlscript.TypeDefKind +import mlscript.compiler.mono.Monomorph + +object Helpers: + /** + * Extract parameters for monomorphization from a `Tup`. + */ + def toFuncParams(term: Term): Iterator[Parameter] = term match + case Tup(fields) => fields.iterator.flatMap { + // The new parser emits `Tup(_: UnitLit(true))` from `fun f() = x`. + case (_, Fld(FldFlags(_, _, _), UnitLit(true))) => None + case (None, Fld(FldFlags(_, spec, _), Var(name))) => Some((spec, Expr.Ref(name))) + case (Some(Var(name)), Fld(FldFlags(_, spec, _), _)) => Some((spec, Expr.Ref(name))) + case _ => throw new MonomorphError( + s"only `Var` can be parameters but we meet ${showStructure(term)}" + ) + } + case _ => throw MonomorphError("expect the list of parameters to be a `Tup`") + + def toFuncArgs(term: Term): IterableOnce[Term] = term match + // The new parser generates `(undefined, )` when no arguments. + // Let's do this temporary fix. + case Tup((_, Fld(FldFlags(_, _, _), UnitLit(true))) :: Nil) => Iterable.empty + case Tup(fields) => fields.iterator.map(_._2.value) + case _ => Some(term) + + def term2Expr(term: Term): Expr = { + term match + case Var(name) => Expr.Ref(name) + case Lam(lhs, rhs) => + val params = toFuncParams(lhs).toList + Expr.Lambda(params, term2Expr(rhs)) + case App(App(Var("=>"), Bra(false, args: Tup)), body) => + val params = toFuncParams(args).toList + Expr.Lambda(params, term2Expr(body)) + case App(App(Var("."), self), App(Var(method), args: Tup)) => + Expr.Apply(Expr.Select(term2Expr(self), Expr.Ref(method)), List.from(toFuncArgs(args).map(term2Expr))) + case App(lhs, rhs) => + val callee = term2Expr(lhs) + val arguments = toFuncArgs(rhs).map(term2Expr).toList + Expr.Apply(callee, arguments) + case Tup(fields) => + Expr.Tuple(fields.map { + case (_, Fld(FldFlags(mut, spec, genGetter), value)) => term2Expr(value) + }) + case Rcd(fields) => + Expr.Record(fields.map { + case (name, Fld(FldFlags(mut, spec, genGetter), value)) => (Expr.Ref(name.name), term2Expr(value)) + }) + case Sel(receiver, fieldName) => + Expr.Select(term2Expr(receiver), Expr.Ref(fieldName.name)) + case Let(rec, Var(name), rhs, body) => + val exprRhs = term2Expr(rhs) + val exprBody = term2Expr(body) + Expr.LetIn(rec, Expr.Ref(name), exprRhs, exprBody) + case Blk(stmts) => Expr.Block(stmts.flatMap[Expr | Item.FuncDecl | Item.FuncDefn] { + case term: Term => Some(term2Expr(term)) + case tyDef: NuTypeDef => throw MonomorphError(s"Unimplemented term2Expr ${term}") + case funDef: NuFunDef => + val NuFunDef(_, nme, sn, targs, rhs) = funDef + val ret: Item.FuncDecl | Item.FuncDefn = rhs match + case Left(Lam(params, body)) => + Item.FuncDecl(Expr.Ref(nme.name), toFuncParams(params).toList, term2Expr(body)) + case Left(body: Term) => Item.FuncDecl(Expr.Ref(nme.name), Nil, term2Expr(body)) + case Right(tp) => Item.FuncDefn(Expr.Ref(nme.name), targs, PolyType(Nil, tp)) //TODO: Check correctness in Type -> Polytype conversion + Some(ret) + case mlscript.DataDefn(_) => throw MonomorphError("unsupported DataDefn") + case mlscript.DatatypeDefn(_, _) => throw MonomorphError("unsupported DatatypeDefn") + case mlscript.TypeDef(_, _, _, _, _, _, _, _) => throw MonomorphError("unsupported TypeDef") + case mlscript.Def(_, _, _, _) => throw MonomorphError("unsupported Def") + case mlscript.LetS(_, _, _) => throw MonomorphError("unsupported LetS") + case mlscript.Constructor(_, _) => throw MonomorphError("unsupported Constructor") + }) + case Bra(rcd, term) => term2Expr(term) + case Asc(term, ty) => Expr.As(term2Expr(term), ty) + case _: Bind => throw MonomorphError("cannot monomorphize `Bind`") + case _: Test => throw MonomorphError("cannot monomorphize `Test`") + case With(term, Rcd(fields)) => + Expr.With(term2Expr(term), Expr.Record(fields.map { + case (name, Fld(FldFlags(mut, spec, getGetter), value)) => (Expr.Ref(name.name), term2Expr(term)) + })) + case CaseOf(term, cases) => + def rec(bra: CaseBranches)(using buffer: ArrayBuffer[CaseBranch]): Unit = bra match + case Case(pat, body, rest) => + val newCase = pat match + case Var(name) => CaseBranch.Instance(Expr.Ref(name), Expr.Ref("_"), term2Expr(body)) + case DecLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case IntLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case StrLit(value) => CaseBranch.Constant(Expr.Literal(value), term2Expr(body)) + case UnitLit(undefinedOrNull) => CaseBranch.Constant(Expr.Literal(UnitValue.Undefined), term2Expr(body)) + buffer.addOne(newCase) + rec(rest) + case NoCases => () + case Wildcard(body) => + buffer.addOne(CaseBranch.Wildcard(term2Expr(body))) + val branchBuffer = ArrayBuffer[CaseBranch]() + rec(cases)(using branchBuffer) + Expr.Match(term2Expr(term), branchBuffer) + + case Subs(array, index) => + Expr.Subscript(term2Expr(array), term2Expr(index)) + case Assign(lhs, rhs) => + Expr.Assign(term2Expr(lhs), term2Expr(rhs)) + case New(None, body) => + throw MonomorphError(s"Unimplemented term2Expr ${term}") + case New(Some((constructor, args)), body) => + val typeName = constructor match + case AppliedType(TypeName(name), _) => name + case TypeName(name) => name + Expr.New(TypeName(typeName), toFuncArgs(args).map(term2Expr).toList) + // case Blk(unit) => Expr.Isolated(trans2Expr(TypingUnit(unit))) + case If(body, alternate) => body match + case IfThen(condition, consequent) => + Expr.IfThenElse( + term2Expr(condition), + term2Expr(consequent), + alternate.map(term2Expr) + ) + case term: IfElse => throw MonomorphError("unsupported IfElse") + case term: IfLet => throw MonomorphError("unsupported IfLet") + case term: IfOpApp => throw MonomorphError("unsupported IfOpApp") + case term: IfOpsApp => throw MonomorphError("unsupported IfOpsApp") + case term: IfBlock => throw MonomorphError("unsupported IfBlock") + case IntLit(value) => Expr.Literal(value) + case DecLit(value) => Expr.Literal(value) + case StrLit(value) => Expr.Literal(value) + case UnitLit(undefinedOrNull) => + Expr.Literal(if undefinedOrNull + then UnitValue.Undefined + else UnitValue.Null) + case _ => throw MonomorphError("unsupported term"+ term.toString) + } + + def func2Item(funDef: NuFunDef): Item.FuncDecl | Item.FuncDefn = + val NuFunDef(_, nme, sn, targs, rhs) = funDef + rhs match + case Left(Lam(params, body)) => + Item.FuncDecl(Expr.Ref(nme.name), toFuncParams(params).toList, term2Expr(body)) + case Left(body: Term) => Item.FuncDecl(Expr.Ref(nme.name), Nil, term2Expr(body)) + case Right(tp) => Item.FuncDefn(Expr.Ref(nme.name), targs, PolyType(Nil, tp)) //TODO: Check correctness in Type -> Polytype conversion + + def type2Item(tyDef: NuTypeDef): Item.TypeDecl = + val NuTypeDef(kind, className, tparams, params, _, _, parents, _, _, body) = tyDef + val isolation = Isolation(body.entities.flatMap { + // Question: Will there be pure terms in class body? + case term: Term => + Some(term2Expr(term)) + case subTypeDef: NuTypeDef => throw MonomorphError(s"Unimplemented func2Item ${tyDef}") + case subFunDef: NuFunDef => + Some(func2Item(subFunDef)) + case term => throw MonomorphError(term.toString) + }) + val typeDecl: Item.TypeDecl = Item.TypeDecl( + Expr.Ref(className.name), // name + kind, // kind + tparams.map(_._2), // typeParams + toFuncParams(params.getOrElse(Tup(Nil))).toList, // params + parents.map { + case Var(name) => (TypeName(name), Nil) + case App(Var(name), args) => (TypeName(name), term2Expr(args) match{ + case Expr.Tuple(fields) => fields + case _ => Nil + }) + case _ => throw MonomorphError("unsupported parent term") + }, // parents + isolation // body + ) + typeDecl + + private given Conversion[TypeDefKind, TypeDeclKind] with + import mlscript.{Als, Cls, Trt} + def apply(kind: TypeDefKind): TypeDeclKind = kind match + case Als => TypeDeclKind.Alias + case Cls => TypeDeclKind.Class + case Trt => TypeDeclKind.Trait + case _ => throw MonomorphError(s"Unsupported TypeDefKind conversion ${kind}") diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala b/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala new file mode 100644 index 000000000..fde9c93ed --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/Monomorph.scala @@ -0,0 +1,334 @@ +package mlscript.compiler.mono + +import mlscript.compiler.debug.{Debug, DummyDebug} +import mlscript.{TypingUnit, NuTypeDef, NuFunDef} +import mlscript.{AppliedType, TypeName} +import mlscript.{App, Asc, Assign, Bind, Blk, Bra, CaseOf, Lam, Let, Lit, + New, Rcd, Sel, Subs, Term, Test, Tup, With, Var, Fld, If} +import mlscript.{IfThen, IfElse, IfLet, IfOpApp, IfOpsApp, IfBlock} +import mlscript.{IntLit, DecLit, StrLit, UnitLit} +import scala.collection.immutable.{HashMap} +import scala.collection.mutable.{Map as MutMap, Set as MutSet} +import scala.collection.mutable.ListBuffer +import mlscript.Cls +import mlscript.CaseBranches +import mlscript.TypeDefKind +import mlscript.AppliedType.apply +import mlscript.compiler.mono.specializer.Builtin +import mlscript.compiler.mono.specializer.Context +import mlscript.compiler.* + +import mlscript.compiler.printer.ExprPrinter +import mlscript.compiler.mono.specializer.BoundedExpr +import mlscript.compiler.mono.specializer.{MonoValue, ObjectValue, UnknownValue, FunctionValue, VariableValue} + +class Monomorph(debug: Debug = DummyDebug) extends DataTypeInferer: + import Helpers._ + import Monomorph._ + + /** + * Specialized implementations of function declarations. + */ + private val funImpls = MutMap[String, (Item.FuncDecl, MutMap[String, Item.FuncDecl], List[BoundedExpr], VariableValue)]() + + private def getfunInfo(nm: String): String = + val info = funImpls.get(nm).get + s"$nm: (${info._3.mkString(" X ")}) -> ${info._4} @${funDependence.get(nm).get.mkString("{", ", ", "}")}" + + private val funDependence = MutMap[String, Set[String]]() + + val evalQueue = MutSet[String]() + val evalCnt = MutMap[String, Int]() + + /** + * Specialized implementations of each type declarations. + */ + private val tyImpls = MutMap[String, SpecializationMap[Item.TypeDecl]]() + private val allTypeImpls = MutMap[String, Item.TypeDecl]() + /** + * Add a prototype type declaration. + */ + private def addPrototypeTypeDecl(typeDecl: Item.TypeDecl) = + tyImpls.addOne(typeDecl.name.name, SpecializationMap(typeDecl)) + allTypeImpls.addOne(typeDecl.name.name, typeDecl) + /** + * An iterator going through all type declarations. + */ + private def allTypeDecls: IterableOnce[Item.TypeDecl] = + tyImpls.values.flatMap { _.iterator } + + /** + * A global store of monomorphized lambda classes. + */ + private val lamTyDefs = MutMap[String, Item.TypeDecl]() + /** + * A global store of anonymous classes. For example, `new { ... }`. + */ + private val anonymTyDefs = MutMap[String, Item.TypeDecl]() + + def findClassByName(name: String): Option[mlscript.compiler.Item.TypeDecl] = + allTypeImpls.get(name) + + val specializer = mono.specializer.Specializer(this)(using debug) + + private def addNewFunction(func: Item.FuncDecl): Unit = { + funImpls.addOne(func.name.name, (func, MutMap(), func.params.map(_ => BoundedExpr()), VariableValue.refresh())) + funDependence.addOne(func.name.name, Set()) + } + + private def getResult(exps: List[Expr]) = mlscript.compiler.ModuleUnit(exps.concat[Expr | Item](funImpls.map(x => x._2._1)) + .concat(allTypeImpls.values.map(x => x.copy(body = Isolation(Nil)))) + .concat(lamTyDefs.values) + .concat(anonymTyDefs.values) + .toList) + + /** + * This function defunctionalizes the top-level `TypingUnit` into a `Module`. + */ + def defunctionalize(tu: TypingUnit): ModuleUnit = + // debug.trace("MONO MODL", PrettyPrinter.show(tu)) { + val exps = tu.entities.zipWithIndex.flatMap[Expr] { + case (term: Term, i) => + val exp = term2Expr(term) + val funcName = s"main$$$$$i" + val asFunc: Item.FuncDecl = Item.FuncDecl(Expr.Ref(funcName), Nil, exp) + addNewFunction(asFunc) + evalQueue.addOne(funcName) + Some(Expr.Apply(Expr.Ref(funcName), Nil)) + case (tyDef: NuTypeDef, _) => + val ret = type2Item(tyDef) + addPrototypeTypeDecl(ret) + None + case (funDef: NuFunDef, _) => + val funcItem = func2Item(funDef) + funcItem match + case funcDecl: Item.FuncDecl => + addNewFunction(funcDecl) + case _ => () + None + case (other, _) => throw MonomorphError(s"Unknown Statement in TypingUnit: ${other}") + }; + debug.log(getResult(exps).getDebugOutput.toLines(using false).mkString("\n")) + while(!evalQueue.isEmpty){ + val crt = evalQueue.head + evalQueue.remove(crt) + updateFunction(crt) + } + funImpls.mapValuesInPlace{ + case (_, (Item.FuncDecl(nm, as, body), mp, la, lr)) => + (Item.FuncDecl(nm, as, specializer.defunctionalize(body)), mp, la, lr) + } + val ret = getResult(exps) + debug.log("") + debug.log("==============final function signatures==================") + funImpls.foreach( + (nm, info) => { + debug.log(s"$nm: (${info._3.mkString(" X ")}) -> ${info._4}") + } + ) + + ret + // }() + + private def updateFunction(crt: String): Unit = { + debug.log(s"evaluating $crt, rests: ${evalQueue}") + val cnt = evalCnt.get(crt).getOrElse(0) + if(cnt <= 10){ + evalCnt.update(crt, cnt+1) + debug.log("=" * 10 + s" updating $crt " + "=" * 10) + debug.log(getfunInfo(crt)) + updateFunc(crt) + debug.log(getfunInfo(crt)) + } + else{ + throw new MonomorphError("stack overflow!!!") + } + } + + /** + * This function monomorphizes the nested `TypingUnit` into a `Isolation`. + */ + private def trans2Expr(body: TypingUnit): Isolation = + debug.trace("MONO BODY", PrettyPrinter.show(body)) { + Isolation(body.entities.flatMap[Expr | Item.FuncDecl | Item.FuncDefn] { + case term: Term => + Some(term2Expr(term)) + case tyDef: NuTypeDef => + val ret = type2Item(tyDef) + addPrototypeTypeDecl(ret) + None + case funDef: NuFunDef => + Some(func2Item(funDef)) + case other => throw MonomorphError(s"Unknown Statement in TypingUnit: ${other}") + }) + }(identity) + + def getFuncRetVal(name: String, args: List[BoundedExpr])(using evalCtx: Context, callingStack: List[String]): BoundedExpr = { + debug.trace[BoundedExpr]("SPEC CALL", name + args.mkString(" with (", ", ", ")")) { + if(funImpls.contains(name)){ + val (funcdecl, mps, oldArgs, oldVs) = funImpls.get(name).get + val old = funDependence.get(name).get + funDependence.update(name, old ++ callingStack.headOption) + // debug.log(s"adding dependence ${callingStack.headOption}") + val nArgs = (oldArgs zip (args.map(_.unfoldVars))).map(_ ++ _).zip(funcdecl.params).map( + (x,y) => if(y._1) then x else x.literals2Prims + ) + + debug.log(s"comparing ${oldArgs.mkString("(", ", ", ")")} with ${nArgs.map(_.getDebugOutput).mkString("(", ", ", ")")}") + if(evalCnt.get(name).isEmpty || (oldArgs zip nArgs).find(x => x._1.compare(x._2)).isDefined){ + funImpls.update(name, (funcdecl, mps, nArgs, oldVs)) + if(!evalQueue.contains(name)){ + if(evalCnt.get(name).isEmpty){ + debug.log(s"first time encounter $name") + updateFunction(name) + } + else{ + debug.log(s"find finer args") + evalQueue.add(name) + } + } + } + BoundedExpr(funImpls.get(name).get._4) + } + else { + debug.log(s"calling unknown function $name(${args.mkString(",")})") + debug.log(funImpls.keySet.toString()) + BoundedExpr(UnknownValue()) + } + }(identity) + } + + private def updateFunc(name: String): Unit = { + val (funcdecl, mps, args, _) = funImpls.get(name).get + val ctx = (funcdecl.params.map(_._2.name) zip args).toMap + val nBody = specializer.evaluate(funcdecl.body)(using Context()++ctx, List(funcdecl.name.name)) + val nVs = nBody.expValue + val oldVs = VariableValue.get(funImpls.get(name).get._4) + debug.log(s"comparing ${oldVs} with ${nVs}") + if(oldVs.compare(nVs)){ + debug.log(s"adding these funcs to queue: ${funDependence.get(name).get}") + funDependence.get(name).get.foreach(x => if !evalQueue.contains(x) then evalQueue.add(x)) + } + funImpls.updateWith(name)(_.map(x => { + val nFuncDecl: Item.FuncDecl = x._1.copy(body = nBody) + VariableValue.update(x._4, nVs) + (nFuncDecl, x._2, x._3, x._4) + })) + } + + def findVar(name: String)(using evalCtx: Context, callingStack: List[String]): MonoValue = { + if(funImpls.contains(name)){ + val funcBody = funImpls.get(name).get + funDependence.update(name, funDependence.get(name).get ++ callingStack.headOption) + FunctionValue(name, funcBody._1.params.map(_._2.name), Nil) + } + else{ + UnknownValue() + } + } + + private def partitationArguments(name: String, params: List[Parameter], args: List[Expr]): (List[Expr], List[Expr]) = + if (args.length != params.length) { + debug.log("") + throw MonomorphError(s"$name expect ${params.length} arguments but ${args.length} were given") + } + val staticArguments = params.iterator.zip(args).flatMap({ + case ((true, _), value) => Some(value) + case _ => None + }).toList + val dynamicArguments = params.iterator.zip(args).flatMap({ + case ((false, _), value) => Some(value) + case _ => None + }).toList + (staticArguments, dynamicArguments) + + private def generateSignature(staticArguments: List[Expr])(using MonomorphContext): String = + staticArguments.iterator.map(infer(_, None)).mkString("__", "_", "") + + private def specializeClassCall(name: String, args: List[Expr])(using MonomorphContext): Option[Expr] = + debug.trace("SPEC CALL", "class " + name + args.mkString(" with (", ", ", ")")) { + ??? + }(_.fold(Debug.noPostTrace)(identity)) + + def createObjValue(tpName: String, args: List[BoundedExpr]): MonoValue = + debug.trace("SPEC NEW", s"$tpName($args)"){ + if(allTypeImpls.contains(tpName)){ + val tp = allTypeImpls.get(tpName).get + val ags = (tp.params.map(_._2.name) zip args) + val ret = ObjectValue(tpName, MutMap(ags: _*)) + val pars = tp.parents.map((supTp, prms) => { + val evArgs = prms.map(specializer.evaluate(_)(using Context() ++ (("this"->BoundedExpr(ret)) :: ags), List(tpName)).expValue) + BoundedExpr(createObjValue(supTp.base.name, evArgs)) + }) + val parObjs = pars.zipWithIndex.map((e, i) => s"sup$$$i" -> e) + debug.log(s"par objs: $parObjs") + ret.fields.addAll(parObjs) + ret + } + else throw MonomorphError(s"tpName ${tpName} not found in implementations ${allTypeImpls}") + }(identity) + + def getFieldVal(obj: ObjectValue, field: String): BoundedExpr = + debug.trace("SPEC SEL", s"$obj :: $field"){ + if(allTypeImpls.contains(obj.name)){ + val tpDef = allTypeImpls.get(obj.name).get + val func = tpDef.body.items.flatMap{ + case funcDecl@Item.FuncDecl(Expr.Ref(nm), prms, bd) if nm.equals(field) => + Some(funcDecl) + case _ => None + }.headOption + if(func.isDefined){ + debug.log("defined") + val Item.FuncDecl(nm, prms, bd) = func.get + val nFuncName = s"${nm.name}$$${obj.name}" + if(!funImpls.contains(nFuncName)){ + val nFunc: Item.FuncDecl = Item.FuncDecl(Expr.Ref(nFuncName), (false, Expr.Ref("this")) :: prms, bd) + addNewFunction(nFunc) + } + BoundedExpr(FunctionValue(nFuncName, prms.map(_._2.name), List("this" -> BoundedExpr(obj)))) + } + else if(obj.fields.contains(field)) + debug.log("contains") + obj.fields.get(field).get + else{ + debug.log("else") + obj.fields.flatMap(x => { + if (x._1.matches("sup\\$[0-9]+")) { + x._2.asValue match{ + case Some(o: ObjectValue) => + Some(getFieldVal(o, field)) + case _ => None + } + } + else None + }).headOption.getOrElse( + throw MonomorphError(s"Field ${field} not Found in"+obj.toString()) + ) + } + } + else { + throw MonomorphError(s"ObjectValue ${obj} not found in implementations ${allTypeImpls}") + } + }(identity) + +object Monomorph: + class SpecializationMap[T <: Item](val prototype: T): + private var basePrototype: Option[T] = None + private val implementations = MutMap[String, T]() + + inline def getOrInsert(signature: String, op: => T): T = + implementations.getOrElseUpdate(signature, op) + inline def size: Int = implementations.size + // signature + item + inline def +=(entry: (String, T)): T = + implementations.addOne(entry) + entry._2 + inline def base: Option[T] = basePrototype + inline def base_=(op: => T): Unit = + basePrototype match + case None => basePrototype = Some(op) + case Some(_) => () + inline def isEmpty: Boolean = implementations.isEmpty + inline def iterator: Iterator[T] = + if implementations.isEmpty then Iterator.empty else + basePrototype.iterator.concat(implementations.values) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala new file mode 100644 index 000000000..b3eef1342 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphContext.scala @@ -0,0 +1,33 @@ +package mlscript.compiler.mono + +import mlscript.compiler.debug.DebugOutput +import scala.collection.immutable.SeqMap +import mlscript.compiler.debug.Printable +import mlscript.compiler.* + +class MonomorphContext(context: List[Map[String, DataType]]) extends Printable: + def +(entry: (String, DataType)): MonomorphContext = + MonomorphContext(context match { + case Nil => Nil + case head :: tail => (head + entry) :: tail + }) + + def :+(entry: (String, DataType)): MonomorphContext = + MonomorphContext((Map.empty + entry) :: context) + + def unary_+ : MonomorphContext = + MonomorphContext(Map.empty :: context) + + def get(key: String): Option[DataType] = + context.iterator.flatMap(_.get(key)).nextOption() + + def getDebugOutput: DebugOutput = + DebugOutput.Map(context.foldRight(SeqMap.empty[String, String]) { (entries, map) => + entries.foldLeft(map) { (map, entry) => + map + (entry._1 -> entry._2.toString) + } + }.toList) + + +object MonomorphContext: + def empty: MonomorphContext = MonomorphContext(Nil) \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala new file mode 100644 index 000000000..e7ef0305e --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/MonomorphError.scala @@ -0,0 +1,3 @@ +package mlscript.compiler.mono + +class MonomorphError(message: String) extends Error(message) diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala new file mode 100644 index 000000000..fc60c04da --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/BoundedExpr.scala @@ -0,0 +1,226 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.{Expr, UnitValue} +import mlscript.compiler.debug.Printable +import mlscript.compiler.debug.DebugOutput +import scala.collection.mutable.Map as MutMap +import scala.collection.mutable.Set as MutSet +import mlscript.Var +import scala.collection.immutable +import mlscript.compiler.mono.MonomorphError + +abstract class MonoValue { + def toBoundedExpr = BoundedExpr(this) + def toStringSafe(using Set[Int]) = this.toString() +} +case class ObjectValue(name: String, fields: MutMap[String, BoundedExpr]) extends MonoValue{ + override def toString(): String = fields.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(s"$name@{", ", ", "}") + override def toStringSafe(using Set[Int]): String = fields.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(s"$name@{", ", ", "}") + def merge(other: ObjectValue)(using inStackExps: Set[Int]): ObjectValue = { + val allKeys = fields.keySet + val nFlds = allKeys.map(k => { + val s1 = fields.get(k).get + val s2 = other.fields.get(k).get + if(inStackExps.contains(s1.hashCode()) && inStackExps.contains(s2.hashCode())) + (k -> s1) + else (k -> (s1 ++ s2)) + }) + ObjectValue(name, MutMap(nFlds.toSeq: _*)) + } + override def equals(x: Any): Boolean = { + x match { + case ObjectValue(xName, _) => name.equals(xName) + case _ => false + } + } +} +case class FunctionValue(name: String, prm: List[String], ctx: List[(String, BoundedExpr)]) extends MonoValue{ + override def toString(): String = prm.mkString(s"$name(", ", ", ")") + ctx.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(" given {", ", ", "}") + override def toStringSafe(using Set[Int]): String = prm.mkString(s"$name(", ", ", ")") + ctx.map(x => (s"${x._1}: ${x._2.toStringSafe}")).mkString(" given {", ", ", "}") + override def equals(x: Any): Boolean = x match{ + case FunctionValue(xName, _, _) => name.equals(xName) + case _ => false + } +} +case class UnknownValue() extends MonoValue{ + val idValue = UnknownValue.refresh() + override def toString(): String = s"?$idValue?" +} +object UnknownValue{ + var unknownCnt: Int = 0 + def refresh() = { + unknownCnt += 1 + unknownCnt + } +} +case class VariableValue(vx: Int, version: Int) extends MonoValue{ + override def toStringSafe(using Set[Int]): String = s"*$vx*=${VariableValue.get(this).toStringSafe}" + override def toString(): String = toStringSafe(using Set()) + def refresh() = VariableValue(vx, version+1) +} +object VariableValue{ + var vxCnt = 0 + val vMap = MutMap[Int, BoundedExpr]() + def refresh(): VariableValue = { + vxCnt += 1 + val ret = VariableValue(vxCnt, 0) + vMap.addOne(vxCnt -> BoundedExpr(ret)) + ret + } + def get(v: VariableValue): BoundedExpr = vMap.get(v.vx).get + def update(v: VariableValue, s: BoundedExpr): Unit = { + vMap.update(v.vx, s) + } +} + +case class LiteralValue(i: BigInt | BigDecimal | Boolean | String | UnitValue) extends MonoValue{ + def asBoolean(): Option[Boolean] = i match{ + case x: Boolean => Some(x) + case _ => None + } + override def toString(): String = i.toString() +} +case class PrimitiveValue() extends MonoValue{ + override def toString(): String = "*LIT*" +} + +class BoundedExpr(private val values: Set[MonoValue]) extends Printable { + def this(singleVal: MonoValue) = this(Set(singleVal)) + def this() = this(Set()) + def getDebugOutput: DebugOutput = DebugOutput.Plain(toStringSafe) + def getObjNames() = values.flatMap{ + // case FunctionValue(name, body, prm, ctx) => Some(name) + case ObjectValue(name, _) => Some(name) + case _ => None + }.toSet + // override def hashCode(): Int = values.hashCode() + override def toString(): String = toStringSafe + var updateCnt: Int = 0 + def toStringSafe(using printed: Set[Int] = Set()): String = { + if(printed.contains(this.hashCode())) s"..." + else values.map(_.toStringSafe(using printed + this.hashCode())).mkString("[", " | ", s"]") + } + def asValue: Option[MonoValue] = { + val tmp = this.unfoldVars + if(tmp.values.size == 1) { + Some(tmp.values.head) + } + else None + } + def getValue: Set[MonoValue] = { + unfoldVars.values.toSet.filterNot(_.isInstanceOf[VariableValue]) + } + + private def splitSpecifiedObjects(vs: Set[MonoValue], nms: Set[String]): (Set[MonoValue], Map[String, ObjectValue]) = { + val ret = vs.map{ + case o@ObjectValue(name, fields) => + if nms.contains(name) then { + (None, Some(name -> o)) + } else { + (Some(o), None) + } + case x => (Some(x), None) + }.unzip + val ret1 = ret._1.flatten + val ret2 = ret._2.flatten.toMap + (ret1, ret2) + } + + def unfoldVars(using instackExps: Set[Int] = Set()): BoundedExpr = { + val vars = values.toList.map{ + case vx: VariableValue => (Some(vx), None) + case others => (None, Some(others)) + }.unzip + val varSets: List[BoundedExpr] = vars._1.flatten.map(x => { + val vSet = VariableValue.get(x) + if(!instackExps.contains(vSet.hashCode())){ + vSet.unfoldVars(using instackExps + vSet.hashCode()) + } + else BoundedExpr(x) + }) + varSets.foldLeft(BoundedExpr(vars._2.flatten.toSet))((x, y) => (x ++ y)(using instackExps + y.hashCode())) + } + + def literals2Prims: BoundedExpr = { + val hasPrim = values.find(x => x.isInstanceOf[PrimitiveValue] || x.isInstanceOf[LiteralValue]).isDefined + if(hasPrim) + BoundedExpr(values.filterNot(x => x.isInstanceOf[PrimitiveValue] || x.isInstanceOf[LiteralValue]) + PrimitiveValue()) + else this + } + + def ++(other: BoundedExpr)(using instackExps: Set[Int] = Set()): BoundedExpr = { + if(this == other) this + else { + // unfoldVars + // other.unfoldVars + val mergingValNms = getObjNames().intersect(other.getObjNames()) + val (restVals1, mergingVals1) = splitSpecifiedObjects(values.toSet, mergingValNms) + val (restVals2, mergingVals2) = splitSpecifiedObjects(other.values.toSet, mergingValNms) + // val map2 = other.values.flatMap(x => if(values.fin(x)) then None else Some(x)) + val ret = mergingValNms.map(nm => (mergingVals1.get(nm), mergingVals2.get(nm)) match + case (Some(x1: ObjectValue), Some(x2: ObjectValue)) => x1.merge(x2)(using instackExps ++ Set(this.hashCode(), other.hashCode())) + case _ => throw MonomorphError(s"Name ${nm} not found in BoundedExpr merging") + ) + // println(s"get ${BoundedExpr(restVals1 ++ restVals2 ++ ret)}") + var ret2 = restVals1 ++ restVals2 + if(ret2.count(x => (x.isInstanceOf[LiteralValue] || x.isInstanceOf[PrimitiveValue])) > 1){ + ret2 = ret2.filterNot(_.isInstanceOf[LiteralValue]) + PrimitiveValue() + } + val retVals = BoundedExpr(ret2 ++ ret) + retVals.updateCnt = this.updateCnt + if(this.compare(retVals)) retVals.updateCnt += 1 + retVals + } + } + + def size = values.size + // lazy val eleCnt: Int = countEles + def eleCnt(using instackExps: Set[Int] = Set()): Int = { + if(values.size == 0) { + 0 + } + else { + val seperated = values.map{ + case o: ObjectValue => (None, Some(o)) + case f: FunctionValue => (Some(1), None) + case _: LiteralValue => (Some(1), None) + case _: PrimitiveValue => (Some(100000), None) + case UnknownValue() => (Some(1), None) + case vx: VariableValue => (Some(VariableValue.get(vx).eleCnt(using instackExps + VariableValue.get(vx).hashCode())), None) + }.unzip + val (lits, objs) = (seperated._1.flatten, seperated._2.flatten) + val objn = objs.map{ + case ObjectValue(name, fields) => + fields.map(x => { + if(instackExps.contains(x._2.hashCode())) 1 + else x._2.eleCnt(using instackExps + x._2.hashCode()) + }).fold(0)(_ + _) + 1 + }.fold(0)(_ + _) + lits.fold(0)(_ + _) + objn + } + } + def compare(other: BoundedExpr)(using instackExps: Set[Int] = Set()): Boolean = { + if(instackExps.contains(this.hashCode()) && instackExps.contains(other.hashCode())) + false + else { + if(values.find(_.isInstanceOf[PrimitiveValue]).isEmpty && other.values.find(_.isInstanceOf[PrimitiveValue]).isDefined) + true + else if(this.size != other.size) + this.size < other.size + else{ + val nms1 = this.getObjNames() + val nms2 = other.getObjNames() + if(nms1.equals(nms2)){ + val (rests1, objs1) = splitSpecifiedObjects(this.values.toSet, nms1) + val (rests2, objs2) = splitSpecifiedObjects(other.values.toSet, nms1) + nms1.find(nm => { + val v1s = objs1.get(nm).get.fields + val v2s = objs2.get(nm).get.fields + v1s.keySet.find(k => v1s.get(k).get.compare(v2s.get(k).get)(using instackExps + this.hashCode() + other.hashCode())).isDefined + }).isDefined + } + else true + } + } + } +} \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala new file mode 100644 index 000000000..a1a7b12c1 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Builtin.scala @@ -0,0 +1,95 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr +import mlscript.compiler.mono.MonomorphError + +object Builtin: + val builtinRefs = Set(">", "-", "+", "*", "&&", "||", "==", "true", "false") + + private val builtinBinaryOperations = Map[String, (Expr, Expr) => Option[Expr]]( + (">", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs > rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs > rhs)) + case (_, _) => None + }), + ("-", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs - rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs - rhs)) + case (_, _) => None + }), + ("+", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs + rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs + rhs)) + case (_, _) => None + }), + ("*", { + case (Expr.Literal(lhs: BigInt), Expr.Literal(rhs: BigInt)) => + Some(Expr.Literal(lhs * rhs)) + case (Expr.Literal(lhs: BigDecimal), Expr.Literal(rhs: BigDecimal)) => + Some(Expr.Literal(lhs * rhs)) + case (_, _) => None + }) + ) + + private val builtinBinaryOperationsValue = Map[String, (MonoValue, MonoValue) => Option[MonoValue]]( + (">", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs > rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs > rhs)) + case (_, _) => None + }), + ("-", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs - rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs - rhs)) + case (_, _) => None + }), + ("+", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs + rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs + rhs)) + case (_, _) => None + }), + ("*", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs * rhs)) + case (LiteralValue(lhs: BigDecimal), LiteralValue(rhs: BigDecimal)) => + Some(LiteralValue(lhs * rhs)) + case (_, _) => None + }), + ("&&", { + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs && rhs)) + case (_, _) => None + }), + ("||", { + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs || rhs)) + case (_, _) => None + }), + ("==", { + case (LiteralValue(lhs: BigInt), LiteralValue(rhs: BigInt)) => + Some(LiteralValue(lhs == rhs)) + case (LiteralValue(lhs: Boolean), LiteralValue(rhs: Boolean)) => + Some(LiteralValue(lhs == rhs)) + case (_, _) => None + }) + ) + + def isBinaryOperator(name: String): Boolean = + builtinBinaryOperations.contains(name) + + def evalulateBinaryOperation(name: String, lhs: Expr, rhs: Expr): Option[Expr] = + builtinBinaryOperations(name)(lhs, rhs) + + def evaluateBinaryOpValue(name: String, lhs: MonoValue, rhs: MonoValue): Option[MonoValue] = + builtinBinaryOperationsValue(name)(lhs, rhs) diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala new file mode 100644 index 000000000..bd1d8faec --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Context.scala @@ -0,0 +1,21 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr +import mlscript.compiler.debug.{DebugOutput, Printable} +import mlscript.compiler.mono.specializer.BoundedExpr + +class Context(private val entries: Map[String, BoundedExpr]) extends Printable: + def this() = this(Map("true" -> BoundedExpr(LiteralValue(true)), "false" -> BoundedExpr(LiteralValue(false)))) + inline def get(name: String): BoundedExpr = entries.get(name).getOrElse(BoundedExpr(UnknownValue())) + inline def +(entry: (String, BoundedExpr)): Context = Context(entries + entry) + inline def ++(other: Context): Context = Context(entries ++ other.entries) + inline def ++(other: IterableOnce[(String, BoundedExpr)]) = Context(entries ++ other) + inline def isEmpty: Boolean = entries.isEmpty + inline def contains(name: String): Boolean = entries.contains(name) + def getDebugOutput: DebugOutput = + DebugOutput.Map(entries.iterator.map { + (key, value) => (key, value.toString) + }.toList) +object Context{ + def toCtx(entries: IterableOnce[(String, BoundedExpr)]) = Context(Map.from(entries)) +} \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala new file mode 100644 index 000000000..80a75fa1a --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Predicates.scala @@ -0,0 +1,6 @@ +package mlscript.compiler.mono.specializer + +import mlscript.compiler.Expr + +object Predicates: + \ No newline at end of file diff --git a/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala new file mode 100644 index 000000000..6a8adea77 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/mono/specializer/Specializer.scala @@ -0,0 +1,228 @@ +package mlscript.compiler.mono.specializer + +import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.Map as MutMap +import mlscript.compiler.debug.Debug +import mlscript.compiler.mono.MonomorphError +import mlscript.compiler.mono.Monomorph +import mlscript.compiler.UnitValue +import mlscript.TypeName +import mlscript.compiler.Item +import mlscript.compiler.CaseBranch +import mlscript.compiler.Expr + +class Specializer(monoer: Monomorph)(using debug: Debug){ + + def evaluate(rawExpr: Expr)(using evalCtx: Context, callingStack: List[String]): Expr = + // debug.trace[Expr]("EVAL ", rawExpr.toString()) { + rawExpr match{ + case Expr.Ref(name) => + rawExpr.expValue = + if evalCtx.contains(name) then evalCtx.get(name) else BoundedExpr(monoer.findVar(name)) + rawExpr + case Expr.Apply(Expr.Apply(opE@Expr.Ref(op), a1), a2) if Builtin.isBinaryOperator(op) => + if(a1.length == 1 && a2.length == 1) + { + val a1E = evaluate(a1.head) + val a2E = evaluate(a2.head) + val pairedAV = (a1E.expValue.asValue, a2E.expValue.asValue) match { + case (Some(i1: LiteralValue), Some(i2: LiteralValue)) => + Builtin.evaluateBinaryOpValue(op, i1, i2) match{ + case Some(value) => value + case None => PrimitiveValue() + } + case _ => PrimitiveValue() + } + val retExp = Expr.Apply(Expr.Apply(opE, List(a1E)), List(a2E)) + retExp.expValue = BoundedExpr(pairedAV) + retExp + } + else throw MonomorphError(s"Malformed Expr: ${rawExpr}") + + case other@Expr.Apply(callee, arguments) => + val calE = evaluate(callee) + val cal = calE.expValue + val nArgs = arguments.map(evaluate) + val args = nArgs.map(_.expValue) + val retV = cal.getValue.map{ + case FunctionValue(name, prm, ctxArg) => + val callResult = monoer.getFuncRetVal(name, ctxArg.unzip._2 ++ args) + // debug.log(s"call result: $callResult") + callResult + case o: ObjectValue => + val sel = monoer.getFieldVal(o, "apply") + sel.asValue match + case Some(FunctionValue(name, prm, ctx)) => + val callResult = monoer.getFuncRetVal(name, ctx.unzip._2 ++ args) + // debug.log(s"call result: $callResult") + callResult + case _ => BoundedExpr(UnknownValue()) + case _ => BoundedExpr(UnknownValue()) + }.fold(BoundedExpr())((x, y) => { + // debug.log(s"merging $x with $y") + val xy = x ++ y + // debug.log(s"result $xy") + xy + }) + val retExp = Expr.Apply(calE, nArgs) + retExp.expValue = retV + retExp + + case Expr.Select(receiver, field) => + val rec = evaluate(receiver) + val retV = rec.expValue.getValue.map{ + case ObjectValue(_, flds) if flds.contains(field.name) => + flds.get(field.name).get + case obj: ObjectValue => + monoer.getFieldVal(obj, field.name) + case _ => + BoundedExpr(UnknownValue()) + }.fold(BoundedExpr())(_ ++ _) + val retExp = Expr.Select(rec, field) + retExp.expValue = retV + retExp + + case Expr.LetIn(false, name, rhs, body) => + val nRhs = evaluate(rhs) + val nCtx = evalCtx + (name.name -> nRhs.expValue) + val nBody = evaluate(body)(using nCtx) + val retExp = Expr.LetIn(false, name, nRhs, nBody) + retExp.expValue = body.expValue + retExp + + case l@Expr.Literal(value) => + l.expValue = BoundedExpr(LiteralValue(value)) + l + + case Expr.New(apply, arguments) => + val nArgs = arguments.map(evaluate(_)) + val args = nArgs.map(_.expValue) + val retV = BoundedExpr(monoer.createObjValue(apply.name, args)) + val retExp = Expr.New(apply, nArgs) + retExp.expValue = retV + retExp + + case Expr.IfThenElse(condition, consequent, Some(alternate)) => + val nCond = evaluate(condition) + val nCons = evaluate(consequent) + val nAlter = evaluate(alternate) + val retV = nCond.expValue.asValue match { + case Some(x: LiteralValue) if x.asBoolean().isDefined => + if(x.asBoolean().get){ + nCons.expValue + } + else { + nAlter.expValue + } + case _ => + nCons.expValue ++ nAlter.expValue + } + val retExp = Expr.IfThenElse(nCond, nCons, Some(nAlter)) + retExp.expValue = retV + retExp + case Expr.IfThenElse(condition, consequent, None) => + val nCond = evaluate(condition) + val nCons = evaluate(consequent) + val retExp = Expr.IfThenElse(nCond, nCons, None) + retExp.expValue = BoundedExpr(LiteralValue(UnitValue.Undefined)) + retExp + + case self@Expr.Lambda(prm, body) => + throw MonomorphError(s"Unhandled case: ${rawExpr}") + + case Expr.Isolated(isolation) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + + case Expr.Tuple(fields) => + if(fields.length == 1){ + evaluate(fields.head) + } + else + throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Record(fields) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.LetIn(true, name, rhs, body) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Block(items) => + val exps = items.flatMap{ + case e: Expr => Some(evaluate(e)) + case _ => None + } + if(exps.length == 0){ + val retE = Expr.Literal(UnitValue.Undefined) + val retV = BoundedExpr(LiteralValue(UnitValue.Undefined)) + retE.expValue = retV + retE + } + else if(exps.length == 1){ + exps.head + } + else { + val retV = exps.reverse.head.expValue + val retE = Expr.Block(exps) + retE.expValue = retV + retE + } + + case Expr.As(value, toType) => + val retV = evaluate(value) + rawExpr.expValue = retV.expValue + rawExpr + case Expr.Assign(assignee, value) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.With(value, fields) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Subscript(receiver, index) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + case Expr.Match(scrutinee, branches) => throw MonomorphError(s"Unhandled case: ${rawExpr}") + } + // }(_.expValue) + + def defunctionalize(rawExpr: Expr): Expr = { + val ret: Expr = rawExpr match { + case _: (Expr.Ref | Expr.Literal) => rawExpr + case Expr.Apply(sel@Expr.Select(receiver, field), args) => + val nRec = defunctionalize(receiver) + val nArgs = args.map(defunctionalize) + val branches = ArrayBuffer[CaseBranch]() + receiver.expValue.getValue.foreach{ + case o@ObjectValue(name, _) => + val selValue = monoer.getFieldVal(o, field.name) + val branchExp = selValue.asValue match{ + // foo.f is a member function + case Some(f: FunctionValue) => + Expr.Apply(Expr.Ref(f.name), Expr.Ref("obj") :: nArgs) + // foo.f is (many candidate) lambda(Object) + case _ if selValue.getValue.forall(_.isInstanceOf[ObjectValue]) => + // foo.f match ... + val scrut = Expr.Select(Expr.Ref("obj"), field) + val brchs = selValue.getValue.toList.map(_.asInstanceOf[ObjectValue]) + .map(o => { + val lambdaMemFunc = monoer.getFieldVal(o, "apply").asValue.get.asInstanceOf[FunctionValue] + val caseVarNm: Expr.Ref = Expr.Ref(s"obj$$${o.name}") + CaseBranch.Instance(Expr.Ref(o.name), caseVarNm, + Expr.Apply(Expr.Ref(lambdaMemFunc.name), caseVarNm :: nArgs)) + }) + Expr.Match(scrut, ArrayBuffer(brchs: _*)) + case _ => throw MonomorphError(s"Unhandled case: ${rawExpr}") + + } + branches.addOne(CaseBranch.Instance(Expr.Ref(name), Expr.Ref("obj"), branchExp)) + case _ => () + } + Expr.Match(nRec, branches) + case Expr.Apply(callee, arguments) => + if(callee.expValue.getValue.find(_.isInstanceOf[ObjectValue]).isDefined) + defunctionalize(Expr.Apply(Expr.Select(callee, Expr.Ref("apply")), arguments)) + else + Expr.Apply(defunctionalize(callee), arguments.map(defunctionalize)) + case Expr.New(typeName, args) => Expr.New(typeName, args.map(defunctionalize)) + case Expr.Tuple(fields) => Expr.Tuple(fields.map(defunctionalize)) + case Expr.LetIn(isRec, name, rhs, body) => Expr.LetIn(isRec, name, defunctionalize(rhs), defunctionalize(body)) + case Expr.IfThenElse(condition, consequent, alternate) => Expr.IfThenElse(defunctionalize(condition), defunctionalize(consequent), alternate.map(defunctionalize)) + case Expr.Block(items) => Expr.Block(items.map{ + case e: Expr => defunctionalize(e) + case other => other + }) + case Expr.Select(receiver, field) => Expr.Select(defunctionalize(receiver), field) + case Expr.As(value, toType) => Expr.As(defunctionalize(value), toType) + case _ => throw MonomorphError(s"Unhandled case: ${rawExpr}") + } + ret.expValue = rawExpr.expValue + ret + } +} diff --git a/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala b/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala new file mode 100644 index 000000000..6026a9ea0 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/printer/ExprPrinter.scala @@ -0,0 +1,73 @@ +package mlscript.compiler.printer + +import mlscript.compiler.{Expr, Isolation, Item, ModuleUnit, Parameter} + +class ExprPrinter: + private val printer = BlockPrinter() + + import printer.{endLine, enter, leave, print} + + private def show(module: ModuleUnit): Unit = module.items.foreach { + case expr: Expr => show(expr) + case item: Item => show(item) + } + + private def show(params: List[Parameter]): String = + params.iterator.map { + case (spec, Expr.Ref(name)) => (if spec then "#" else "") + name + }.mkString("(", ", ", ")") + + private def show(item: Item): Unit = item match + case Item.TypeDecl(Expr.Ref(name), kind, typeParams, params, parents, body) => + val typeParamsStr = if typeParams.isEmpty then "" + else typeParams.iterator.map(_.name).mkString("[", ", ", "]") + val reprParents = if parents.isEmpty then "" + else parents.iterator.map { case (parent, args) => + parent.show(true) + args.iterator.mkString("(", ", ", ")") + }.mkString(": ", ", ", "") + print(s"$kind $name$typeParamsStr${show(params)}$reprParents ") + show(body) + case Item.FuncDecl(Expr.Ref(name), params, body) => + print(s"fun $name${show(params)} =") + enter() + show(body) + leave() + case Item.FuncDefn(Expr.Ref(name), typeParams, polyType) => + val reprTypeParams = if typeParams.isEmpty then "" else + s"${typeParams.mkString("[", ", ", "]")} => " + print(s"fun $name: $reprTypeParams${polyType.show}") + + private def show(isolation: Isolation): Unit = + enter("{", "}") + isolation.items.foreach { + case expr: Expr => show(expr) + case item: Item => show(item) + } + leave() + + private def show(expr: Expr) = + print(expr.toString) + endLine() + + def toLines: List[String] = printer.toLines + + override def toString(): String = printer.toString + +object ExprPrinter: + def print(node: ModuleUnit | Item | Isolation | Expr): String = + val printer = ExprPrinter() + node match + case module: ModuleUnit => printer.show(module) + case item: Item => printer.show(item) + case isolation: Isolation => printer.show(isolation) + case expr: Expr => printer.show(expr) + printer.toString + + def printLines(node: ModuleUnit | Item | Isolation | Expr): List[String] = + val printer = ExprPrinter() + node match + case module: ModuleUnit => printer.show(module) + case item: Item => printer.show(item) + case isolation: Isolation => printer.show(isolation) + case expr: Expr => printer.show(expr) + printer.toLines diff --git a/compiler/shared/main/scala/mlscript/compiler/syntax.scala b/compiler/shared/main/scala/mlscript/compiler/syntax.scala new file mode 100644 index 000000000..b7e205112 --- /dev/null +++ b/compiler/shared/main/scala/mlscript/compiler/syntax.scala @@ -0,0 +1,271 @@ +package mlscript.compiler + +import mlscript.compiler.debug.{DebugOutput, Printable} +import mlscript.compiler.printer.ExprPrinter +import scala.collection.mutable.ArrayBuffer +import mlscript.{Type, Union, Inter, Function, Record, Tuple, Recursive, AppliedType, + Neg, Rem, Bounds, WithExtension, Constrained, Top, Bot, Literal, + TypeName, TypeVar, PolyType, NamedType} +import scala.collection.immutable.HashMap +import mlscript.compiler.mono.specializer.BoundedExpr +import mlscript.compiler.mono.specializer.Builtin + +trait ASTNode: + var parent: ASTNode = null + def setNodeFields(): Unit + var expValue: BoundedExpr = BoundedExpr() + var freeVars: Set[String] = null + var isStatic: Boolean = false + +enum Expr extends Printable, ASTNode: + case Ref(name: String) + case Lambda(params: List[Parameter], body: Expr) + case Apply(callee: Expr, arguments: List[Expr]) + case Tuple(fields: List[Expr]) + case Record(fields: List[(Ref, Expr)]) + case Select(receiver: Expr, field: Ref) + case LetIn(isRec: Boolean, name: Ref, rhs: Expr, body: Expr) + case Block(items: List[Expr | Item.FuncDecl | Item.FuncDefn]) + case As(value: Expr, toType: Type) + case Assign(assignee: Expr, value: Expr) + case With(value: Expr, fields: Expr.Record) + case Subscript(receiver: Expr, index: Expr) + case Match(scrutinee: Expr, branches: ArrayBuffer[CaseBranch]) + case Literal(value: BigInt | BigDecimal | Boolean | String | UnitValue) + case New(typeName: TypeName, args: List[Expr]) + case IfThenElse(condition: Expr, consequent: Expr, alternate: Option[Expr]) + case Isolated(isolation: Isolation) + + val workaround = setNodeFields() + + def setNodeFields(): Unit = this match + case Expr.Ref(name) => + freeVars = if Builtin.builtinRefs.contains(name) then Set() else Set(name) + case Expr.Lambda(params, body) => + body.parent = this; freeVars = body.freeVars -- params.map(_._2.name) + case Expr.Apply(callee, arguments) => + callee.parent = this; arguments.foreach(x => x.parent = this); freeVars = callee.freeVars ++ arguments.flatMap(_.freeVars); isStatic = arguments.map(_.isStatic).fold(callee.isStatic)(_ && _) + case Expr.Tuple(fields) => + fields.foreach(x => x.parent = this); freeVars = fields.flatMap(_.freeVars).toSet; isStatic = fields.map(_.isStatic).fold(true)(_ && _) + case Expr.Record(fields) => + fields.foreach(x => x._2.parent = this); freeVars = fields.flatMap(_._2.freeVars).toSet -- fields.map(_._1.name); isStatic = fields.map(_._2.isStatic).fold(true)(_ && _) + case Expr.Select(receiver, field) => + receiver.parent = this; field.parent = this; freeVars = receiver.freeVars; isStatic = receiver.isStatic + case Expr.LetIn(isRec, name, rhs, body) => + rhs.parent = this; body.parent = this; freeVars = rhs.freeVars ++ body.freeVars - name.name; isStatic = rhs.isStatic && body.isStatic + case Expr.Block(items) => + val expItems = items.flatMap{ + case x: Expr => Some(x) + case _ => None + } + freeVars = expItems.flatMap(_.freeVars).toSet + expItems.foreach(x => {x.parent = this}) + isStatic = expItems.map(_.isStatic).fold(true)(_ && _) + case Expr.As(value, toType) => + value.parent = this; freeVars = value.freeVars; isStatic = value.isStatic + case Expr.Assign(assignee, value) => + assignee.parent = this; value.parent = this; freeVars = assignee.freeVars ++ value.freeVars; isStatic = true + case Expr.With(value, fields) => + value.parent = this; fields.parent = this; freeVars = value.freeVars ++ fields.freeVars; isStatic = value.isStatic && fields.isStatic + case Expr.Subscript(receiver, index) => + receiver.parent = this; index.parent = this; freeVars = receiver.freeVars ++ index.freeVars; isStatic = receiver.isStatic && index.isStatic + case Expr.Match(scrutinee, branches) => + scrutinee.parent = this + isStatic = scrutinee.isStatic + freeVars = scrutinee.freeVars ++ branches.flatMap{ + case CaseBranch.Instance(className, alias, body) => + isStatic &&= body.isStatic + body.freeVars - alias.name + case CaseBranch.Constant(literal, body) => + isStatic &&= body.isStatic + body.freeVars + case CaseBranch.Wildcard(body) => + isStatic &&= body.isStatic + body.freeVars + } + branches.foreach(x => x.body.parent = this) + case Expr.Literal(value) => + freeVars = Set() + isStatic = true + case Expr.New(typeName, args) => + args.foreach(x => x.parent = this) + isStatic = args.map(_.isStatic).fold(true)(_ && _) + freeVars = args.flatMap(_.freeVars).toSet + typeName.name + case Expr.IfThenElse(condition, consequent, alternate) => + condition.parent = this + consequent.parent = this + alternate.foreach(x => x.parent = this) + freeVars = condition.freeVars ++ consequent.freeVars ++ alternate.map(_.freeVars).getOrElse(Set()) + isStatic = alternate.map(_.isStatic && condition.isStatic && consequent.isStatic).getOrElse(true) + case Expr.Isolated(isolation) => + val exps = isolation.items.flatMap{ + case x: Expr => Some(x) + case _ => None + } + exps.foreach{x => x.parent = this} + freeVars = exps.flatMap(_.freeVars).toSet + isStatic = exps.map(_.isStatic).fold(true)(_ && _) + + def asBoolean(): Boolean = this match + case Literal(value: BigInt) => value != 0 + case Literal(value: BigDecimal) => value != 0 + case Literal(value: Boolean) => value + case Literal(value: String) => !value.isEmpty() + case Literal(_) => false + case _ => false + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = + // val header = if this.parent == null then this.freeVars.mkString("[", ", ", "]~") else "" + val body = this match { + case Ref(name) => name + case Lambda(params, body) => + val head = params.mkString("(", ", ", ")") + s"(fun $head -> $body)" + case Apply(Apply(Ref(op), lhs :: Nil), rhs :: Nil) + if !op.headOption.forall(_.isLetter) => + s"($lhs $op $rhs)" + case Apply(callee, arguments) => + callee.toString + arguments.mkString("(", ", ", ")") + case Tuple(fields) => + val inner = fields.mkString(", ") + "(" + (if fields.length == 1 then inner + ", " else inner) + ")" + case Record(fields) => + "{" + fields.iterator.map { (name, value) => s"$name = $value" } + "}" + case Select(receiver, field) => s"$receiver.$field" + case LetIn(isRec, name, rhs, body) => s"let $name = $rhs in $body" + case Block(items) => items.mkString(";") + case As(value, toType) => s"$value as $toType" + case Assign(assignee, value) => s"$assignee = $value" + case With(value, fields) => s"$value with $fields" + case Subscript(receiver, index) => s"$receiver[$index]" + case Match(scrutinee, branches) => + s"$scrutinee match " + branches.iterator.mkString("{", "; ", "}") + case Literal(value) => "#" + value.toString + case New(callee, args) => + s"new ${callee.name}" + args.mkString(" (", ", ", ") ") + case IfThenElse(condition, consequent, None) => + s"if $condition then $consequent" + case IfThenElse(condition, consequent, Some(alternate)) => + s"if $condition then $consequent else $alternate" + case Isolated(isolation) => s"{\n$isolation\n}" + } + // header + + body +end Expr + +// This corresponds to `mlscript.UnitLit`. +enum UnitValue: + case Null, Undefined + + override def toString(): String = + this match + case Null => "null" + case Undefined => "()" // `()` is shorter than `undefined` + +enum CaseBranch: + val body: Expr + + case Instance(className: Expr.Ref, alias: Expr.Ref, body: Expr) + case Constant(literal: Expr.Literal, body: Expr) + case Wildcard(body: Expr) + + override def toString(): String = + this match + case Instance(Expr.Ref(className), Expr.Ref(alias), body) => + s"case $alias: $className => $body" + case Constant(literal, body) => s"case $literal => $body" + case Wildcard(body) => s"_ => $body" + +enum TypeDeclKind: + case Alias, Class, Trait + + override def toString(): String = this match + case Alias => "alias" + case Class => "class" + case Trait => "trait" + + +/** + * Function parameters: `(specializable, name)`. + */ +type Parameter = (Boolean, Expr.Ref) + +enum Item extends Printable: + val name: Expr.Ref + + /** + * Type declarations: aliases, classes and traits. + */ + case TypeDecl(name: Expr.Ref, kind: TypeDeclKind, typeParams: List[TypeName], + params: List[Parameter], parents: List[(NamedType, List[Expr])], body: Isolation) + /** + * Function declaration (with implementation). + */ + case FuncDecl(name: Expr.Ref, params: List[Parameter], body: Expr) + /** + * Function definition (with definition) + */ + case FuncDefn(name: Expr.Ref, typeParams: List[TypeName], body: PolyType) + + override def toString(): String = this match + case TypeDecl(Expr.Ref(name), kind, typeParams, params, parents, body) => + val typeParamsStr = if typeParams.isEmpty then "" + else typeParams.iterator.map(_.name).mkString("[", ", ", "]") + val parentsStr = if parents.isEmpty then "" + else parents.mkString(" extends ", " with ", " ") + s"$kind $name$typeParamsStr$parentsStr { $body }" + case FuncDecl(Expr.Ref(name), params, body) => + val parameters = params.iterator.map { + case (spec, Expr.Ref(name)) => + (if spec then "#" else "") + name + }.mkString("(", ", ", ")") + s"fun $name$parameters = $body" + case FuncDefn(Expr.Ref(name), Nil, polyType) => + s"fun $name: $polyType" + case FuncDefn(Expr.Ref(name), typeParams, polyType) => + s"fun $name: ${typeParams.mkString("[", ", ", "]")} => $polyType" + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + +object Item: + /** + * A shorthand constructor for classes without type parameters and parents. + */ + def classDecl(name: String, params: List[Parameter], body: Isolation): Item.TypeDecl = + Item.TypeDecl(Expr.Ref(name), TypeDeclKind.Class, Nil, params, Nil, body) + +/** + * An `Isolation` is like a `TypingUnit` but without nested classes. + */ +class Isolation(val items: List[Expr | Item.FuncDecl | Item.FuncDefn]) extends Printable: + private val namedItemMap = HashMap.from(items.iterator.flatMap { + case _: Expr => None: Option[(String, Item.FuncDecl | Item.FuncDefn)] + case item: Item.FuncDecl => Some((item.name.name, item)) + case item: Item.FuncDefn => Some((item.name.name, item)) + }) + + def get(name: String): Option[Item.FuncDecl | Item.FuncDefn] = + namedItemMap.get(name) + + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = items.mkString("\n") + +object Isolation: + def empty = Isolation(Nil) + +/** + * A `Module` is like a `TypingUnit`. + * This name conflicts with `java.lang.Module`. + * TODO: Find a better name. + */ +class ModuleUnit(val items: List[Expr | Item]) extends Printable: + def getDebugOutput: DebugOutput = + DebugOutput.Code(ExprPrinter.printLines(this)) + + override def toString(): String = items.mkString("\n") diff --git a/compiler/shared/test/diff/LambLift.mls b/compiler/shared/test/diff/LambLift.mls new file mode 100644 index 000000000..5e5054efe --- /dev/null +++ b/compiler/shared/test/diff/LambLift.mls @@ -0,0 +1,87 @@ +:NewDefs + +:AllowRuntimeErrors +fun foo() = + let local(x) = + class Foo { + fun bar = x + foo() + } + (new Foo()).bar + local(1) +foo() +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Blk(...))), App(Var(foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([x,]) {fun bar = () => +((this).x, foo$1(),)} +//│ let local$2 = (x,) => {('(' new Foo$1([x,]) {} ')').bar} +//│ fun foo$1 = () => {local$2(1,)} +//│ Code(List(foo$1())) +//│ } +//│ fun foo: () -> Int +//│ Int +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +fun foo(f) = + f(1) +foo(x => x+1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([]) {fun apply = (x,) => +(x, 1,)} +//│ fun foo$1 = (f,) => {f(1,)} +//│ Code(List(foo$1({new Lambda1$2$1([]) {}},))) +//│ } +//│ fun foo: forall 'a. (1 -> 'a) -> 'a +//│ Int +//│ res +//│ = 2 + +fun foo(x) = + let bar(f) = + f(x) + bar(y => y+x) +foo(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$3$1([x,]) {fun apply = (y,) => +(y, (this).x,)} +//│ let bar$2 = (f, x,) => {f(x,)} +//│ fun foo$1 = (x,) => {bar$2({new Lambda1$3$1([x,]) {}}, x,)} +//│ Code(List(foo$1(1,))) +//│ } +//│ fun foo: Int -> Int +//│ Int +//│ res +//│ = 2 + +fun foo(f) = + f(1) +class A(y: Int){ + fun bar(z) = y+z +} +fun app(a) = + foo(z => a.bar(z)) +app(new A(1)) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(f)), Blk(...))), NuTypeDef(class, A, (), Tup(y: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: Var(y), _: Var(z))))))), NuFunDef(None, app, None, [], Lam(Tup(_: Var(a)), Blk(...))), App(Var(app), Tup(_: New(Some((TypeName(A),[1,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class A$1([y: Int,]) {fun bar = (z,) => +((this).y, z,)} +//│ class Lambda1$3$2([a,]) {fun apply = (z,) => ((this).a).bar(z,)} +//│ fun foo$2 = (f,) => {f(1,)} +//│ fun app$1 = (a,) => {foo$2({new Lambda1$3$2([a,]) {}},)} +//│ Code(List(app$1(new A$1([1,]) {},))) +//│ } +//│ fun foo: forall 'a. (1 -> 'a) -> 'a +//│ class A(y: Int) { +//│ fun bar: Int -> Int +//│ } +//│ fun app: forall 'b. {bar: 1 -> 'b} -> 'b +//│ Int +//│ res +//│ = 2 diff --git a/compiler/shared/test/diff/LiftType.mls b/compiler/shared/test/diff/LiftType.mls index 454a20d26..2b4ccc4f0 100644 --- a/compiler/shared/test/diff/LiftType.mls +++ b/compiler/shared/test/diff/LiftType.mls @@ -8,7 +8,7 @@ class CTX{ //│ |#class| |CTX|{|→|#class| |A| |{||}|↵|#fun| |foo|(|f|#:| |A| |#=>| |A|)|#:| |(|A| |#=>| |A|)| |#=>| |A| |#=| |f|(|#new| |A|)|←|↵|}| //│ Parsed: {class CTX {class A {}; fun foo = (f: (A,) => A,) => f(new A([]) {},) : (A -> A) -> A}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹›))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) +//│ TypingUnit(NuTypeDef(class, CTX, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), NuFunDef(None, foo, None, [], Lam(Tup(f: Lam(Tup(_: Var(A)), Var(A))), Asc(App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit()))), Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(A))))),TypeName(A)))))),TypeName(A)))))))) //│ Lifted: //│ TypingUnit { //│ class CTX$1_A$2([par$CTX$1,]) {} @@ -29,8 +29,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: Var(B))), Asc(Tup(_: Sel(Var(any), _2), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3,],) => [(any)._2, (any)._1,] : [CTX$1_B$3, CTX$1_A$2] //│ } @@ -48,8 +48,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Bra(rcd = true, Rcd(Var(p1) = Var(A), Var(p2) = Var(B)))), Asc(Tup(_: Sel(Var(any), p2), _: Sel(Var(any), p1)), Tuple(List((None,Field(None,TypeName(B))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: '{' {p1: CTX$1_A$2, p2: CTX$1_B$3} '}',) => [(any).p2, (any).p1,] : [CTX$1_B$3, CTX$1_A$2] //│ } @@ -67,8 +67,8 @@ class CTX(x, y){ //│ TypingUnit(NuTypeDef(class, CTX, (), Tup(_: Var(x), _: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(x)))), NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(y)))), NuFunDef(None, foo, None, [], Lam(Tup(any: Tup(_: Var(A), _: TyApp(Var(B), List(TypeName(A))))), Asc(Tup(_: Var(any), _: Sel(Var(any), _1)), Tuple(List((None,Field(None,Tuple(List((None,Field(None,AppliedType(TypeName(B),List(TypeName(A))))), (None,Field(None,TypeName(A))))))), (None,Field(None,TypeName(A))))))))))) //│ Lifted: //│ TypingUnit { -//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = ((this).par$CTX$1).x} -//│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = ((this).par$CTX$1).y} +//│ class CTX$1_A$2([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).x} +//│ class CTX$1_B$3[T]([par$CTX$1,]) {fun foo = () => ((this).par$CTX$1).y} //│ class CTX$1([x, y,]) { //│ fun foo = (any: [CTX$1_A$2, CTX$1_B$3‹CTX$1_A$2›,],) => [any, (any)._1,] : [[CTX$1_B$3[CTX$1_A$2], CTX$1_A$2], CTX$1_A$2] //│ } diff --git a/compiler/shared/test/diff/Lifter.mls b/compiler/shared/test/diff/Lifter.mls index 29d225c0f..bf77d3a62 100644 --- a/compiler/shared/test/diff/Lifter.mls +++ b/compiler/shared/test/diff/Lifter.mls @@ -28,32 +28,32 @@ class A(x) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getB1| |#=| |B1|(|y|)|↵|#class| |C|(|z|)| |{|→|#fun| |inc|(||)| |#=| |x| |+| |1|↵|#fun| |getY| |#=| |y|↵|#fun| |getA| |#=| |A|(|z|)|↵|#fun| |getB|(|w|)| |#=| |B|(|w|)|↵|#fun| |getC| |#=| |#new| |C|(|inc|(||)|)|↵|#fun| |getSelf| |#=| |this|←|↵|}|←|↵|}|↵|#class| |B1|(|y|)| |{|→|#fun| |getX| |#=| |x|↵|#fun| |getY| |#=| |y|↵|#fun| |getB| |#=| |#new| |B|(|y|)|↵|#fun| |getB1| |#=| |#new| |B1|(|y|)|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|(|x|)|↵|#fun| |getB2|(|y|)| |#=| |B1|(|y|)|↵|#fun| |getB3|(|z|)| |#=| |getB2|(|z|)|↵|#fun| |getA| |#=| |A|(|x|)|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {fun getX = x; fun getB1 = B1(y,); class C(z,) {fun inc = () => +(x, 1,); fun getY = y; fun getA = A(z,); fun getB = (w,) => B(w,); fun getC = new C([inc(),]) {}; fun getSelf = this}}; class B1(y,) {fun getX = x; fun getY = y; fun getB = new B([y,]) {}; fun getB1 = new B1([y,]) {}}; fun getB = new B([x,]) {}; fun getB2 = (y,) => B1(y,); fun getB3 = (z,) => getB2(z,); fun getA = A(x,)}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), ‹›)), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), ‹›)), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), ‹›)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), ‹›)), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getB1, None, [], App(Var(B1), Tup(_: Var(y)))), NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, inc, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(x), _: IntLit(1))))), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(z)))), NuFunDef(None, getB, None, [], Lam(Tup(_: Var(w)), App(Var(B), Tup(_: Var(w))))), NuFunDef(None, getC, None, [], New(Some((TypeName(C),[inc(),])), TypingUnit())), NuFunDef(None, getSelf, None, [], Var(this)))))), NuTypeDef(class, B1, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuFunDef(None, getX, None, [], Var(x)), NuFunDef(None, getY, None, [], Var(y)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[y,])), TypingUnit())), NuFunDef(None, getB1, None, [], New(Some((TypeName(B1),[y,])), TypingUnit())))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[x,])), TypingUnit())), NuFunDef(None, getB2, None, [], Lam(Tup(_: Var(y)), App(Var(B1), Tup(_: Var(y))))), NuFunDef(None, getB3, None, [], Lam(Tup(_: Var(z)), App(Var(getB2), Tup(_: Var(z))))), NuFunDef(None, getA, None, [], App(Var(A), Tup(_: Var(x))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$4([par$A$1_B$2, z,]) { -//│ fun inc = () => +((((this).par$A$1_B$2).par$A$1).x, 1,) -//│ fun getY = ((this).par$A$1_B$2).y -//│ fun getA = A$1((this).z,) +//│ class A$1_B$2_C$4([par$A$1_B$2, z, x,]) { +//│ fun inc = () => +((this).x, 1,) +//│ fun getY = () => ((this).par$A$1_B$2).y +//│ fun getA = () => A$1((this).z,) //│ fun getB = (w,) => A$1_B$2(((this).par$A$1_B$2).par$A$1, w,) -//│ fun getC = new A$1_B$2_C$4([(this).par$A$1_B$2, (this).inc(),]) {} -//│ fun getSelf = this +//│ fun getC = () => new A$1_B$2_C$4([(this).par$A$1_B$2, (this).inc(), (this).x,]) {} +//│ fun getSelf = () => this //│ } //│ class A$1_B$2([par$A$1, y,]) { -//│ fun getX = ((this).par$A$1).x -//│ fun getB1 = A$1_B1$3((this).par$A$1, (this).y,) +//│ fun getX = () => ((this).par$A$1).x +//│ fun getB1 = () => A$1_B1$3((this).par$A$1, (this).y,) //│ } //│ class A$1_B1$3([par$A$1, y,]) { -//│ fun getX = ((this).par$A$1).x -//│ fun getY = (this).y -//│ fun getB = new A$1_B$2([(this).par$A$1, (this).y,]) {} -//│ fun getB1 = new A$1_B1$3([(this).par$A$1, (this).y,]) {} +//│ fun getX = () => ((this).par$A$1).x +//│ fun getY = () => (this).y +//│ fun getB = () => new A$1_B$2([(this).par$A$1, (this).y,]) {} +//│ fun getB1 = () => new A$1_B1$3([(this).par$A$1, (this).y,]) {} //│ } //│ class A$1([x,]) { -//│ fun getB = new A$1_B$2([this, (this).x,]) {} +//│ fun getB = () => new A$1_B$2([this, (this).x,]) {} //│ fun getB2 = (y,) => A$1_B1$3(this, y,) //│ fun getB3 = (z,) => (this).getB2(z,) -//│ fun getA = A$1((this).x,) +//│ fun getA = () => A$1((this).x,) //│ } //│ } //│ @@ -71,8 +71,8 @@ class A(x) { //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit(NuTypeDef(class, C, (), Tup(_: Var(z)), (), None, None, TypingUnit(NuFunDef(None, sum, None, [], App(Var(+), Tup(_: App(Var(+), Tup(_: Var(x), _: Var(y))), _: Var(z))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2_C$3([par$A$1_B$2, z,]) { -//│ fun sum = +(+((((this).par$A$1_B$2).par$A$1).x, ((this).par$A$1_B$2).y,), (this).z,) +//│ class A$1_B$2_C$3([par$A$1_B$2, z, x,]) { +//│ fun sum = () => +(+((this).x, ((this).par$A$1_B$2).y,), (this).z,) //│ } //│ class A$1_B$2([par$A$1, y,]) {} //│ class A$1([x,]) {} @@ -108,7 +108,7 @@ new C{ //│ |#class| |A|(|x|)| |{|→|#class| |B|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |11|←|↵|}|↵|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |2|↵|#fun| |bar| |#=| |12|←|↵|}|↵|#fun| |bar| |#=| |13|←|↵|}|↵|#class| |C|#:| |A|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |3|↵|#fun| |bar| |#=| |14|←|↵|}|↵|#fun| |bar| |#=| |15|←|↵|}|↵|#new| |C|{|→|#fun| |getB| |#=| |#new| |B|{|→|#fun| |foo| |#=| |4|↵|#fun| |bar| |#=| |16|←|↵|}|↵|#fun| |bar| |#=| |17|←|↵|}| //│ Parsed: {class A(x,) {class B {fun foo = 1; fun bar = 11}; fun getB = new B([]) {fun foo = 2; fun bar = 12}; fun bar = 13}; class C: A {fun getB = new B([]) {fun foo = 3; fun bar = 14}; fun bar = 15}; new C([]) {fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 2; fun bar = 12›)), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹fun foo = 3; fun bar = 14›)), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), ‹fun getB = new B([]) {fun foo = 4; fun bar = 16}; fun bar = 17›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], IntLit(11)))), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(2)), NuFunDef(None, bar, None, [], IntLit(12))))), NuFunDef(None, bar, None, [], IntLit(13)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(3)), NuFunDef(None, bar, None, [], IntLit(14))))), NuFunDef(None, bar, None, [], IntLit(15)))), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(4)), NuFunDef(None, bar, None, [], IntLit(16))))), NuFunDef(None, bar, None, [], IntLit(17))))) //│ Lifted: //│ Lifting failed: java.util.NoSuchElementException: None.get //│ @@ -148,7 +148,7 @@ class A(x: Int): {a1: Int} & B & D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)|#:| |{|a1|#:| |Int|}| |&| |B|‹|T|›| |&| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|#:| |T|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): {a1: Int} & B[T] & D[x] {fun getA = () => new C([]) {fun foo = (x: T,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x: T,) => x›)))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(x: Var(T)), Var(x)))))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -171,7 +171,7 @@ class A(x: Int) extends {a1: Int}, B, D(x){ //│ |#class| |B|‹|T|›| |{||}|↵|#class| |C| |{||}|↵|#class| |D|(|y|#:| |Int|)| |{||}|↵|#class| |A|‹|T|,| |U|›|(|x|#:| |Int|)| |#extends| |{|a1|#:| |Int|}|,| |B|‹|T|›|,| |D|(|x|)|{|→|#fun| |getA|(||)| |#=| |#new| |C|{|→|#fun| |foo|(|x|)| |#=| |x|←|↵|}|←|↵|}| //│ Parsed: {class B‹T› {}; class C {}; class D(y: Int,) {}; class A‹T, U›(x: Int,): '{' {a1: Int} '}', B‹T›, D(x,) {fun getA = () => new C([]) {fun foo = (x,) => x}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), ‹fun foo = (x,) => x›)))))) +//│ TypingUnit(NuTypeDef(class, B, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit()), NuTypeDef(class, D, (), Tup(y: Var(Int)), (), None, None, TypingUnit()), NuTypeDef(class, A, ((None,TypeName(T)), (None,TypeName(U))), Tup(x: Var(Int)), (Bra(rcd = true, Rcd(Var(a1) = Var(Int))), TyApp(Var(B), List(TypeName(T))), App(Var(D), Tup(_: Var(x)))), None, None, TypingUnit(NuFunDef(None, getA, None, [], Lam(Tup(), New(Some((TypeName(C),[])), TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x)))))))))) //│ Lifted: //│ TypingUnit { //│ class B$1[T]([]) {} @@ -192,13 +192,13 @@ class Child(x): { age: T } & { name: String} { //│ |#class| |Child|‹|T|,| |U|›|(|x|)|#:| |{| |age|#:| |T| |}| |&| |{| |name|#:| |String|}| |{|→|#class| |Inner|{|→|#fun| |foo| |#=| |age|←|↵|}|↵|#fun| |bar| |#=| |age|↵|#fun| |boo| |#=| |#new| |Inner|←|↵|}| //│ Parsed: {class Child‹T, U›(x,): {age: T} & {name: String} {class Inner {fun foo = age}; fun bar = age; fun boo = new Inner([]) {}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), ‹›))))) +//│ TypingUnit(NuTypeDef(class, Child, ((None,TypeName(T)), (None,TypeName(U))), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, Inner, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Var(age)))), NuFunDef(None, bar, None, [], Var(age)), NuFunDef(None, boo, None, [], New(Some((TypeName(Inner),[])), TypingUnit()))))) //│ Lifted: //│ TypingUnit { -//│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = (this).age} +//│ class Child$1_Inner$2([par$Child$1, age,]) {fun foo = () => (this).age} //│ class Child$1[T,U]([x,]) { -//│ fun bar = age -//│ fun boo = new Child$1_Inner$2([this, age,]) {} +//│ fun bar = () => age +//│ fun boo = () => new Child$1_Inner$2([this, age,]) {} //│ } //│ } //│ @@ -215,11 +215,11 @@ new A(0) { //│ |#class| |A|(|x|#:| |Int|)| |{|→|#fun| |getA|#:| |Int| |#=| |0|↵|#fun| |getA1| |#=| |1|←|↵|}|↵|#new| |A|(|0|)| |{|→|#fun| |getA| |#=| |3|↵|#fun| |getA2| |#=| |2|←|↵|}| //│ Parsed: {class A(x: Int,) {fun getA = 0 : Int; fun getA1 = 1}; new A([0,]) {fun getA = 3; fun getA2 = 2}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), ‹fun getA = 3; fun getA2 = 2›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], Asc(IntLit(0), TypeName(Int))), NuFunDef(None, getA1, None, [], IntLit(1)))), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(3)), NuFunDef(None, getA2, None, [], IntLit(2))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([x: Int,]) {fun getA = 0 : Int; fun getA1 = 1} -//│ class A$1$2([x: Int,]): A$1((this).x,) {fun getA = 3; fun getA2 = 2} +//│ class A$1([x: Int,]) {fun getA = () => 0 : Int; fun getA1 = () => 1} +//│ class A$1$2([x: Int,]): A$1((this).x,) {fun getA = () => 3; fun getA2 = () => 2} //│ Code(List({new A$1$2([0,]) {}})) //│ } //│ @@ -236,13 +236,13 @@ new A(1) { //│ |#class| |A|(|x|)| |{|→|#class| |B|(|y|)| |{| |}|←|↵|}|↵|#new| |A|(|1|)| |{|→|#fun| |getB| |#=| |#new| |B|(|2|)|{|→|#fun| |getB| |#=| |#new| |B|(|3|)|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {class B(y,) {}}; new A([1,]) {fun getB = new B([2,]) {fun getB = new B([3,]) {}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), ‹fun getB = new B([2,]) {fun getB = new B([3,]) {}}›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(_: Var(y)), (), None, None, TypingUnit()))), New(Some((TypeName(A),[1,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[2,])), TypingUnit(NuFunDef(None, getB, None, [], New(Some((TypeName(B),[3,])), TypingUnit())))))))) //│ Lifted: //│ TypingUnit { //│ class A$1_B$2([par$A$1, y,]) {} //│ class A$1([x,]) {} -//│ class A$1$3_B$2$4([par$A$1$3, y,]): A$1_B$2((this).par$A$1$3, (this).y,) {fun getB = new A$1_B$2([(this).par$A$1$3, 3,]) {}} -//│ class A$1$3([x,]): A$1((this).x,) {fun getB = {new A$1$3_B$2$4([this, 2,]) {}}} +//│ class A$1$3_B$2$4([par$A$1$3, y,]): A$1_B$2((this).par$A$1$3, (this).y,) {fun getB = () => new A$1_B$2([(this).par$A$1$3, 3,]) {}} +//│ class A$1$3([x,]): A$1((this).x,) {fun getB = () => {new A$1$3_B$2$4([this, 2,]) {}}} //│ Code(List({new A$1$3([1,]) {}})) //│ } //│ @@ -269,18 +269,18 @@ new B{ //│ |#class| |A| |{|→|#fun| |getA| |#=| |0|↵|#fun| |funcA| |#=| |10|←|↵|}|↵|#class| |B|#:| |A|{|→|#fun| |getA| |#=| |1|↵|#fun| |funcB| |#=| |11|←|↵|}|↵|#new| |A|↵|#new| |B|↵|#fun| |f|(|x|)| |#=| |#if| |x| |is| |A| |#then| |0| |#else| |1|↵|f|(|#new| |A|{|→|#fun| |getA| |#=| |2|←|↵|}|)|↵|#new| |B|{|→|#fun| |getA| |#=| |funcB|←|↵|}| //│ Parsed: {class A {fun getA = 0; fun funcA = 10}; class B: A {fun getA = 1; fun funcB = 11}; new A([]) {}; new B([]) {}; fun f = (x,) => if (is(x, A,)) then 0 else 1; f(new A([]) {fun getA = 2},); new B([]) {fun getA = funcB}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), ‹›), New(Some((TypeName(B),[])), ‹›), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), ‹fun getA = 2›))), New(Some((TypeName(B),[])), ‹fun getA = funcB›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(0)), NuFunDef(None, funcA, None, [], IntLit(10)))), NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, getA, None, [], IntLit(1)), NuFunDef(None, funcB, None, [], IntLit(11)))), New(Some((TypeName(A),[])), TypingUnit()), New(Some((TypeName(B),[])), TypingUnit()), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), If(IfThen(App(Var(is), Tup(_: Var(x), _: Var(A))), IntLit(0), Some(IntLit(1))))), App(Var(f), Tup(_: New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, getA, None, [], IntLit(2)))))), New(Some((TypeName(B),[])), TypingUnit(NuFunDef(None, getA, None, [], Var(funcB))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([]) {fun getA = 0; fun funcA = 10} -//│ class B$2([]) {fun getA = 1; fun funcB = 11} -//│ class A$1$3([]): A$1() {fun getA = 2} -//│ class B$2$4([]): B$2() {fun getA = (this).funcB} -//│ fun f = (x,) => if (is(x, A$1(),)) then 0 else 1 +//│ class A$1([]) {fun getA = () => 0; fun funcA = () => 10} +//│ class B$2([]) {fun getA = () => 1; fun funcB = () => 11} +//│ class A$2$3([]): A$1() {fun getA = () => 2} +//│ class B$3$4([]): B$2() {fun getA = () => (this).funcB} +//│ fun f$1 = (x,) => if (is(x, A$1(),)) then 0 else 1 //│ Code(List(new A$1([]) {})) //│ Code(List(new B$2([]) {})) -//│ Code(List(f({new A$1$3([]) {}},))) -//│ Code(List({new B$2$4([]) {}})) +//│ Code(List(f$1({new A$2$3([]) {}},))) +//│ Code(List({new B$3$4([]) {}})) //│ } //│ @@ -313,11 +313,11 @@ class A{ //│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} -//│ class A$1_C$3([par$A$1,]) {fun funC = 2; fun foo = 1000} -//│ class A$1_D$4_E$5([par$A$1_D$4,]) {fun funE = 4; fun foo = 100000} -//│ class A$1_D$4_F$6([par$A$1_D$4,]) {fun funF = 5; fun foo = 1000000} -//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} +//│ class A$1_C$3([par$A$1,]) {fun funC = () => 2; fun foo = () => 1000} +//│ class A$1_D$4_E$5([par$A$1_D$4,]) {fun funE = () => 4; fun foo = () => 100000} +//│ class A$1_D$4_F$6([par$A$1_D$4,]) {fun funF = () => 5; fun foo = () => 1000000} +//│ class A$1_D$4([par$A$1,]) {fun funD = () => 3; fun foo = () => 10000} //│ class A$1([]) {} //│ } //│ @@ -353,27 +353,27 @@ class A{ //│ |#class| |A|{|→|#class| |B|{|→|#fun| |funB| |#=| |1|↵|#fun| |foo| |#=| |100|←|↵|}|↵|#class| |C|#:| |B|{|→|#fun| |funC| |#=| |2|↵|#fun| |foo| |#=| |1000|↵|#fun| |getB| |#=| |#new| |B|←|↵|}|↵|#class| |D|{|→|#fun| |funD| |#=| |3|↵|#fun| |foo| |#=| |10000| |↵|#class| |E|#:| |C|{|→|#fun| |funE| |#=| |4|↵|#fun| |foo| |#=| |100000|↵|#fun| |getD| |#=| |#new| |D|←|↵|}|↵|#class| |F|#:| |E|{|→|#fun| |funF| |#=| |5|↵|#fun| |foo| |#=| |1000000|↵|#fun| |getE| |#=| |#new| |E|{|→|#fun| |foo| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {class B {fun funB = 1; fun foo = 100}; class C: B {fun funC = 2; fun foo = 1000; fun getB = new B([]) {}}; class D {fun funD = 3; fun foo = 10000; class E: C {fun funE = 4; fun foo = 100000; fun getD = new D([]) {}}; class F: E {fun funF = 5; fun foo = 1000000; fun getE = new E([]) {fun foo = 0}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), ‹›)))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), ‹›)))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), ‹fun foo = 0›))))))))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funB, None, [], IntLit(1)), NuFunDef(None, foo, None, [], IntLit(100)))), NuTypeDef(class, C, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funC, None, [], IntLit(2)), NuFunDef(None, foo, None, [], IntLit(1000)), NuFunDef(None, getB, None, [], New(Some((TypeName(B),[])), TypingUnit())))), NuTypeDef(class, D, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funD, None, [], IntLit(3)), NuFunDef(None, foo, None, [], IntLit(10000)), NuTypeDef(class, E, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funE, None, [], IntLit(4)), NuFunDef(None, foo, None, [], IntLit(100000)), NuFunDef(None, getD, None, [], New(Some((TypeName(D),[])), TypingUnit())))), NuTypeDef(class, F, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, funF, None, [], IntLit(5)), NuFunDef(None, foo, None, [], IntLit(1000000)), NuFunDef(None, getE, None, [], New(Some((TypeName(E),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun funB = 1; fun foo = 100} +//│ class A$1_B$2([par$A$1,]) {fun funB = () => 1; fun foo = () => 100} //│ class A$1_C$3([par$A$1,]) { -//│ fun funC = 2 -//│ fun foo = 1000 -//│ fun getB = new A$1_B$2([(this).par$A$1,]) {} +//│ fun funC = () => 2 +//│ fun foo = () => 1000 +//│ fun getB = () => new A$1_B$2([(this).par$A$1,]) {} //│ } //│ class A$1_D$4_E$5([par$A$1_D$4,]) { -//│ fun funE = 4 -//│ fun foo = 100000 -//│ fun getD = new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} +//│ fun funE = () => 4 +//│ fun foo = () => 100000 +//│ fun getD = () => new A$1_D$4([((this).par$A$1_D$4).par$A$1,]) {} //│ } -//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = 0} +//│ class A$1_D$4_F$6_E$1$7([par$A$1_D$4_F$6,]): A$1_D$4_E$5(((this).par$A$1_D$4_F$6).par$A$1_D$4,) {fun foo = () => 0} //│ class A$1_D$4_F$6([par$A$1_D$4,]) { -//│ fun funF = 5 -//│ fun foo = 1000000 -//│ fun getE = {new A$1_D$4_F$6_E$1$7([this,]) {}} +//│ fun funF = () => 5 +//│ fun foo = () => 1000000 +//│ fun getE = () => {new A$1_D$4_F$6_E$1$7([this,]) {}} //│ } -//│ class A$1_D$4([par$A$1,]) {fun funD = 3; fun foo = 10000} +//│ class A$1_D$4([par$A$1,]) {fun funD = () => 3; fun foo = () => 10000} //│ class A$1([]) {} //│ } //│ @@ -389,11 +389,11 @@ new A //│ |#class| |A|{|→|#class| |B|{|→|#fun| |foo| |#=| |1|←|↵|}|↵|#fun| |bar| |#=| |#new| |B|←|↵|}|↵|#new| |A| //│ Parsed: {class A {class B {fun foo = 1}; fun bar = new B([]) {}}; new A([]) {}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), ‹›)))), New(Some((TypeName(A),[])), ‹›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)))), NuFunDef(None, bar, None, [], New(Some((TypeName(B),[])), TypingUnit())))), New(Some((TypeName(A),[])), TypingUnit())) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1,]) {fun foo = 1} -//│ class A$1([]) {fun bar = new A$1_B$2([this,]) {}} +//│ class A$1_B$2([par$A$1,]) {fun foo = () => 1} +//│ class A$1([]) {fun bar = () => new A$1_B$2([this,]) {}} //│ Code(List(new A$1([]) {})) //│ } //│ @@ -414,20 +414,20 @@ let x = new A{ //│ |#class| |A|(|x|)| |{|→|#fun| |foo| |#=| |0|↵|#fun| |bar| |#=| |x|←|↵|}|↵|#let| |x| |#=| |#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |newFun| |#=| |2|↵|#fun| |bar| |#=| |#new| |A|(|foo|)|{|→|#fun| |foo| |#=| |bar| |+| |1|↵|#fun| |bar2| |#=| |newFun| |+| |1|←|↵|}|←|↵|}| //│ Parsed: {class A(x,) {fun foo = 0; fun bar = x}; let x = new A([]) {fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), ‹fun foo = 1; fun newFun = 2; fun bar = new A([foo,]) {fun foo = +(bar, 1,); fun bar2 = +(newFun, 1,)}›))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], IntLit(0)), NuFunDef(None, bar, None, [], Var(x)))), NuFunDef(Some(false), x, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, newFun, None, [], IntLit(2)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[foo,])), TypingUnit(NuFunDef(None, foo, None, [], App(Var(+), Tup(_: Var(bar), _: IntLit(1)))), NuFunDef(None, bar2, None, [], App(Var(+), Tup(_: Var(newFun), _: IntLit(1))))))))))) //│ Lifted: //│ TypingUnit { -//│ class A$1([x,]) {fun foo = 0; fun bar = (this).x} -//│ class A$1$2_A$2$3([par$A$1$2, x,]): A$1((this).x,) { -//│ fun foo = +((this).bar, 1,) -//│ fun bar2 = +(((this).par$A$1$2).newFun, 1,) +//│ class A$1([x,]) {fun foo = () => 0; fun bar = () => (this).x} +//│ class A$2$2_A$3$3([par$A$2$2, x,]): A$1((this).x,) { +//│ fun foo = () => +((this).bar, 1,) +//│ fun bar2 = () => +(((this).par$A$2$2).newFun, 1,) //│ } -//│ class A$1$2([x,]): A$1((this).x,) { -//│ fun foo = 1 -//│ fun newFun = 2 -//│ fun bar = {new A$1$2_A$2$3([this, (this).foo,]) {}} +//│ class A$2$2([x,]): A$1((this).x,) { +//│ fun foo = () => 1 +//│ fun newFun = () => 2 +//│ fun bar = () => {new A$2$2_A$3$3([this, (this).foo,]) {}} //│ } -//│ let x = {new A$1$2([]) {}} +//│ let x$1 = () => {new A$2$2([]) {}} //│ } //│ @@ -451,27 +451,30 @@ new A{ //│ |#class| |A| |{||}|↵|#new| |A|{|→|#fun| |foo| |#=| |1|↵|#fun| |bar| |#=| |#new| |A|{|→|#fun| |foo1| |#=| |foo|↵|#fun| |bar1| |#=| |#new| |A|{|→|#fun| |foo2| |#=| |foo|↵|#fun| |bar2| |#=| |#new| |A|{|→|#fun| |foo3| |#=| |foo|↵|#fun| |bar3| |#=| |#new| |A|{|→|#fun| |foo4| |#=| |foo|↵|#fun| |bar4| |#=| |0|←|↵|}|←|↵|}|←|↵|}|←|↵|}|←|↵|}| //│ Parsed: {class A {}; new A([]) {fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), ‹fun foo = 1; fun bar = new A([]) {fun foo1 = foo; fun bar1 = new A([]) {fun foo2 = foo; fun bar2 = new A([]) {fun foo3 = foo; fun bar3 = new A([]) {fun foo4 = foo; fun bar4 = 0}}}}›)) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit()), New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo, None, [], IntLit(1)), NuFunDef(None, bar, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo1, None, [], Var(foo)), NuFunDef(None, bar1, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo2, None, [], Var(foo)), NuFunDef(None, bar2, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo3, None, [], Var(foo)), NuFunDef(None, bar3, None, [], New(Some((TypeName(A),[])), TypingUnit(NuFunDef(None, foo4, None, [], Var(foo)), NuFunDef(None, bar4, None, [], IntLit(0))))))))))))))))) //│ Lifted: //│ TypingUnit { //│ class A$1([]) {} //│ class A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([par$A$1$2_A$2$3_A$3$4_A$4$5,]): A$1() { -//│ fun foo4 = (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar4 = 0 +//│ fun foo4 = () => (((((this).par$A$1$2_A$2$3_A$3$4_A$4$5).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar4 = () => 0 //│ } //│ class A$1$2_A$2$3_A$3$4_A$4$5([par$A$1$2_A$2$3_A$3$4,]): A$1() { -//│ fun foo3 = ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar3 = {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} +//│ fun foo3 = () => ((((this).par$A$1$2_A$2$3_A$3$4).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar3 = () => {new A$1$2_A$2$3_A$3$4_A$4$5_A$5$6([this,]) {}} //│ } //│ class A$1$2_A$2$3_A$3$4([par$A$1$2_A$2$3,]): A$1() { -//│ fun foo2 = (((this).par$A$1$2_A$2$3).par$A$1$2).foo -//│ fun bar2 = {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} +//│ fun foo2 = () => (((this).par$A$1$2_A$2$3).par$A$1$2).foo +//│ fun bar2 = () => {new A$1$2_A$2$3_A$3$4_A$4$5([this,]) {}} //│ } //│ class A$1$2_A$2$3([par$A$1$2,]): A$1() { -//│ fun foo1 = ((this).par$A$1$2).foo -//│ fun bar1 = {new A$1$2_A$2$3_A$3$4([this,]) {}} +//│ fun foo1 = () => ((this).par$A$1$2).foo +//│ fun bar1 = () => {new A$1$2_A$2$3_A$3$4([this,]) {}} +//│ } +//│ class A$1$2([]): A$1() { +//│ fun foo = () => 1 +//│ fun bar = () => {new A$1$2_A$2$3([this,]) {}} //│ } -//│ class A$1$2([]): A$1() {fun foo = 1; fun bar = {new A$1$2_A$2$3([this,]) {}}} //│ Code(List({new A$1$2([]) {}})) //│ } //│ diff --git a/compiler/shared/test/diff/LifterBlks.mls b/compiler/shared/test/diff/LifterBlks.mls index 2ca0c8b44..67d569bd5 100644 --- a/compiler/shared/test/diff/LifterBlks.mls +++ b/compiler/shared/test/diff/LifterBlks.mls @@ -9,7 +9,7 @@ fun foo = //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: -//│ TypingUnit {fun foo = {print("ok",); print("ko",)}} +//│ TypingUnit {fun foo$1 = () => {print("ok",); print("ko",)}} //│ class A{ @@ -28,7 +28,7 @@ class A{ //│ fun foo = - fun local(x) = + let local(x) = class Foo { fun bar = x + 1 } @@ -38,14 +38,16 @@ fun foo = fun tmp = 1 print of local of 0 + local of 1 fun tmp = 2 -//│ |#fun| |foo| |#=|→|#fun| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| -//│ Parsed: {fun foo = {fun local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} +//│ |#fun| |foo| |#=|→|#let| |local|(|x|)| |#=|→|#class| |Foo| |{|→|#fun| |bar| |#=| |x| |+| |1|←|↵|}|↵|Foo|(||)|.bar|←|↵|print| |#of| |local|(|0|)| |+| |local|(|1|)|↵|print| |#of| |(|local| |#of| |0|)| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |1|↵|print| |#of| |local| |#of| |0| |+| |local| |#of| |1|↵|#fun| |tmp| |#=| |2|←| +//│ Parsed: {fun foo = {let local = (x,) => {class Foo {fun bar = +(x, 1,)}; (Foo()).bar}; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); fun tmp = 1; print(local(+(0, local(1,),),),); fun tmp = 2}} //│ Parsed: //│ TypingUnit(NuFunDef(None, foo, None, [], Blk(...))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x,]) {fun bar = +((this).x, 1,)} -//│ fun foo = {fun local = (x,) => {(Foo$1(x,)).bar}; fun tmp = 1; fun tmp = 2; print(+(local(0,), local(1,),),); print(+('(' local(0,) ')', local(1,),),); print(local(+(0, local(1,),),),)} +//│ class Foo$1([x,]) {fun bar = () => +((this).x, 1,)} +//│ let local$3 = (x,) => {(Foo$1(x,)).bar} +//│ fun tmp$2 = () => 1 +//│ fun foo$1 = () => {print(+(local$3(0,), local$3(1,),),); print(+('(' local$3(0,) ')', local$3(1,),),); print(local$3(+(0, local$3(1,),),),)} //│ } //│ @@ -55,13 +57,13 @@ f(0) //│ |#class| |A|(|y|)|{||}|↵|#let| |f| |#=| |x| |#=>| |#new| |A|(|0|)|{|#fun| |bar| |#=| |x|+|y|}|↵|f|(|0|)| //│ Parsed: {class A(y,) {}; let f = (x,) => new A([0,]) {fun bar = +(x, y,)}; f(0,)} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), ‹fun bar = +(x, y,)›))), App(Var(f), Tup(_: IntLit(0)))) +//│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(y)), (), None, None, TypingUnit()), NuFunDef(Some(false), f, None, [], Lam(Tup(_: Var(x)), New(Some((TypeName(A),[0,])), TypingUnit(NuFunDef(None, bar, None, [], App(Var(+), Tup(_: Var(x), _: Var(y)))))))), App(Var(f), Tup(_: IntLit(0)))) //│ Lifted: //│ TypingUnit { //│ class A$1([y,]) {} -//│ class A$1$2([y, x,]): A$1((this).y,) {fun bar = +((this).x, (this).y,)} -//│ let f = (x,) => {new A$1$2([0, x,]) {}} -//│ Code(List(f(0,))) +//│ class A$2$2([y, x,]): A$1((this).y,) {fun bar = () => +((this).x, (this).y,)} +//│ let f$1 = (x,) => {new A$2$2([0, x,]) {}} +//│ Code(List(f$1(0,))) //│ } //│ @@ -81,10 +83,14 @@ class A(x){ //│ TypingUnit(NuTypeDef(class, A, (), Tup(_: Var(x)), (), None, None, TypingUnit(NuFunDef(None, w, None, [], Var(x)), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(y)), Blk(...)))))) //│ Lifted: //│ TypingUnit { -//│ class A$1_B$2([par$A$1, z, y,]) {fun bar = +(+(((this).par$A$1).x, (this).y,), (this).z,)} -//│ class A$1_B$1$3([par$A$1, z, y,]): A$1_B$2((this).par$A$1, (this).z, (this).y,) {fun bar = +(+(((this).par$A$1).w, (this).y,), (this).z,)} +//│ class A$1_B$2([par$A$1, z, y,]) { +//│ fun bar = () => +(+(((this).par$A$1).x, (this).y,), (this).z,) +//│ } +//│ class A$1_B$1$3([par$A$1, z, y,]): A$1_B$2((this).par$A$1, (this).z, (this).y,) { +//│ fun bar = () => +(+(((this).par$A$1).w, (this).y,), (this).z,) +//│ } //│ class A$1([x,]) { -//│ fun w = (this).x +//│ fun w = () => (this).x //│ fun foo = (y,) => {{new A$1_B$1$3([this, 0, y,]) {}}} //│ } //│ } @@ -109,15 +115,15 @@ fun f(x,y,z) = //│ Lifted: //│ TypingUnit { //│ class A$1([x, y,]) { -//│ fun foo = new B$2([(this).y, (this).x,]) {} -//│ fun bar1 = (this).x +//│ fun foo = () => new B$2([(this).y, (this).x,]) {} +//│ fun bar1 = () => (this).x //│ } //│ class B$2([y, x,]) { -//│ fun foo = new A$1([(this).x, (this).y,]) {} -//│ fun bar2 = (this).y +//│ fun foo = () => new A$1([(this).x, (this).y,]) {} +//│ fun bar2 = () => (this).y //│ } -//│ class C$3([x, y,]): A$1((this).x, (this).y,), B$2((this).y, (this).x,) {fun bar = +((this).bar1, (this).bar2,)} -//│ fun f = (x, y, z,) => {} +//│ class C$3([x, y,]): A$1((this).x, (this).y,), B$2((this).y, (this).x,) {fun bar = () => +((this).bar1, (this).bar2,)} +//│ fun f$1 = (x, y, z,) => {} //│ } //│ @@ -140,35 +146,51 @@ fun f(x,y,z) = //│ Lifted: //│ TypingUnit { //│ class C$1_A$2([par$C$1,]) { -//│ fun foo = new C$1_B$3([(this).par$C$1,]) {} -//│ fun bar1 = ((this).par$C$1).x +//│ fun foo = () => new C$1_B$3([(this).par$C$1,]) {} +//│ fun bar1 = () => ((this).par$C$1).x //│ } //│ class C$1_B$3([par$C$1,]) { -//│ fun foo = new C$1_A$2([(this).par$C$1,]) {} -//│ fun bar2 = ((this).par$C$1).y +//│ fun foo = () => new C$1_A$2([(this).par$C$1,]) {} +//│ fun bar2 = () => ((this).par$C$1).y //│ } //│ class C$1([x, y, z,]) { -//│ fun boo = +(+(('(' new C$1_A$2([this,]) {} ')').bar1, (C$1_B$3(this,)).bar2,), (this).z,) +//│ fun boo = () => +(+(('(' new C$1_A$2([this,]) {} ')').bar1, (C$1_B$3(this,)).bar2,), (this).z,) //│ } -//│ fun f = (x, y, z,) => {} +//│ fun f$1 = (x, y, z,) => {} //│ } //│ -fun f(x) = - let g(x) = x + 1 +fun f(y) = + let g(x) = x + y + 1 class Foo(x) { fun h = g(x) } - Foo(x).h -//│ |#fun| |f|(|x|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|↵|Foo|(|x|)|.h|←| -//│ Parsed: {fun f = (x,) => {let g = (x,) => +(x, 1,); class Foo(x,) {fun h = g(x,)}; (Foo(x,)).h}} +//│ |#fun| |f|(|y|)| |#=|→|#let| |g|(|x|)| |#=| |x| |+| |y| |+| |1|↵|#class| |Foo|(|x|)| |{|→|#fun| |h| |#=| |g|(|x|)|←|↵|}|←| +//│ Parsed: {fun f = (y,) => {let g = (x,) => +(+(x, y,), 1,); class Foo(x,) {fun h = g(x,)}}} //│ Parsed: -//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(y)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x, g,]) {fun h = (this).g((this).x,)} -//│ fun f = (x,) => {let g = (x,) => +(x, 1,); (Foo$1(x, g,)).h} +//│ class Foo$1([x, y,]) {fun h = () => g$2((this).x, y,)} +//│ let g$2 = (x, y,) => +(+(x, y,), 1,) +//│ fun f$1 = (y,) => {} //│ } +//│ + Foo(1).h +//│ | |Foo|(|1|)|.h| +//│ Parsed: {(Foo(1,)).h} +//│ Parsed: +//│ TypingUnit(Sel(App(Var(Foo), Tup(_: IntLit(1))), h)) +//│ Lifted: +//│ TypingUnit {Code(List((Foo(1,)).h))} +//│ + Foo(x).h +//│ | |Foo|(|x|)|.h| +//│ Parsed: {(Foo(x,)).h} +//│ Parsed: +//│ TypingUnit(Sel(App(Var(Foo), Tup(_: Var(x))), h)) +//│ Lifted: +//│ TypingUnit {Code(List((Foo(x,)).h))} //│ fun f(x) = @@ -185,8 +207,10 @@ fun f(x) = //│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...)))) //│ Lifted: //│ TypingUnit { -//│ class Foo$1([x, y, g,]) {fun bar = +((this).g((this).x,), (this).y,)} -//│ fun f = (x,) => {let g = (x,) => {let h = (x,) => +(x, 2,); (Foo$1(h(x,), x, g,)).bar}; (Foo$1(x, x, g,)).bar} +//│ class Foo$1([x, y,]) {fun bar = () => +(g$2((this).x,), (this).y,)} +//│ let h$3 = (x,) => +(x, 2,) +//│ let g$2 = (x,) => {(Foo$1(h$3(x,), x,)).bar} +//│ fun f$1 = (x,) => {(Foo$1(x, x,)).bar} //│ } //│ @@ -212,25 +236,26 @@ fun foo(x: T): string = //│ TypingUnit(NuFunDef(None, foo, None, [TypeName(T), TypeName(U)], Lam(Tup(x: Var(T)), Asc(Blk(...), TypeName(string))))) //│ Lifted: //│ TypingUnit { -//│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = this} -//│ fun foo[T, U] = (x: T,) => {"rua"} : string +//│ class A$1[T,U]([y,]): B‹T›, C(y: U,) {fun bar = () => this} +//│ fun foo$1[T, U] = (x: T,) => {"rua"} : string //│ } //│ class A{ class B{ - fun f: T => B => T = x => y => x + fun f = x => y => x fun g: T => B => T } } -//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f|#:| |T| |#=>| |B| |#=>| |T| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| -//│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x : T -> B -> T; fun g: T -> B -> T}}} +//│ |#class| |A|‹|T|›|{|→|#class| |B|{|→|#fun| |f| |#=| |x| |#=>| |y| |#=>| |x|↵|#fun| |g|#:| |T| |#=>| |B| |#=>| |T|←|↵|}|←|↵|}| +//│ Parsed: {class A‹T› {class B {fun f = (x,) => (y,) => x; fun g: T -> B -> T}}} //│ Parsed: -//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Asc(Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x))), Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T))))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) +//│ TypingUnit(NuTypeDef(class, A, ((None,TypeName(T))), Tup(), (), None, None, TypingUnit(NuTypeDef(class, B, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Lam(Tup(_: Var(y)), Var(x)))), NuFunDef(None, g, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,TypeName(T))))),Function(Tuple(List((None,Field(None,TypeName(B))))),TypeName(T)))))))))) //│ Lifted: //│ TypingUnit { +//│ class A$1_B$2_Lambda1$1$3([par$A$1_B$2, x,]) {fun apply = (y,) => (this).x} //│ class A$1_B$2[T]([par$A$1,]) { -//│ fun f = (x,) => (y,) => x : T -> A$1_B$2 -> T +//│ fun f = (x,) => {new A$1_B$2_Lambda1$1$3([this, x,]) {}} //│ fun g = T -> A$1_B$2 -> T //│ } //│ class A$1[T]([]) {} @@ -273,8 +298,9 @@ fun ctx(a,b) = //│ TypingUnit { //│ class Func$1[T,U]([]) {fun apply = T -> U} //│ class Lambda$2[T,U]([]) {} -//│ class Lambda$1$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} -//│ fun ctx = (a, b,) => {fun foo = (f: Func$1, x,) => {(f).apply(x,)}; foo({new Lambda$1$3([a,]) {}}, b,)} +//│ class Lambda$3$3([a,]): Lambda$2() {fun apply = (x,) => +((this).a, x,)} +//│ fun foo$2 = (f: Func$1, x,) => {(f).apply(x,)} +//│ fun ctx$1 = (a, b,) => {foo$2({new Lambda$3$3([a,]) {}}, b,)} //│ } //│ @@ -288,3 +314,19 @@ f(MyClass) //│ Lifted: //│ Lifting failed: mlscript.codegen.CodeGenError: Cannot find type T. Class values are not supported in lifter. //│ + +class A { + fun foo = + fun bar = foo() + bar() +} +//│ |#class| |A| |{|→|#fun| |foo| |#=| |→|#fun| |bar| |#=| |foo|(||)|↵|bar|(||)|←|←|↵|}| +//│ Parsed: {class A {fun foo = {fun bar = foo(); bar()}}} +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, A, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Blk(...))))) +//│ Lifted: +//│ TypingUnit { +//│ class A$1([]) {fun foo = () => {bar$1(this,)}} +//│ fun bar$1 = (this,) => (this).foo() +//│ } +//│ diff --git a/compiler/shared/test/diff/mono.mls b/compiler/shared/test/diff/mono.mls new file mode 100644 index 000000000..5116e6600 --- /dev/null +++ b/compiler/shared/test/diff/mono.mls @@ -0,0 +1,1204 @@ + +:NewDefs + +:mono +fun f(x: Int) = if x then 42 else 1337 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(x: Var(Int)), If(IfThen(Var(x), IntLit(42), Some(IntLit(1337)))))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x: Int,) => if (x) then 42 else 1337 +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ fun f$1(x) = +//│ if x then #42 else #1337 +//│ fun f: (x: Int) -> (1337 | 42) + +:mono +fun foo() = 42 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), IntLit(42)))) +//│ Lifted: +//│ TypingUnit {fun foo$1 = () => 42} +//│ Mono: +//│ +//│ Defunc result: +//│ fun foo$1() = +//│ #42 +//│ fun foo: () -> 42 + +:mono +fun foo(x, #b) = if b then x else 1337 +let a = foo(42, true) +let b = foo(23, false) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x), _: Var(b)), If(IfThen(Var(b), Var(x), Some(IntLit(1337))))), NuFunDef(Some(false), a, None, [], App(Var(foo), Tup(_: IntLit(42), _: Var(true)))), NuFunDef(Some(false), b, None, [], App(Var(foo), Tup(_: IntLit(23), _: Var(false))))) +//│ Lifted: +//│ TypingUnit { +//│ fun foo$3 = (x, #b,) => if (b) then x else 1337 +//│ let a$1 = () => foo$3(42, true,) +//│ let b$2 = () => foo$3(23, false,) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ fun b$2() = +//│ foo$3(#23, false) +//│ fun foo$3(x, #b) = +//│ if b then x else #1337 +//│ fun a$1() = +//│ foo$3(#42, true) +//│ fun foo: forall 'a. ('a, Object) -> (1337 | 'a) +//│ let a: 1337 | 42 +//│ let b: 1337 | 23 +//│ a +//│ = 42 +//│ b +//│ = 1337 + +:mono +let x = 42 + 1337 +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), x, None, [], App(Var(+), Tup(_: IntLit(42), _: IntLit(1337))))) +//│ Lifted: +//│ TypingUnit {let x$1 = () => +(42, 1337,)} +//│ Mono: +//│ +//│ Defunc result: +//│ fun x$1() = +//│ +(#42, #1337) +//│ let x: Int +//│ x +//│ = 1379 + +//:mono +//:e // FIXME: Mutable Parameters +//class Bar(#x) +//fun foo(#b) = b +//let a = foo(new Bar(1)) +//let b = foo(new Bar(2)) + +//:mono +//:w // FIXME: Mutable Parameters +//class OneInt(#a){ +// fun inc() = a+1 +//} +//(new OneInt(1)).inc() + +//:mono +//:e // FIXME: Mutable Parameters +//class OneInt(#a){ +// fun add(x) = +// new OneInt(a+x.a) +//} +//(new OneInt(1)).add(new OneInt(2)) + +:mono +if true then 1 else 0 +if 1+1 > 1 then 1 - 1 else 1*1 +//│ Parsed: +//│ TypingUnit(If(IfThen(Var(true), IntLit(1), Some(IntLit(0))), If(IfThen(App(Var(>), Tup(_: App(Var(+), Tup(_: IntLit(1), _: IntLit(1))), _: IntLit(1))), App(Var(-), Tup(_: IntLit(1), _: IntLit(1))), Some(App(Var(*), Tup(_: IntLit(1), _: IntLit(1)))))) +//│ Lifted: +//│ TypingUnit { +//│ Code(List(if (true) then 1 else 0)) +//│ Code(List(if (>(+(1, 1,), 1,)) then -(1, 1,) else *(1, 1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$0() +//│ main$$1() +//│ fun main$$0() = +//│ if true then #1 else #0 +//│ fun main$$1() = +//│ if >(+(#1, #1), #1) then -(#1, #1) else *(#1, #1) +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 0 + +:mono +if(b) then 1 else 2 +//│ Parsed: +//│ TypingUnit(If(IfThen(Bra(rcd = false, Var(b)), IntLit(1), Some(IntLit(2)))) +//│ Lifted: +//│ TypingUnit {Code(List(if ('(' b ')') then 1 else 2))} +//│ Mono: +//│ +//│ Defunc result: +//│ main$$0() +//│ fun main$$0() = +//│ if b then #1 else #2 +//│ 1 | 2 +//│ res +//│ = 2 + +:mono +((f, g) => f(g))(f => f, true) +//│ Parsed: +//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(f), _: Var(g)), App(Var(f), Tup(_: Var(g))))), Tup(_: Lam(Tup(_: Var(f)), Var(f)), _: Var(true)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda2$1$1([]) {fun apply = (f, g,) => f(g,)} +//│ class Lambda1$2$2([]) {fun apply = (f,) => f} +//│ Code(List('(' {new Lambda2$1$1([]) {}} ')'({new Lambda1$2$2([]) {}}, true,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun apply$Lambda2$1$1(this, f, g) = +//│ f match {case obj: Lambda1$2$2 => apply$Lambda1$2$2(obj, g)} +//│ fun main$$2() = +//│ new Lambda2$1$1 () match {case obj: Lambda2$1$1 => apply$Lambda2$1$1(obj, new Lambda1$2$2 () , true)} +//│ fun apply$Lambda1$2$2(this, f) = +//│ f +//│ class Lambda2$1$1() { +//│ } +//│ class Lambda1$2$2() { +//│ } +//│ true +//│ res +//│ = true + + +:mono +(b => if b then true else false) (true) +//│ Parsed: +//│ TypingUnit(App(Bra(rcd = false, Lam(Tup(_: Var(b)), If(IfThen(Var(b), Var(true), Some(Var(false))))), Tup(_: Var(true)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$1$1([]) {fun apply = (b,) => if (b) then true else false} +//│ Code(List('(' {new Lambda1$1$1([]) {}} ')'(true,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun apply$Lambda1$1$1(this, b) = +//│ if b then true else false +//│ fun main$$1() = +//│ new Lambda1$1$1 () match {case obj: Lambda1$1$1 => apply$Lambda1$1$1(obj, true)} +//│ class Lambda1$1$1() { +//│ } +//│ Bool +//│ res +//│ = true + +:mono +fun f(x) = + if(x > 0) then x+1 else x - 1 +f(2)+3 +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(+), Tup(_: App(Var(f), Tup(_: IntLit(2))), _: IntLit(3)))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x,) => {if ('(' >(x, 0,) ')') then +(x, 1,) else -(x, 1,)} +//│ Code(List(+(f$1(2,), 3,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun f$1(x) = +//│ if >(x, #0) then +(x, #1) else -(x, #1) +//│ fun main$$1() = +//│ +(f$1(#2), #3) +//│ fun f: Int -> Int +//│ Int +//│ res +//│ = 6 + +:mono +fun fac(n) = + if (n > 1) then fac(n - 1) * n else 1 +fac(2) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, fac, None, [], Lam(Tup(_: Var(n)), Blk(...))), App(Var(fac), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ fun fac$1 = (n,) => {if ('(' >(n, 1,) ')') then *(fac$1(-(n, 1,),), n,) else 1} +//│ Code(List(fac$1(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun fac$1(n) = +//│ if >(n, #1) then *(fac$1(-(n, #1)), n) else #1 +//│ fun main$$1() = +//│ fac$1(#2) +//│ fun fac: Int -> Int +//│ Int +//│ res +//│ = 2 + +:mono +class List(val l: List | Nil | undefined, val hasTail: Bool) {} +class Nil(val l: List | Nil | undefined, val hasTail: Bool) {} +fun count(lst) = + if lst.hasTail then + let l = lst.l + if l is undefined then 1 else count(l)+1 + else 0 +count(new List(new List(new Nil(undefined, false), true), true)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(l: App(Var(|), Tup(_: App(Var(|), Tup(_: Var(List), _: Var(Nil))), _: UnitLit(true))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, count, None, [], Lam(Tup(_: Var(lst)), Blk(...))), App(Var(count), Tup(_: New(Some((TypeName(List),[new List([new Nil([undefined, false,]) {}, true,]) {}, true,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} +//│ class Nil$2([val l: |(|(List, Nil,), undefined,), val hasTail: Bool,]) {} +//│ let l$2 = (lst,) => (lst).l +//│ fun count$1 = (lst,) => {if ((lst).hasTail) then {if (is(l, undefined,)) then 1 else +(count$1(l,), 1,)} else 0} +//│ Code(List(count$1(new List$1([new List$1([new Nil$2([undefined, false,]) {}, true,]) {}, true,]) {},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ fun l$2(lst) = +//│ lst.l +//│ fun count$1(lst) = +//│ if lst.hasTail then if is(l, #()) then #1 else +(count$1(l), #1) else #0 +//│ fun main$$4() = +//│ count$1(new List$1 (new List$1 (new Nil$2 (#(), false) , true) , true) ) +//│ class Nil$2(l, hasTail) { +//│ } +//│ class List$1(l, hasTail) { +//│ } +//│ class List(l: List | Nil | (), hasTail: Bool) +//│ class Nil(l: List | Nil | (), hasTail: Bool) +//│ fun count: forall 'a. 'a -> Int +//│ Int +//│ where +//│ 'a <: {hasTail: Object, l: Object & 'a & ~() | ()} +//│ res +//│ = 2 + +//:mono +//class Cons(e, tail){ +// fun gen() = new Cons(e, tail.gen()) +//} +//class Nil(){ +// fun gen() = new Cons(0, this) +//} +//fun generate(x) = +// if x > 0 then new Cons(x, generate(x+1)) else new Nil() +//generate(10).gen() + +:mono +class List(e: Int, tail: List | Nil) { + fun map: (Int -> Int) -> List + fun map(f)= new List(f(e), tail.map(f)) + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun map(f) = this + fun count() = 0 +} +fun add2(x) = x+2 +(new List(1, new List(2, new Nil()))).map(x => x+1).map(x => add2(x)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, map, None, [], PolyType(List(),Function(Tuple(List((None,Field(None,Function(Tuple(List((None,Field(None,TypeName(Int))))),TypeName(Int)))))),TypeName(List)))), NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), New(Some((TypeName(List),[f(e,), (tail).map(f,),])), TypingUnit()))), NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, map, None, [], Lam(Tup(_: Var(f)), Var(this))), NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, add2, None, [], Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit())), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1)))))), map), Tup(_: Lam(Tup(_: Var(x)), App(Var(add2), Tup(_: Var(x))))))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([e: Int, tail: |(List, Nil,),]) { +//│ fun map = (Int -> Int) -> List$1 +//│ fun map = (f,) => new List$1([f((this).e,), ((this).tail).map(f,),]) {} +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun map = (f,) => this; fun count = () => 0} +//│ class Lambda1$2$3([]) {fun apply = (x,) => +(x, 1,)} +//│ class Lambda1$3$4([]) {fun apply = (x,) => add2$1(x,)} +//│ fun add2$1 = (x,) => +(x, 2,) +//│ Code(List((('(' new List$1([1, new List$1([2, new Nil$2([]) {},]) {},]) {} ')').map({new Lambda1$2$3([]) {}},)).map({new Lambda1$3$4([]) {}},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ fun map$List$1(this, f) = +//│ new List$1 (f match {case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, this.e); case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, this.e)}, this.tail match {case obj: List$1 => map$List$1(obj, f); case obj: Nil$2 => map$Nil$2(obj, f)}) +//│ fun add2$1(x) = +//│ +(x, #2) +//│ fun main$$5() = +//│ new List$1 (#1, new List$1 (#2, new Nil$2 () ) ) match {case obj: List$1 => map$List$1(obj, new Lambda1$2$3 () )} match {case obj: List$1 => map$List$1(obj, new Lambda1$3$4 () )} +//│ fun apply$Lambda1$3$4(this, x) = +//│ add2$1(x) +//│ fun map$Nil$2(this, f) = +//│ this +//│ fun apply$Lambda1$2$3(this, x) = +//│ +(x, #1) +//│ class Lambda1$3$4() { +//│ } +//│ class Nil$2() { +//│ } +//│ class List$1(e, tail) { +//│ } +//│ class Lambda1$2$3() { +//│ } +//│ class List(e: Int, tail: List | Nil) { +//│ fun count: () -> Int +//│ fun map: (Int -> Int) -> List +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ fun map: anything -> Nil +//│ } +//│ fun add2: Int -> Int +//│ List +//│ res +//│ = List {} + +:mono +:AllowRuntimeErrors +class List(e: Int, tail: List | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +fun foo(x) = x.count() +fun generate(x) = + if x > 0 then new List(x, generate(x+1)) else new Nil() +foo(new List(1, new List(2, new Nil()))) +foo(generate(1)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, List, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(List), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), App(Sel(Var(x), count), Tup()))), NuFunDef(None, generate, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(List),[1, new List([2, new Nil([]) {},]) {},])), TypingUnit()))), App(Var(foo), Tup(_: App(Var(generate), Tup(_: IntLit(1)))))) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([e: Int, tail: |(List, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ fun foo$1 = (x,) => (x).count() +//│ fun generate$2 = (x,) => {if (>(x, 0,)) then new List$1([x, generate$2(+(x, 1,),),]) {} else new Nil$2([]) {}} +//│ Code(List(foo$1(new List$1([1, new List$1([2, new Nil$2([]) {},]) {},]) {},))) +//│ Code(List(foo$1(generate$2(1,),))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ fun foo$1(x) = +//│ x match {case obj: Nil$2 => count$Nil$2(obj); case obj: List$1 => count$List$1(obj)} +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun count$List$1(this) = +//│ +(#1, this.tail match {case obj: List$1 => count$List$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun generate$2(x) = +//│ if >(x, #0) then new List$1 (x, generate$2(+(x, #1))) else new Nil$2 () +//│ fun main$$5() = +//│ foo$1(generate$2(#1)) +//│ fun main$$4() = +//│ foo$1(new List$1 (#1, new List$1 (#2, new Nil$2 () ) ) ) +//│ class Nil$2() { +//│ } +//│ class List$1(e, tail) { +//│ } +//│ class List(e: Int, tail: List | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ fun foo: forall 'a. {count: () -> 'a} -> 'a +//│ fun generate: Int -> (List | Nil) +//│ Int +//│ res +//│ = 2 +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +fun foo(x) = + (f => f(x))(z => z+1) +foo(2) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([x,]) {fun apply = (f,) => f((this).x,)} +//│ class Lambda1$3$2([]) {fun apply = (z,) => +(z, 1,)} +//│ fun foo$1 = (x,) => {'(' {new Lambda1$2$1([x,]) {}} ')'({new Lambda1$3$2([]) {}},)} +//│ Code(List(foo$1(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$3() +//│ fun apply$Lambda1$2$1(this, f) = +//│ f match {case obj: Lambda1$3$2 => apply$Lambda1$3$2(obj, this.x)} +//│ fun foo$1(x) = +//│ new Lambda1$2$1 (x) match {case obj: Lambda1$2$1 => apply$Lambda1$2$1(obj, new Lambda1$3$2 () )} +//│ fun main$$3() = +//│ foo$1(#2) +//│ fun apply$Lambda1$3$2(this, z) = +//│ +(z, #1) +//│ class Lambda1$2$1(x) { +//│ } +//│ class Lambda1$3$2() { +//│ } +//│ fun foo: Int -> Int +//│ Int +//│ res +//│ = 3 + +:mono +fun f(x) = + (y => f(x+y))(x+1) +f(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(f), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ class Lambda1$2$1([x,]) {fun apply = (y,) => f$1(+((this).x, y,),)} +//│ fun f$1 = (x,) => {'(' {new Lambda1$2$1([x,]) {}} ')'(+(x, 1,),)} +//│ Code(List(f$1(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun apply$Lambda1$2$1(this, y) = +//│ f$1(+(this.x, y)) +//│ fun f$1(x) = +//│ new Lambda1$2$1 (x) match {case obj: Lambda1$2$1 => apply$Lambda1$2$1(obj, +(x, #1))} +//│ fun main$$2() = +//│ f$1(#1) +//│ class Lambda1$2$1(x) { +//│ } +//│ fun f: Int -> nothing +//│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + + +:mono +fun f(x) = f(x) +f(0) +f(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), App(Var(f), Tup(_: Var(x))))), App(Var(f), Tup(_: IntLit(0))), App(Var(f), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ fun f$1 = (x,) => f$1(x,) +//│ Code(List(f$1(0,))) +//│ Code(List(f$1(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ main$$2() +//│ fun f$1(x) = +//│ f$1(x) +//│ fun main$$2() = +//│ f$1(#1) +//│ fun main$$1() = +//│ f$1(#0) +//│ fun f: anything -> nothing +//│ nothing +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +class Cons(e: 'A, tail: Cons | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +class Lambda(){ + fun apply(l) = + l.count() +} +class Lambda2(a: Int){ + fun apply(l) = + (new Cons(a, l)).count() +} +fun foo(x) = + x.apply(new Cons(1, new Nil())) + x.apply(new Nil()) +foo(new Lambda()) +foo(new Lambda2(2)) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var('A), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuTypeDef(class, Lambda, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuTypeDef(class, Lambda2, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, apply, None, [], Lam(Tup(_: Var(l)), Blk(...))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda),[])), TypingUnit()))), App(Var(foo), Tup(_: New(Some((TypeName(Lambda2),[2,])), TypingUnit())))) +//│ Lifted: +//│ TypingUnit { +//│ class Cons$1([e: 'A, tail: |(Cons, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ class Lambda$3([]) {fun apply = (l,) => {(l).count()}} +//│ class Lambda2$4([a: Int,]) { +//│ fun apply = (l,) => {('(' new Cons$1([(this).a, l,]) {} ')').count()} +//│ } +//│ fun foo$1 = (x,) => {+((x).apply(new Cons$1([1, new Nil$2([]) {},]) {},), (x).apply(new Nil$2([]) {},),)} +//│ Code(List(foo$1(new Lambda$3([]) {},))) +//│ Code(List(foo$1(new Lambda2$4([2,]) {},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun count$Cons$1(this) = +//│ +(#1, this.tail match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun foo$1(x) = +//│ +(x match {case obj: Lambda2$4 => apply$Lambda2$4(obj, new Cons$1 (#1, new Nil$2 () ) ); case obj: Lambda$3 => apply$Lambda$3(obj, new Cons$1 (#1, new Nil$2 () ) )}, x match {case obj: Lambda2$4 => apply$Lambda2$4(obj, new Nil$2 () ); case obj: Lambda$3 => apply$Lambda$3(obj, new Nil$2 () )}) +//│ fun apply$Lambda$3(this, l) = +//│ l match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)} +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun apply$Lambda2$4(this, l) = +//│ new Cons$1 (this.a, l) match {case obj: Cons$1 => count$Cons$1(obj)} +//│ fun main$$6() = +//│ foo$1(new Lambda2$4 (#2) ) +//│ fun main$$5() = +//│ foo$1(new Lambda$3 () ) +//│ class Nil$2() { +//│ } +//│ class Lambda2$4(a) { +//│ } +//│ class Cons$1(e, tail) { +//│ } +//│ class Lambda$3() { +//│ } +//│ class Cons(e: nothing, tail: Cons | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ class Lambda() { +//│ fun apply: forall 'a. {count: () -> 'a} -> 'a +//│ } +//│ class Lambda2(a: Int) { +//│ fun apply: (Cons | Nil) -> Int +//│ } +//│ fun foo: {apply: (Cons | Nil) -> Int} -> Int +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 3 + +:mono +class Cons(e: Int, tail: Cons | Nil) { + fun count(): Int + fun count() = 1 + tail.count() +} +class Nil() { + fun count() = 0 +} +fun foo(x) = + x(new Cons(1, new Nil())) + x(new Nil()) +foo(l => l.count()) +foo(l => (new Cons(2, l)).count()) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Cons, (), Tup(e: Var(Int), tail: App(Var(|), Tup(_: Var(Cons), _: Var(Nil)))), (), None, None, TypingUnit(NuFunDef(None, count, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, count, None, [], Lam(Tup(), App(Var(+), Tup(_: IntLit(1), _: App(Sel(Var(tail), count), Tup()))))))), NuTypeDef(class, Nil, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, count, None, [], Lam(Tup(), IntLit(0))))), NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Var(l), count), Tup())))), App(Var(foo), Tup(_: Lam(Tup(_: Var(l)), App(Sel(Bra(rcd = false, New(Some((TypeName(Cons),[2, l,])), TypingUnit())), count), Tup()))))) +//│ Lifted: +//│ TypingUnit { +//│ class Cons$1([e: Int, tail: |(Cons, Nil,),]) { +//│ fun count = () -> Int +//│ fun count = () => +(1, ((this).tail).count(),) +//│ } +//│ class Nil$2([]) {fun count = () => 0} +//│ class Lambda1$2$3([]) {fun apply = (l,) => (l).count()} +//│ class Lambda1$3$4([]) { +//│ fun apply = (l,) => ('(' new Cons$1([2, l,]) {} ')').count() +//│ } +//│ fun foo$1 = (x,) => {+(x(new Cons$1([1, new Nil$2([]) {},]) {},), x(new Nil$2([]) {},),)} +//│ Code(List(foo$1({new Lambda1$2$3([]) {}},))) +//│ Code(List(foo$1({new Lambda1$3$4([]) {}},))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun count$Cons$1(this) = +//│ +(#1, this.tail match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)}) +//│ fun foo$1(x) = +//│ +(x match {case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, new Cons$1 (#1, new Nil$2 () ) ); case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, new Cons$1 (#1, new Nil$2 () ) )}, x match {case obj: Lambda1$3$4 => apply$Lambda1$3$4(obj, new Nil$2 () ); case obj: Lambda1$2$3 => apply$Lambda1$2$3(obj, new Nil$2 () )}) +//│ fun count$Nil$2(this) = +//│ #0 +//│ fun main$$6() = +//│ foo$1(new Lambda1$3$4 () ) +//│ fun main$$5() = +//│ foo$1(new Lambda1$2$3 () ) +//│ fun apply$Lambda1$3$4(this, l) = +//│ new Cons$1 (#2, l) match {case obj: Cons$1 => count$Cons$1(obj)} +//│ fun apply$Lambda1$2$3(this, l) = +//│ l match {case obj: Cons$1 => count$Cons$1(obj); case obj: Nil$2 => count$Nil$2(obj)} +//│ class Lambda1$3$4() { +//│ } +//│ class Nil$2() { +//│ } +//│ class Cons$1(e, tail) { +//│ } +//│ class Lambda1$2$3() { +//│ } +//│ class Cons(e: Int, tail: Cons | Nil) { +//│ fun count: () -> Int +//│ } +//│ class Nil() { +//│ fun count: () -> 0 +//│ } +//│ fun foo: ((Cons | Nil) -> Int) -> Int +//│ Int +//│ res +//│ = 1 +//│ res +//│ = 3 + +:mono +class Exp() { + virtual fun derive(x: Int): Exp + virtual fun derive(x: Int) = Exp() + virtual fun isEmpty(): Bool + virtual fun isEmpty() = false +} +class E() extends Exp { + fun derive(x) = + new E + fun isEmpty() = + false +} +class Ep() extends Exp { + fun derive(x) = + new E + fun isEmpty() = + true +} +class Ch(i: Int) extends Exp { + fun derive(x) = + if x == i then new Ep else new E + fun isEmpty() = + false +} +class A(e1: Exp, e2: Exp) extends Exp { + fun derive(x) = + new A(e1.derive(x), e2.derive(x)) + fun isEmpty() = + e1.isEmpty() || e2.isEmpty() +} +class C(e1: Exp, e2: Exp) extends Exp { + fun derive(x) = + if e1.isEmpty() then new A(new C(e1.derive(x), e2), e2.derive(x)) else new C(e1.derive(x), e2) + fun isEmpty() = + e1.isEmpty() && e2.isEmpty() +} +(new C(new Ch(1), new A(new Ch(2), new Ch(3)))).derive(0).isEmpty() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Exp, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, derive, None, [], PolyType(List(),Function(Tuple(List((Some(x),Field(None,TypeName(Int))))),TypeName(Exp)))), NuFunDef(None, derive, None, [], Lam(Tup(x: Var(Int)), App(Var(Exp), Tup()))), NuFunDef(None, isEmpty, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Bool)))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Var(false))))), NuTypeDef(class, E, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ep, (), Tup(), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, Ch, (), Tup(i: Var(Int)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, A, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), NuTypeDef(class, C, (), Tup(e1: Var(Exp), e2: Var(Exp)), (Var(Exp)), None, None, TypingUnit(NuFunDef(None, derive, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, isEmpty, None, [], Lam(Tup(), Blk(...))))), App(Sel(App(Sel(Bra(rcd = false, New(Some((TypeName(C),[new Ch([1,]) {}, new A([new Ch([2,]) {}, new Ch([3,]) {},]) {},])), TypingUnit())), derive), Tup(_: IntLit(0))), isEmpty), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Exp$1([]) { +//│ fun derive = (x: Int) -> Exp$1 +//│ fun derive = (x: Int,) => Exp$1() +//│ fun isEmpty = () -> Bool +//│ fun isEmpty = () => false +//│ } +//│ class E$2([]): Exp$1() { +//│ fun derive = (x,) => {new E$2([]) {}} +//│ fun isEmpty = () => {false} +//│ } +//│ class Ep$3([]): Exp$1() { +//│ fun derive = (x,) => {new E$2([]) {}} +//│ fun isEmpty = () => {true} +//│ } +//│ class Ch$4([i: Int,]): Exp$1() { +//│ fun derive = (x,) => {if (==(x, (this).i,)) then new Ep$3([]) {} else new E$2([]) {}} +//│ fun isEmpty = () => {false} +//│ } +//│ class A$5([e1: Exp, e2: Exp,]): Exp$1() { +//│ fun derive = (x,) => {new A$5([((this).e1).derive(x,), ((this).e2).derive(x,),]) {}} +//│ fun isEmpty = () => {||(((this).e1).isEmpty(), ((this).e2).isEmpty(),)} +//│ } +//│ class C$6([e1: Exp, e2: Exp,]): Exp$1() { +//│ fun derive = (x,) => {if (((this).e1).isEmpty()) then new A$5([new C$6([((this).e1).derive(x,), (this).e2,]) {}, ((this).e2).derive(x,),]) {} else new C$6([((this).e1).derive(x,), (this).e2,]) {}} +//│ fun isEmpty = () => {&&(((this).e1).isEmpty(), ((this).e2).isEmpty(),)} +//│ } +//│ Code(List((('(' new C$6([new Ch$4([1,]) {}, new A$5([new Ch$4([2,]) {}, new Ch$4([3,]) {},]) {},]) {} ')').derive(0,)).isEmpty())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$6() +//│ fun isEmpty$E$2(this) = +//│ false +//│ fun isEmpty$A$5(this) = +//│ ||(this.e1 match {case obj: Ch$4 => isEmpty$Ch$4(obj)}, this.e2 match {case obj: Ch$4 => isEmpty$Ch$4(obj)}) +//│ fun isEmpty$Ch$4(this) = +//│ false +//│ fun derive$A$5(this, x) = +//│ new A$5 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2 match {case obj: Ch$4 => derive$Ch$4(obj, x)}) +//│ fun isEmpty$C$6(this) = +//│ &&(this.e1 match {case obj: Ep$3 => isEmpty$Ep$3(obj); case obj: E$2 => isEmpty$E$2(obj)}, this.e2 match {case obj: A$5 => isEmpty$A$5(obj)}) +//│ fun derive$C$6(this, x) = +//│ if this.e1 match {case obj: Ch$4 => isEmpty$Ch$4(obj)} then new A$5 (new C$6 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2) , this.e2 match {case obj: A$5 => derive$A$5(obj, x)}) else new C$6 (this.e1 match {case obj: Ch$4 => derive$Ch$4(obj, x)}, this.e2) +//│ fun main$$6() = +//│ new C$6 (new Ch$4 (#1) , new A$5 (new Ch$4 (#2) , new Ch$4 (#3) ) ) match {case obj: C$6 => derive$C$6(obj, #0)} match {case obj: C$6 => isEmpty$C$6(obj)} +//│ fun derive$Ch$4(this, x) = +//│ if ==(x, this.i) then new Ep$3 () else new E$2 () +//│ fun isEmpty$Ep$3(this) = +//│ true +//│ class A$5(e1, e2): Exp$1() { +//│ } +//│ class E$2(): Exp$1() { +//│ } +//│ class C$6(e1, e2): Exp$1() { +//│ } +//│ class Ch$4(i): Exp$1() { +//│ } +//│ class Ep$3(): Exp$1() { +//│ } +//│ class Exp$1() { +//│ } +//│ class Exp() { +//│ fun derive: (x: Int) -> Exp +//│ fun isEmpty: () -> Bool +//│ } +//│ class E() extends Exp { +//│ fun derive: anything -> E +//│ fun isEmpty: () -> false +//│ } +//│ class Ep() extends Exp { +//│ fun derive: anything -> E +//│ fun isEmpty: () -> true +//│ } +//│ class Ch(i: Int) extends Exp { +//│ fun derive: Num -> (E | Ep) +//│ fun isEmpty: () -> false +//│ } +//│ class A(e1: Exp, e2: Exp) extends Exp { +//│ fun derive: Int -> A +//│ fun isEmpty: () -> Bool +//│ } +//│ class C(e1: Exp, e2: Exp) extends Exp { +//│ fun derive: Int -> (A | C) +//│ fun isEmpty: () -> Bool +//│ } +//│ Bool +//│ res +//│ = false + + +:mono +val anyUnknown = false +class List(l: List | Nil, hasTail: Bool) {} +class Nil(hasTail: Bool) {} +fun gen() = + if anyUnknown then new List(gen(), true) else new Nil(false) +gen() +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), anyUnknown, None, [], Var(false)), NuTypeDef(class, List, (), Tup(l: App(Var(|), Tup(_: Var(List), _: Var(Nil))), hasTail: Var(Bool)), (), None, None, TypingUnit()), NuTypeDef(class, Nil, (), Tup(hasTail: Var(Bool)), (), None, None, TypingUnit()), NuFunDef(None, gen, None, [], Lam(Tup(), Blk(...))), App(Var(gen), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class List$1([l: |(List, Nil,), hasTail: Bool,]) {} +//│ class Nil$2([hasTail: Bool,]) {} +//│ let anyUnknown$2 = () => false +//│ fun gen$1 = () => {if (anyUnknown) then new List$1([gen$1(), true,]) {} else new Nil$2([false,]) {}} +//│ Code(List(gen$1())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ fun anyUnknown$2() = +//│ false +//│ fun gen$1() = +//│ if anyUnknown then new List$1 (gen$1(), true) else new Nil$2 (false) +//│ fun main$$4() = +//│ gen$1() +//│ class Nil$2(hasTail) { +//│ } +//│ class List$1(l, hasTail) { +//│ } +//│ val anyUnknown: false +//│ class List(l: List | Nil, hasTail: Bool) +//│ class Nil(hasTail: Bool) +//│ fun gen: () -> (List | Nil) +//│ List | Nil +//│ anyUnknown +//│ = false +//│ res +//│ = Nil {} + + + +:mono +class Foo(x: Int){ + fun bar(y) = x+y + fun boo(z) = bar(z)+x +} +(new Foo(1)).boo(2) +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, bar, None, [], Lam(Tup(_: Var(y)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, boo, None, [], Lam(Tup(_: Var(z)), App(Var(+), Tup(_: App(Var(bar), Tup(_: Var(z))), _: Var(x))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Foo),[1,])), TypingUnit())), boo), Tup(_: IntLit(2)))) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([x: Int,]) { +//│ fun bar = (y,) => +((this).x, y,) +//│ fun boo = (z,) => +((this).bar(z,), (this).x,) +//│ } +//│ Code(List(('(' new Foo$1([1,]) {} ')').boo(2,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun boo$Foo$1(this, z) = +//│ +(this match {case obj: Foo$1 => bar$Foo$1(obj, z)}, this.x) +//│ fun bar$Foo$1(this, y) = +//│ +(this.x, y) +//│ fun main$$1() = +//│ new Foo$1 (#1) match {case obj: Foo$1 => boo$Foo$1(obj, #2)} +//│ class Foo$1(x) { +//│ } +//│ class Foo(x: Int) { +//│ fun bar: Int -> Int +//│ fun boo: Int -> Int +//│ } +//│ Int +//│ res +//│ = 4 + +:mono +class OneInt(a: Int){ + fun fac: () -> Int + fun fac = () -> + if(a > 0) then (new OneInt(a - 1)).fac() else 1 +} +(new OneInt(10)).fac() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, fac, None, [], PolyType(List(),Function(Tuple(List()),TypeName(Int)))), NuFunDef(None, fac, None, [], Lam(Tup(), Blk(...))))), App(Sel(Bra(rcd = false, New(Some((TypeName(OneInt),[10,])), TypingUnit())), fac), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class OneInt$1([a: Int,]) { +//│ fun fac = () -> Int +//│ fun fac = () => {if ('(' >((this).a, 0,) ')') then ('(' new OneInt$1([-((this).a, 1,),]) {} ')').fac() else 1} +//│ } +//│ Code(List(('(' new OneInt$1([10,]) {} ')').fac())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$1() +//│ fun fac$OneInt$1(this) = +//│ if >(this.a, #0) then new OneInt$1 (-(this.a, #1)) match {case obj: OneInt$1 => fac$OneInt$1(obj)} else #1 +//│ fun main$$1() = +//│ new OneInt$1 (#10) match {case obj: OneInt$1 => fac$OneInt$1(obj)} +//│ class OneInt$1(a) { +//│ } +//│ class OneInt(a: Int) { +//│ fun fac: () -> Int +//│ } +//│ Int +//│ res +//│ = 1 + +//:mono +//:e // FIXME: Mutable Parameters +//trait AnyFoo { +//} +//class FooPlus(#a): AnyFoo { +// fun bar(b) = a + b +//} +//class FooMinus(#a): AnyFoo { +// fun bar(b) = a - b +//} +//fun f(x) = x.bar(42) +//f(new FooPlus(1)) +//f(new FooMinus(2)) + +:mono +val any = -20 +fun f(x) = + if x > any then 0 + else g(x - 1) +fun g(x) = + if x > any then g(x - 1) + else f(x - 2) +g(1) +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), any, None, [], IntLit(-20)), NuFunDef(None, f, None, [], Lam(Tup(_: Var(x)), Blk(...))), NuFunDef(None, g, None, [], Lam(Tup(_: Var(x)), Blk(...))), App(Var(g), Tup(_: IntLit(1)))) +//│ Lifted: +//│ TypingUnit { +//│ let any$3 = () => -20 +//│ fun f$1 = (x,) => {if (>(x, any,)) then 0 else g$2(-(x, 1,),)} +//│ fun g$2 = (x,) => {if (>(x, any,)) then g$2(-(x, 1,),) else f$1(-(x, 2,),)} +//│ Code(List(g$2(1,))) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$3() +//│ fun any$3() = +//│ #-20 +//│ fun f$1(x) = +//│ if >(x, any) then #0 else g$2(-(x, #1)) +//│ fun g$2(x) = +//│ if >(x, any) then g$2(-(x, #1)) else f$1(-(x, #2)) +//│ fun main$$3() = +//│ g$2(#1) +//│ val any: -20 +//│ fun f: Int -> 0 +//│ fun g: Int -> 0 +//│ 0 +//│ any +//│ = -20 +//│ res +//│ Runtime error: +//│ RangeError: Maximum call stack size exceeded + +:mono +class OneInt(a: Int){ + fun get = () -> a +} +class OneBool(b: Bool){ + fun get = () -> b +} +(if b then new OneInt(1) else new OneBool(true)).get() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, OneInt, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, OneBool, (), Tup(b: Var(Bool)), (), None, None, TypingUnit(NuFunDef(None, get, None, [], Lam(Tup(), Var(b))))), App(Sel(Bra(rcd = false, If(IfThen(Var(b), New(Some((TypeName(OneInt),[1,])), TypingUnit()), Some(New(Some((TypeName(OneBool),[true,])), TypingUnit())))), get), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class OneInt$1([a: Int,]) {fun get = () => (this).a} +//│ class OneBool$2([b: Bool,]) {fun get = () => (this).b} +//│ Code(List(('(' if (b) then new OneInt$1([1,]) {} else new OneBool$2([true,]) {} ')').get())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$2() +//│ fun get$OneInt$1(this) = +//│ this.a +//│ fun get$OneBool$2(this) = +//│ this.b +//│ fun main$$2() = +//│ if b then new OneInt$1 (#1) else new OneBool$2 (true) match {case obj: OneInt$1 => get$OneInt$1(obj); case obj: OneBool$2 => get$OneBool$2(obj)} +//│ class OneInt$1(a) { +//│ } +//│ class OneBool$2(b) { +//│ } +//│ class OneInt(a: Int) { +//│ fun get: () -> Int +//│ } +//│ class OneBool(b: Bool) { +//│ fun get: () -> Bool +//│ } +//│ Int | false | true +//│ res +//│ = true + +:mono +class Bar(x: Int) { + fun foo(x) = x + fun FooMinus(y: Int) = x + y + fun car = foo(2) +} +class Car { + fun da(b: Bar) = b.foo(2) +} +fun baz(b: Bar) = b.foo(2) +let bar = Bar(42) +baz(bar) +(new Car()).da(Bar(1337)) +bar.car +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Bar, (), Tup(x: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(_: Var(x)), Var(x))), NuFunDef(None, FooMinus, None, [], Lam(Tup(y: Var(Int)), App(Var(+), Tup(_: Var(x), _: Var(y))))), NuFunDef(None, car, None, [], App(Var(foo), Tup(_: IntLit(2)))))), NuTypeDef(class, Car, (), Tup(), (), None, None, TypingUnit(NuFunDef(None, da, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))))), NuFunDef(None, baz, None, [], Lam(Tup(b: Var(Bar)), App(Sel(Var(b), foo), Tup(_: IntLit(2))))), NuFunDef(Some(false), bar, None, [], App(Var(Bar), Tup(_: IntLit(42)))), App(Var(baz), Tup(_: Var(bar))), App(Sel(Bra(rcd = false, New(Some((TypeName(Car),[])), TypingUnit())), da), Tup(_: App(Var(Bar), Tup(_: IntLit(1337))))), Sel(Var(bar), car)) +//│ Lifted: +//│ TypingUnit { +//│ class Bar$1([x: Int,]) { +//│ fun foo = (x,) => x +//│ fun FooMinus = (y: Int,) => +((this).x, y,) +//│ fun car = () => (this).foo(2,) +//│ } +//│ class Car$2([]) {fun da = (b: Bar$1,) => (b).foo(2,)} +//│ fun baz$2 = (b: Bar$1,) => (b).foo(2,) +//│ let bar$1 = () => Bar$1(42,) +//│ Code(List(baz$2(bar,))) +//│ Code(List(('(' new Car$2([]) {} ')').da(Bar$1(1337,),))) +//│ Code(List((bar).car)) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ main$$6() +//│ fun bar$1() = +//│ Bar$1(#42) +//│ fun da$Car$2(this, b) = +//│ b match {} +//│ fun main$$6() = +//│ bar.car +//│ fun baz$2(b) = +//│ b match {} +//│ fun main$$5() = +//│ new Car$2 () match {case obj: Car$2 => da$Car$2(obj, Bar$1(#1337))} +//│ fun main$$4() = +//│ baz$2(bar) +//│ class Bar$1(x) { +//│ } +//│ class Car$2() { +//│ } +//│ class Bar(x: Int) { +//│ fun FooMinus: (y: Int) -> Int +//│ fun car: 2 +//│ fun foo: forall 'a. 'a -> 'a +//│ } +//│ class Car { +//│ constructor() +//│ fun da: (b: Bar) -> 2 +//│ } +//│ fun baz: (b: Bar) -> 2 +//│ let bar: Bar +//│ 2 +//│ bar +//│ = Bar {} +//│ res +//│ = 2 +//│ res +//│ = 2 +//│ res +//│ = 2 + +:mono +val c = 5 +class Sup(a: Int){ + virtual fun foo = () -> a +} +class Sub(b: Int) extends Sup(b+b){ +} +class Sub2(c: Int) extends Sub(c+c){ + fun foo = () -> a+c +} +(new Sub(10)).foo() +(new Sub2(c)).foo() +//│ Parsed: +//│ TypingUnit(NuFunDef(Some(false), c, None, [], IntLit(5)), NuTypeDef(class, Sup, (), Tup(a: Var(Int)), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), Var(a))))), NuTypeDef(class, Sub, (), Tup(b: Var(Int)), (App(Var(Sup), Tup(_: App(Var(+), Tup(_: Var(b), _: Var(b)))))), None, None, TypingUnit()), NuTypeDef(class, Sub2, (), Tup(c: Var(Int)), (App(Var(Sub), Tup(_: App(Var(+), Tup(_: Var(c), _: Var(c)))))), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(+), Tup(_: Var(a), _: Var(c))))))), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub),[10,])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(Sub2),[c,])), TypingUnit())), foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Sup$1([a: Int,]) {fun foo = () => (this).a} +//│ class Sub$2([b: Int,]): Sup$1(+((this).b, (this).b,),) {} +//│ class Sub2$3([c: Int,]): Sub$2(+((this).c, (this).c,),) {fun foo = () => +((this).a, (this).c,)} +//│ let c$1 = () => 5 +//│ Code(List(('(' new Sub$2([10,]) {} ')').foo())) +//│ Code(List(('(' new Sub2$3([c,]) {} ')').foo())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$4() +//│ main$$5() +//│ fun c$1() = +//│ #5 +//│ fun main$$5() = +//│ new Sub2$3 (c) match {case obj: Sub2$3 => foo$Sub2$3(obj)} +//│ fun main$$4() = +//│ new Sub$2 (#10) match {case obj: Sub$2 => foo$Sup$1(obj)} +//│ fun foo$Sup$1(this) = +//│ this.a +//│ fun foo$Sub2$3(this) = +//│ +(this.a, this.c) +//│ class Sub2$3(c): Sub$2(+(this.c, this.c)) { +//│ } +//│ class Sup$1(a) { +//│ } +//│ class Sub$2(b): Sup$1(+(this.b, this.b)) { +//│ } +//│ val c: 5 +//│ class Sup(a: Int) { +//│ fun foo: () -> Int +//│ } +//│ class Sub(b: Int) extends Sup { +//│ fun foo: () -> Int +//│ } +//│ class Sub2(c: Int) extends Sub, Sup { +//│ fun foo: () -> Int +//│ } +//│ Int +//│ c +//│ = 5 +//│ res +//│ = 20 +//│ res +//│ = 47 + +:mono +class Foo(f: Int -> Int){ + fun foo = () -> f(1) +} +class F1() extends Foo(x => x+1){} +class F2() extends Foo(x => x+2){} +(new F1()).foo() +(new F2()).foo() +//│ Parsed: +//│ TypingUnit(NuTypeDef(class, Foo, (), Tup(f: App(Var(->), Tup(_: Var(Int), _: Var(Int)))), (), None, None, TypingUnit(NuFunDef(None, foo, None, [], Lam(Tup(), App(Var(f), Tup(_: IntLit(1))))))), NuTypeDef(class, F1, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(1))))))), None, None, TypingUnit()), NuTypeDef(class, F2, (), Tup(), (App(Var(Foo), Tup(_: Lam(Tup(_: Var(x)), App(Var(+), Tup(_: Var(x), _: IntLit(2))))))), None, None, TypingUnit()), App(Sel(Bra(rcd = false, New(Some((TypeName(F1),[])), TypingUnit())), foo), Tup()), App(Sel(Bra(rcd = false, New(Some((TypeName(F2),[])), TypingUnit())), foo), Tup())) +//│ Lifted: +//│ TypingUnit { +//│ class Foo$1([f: ->(Int, Int,),]) {fun foo = () => (this).f(1,)} +//│ class F1$2_Lambda1$1$4([par$F1$2,]) {fun apply = (x,) => +(x, 1,)} +//│ class F1$2([]): Foo$1({new F1$2_Lambda1$1$4([this,]) {}},) {} +//│ class F2$3_Lambda1$2$5([par$F2$3,]) {fun apply = (x,) => +(x, 2,)} +//│ class F2$3([]): Foo$1({new F2$3_Lambda1$2$5([this,]) {}},) {} +//│ Code(List(('(' new F1$2([]) {} ')').foo())) +//│ Code(List(('(' new F2$3([]) {} ')').foo())) +//│ } +//│ Mono: +//│ +//│ Defunc result: +//│ main$$5() +//│ main$$6() +//│ fun apply$F2$3_Lambda1$2$5(this, x) = +//│ +(x, #2) +//│ fun foo$Foo$1(this) = +//│ this match {case obj: Foo$1 => obj.f match {case obj$F2$3_Lambda1$2$5: F2$3_Lambda1$2$5 => apply$F2$3_Lambda1$2$5(obj$F2$3_Lambda1$2$5, #1); case obj$F1$2_Lambda1$1$4: F1$2_Lambda1$1$4 => apply$F1$2_Lambda1$1$4(obj$F1$2_Lambda1$1$4, #1)}} +//│ fun main$$6() = +//│ new F2$3 () match {case obj: F2$3 => foo$Foo$1(obj)} +//│ fun main$$5() = +//│ new F1$2 () match {case obj: F1$2 => foo$Foo$1(obj)} +//│ fun apply$F1$2_Lambda1$1$4(this, x) = +//│ +(x, #1) +//│ class F1$2(): Foo$1(new F1$2_Lambda1$1$4 (this) ) { +//│ } +//│ class F2$3_Lambda1$2$5(par$F2$3) { +//│ } +//│ class F2$3(): Foo$1(new F2$3_Lambda1$2$5 (this) ) { +//│ } +//│ class Foo$1(f) { +//│ } +//│ class F1$2_Lambda1$1$4(par$F1$2) { +//│ } +//│ class Foo(f: Int -> Int) { +//│ fun foo: () -> Int +//│ } +//│ class F1() extends Foo { +//│ fun foo: () -> Int +//│ } +//│ class F2() extends Foo { +//│ fun foo: () -> Int +//│ } +//│ Int +//│ res +//│ = 2 +//│ res +//│ = 3 diff --git a/compiler/shared/test/scala/mlscript/compiler/Test.scala b/compiler/shared/test/scala/mlscript/compiler/Test.scala index df325ec59..e0df0d8f0 100644 --- a/compiler/shared/test/scala/mlscript/compiler/Test.scala +++ b/compiler/shared/test/scala/mlscript/compiler/Test.scala @@ -1,10 +1,14 @@ -package mlscript -package compiler +package mlscript.compiler import mlscript.utils.shorthands.* import scala.util.control.NonFatal import scala.collection.mutable.StringBuilder import mlscript.codegen.Helpers.inspect as showStructure +import mlscript.{DiffTests, ModeType, TypingUnit} +import mlscript.compiler.debug.TreeDebug +import mlscript.compiler.mono.Monomorph +import mlscript.compiler.printer.ExprPrinter +import mlscript.compiler.mono.MonomorphError class DiffTestCompiler extends DiffTests { import DiffTestCompiler.* @@ -16,13 +20,28 @@ class DiffTestCompiler extends DiffTests { outputBuilder ++= "\nLifted:\n" var rstUnit = unit; try - rstUnit = ClassLifter().liftTypingUnit(unit) + rstUnit = ClassLifter(mode.fullExceptionStack).liftTypingUnit(unit) outputBuilder ++= PrettyPrinter.showTypingUnit(rstUnit) catch case NonFatal(err) => outputBuilder ++= "Lifting failed: " ++ err.toString() - if mode.fullExceptionStack then outputBuilder ++= - "\n" ++ err.getStackTrace().map(_.toString()).mkString("\n") + if mode.fullExceptionStack then + outputBuilder ++= "\n" ++ err.getStackTrace().map(_.toString()).mkString("\n") + if(mode.mono){ + outputBuilder ++= "\nMono:\n" + val treeDebug = new TreeDebug() + try{ + val monomorph = new Monomorph(treeDebug) + val monomorphized = monomorph.defunctionalize(rstUnit) + outputBuilder ++= "\nDefunc result: \n" + outputBuilder ++= ExprPrinter.print(monomorphized) + outputBuilder ++= "\n" + }catch{ + case error: MonomorphError => outputBuilder ++= (error.getMessage() :: error.getStackTrace().map(_.toString()).toList).mkString("\n") + // case error: StackOverflowError => outputBuilder ++= (error.getMessage() :: error.getStackTrace().take(40).map(_.toString()).toList).mkString("\n") + } + // outputBuilder ++= treeDebug.getLines.mkString("\n") + } outputBuilder.toString().linesIterator.toList override protected lazy val files = allFiles.filter { file => diff --git a/shared/src/main/scala/mlscript/codegen/Helpers.scala b/shared/src/main/scala/mlscript/codegen/Helpers.scala index 96b411447..2ffcbdcf9 100644 --- a/shared/src/main/scala/mlscript/codegen/Helpers.scala +++ b/shared/src/main/scala/mlscript/codegen/Helpers.scala @@ -49,7 +49,7 @@ object Helpers { val elems = fs.map{case L(l) => s"...${inspect(l)}" case R(Fld(_, r)) => inspect(r)}.mkString(", ") s"Splc($elems)" case If(bod, els) => s"If(${inspect(bod)}, ${els.map(inspect)})" - case New(base, body) => s"New(${base}, ${body})" + case New(base, body) => s"New(${base}, ${inspect(body)})" case TyApp(base, targs) => s"TyApp(${inspect(base)}, ${targs})" case Def(rec, nme, rhs, isByname) => s"Def($rec, $nme, ${rhs.fold(inspect, "" + _)}, $isByname)" diff --git a/shared/src/test/scala/mlscript/DiffTests.scala b/shared/src/test/scala/mlscript/DiffTests.scala index 686694824..07b66ff05 100644 --- a/shared/src/test/scala/mlscript/DiffTests.scala +++ b/shared/src/test/scala/mlscript/DiffTests.scala @@ -39,6 +39,7 @@ abstract class ModeType { def expectCodeGenErrors: Bool def showRepl: Bool def allowEscape: Bool + def mono: Bool } class DiffTests @@ -163,13 +164,14 @@ class DiffTests expectCodeGenErrors: Bool = false, showRepl: Bool = false, allowEscape: Bool = false, + mono: Bool = false, // noProvs: Bool = false, ) extends ModeType { def isDebugging: Bool = dbg || dbgSimplif } val defaultMode = Mode() - var parseOnly = basePath.headOption.contains("parser") || basePath.headOption.contains("compiler") + var parseOnly = basePath.headOption.contains("parser") var allowTypeErrors = false var allowParseErrors = false var showRelativeLineNums = false @@ -260,6 +262,7 @@ class DiffTests case "re" => mode.copy(expectRuntimeErrors = true) case "r" | "showRepl" => mode.copy(showRepl = true) case "escape" => mode.copy(allowEscape = true) + case "mono" => {mode.copy(mono = true)} case "exit" => out.println(exitMarker) ls.dropWhile(_ =:= exitMarker).tails.foreach {