From 7988884ff273276a6acd3e32234347a5a9d1fc26 Mon Sep 17 00:00:00 2001
From: Luyu Cheng <chengluyu@live.cn>
Date: Sat, 30 Dec 2023 02:33:23 +0800
Subject: [PATCH] Fix name duplication in code generation for new definition
 typing

Please `git cherrypick` this to a separate PR.
---
 .../src/main/scala/mlscript/JSBackend.scala   |  2 +-
 .../main/scala/mlscript/codegen/Scope.scala   | 30 +++++---
 .../main/scala/mlscript/codegen/Symbol.scala  | 20 +++++-
 .../diff/codegen/AuxiliaryConstructors.mls    |  8 +--
 .../src/test/diff/codegen/ConstructorStmt.mls | 10 +--
 shared/src/test/diff/codegen/Nested.mls       | 36 +++++-----
 shared/src/test/diff/codegen/New.mls          |  4 +-
 shared/src/test/diff/codegen/NewMatching.mls  |  2 +-
 shared/src/test/diff/codegen/NewMutualRef.mls | 72 +++++++++++++++++++
 shared/src/test/diff/codegen/NuReplHost.mls   |  4 +-
 shared/src/test/diff/codegen/SymbolicOps.mls  | 10 +--
 shared/src/test/diff/mlscript/Sequence.mls    |  2 +-
 shared/src/test/diff/nu/ArrayProg.mls         |  2 +-
 shared/src/test/diff/nu/CtorSubtraction.mls   |  4 +-
 shared/src/test/diff/nu/FlatIndentFuns.mls    |  4 +-
 shared/src/test/diff/nu/FlatMonads_repro.mls  |  2 +-
 shared/src/test/diff/nu/HeungTung.mls         |  2 +-
 shared/src/test/diff/nu/LamPatterns.mls       |  4 +-
 shared/src/test/diff/nu/LocalLets.mls         |  2 +-
 shared/src/test/diff/nu/MIscPoly.mls          |  2 +-
 shared/src/test/diff/nu/Misc.mls              | 14 ++--
 shared/src/test/diff/nu/NamedArgs.mls         | 10 +--
 shared/src/test/diff/nu/NestedRecords.mls     |  2 +-
 shared/src/test/diff/nu/NewNew.mls            |  2 +-
 shared/src/test/diff/nu/Res.mls               |  2 +-
 shared/src/test/diff/nu/Vals.mls              |  2 +-
 26 files changed, 177 insertions(+), 77 deletions(-)
 create mode 100644 shared/src/test/diff/codegen/NewMutualRef.mls

diff --git a/shared/src/main/scala/mlscript/JSBackend.scala b/shared/src/main/scala/mlscript/JSBackend.scala
index 9c8b3d34fd..ddca1a2799 100644
--- a/shared/src/main/scala/mlscript/JSBackend.scala
+++ b/shared/src/main/scala/mlscript/JSBackend.scala
@@ -1407,7 +1407,7 @@ abstract class JSTestBackend extends JSBackend(allowUnresolvedSymbols = false) {
         val isByvalueRecIn = if (isByname) None else Some(true)
         val bodyIsLam = body match { case _: Lam => true case _ => false }
         val symb = symNme.map(_.name)
-        scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb)
+        scope.declareValue(nme, isByvalueRecIn, bodyIsLam, symb, true)
       case _ => ()
     }
     
diff --git a/shared/src/main/scala/mlscript/codegen/Scope.scala b/shared/src/main/scala/mlscript/codegen/Scope.scala
index 80afdc3111..68c442ca87 100644
--- a/shared/src/main/scala/mlscript/codegen/Scope.scala
+++ b/shared/src/main/scala/mlscript/codegen/Scope.scala
@@ -313,18 +313,26 @@ class Scope(val name: Str, enclosing: Opt[Scope]) {
     symbol
   }
 
-  def declareValue(lexicalName: Str, isByvalueRec: Option[Boolean], isLam: Boolean, symbolicName: Opt[Str]): ValueSymbol = {
+  def declareValue(
+      lexicalName: Str,
+      isByvalueRec: Option[Boolean],
+      isLam: Boolean,
+      symbolicName: Opt[Str],
+      /** Workaround for the first pass traversal with new definition typing. */
+      forNewDefsDryRun: Bool = false
+  ): ValueSymbol = {
     val runtimeName = lexicalValueSymbols.get(lexicalName) match {
       // If we are implementing a stub symbol and the stub symbol did not shadow any other
       // symbols, it is safe to reuse its `runtimeName`.
-      case S(sym: StubValueSymbol) if !sym.shadowing => sym.runtimeName
-      case S(sym: BuiltinSymbol) if !sym.accessed    => sym.runtimeName
-      case _                                         => allocateRuntimeName(lexicalName)
+      case S(sym: StubValueSymbol) if !sym.shadowing   => sym.runtimeName
+      case S(sym: ValueSymbol) if sym.forNewDefsDryRun => sym.runtimeName
+      case S(sym: BuiltinSymbol) if !sym.accessed      => sym.runtimeName
+      case _                                           => allocateRuntimeName(lexicalName)
     }
-    val symbol = ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam)
+    val symbol = ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun)
     register(symbol)
     symbolicName.foreach { symbolicName =>
-      register(ValueSymbol(symbolicName, runtimeName, isByvalueRec, isLam))
+      register(ValueSymbol(symbolicName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun))
     }
     symbol
   }
@@ -350,10 +358,16 @@ class Scope(val name: Str, enclosing: Opt[Scope]) {
       allowEscape: Bool
   ): StubValueSymbol = {
     val symbol = lexicalValueSymbols.get(lexicalName) match {
+      // If the existing symbol is a value symbol, but the value symbol is
+      // declared in the dry-run of new definition typing, we can reuse the
+      // runtime name.
+      case S(valueSymbol: ValueSymbol) if valueSymbol.forNewDefsDryRun =>
+        StubValueSymbol(lexicalName, valueSymbol.runtimeName, false, previous)
       // If a stub with the same name has been defined, use the name.
-      case S(value) => StubValueSymbol(lexicalName, value.runtimeName, true, previous)
+      case S(symbol) => StubValueSymbol(lexicalName, symbol.runtimeName, true, previous)
       // Otherwise, we will allocate a new name.
-      case N => StubValueSymbol(lexicalName, allocateRuntimeName(lexicalName), false, previous)
+      case N =>
+        StubValueSymbol(lexicalName, allocateRuntimeName(lexicalName), false, previous)
     }
     register(symbol)
     symbolicName.foreach { symbolicName =>
diff --git a/shared/src/main/scala/mlscript/codegen/Symbol.scala b/shared/src/main/scala/mlscript/codegen/Symbol.scala
index 2d844d2f70..85474c8f78 100644
--- a/shared/src/main/scala/mlscript/codegen/Symbol.scala
+++ b/shared/src/main/scala/mlscript/codegen/Symbol.scala
@@ -45,13 +45,27 @@ sealed trait NuTypeSymbol { sym: TypeSymbol =>
   def isNested: Bool = qualifier.isDefined // is nested in another class/mixin/module
 }
 
-sealed class ValueSymbol(val lexicalName: Str, val runtimeName: Str, val isByvalueRec: Option[Boolean], val isLam: Boolean) extends RuntimeSymbol {
+sealed class ValueSymbol(
+    val lexicalName: Str,
+    val runtimeName: Str,
+    val isByvalueRec: Option[Boolean],
+    val isLam: Boolean,
+    /** Workaround for the first pass traversal with new definition typing. */
+    val forNewDefsDryRun: Boolean
+) extends RuntimeSymbol {
   override def toString: Str = s"value $lexicalName"
 }
 
 object ValueSymbol {
-  def apply(lexicalName: Str, runtimeName: Str, isByvalueRec: Option[Boolean], isLam: Boolean): ValueSymbol =
-    new ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam)
+  def apply(
+      lexicalName: Str,
+      runtimeName: Str,
+      isByvalueRec: Option[Boolean],
+      isLam: Boolean,
+      /** Workaround for the first pass traversal with new definition typing. */
+      forNewDefsDryRun: Boolean = false
+  ): ValueSymbol =
+    new ValueSymbol(lexicalName, runtimeName, isByvalueRec, isLam, forNewDefsDryRun)
 }
 
 sealed case class TypeAliasSymbol(
diff --git a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls
index 5c729795cb..3fd393ed25 100644
--- a/shared/src/test/diff/codegen/AuxiliaryConstructors.mls
+++ b/shared/src/test/diff/codegen/AuxiliaryConstructors.mls
@@ -464,11 +464,11 @@ n.ll
 //│ class TypingUnit19 {}
 //│ const typing_unit19 = new TypingUnit19;
 //│ // Query 1
-//│ globalThis.m1 = g(1);
+//│ globalThis.m = g(1);
 //│ // Query 2
-//│ globalThis.n1 = m1(2);
+//│ globalThis.n = m(2);
 //│ // Query 3
-//│ res = n1.ll;
+//│ res = n.ll;
 //│ // End of generated code
 //│ m
 //│   = [Function (anonymous)]
@@ -487,7 +487,7 @@ let mm = new M()
 //│ class TypingUnit21 {}
 //│ const typing_unit21 = new TypingUnit21;
 //│ // Query 1
-//│ globalThis.mm1 = new M.class();
+//│ globalThis.mm = new M.class();
 //│ // End of generated code
 //│ mm
 //│    = M {}
diff --git a/shared/src/test/diff/codegen/ConstructorStmt.mls b/shared/src/test/diff/codegen/ConstructorStmt.mls
index 4f769b8f32..a61301347e 100644
--- a/shared/src/test/diff/codegen/ConstructorStmt.mls
+++ b/shared/src/test/diff/codegen/ConstructorStmt.mls
@@ -105,7 +105,7 @@ let aa = A(42)
 //│ class TypingUnit5 {}
 //│ const typing_unit5 = new TypingUnit5;
 //│ // Query 1
-//│ globalThis.aa1 = A(42);
+//│ globalThis.aa = A(42);
 //│ // End of generated code
 //│ aa
 //│    = A {}
@@ -119,7 +119,7 @@ aa
 //│ class TypingUnit6 {}
 //│ const typing_unit6 = new TypingUnit6;
 //│ // Query 1
-//│ res = aa1;
+//│ res = aa;
 //│ // End of generated code
 //│ res
 //│     = A {}
@@ -131,7 +131,7 @@ let ab = A(0)
 //│ class TypingUnit7 {}
 //│ const typing_unit7 = new TypingUnit7;
 //│ // Query 1
-//│ globalThis.ab1 = A(0);
+//│ globalThis.ab = A(0);
 //│ // End of generated code
 //│ ab
 //│    = A {}
@@ -408,9 +408,9 @@ www.add(42)
 //│ class TypingUnit15 {}
 //│ const typing_unit15 = new TypingUnit15;
 //│ // Query 1
-//│ globalThis.www1 = W();
+//│ globalThis.www = W();
 //│ // Query 2
-//│ res = www1.add(42);
+//│ res = www.add(42);
 //│ // End of generated code
 //│ www
 //│     = W {}
diff --git a/shared/src/test/diff/codegen/Nested.mls b/shared/src/test/diff/codegen/Nested.mls
index 227d0c7a2d..10843c74aa 100644
--- a/shared/src/test/diff/codegen/Nested.mls
+++ b/shared/src/test/diff/codegen/Nested.mls
@@ -78,9 +78,9 @@ bb.b
 //│ class TypingUnit1 {}
 //│ const typing_unit1 = new TypingUnit1;
 //│ // Query 1
-//│ globalThis.bb1 = A.B(A.a);
+//│ globalThis.bb = A.B(A.a);
 //│ // Query 2
-//│ res = bb1.b;
+//│ res = bb.b;
 //│ // End of generated code
 //│ bb
 //│    = B {}
@@ -241,9 +241,9 @@ ee.x
 //│ class TypingUnit5 {}
 //│ const typing_unit5 = new TypingUnit5;
 //│ // Query 1
-//│ globalThis.ee1 = D.createE(42);
+//│ globalThis.ee = D.createE(42);
 //│ // Query 2
-//│ res = ee1.x;
+//│ res = ee.x;
 //│ // End of generated code
 //│ ee
 //│    = E {}
@@ -361,13 +361,13 @@ gg.sum
 //│ class TypingUnit7 {}
 //│ const typing_unit7 = new TypingUnit7;
 //│ // Query 1
-//│ globalThis.es1 = E(1);
+//│ globalThis.es = E(1);
 //│ // Query 2
-//│ globalThis.fff1 = es1.F(2);
+//│ globalThis.fff = es.F(2);
 //│ // Query 3
-//│ globalThis.gg1 = fff1.G(3);
+//│ globalThis.gg = fff.G(3);
 //│ // Query 4
-//│ res = gg1.sum;
+//│ res = gg.sum;
 //│ // End of generated code
 //│ es
 //│    = E {}
@@ -559,11 +559,11 @@ i.x
 //│ class TypingUnit10 {}
 //│ const typing_unit10 = new TypingUnit10;
 //│ // Query 1
-//│ globalThis.jj1 = G.H.J(42);
+//│ globalThis.jj = G.H.J(42);
 //│ // Query 2
-//│ globalThis.i1 = jj1.ii(2);
+//│ globalThis.i = jj.ii(2);
 //│ // Query 3
-//│ res = i1.x;
+//│ res = i.x;
 //│ // End of generated code
 //│ jj
 //│    = J {}
@@ -666,9 +666,9 @@ j.i.x
 //│ class TypingUnit12 {}
 //│ const typing_unit12 = new TypingUnit12;
 //│ // Query 1
-//│ globalThis.j1 = H.J(42);
+//│ globalThis.j = H.J(42);
 //│ // Query 2
-//│ res = j1.i.x;
+//│ res = j.i.x;
 //│ // End of generated code
 //│ j
 //│   = J {}
@@ -757,11 +757,11 @@ ij.incY
 //│ const typing_unit13 = new TypingUnit13;
 //│ globalThis.I = typing_unit13.I;
 //│ // Query 1
-//│ globalThis.i3 = I(1);
+//│ globalThis.i1 = I(1);
 //│ // Query 2
-//│ globalThis.ij1 = i3.J(0);
+//│ globalThis.ij = i1.J(0);
 //│ // Query 3
-//│ res = ij1.incY;
+//│ res = ij.incY;
 //│ // End of generated code
 //│ i
 //│   = I {}
@@ -890,9 +890,9 @@ let n = J.N(2)
 //│ class TypingUnit15 {}
 //│ const typing_unit15 = new TypingUnit15;
 //│ // Query 1
-//│ globalThis.m1 = J.M();
+//│ globalThis.m = J.M();
 //│ // Query 2
-//│ globalThis.n1 = J.N(2);
+//│ globalThis.n = J.N(2);
 //│ // End of generated code
 //│ m
 //│   = M {}
diff --git a/shared/src/test/diff/codegen/New.mls b/shared/src/test/diff/codegen/New.mls
index 8636a83c8b..9909f20df2 100644
--- a/shared/src/test/diff/codegen/New.mls
+++ b/shared/src/test/diff/codegen/New.mls
@@ -46,7 +46,7 @@ let c = C
 //│ class TypingUnit3 {}
 //│ const typing_unit3 = new TypingUnit3;
 //│ // Query 1
-//│ globalThis.c1 = C;
+//│ globalThis.c = C;
 //│ // End of generated code
 //│ c
 //│   = [class C]
@@ -93,7 +93,7 @@ let c = C
 //│ class TypingUnit8 {}
 //│ const typing_unit8 = new TypingUnit8;
 //│ // Query 1
-//│ globalThis.c3 = C;
+//│ globalThis.c1 = C;
 //│ // End of generated code
 //│ c
 //│   = [Function (anonymous)] {
diff --git a/shared/src/test/diff/codegen/NewMatching.mls b/shared/src/test/diff/codegen/NewMatching.mls
index acdef0ef4a..50d2dbc1da 100644
--- a/shared/src/test/diff/codegen/NewMatching.mls
+++ b/shared/src/test/diff/codegen/NewMatching.mls
@@ -136,7 +136,7 @@ fun foo(s) =
 //│ // Query 1
 //│ globalThis.foo = function foo(s) {
 //│   return ((() => {
-//│     return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s21.value))(Some.unapply(s)) : 0;
+//│     return s instanceof Some.class ? (([t]) => ((b) => b + t.x)(s2.value))(Some.unapply(s)) : 0;
 //│   })());
 //│ };
 //│ // End of generated code
diff --git a/shared/src/test/diff/codegen/NewMutualRef.mls b/shared/src/test/diff/codegen/NewMutualRef.mls
new file mode 100644
index 0000000000..162a4f96f0
--- /dev/null
+++ b/shared/src/test/diff/codegen/NewMutualRef.mls
@@ -0,0 +1,72 @@
+:NewDefs
+
+:js
+fun foo: Int -> Int
+fun foo = x => x + 1 // <- This will be added as a value symbol before translating `Bar`.
+class Bar {
+  fun calc(x) = foo(x)
+}
+//│ fun foo: Int -> Int
+//│ class Bar {
+//│   constructor()
+//│   fun calc: Int -> Int
+//│ }
+//│ fun foo: Int -> Int
+//│ // Prelude
+//│ let res;
+//│ class TypingUnit {
+//│   #Bar;
+//│   constructor() {
+//│   }
+//│   get Bar() {
+//│     const qualifier = this;
+//│     if (this.#Bar === undefined) {
+//│       class Bar {
+//│         constructor() {
+//│         }
+//│         calc(x) {
+//│           return foo(x);
+//│         }
+//│       };
+//│       this.#Bar = Bar;
+//│     }
+//│     return this.#Bar;
+//│   }
+//│ }
+//│ const typing_unit = new TypingUnit;
+//│ globalThis.Bar = typing_unit.Bar;
+//│ // Query 1 is empty
+//│ // Query 2
+//│ globalThis.foo = function foo(x) {
+//│   return x + 1;
+//│ };
+//│ // End of generated code
+
+// Note: This test case looks trivial but it was like:
+//
+// ```
+// :re
+// (new Bar()).calc(0)
+// //│ Int
+// //│ res
+// //│ Runtime error:
+// //│   ReferenceError: foo is not defined
+// ```
+//
+// My fix is a little bit hacky. The root of the problem is: when generating
+// code within a class, we need all top-level bindings to be accessible. This
+// part of implementation of new-definition-typing chose to declare all term
+// `NuFunDef` as `ValueSymbol` in advance, but this can lead to the fact that
+// the same symbol is declared multiple times, thus wasting some runtime names.
+// Consequently, the code that references these wasted runtime names are invalid.
+// 
+// Actually, I have a better solution, but it requires adjusting the order of
+// translation, and I don't have much time to spend on this at the moment. So,
+// my current fix is rather hacky. But I will complete this part after `PreTyper`
+// is finished, when I replacing the old Scope with the new Scope.
+//
+//                                                      Luyu Cheng on 2023/12/30
+(new Bar()).calc(0)
+//│ Int
+//│ res
+//│     = 1
diff --git a/shared/src/test/diff/codegen/NuReplHost.mls b/shared/src/test/diff/codegen/NuReplHost.mls
index c5aaf4563f..d4805d1c82 100644
--- a/shared/src/test/diff/codegen/NuReplHost.mls
+++ b/shared/src/test/diff/codegen/NuReplHost.mls
@@ -33,7 +33,7 @@ let r = foo(1)
 //│ └─┬ Query 2/2
 //│   ├── Prelude: <empty>
 //│   ├── Code:
-//│   ├──   globalThis.r1 = foo(1);
+//│   ├──   globalThis.r = foo(1);
 //│   └── Reply: [runtime error] Error: an error was thrown
 //│ r
 //│ Runtime error:
@@ -44,7 +44,7 @@ r
 //│ nothing
 //│ res
 //│ Runtime error:
-//│   ReferenceError: r1 is not defined
+//│   ReferenceError: r is not defined
 
 
 
diff --git a/shared/src/test/diff/codegen/SymbolicOps.mls b/shared/src/test/diff/codegen/SymbolicOps.mls
index 37e42ce6a0..9dd61cb78a 100644
--- a/shared/src/test/diff/codegen/SymbolicOps.mls
+++ b/shared/src/test/diff/codegen/SymbolicOps.mls
@@ -14,7 +14,7 @@ let r = succ >> succ
 //│ class TypingUnit1 {}
 //│ const typing_unit1 = new TypingUnit1;
 //│ // Query 1
-//│ globalThis.r1 = compose(succ, succ);
+//│ globalThis.r = compose(succ, succ);
 //│ // End of generated code
 //│ r
 //│   = [Function (anonymous)]
@@ -65,7 +65,7 @@ let f = (>>)
 //│ class TypingUnit7 {}
 //│ const typing_unit7 = new TypingUnit7;
 //│ // Query 1
-//│ globalThis.f1 = compose;
+//│ globalThis.f = compose;
 //│ // End of generated code
 //│ f
 //│   = [Function: compose]
@@ -315,7 +315,7 @@ fun (:-D) dd(a, b) = a + b
 val (->) f(x, y) = [x, y]
 //│ val (->) f: forall 'a 'b. ('a, 'b) -> ['a, 'b]
 //│ f
-//│   = [Function: f3]
+//│   = [Function: f1]
 
 12 -> 34
 //│ [12, 34]
@@ -326,7 +326,7 @@ val (->) f(x, y) = [x, y]
 let (->) _ = f
 //│ let (->) _: forall 'a 'b. ('a, 'b) -> ['a, 'b]
 //│ _
-//│   = [Function: f3]
+//│   = [Function: f1]
 
 :js
 12 -> 34
@@ -335,7 +335,7 @@ let (->) _ = f
 //│ class TypingUnit42 {}
 //│ const typing_unit42 = new TypingUnit42;
 //│ // Query 1
-//│ res = _1(12, 34);
+//│ res = _(12, 34);
 //│ // End of generated code
 //│ res
 //│     = [ 12, 34 ]
diff --git a/shared/src/test/diff/mlscript/Sequence.mls b/shared/src/test/diff/mlscript/Sequence.mls
index 6c52dff4ca..919c7251b1 100644
--- a/shared/src/test/diff/mlscript/Sequence.mls
+++ b/shared/src/test/diff/mlscript/Sequence.mls
@@ -4,7 +4,7 @@
 let test(x) = log(x); x + 1
 //│ let test: Int -> Int
 //│ test
-//│      = [Function: test1]
+//│      = [Function: test]
 
 test(log("here we go"); 123)
 //│ Int
diff --git a/shared/src/test/diff/nu/ArrayProg.mls b/shared/src/test/diff/nu/ArrayProg.mls
index b33cb35fab..857ee4e3ac 100644
--- a/shared/src/test/diff/nu/ArrayProg.mls
+++ b/shared/src/test/diff/nu/ArrayProg.mls
@@ -40,7 +40,7 @@ fun zip(xs, ys) = mapi of xs, (x, i) =>
 zip
 //│ forall 'a 'b. (Array['a], Array[Object & 'b & ~()]) -> Array[['a, 'b]]
 //│ res
-//│     = [Function: zip1]
+//│     = [Function: zip]
 
 
 
diff --git a/shared/src/test/diff/nu/CtorSubtraction.mls b/shared/src/test/diff/nu/CtorSubtraction.mls
index 38d37eaaac..9a58ce6842 100644
--- a/shared/src/test/diff/nu/CtorSubtraction.mls
+++ b/shared/src/test/diff/nu/CtorSubtraction.mls
@@ -16,12 +16,12 @@ fun x = case
 x : Int -> Int
 //│ Int -> Int
 //│ res
-//│     = [Function: x1]
+//│     = [Function: x]
 
 x : Cls -> nothing
 //│ Cls -> nothing
 //│ res
-//│     = [Function: x1]
+//│     = [Function: x]
 
 
 fun x: (Int | Str | Cls) \ Cls
diff --git a/shared/src/test/diff/nu/FlatIndentFuns.mls b/shared/src/test/diff/nu/FlatIndentFuns.mls
index 77ace9e704..3a58afdd03 100644
--- a/shared/src/test/diff/nu/FlatIndentFuns.mls
+++ b/shared/src/test/diff/nu/FlatIndentFuns.mls
@@ -20,7 +20,7 @@ y =>
 x + y
 //│ let r: Int -> Int -> Int
 //│ r
-//│   = [Function: r1]
+//│   = [Function: r]
 
 r(1)(2)
 //│ Int
@@ -59,6 +59,6 @@ x + y
 //│ ╙──      	
 //│ let r: Int -> Int -> Int
 //│ r
-//│   = [Function: r3]
+//│   = [Function: r1]
 
 
diff --git a/shared/src/test/diff/nu/FlatMonads_repro.mls b/shared/src/test/diff/nu/FlatMonads_repro.mls
index 1fe5bef9a8..938516f499 100644
--- a/shared/src/test/diff/nu/FlatMonads_repro.mls
+++ b/shared/src/test/diff/nu/FlatMonads_repro.mls
@@ -48,7 +48,7 @@ let ri(f) = Bind(Pure(42), f)
 //│   where
 //│     'CC :> 42
 //│ ri
-//│    = [Function: ri1]
+//│    = [Function: ri]
 
 ri(Pure)
 //│ Bind['CC, 'AA]
diff --git a/shared/src/test/diff/nu/HeungTung.mls b/shared/src/test/diff/nu/HeungTung.mls
index 264a541703..51f4efad8b 100644
--- a/shared/src/test/diff/nu/HeungTung.mls
+++ b/shared/src/test/diff/nu/HeungTung.mls
@@ -202,7 +202,7 @@ type Res = M(T)
 let f = x => [x, x]
 //│ let f: forall 'a. 'a -> ['a, 'a]
 //│ f
-//│   = [Function: f3]
+//│   = [Function: f1]
 
 [f(1), f(true)]
 //│ [[1, 1], [true, true]]
diff --git a/shared/src/test/diff/nu/LamPatterns.mls b/shared/src/test/diff/nu/LamPatterns.mls
index cb78cf3498..58aa85eb8e 100644
--- a/shared/src/test/diff/nu/LamPatterns.mls
+++ b/shared/src/test/diff/nu/LamPatterns.mls
@@ -24,12 +24,12 @@ let f = Some => 0
 //│ class TypingUnit2 {}
 //│ const typing_unit2 = new TypingUnit2;
 //│ // Query 1
-//│ globalThis.f1 = function f1(Some) {
+//│ globalThis.f = function f(Some) {
 //│   return 0;
 //│ };
 //│ // End of generated code
 //│ f
-//│   = [Function: f1]
+//│   = [Function: f]
 
 // :e // TODO
 f(Some)
diff --git a/shared/src/test/diff/nu/LocalLets.mls b/shared/src/test/diff/nu/LocalLets.mls
index 15717f5ded..211987ae06 100644
--- a/shared/src/test/diff/nu/LocalLets.mls
+++ b/shared/src/test/diff/nu/LocalLets.mls
@@ -32,6 +32,6 @@ let E(x) = new E(1)
 //│ ╙──      	               ^
 //│ let E: anything -> error
 //│ E
-//│   = [Function: E2]
+//│   = [Function: E1]
 
 
diff --git a/shared/src/test/diff/nu/MIscPoly.mls b/shared/src/test/diff/nu/MIscPoly.mls
index 34235988a1..3d9c94a5af 100644
--- a/shared/src/test/diff/nu/MIscPoly.mls
+++ b/shared/src/test/diff/nu/MIscPoly.mls
@@ -69,7 +69,7 @@ r()
 //│ nothing
 //│ res
 //│ Runtime error:
-//│   TypeError: r1 is not a function
+//│   TypeError: r is not a function
 
 
 
diff --git a/shared/src/test/diff/nu/Misc.mls b/shared/src/test/diff/nu/Misc.mls
index a0aa87e20c..821a12d2c7 100644
--- a/shared/src/test/diff/nu/Misc.mls
+++ b/shared/src/test/diff/nu/Misc.mls
@@ -65,7 +65,7 @@ f of [1, 2]
 let f = (x, y) => x + y
 //│ let f: (Int, Int) -> Int
 //│ f
-//│   = [Function: f5]
+//│   = [Function: f4]
 
 f(1, 2)
 //│ Int
@@ -96,7 +96,7 @@ let f = ((x, y)) => x + y
 //│ ╙──      	         ^^^^^^
 //│ let f: ([Int, Int]) -> Int
 //│ f
-//│   = [Function: f7]
+//│   = [Function: f5]
 
 :e
 f(1, 2)
@@ -132,7 +132,7 @@ f[1, 2]
 //│ ╙──       	^^^^^^^
 //│ ([Int, Int]) -> Int
 //│ res
-//│     = [Function: f7]
+//│     = [Function: f5]
 
 
 :pe
@@ -142,14 +142,14 @@ let f = (((x, y))) => x + y
 //│ ╙──       	          ^^^^^^
 //│ let f: ([Int, Int]) -> Int
 //│ f
-//│   = [Function: f9]
+//│   = [Function: f6]
 
 
 // * TODO maybe parse as type lambda?
 let f = [x, y] => x + y
 //│ let f: ([Int, Int]) -> Int
 //│ f
-//│   = [Function: f11]
+//│   = [Function: f7]
 
 :e
 f(1, 2)
@@ -173,7 +173,7 @@ f([1, 2])
 let f = ([x, y]) => x + y
 //│ let f: ([Int, Int]) -> Int
 //│ f
-//│   = [Function: f13]
+//│   = [Function: f8]
 
 f([1, 2])
 //│ Int
@@ -197,7 +197,7 @@ f(1, 2)
 let f = [[[x, y]]] => x + y
 //│ let f: ([[[Int, Int]]]) -> Int
 //│ f
-//│   = [Function: f15]
+//│   = [Function: f9]
 
 :e
 f([[1, 2]])
diff --git a/shared/src/test/diff/nu/NamedArgs.mls b/shared/src/test/diff/nu/NamedArgs.mls
index c846ee548b..8c4d4606f1 100644
--- a/shared/src/test/diff/nu/NamedArgs.mls
+++ b/shared/src/test/diff/nu/NamedArgs.mls
@@ -116,9 +116,9 @@ test(0, y: 200)
 //│ class TypingUnit13 {}
 //│ const typing_unit13 = new TypingUnit13;
 //│ // Query 1
-//│ globalThis.tmp1 = 2;
+//│ globalThis.tmp = 2;
 //│ // Query 2
-//│ res = test1(0, tmp1);
+//│ res = test1(0, tmp);
 //│ // Query 3
 //│ res = test1(0, 200);
 //│ // End of generated code
@@ -171,11 +171,11 @@ fff(y: 2, z: y_1 + 1, x: z_1 - 2)
 //│ class TypingUnit17 {}
 //│ const typing_unit17 = new TypingUnit17;
 //│ // Query 1
-//│ globalThis["y_11"] = 2;
+//│ globalThis["y_1"] = 2;
 //│ // Query 2
-//│ globalThis["z_11"] = 3;
+//│ globalThis["z_1"] = 3;
 //│ // Query 3
-//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_11 - 2))(y_11 + 1);
+//│ res = ((z_2) => ((x_1) => fff(x_1, 2, z_2))(z_1 - 2))(y_1 + 1);
 //│ // End of generated code
 //│ y_1
 //│     = 2
diff --git a/shared/src/test/diff/nu/NestedRecords.mls b/shared/src/test/diff/nu/NestedRecords.mls
index ca216f4788..ebe7bbcbd6 100644
--- a/shared/src/test/diff/nu/NestedRecords.mls
+++ b/shared/src/test/diff/nu/NestedRecords.mls
@@ -4,7 +4,7 @@
 let f(x) = [x, x]
 //│ let f: forall 'a. 'a -> ['a, 'a]
 //│ f
-//│   = [Function: f1]
+//│   = [Function: f]
 
 let a = { u: f(f(f(1))), v: f(f(f(1))) }
 //│ let a: {u: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]], v: [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]}
diff --git a/shared/src/test/diff/nu/NewNew.mls b/shared/src/test/diff/nu/NewNew.mls
index 8ab334a692..c135ca38a9 100644
--- a/shared/src/test/diff/nu/NewNew.mls
+++ b/shared/src/test/diff/nu/NewNew.mls
@@ -103,7 +103,7 @@ f(1)
 //│ error
 //│ res
 //│ Runtime error:
-//│   TypeError: f9 is not a function
+//│   TypeError: f4 is not a function
 
 :e
 new Foo("2")
diff --git a/shared/src/test/diff/nu/Res.mls b/shared/src/test/diff/nu/Res.mls
index e8936ec349..0f7f660b69 100644
--- a/shared/src/test/diff/nu/Res.mls
+++ b/shared/src/test/diff/nu/Res.mls
@@ -19,7 +19,7 @@ res(1)
 let res = x => x + 2
 //│ let res: Int -> Int
 //│ res
-//│     = [Function: res2]
+//│     = [Function: res1]
 
 res(1)
 //│ Int
diff --git a/shared/src/test/diff/nu/Vals.mls b/shared/src/test/diff/nu/Vals.mls
index e90080f1b9..413b7a8498 100644
--- a/shared/src/test/diff/nu/Vals.mls
+++ b/shared/src/test/diff/nu/Vals.mls
@@ -32,7 +32,7 @@ val a = a
 val f(x) = x
 //│ val f: forall 'a. 'a -> 'a
 //│ f
-//│   = [Function: f1]
+//│   = [Function: f]
 
 f(123)
 //│ 123