Skip to content

Commit c8fff6c

Browse files
CopilotLPTK
authored andcommitted
Fix nondeterministic private field ordering in Lifter
The private fields generated by the lifter had nondeterministic ordering because they were built by iterating over Map values derived from Set operations. Scala's Set and Map do not guarantee stable iteration order. The fix uses sorted ordered lists (passedSymsOrdered, capturesOrdered, passedDefnsOrdered, and new liftedObjsOrdered) to look up map values in a deterministic order based on symbol UIDs, instead of iterating map values directly. Agent-Logs-Url: https://github.com/LPTK/mlscript/sessions/07ac81ed-dfff-467c-af13-4a25818d2faa
1 parent bb1f894 commit c8fff6c

2 files changed

Lines changed: 11 additions & 7 deletions

File tree

hkmc2/shared/src/main/scala/hkmc2/codegen/Lifter.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
792792
protected val liftedObjsSyms: Map[InnerSymbol, VarSymbol] = node.liftedObjSyms.map: s =>
793793
s -> VarSymbol(Tree.Ident(s.nme + "$"))
794794
.toMap
795+
protected val liftedObjsOrdered: List[InnerSymbol] = node.liftedObjSyms.toList.sortBy(_.uid)
795796
override lazy val liftedObjsMap: Map[InnerSymbol, LocalPath] = liftedObjsSyms.map:
796797
case k -> v => k -> v.asLocalPath
797798

@@ -806,6 +807,7 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
806807
protected val liftedObjsSyms: Map[InnerSymbol, TermSymbol] = node.liftedObjSyms.map: s =>
807808
s -> TermSymbol(syntax.ImmutVal, S(sym), Tree.Ident(s.nme + "$"))
808809
.toMap
810+
protected val liftedObjsOrdered: List[InnerSymbol] = node.liftedObjSyms.toList.sortBy(_.uid)
809811
override lazy val liftedObjsMap: Map[InnerSymbol, LocalPath] = liftedObjsSyms.map:
810812
case k -> v => k -> v.asLocalPath
811813
protected def rewriteMethods(node: ScopeNode, methods: List[FunDefn])(using ctx: LifterCtxNew) =
@@ -879,7 +881,7 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
879881
val newCls = obj.cls.copy(
880882
ctor = ctorWithCap,
881883
preCtor = rewrittenPrector,
882-
privateFields = captureSym :: liftedObjsSyms.values.toList ::: obj.cls.privateFields,
884+
privateFields = captureSym :: liftedObjsOrdered.map(liftedObjsSyms) ::: obj.cls.privateFields,
883885
methods = newMtds,
884886
)(obj.cls.configOverride)
885887
LifterResult(newCls, rewriterCtor.extraDefns.toList ::: rewriterPreCtor.extraDefns.toList ::: extras)
@@ -898,7 +900,7 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
898900
val LifterResult(newMtds, extras) = rewriteMethods(node, obj.clsBody.methods)
899901
val newComp = obj.clsBody.copy(
900902
ctor = ctorWithCap,
901-
privateFields = captureSym :: liftedObjsSyms.values.toList ::: obj.clsBody.privateFields,
903+
privateFields = captureSym :: liftedObjsOrdered.map(liftedObjsSyms) ::: obj.clsBody.privateFields,
902904
methods = newMtds
903905
)
904906
LifterResult(newComp, rewriterCtor.extraDefns.toList ::: extras)
@@ -1040,9 +1042,11 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
10401042
)
10411043
.toMap
10421044

1043-
private val extraPrivSyms =
1044-
liftedObjsSyms.values ++ passedSymsMap_.values.map(_.ts)
1045-
++ capSymsMap_.values.map(_.ts) ++ defnSymsMap_.values.map(_.ts)
1045+
private lazy val extraPrivSyms: List[TermSymbol] =
1046+
liftedObjsOrdered.map(liftedObjsSyms)
1047+
::: passedDefnsOrdered.map(defnSymsMap_(_).ts)
1048+
::: capturesOrdered.map(capSymsMap_(_).ts)
1049+
::: passedSymsOrdered.map(passedSymsMap_(_).ts)
10461050

10471051
override lazy val capturesOrdered: List[ScopedInfo] = reqCaptures.toList.sortBy(c => capSymsMap_(c).vs.uid)
10481052

@@ -1173,7 +1177,7 @@ class Lifter(topLevelBlk: Block)(using State, Raise, Config):
11731177
k = syntax.Cls, // turn objects into classes
11741178
ctor = ctorWithDefns,
11751179
preCtor = rewrittenPrector,
1176-
privateFields = captureSym :: extraPrivSyms.toList ::: obj.cls.privateFields,
1180+
privateFields = captureSym :: extraPrivSyms ::: obj.cls.privateFields,
11771181
methods = newMtds,
11781182
auxParams = newAuxList
11791183
)(obj.cls.configOverride)

hkmc2/shared/src/test/mlscript/lifter/ClassInFun.mls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ f().foo()
157157
//│ };
158158
//│ define Good⁰ as class Good¹() {
159159
//│ private val Good$cap⁰;
160+
//│ private val scope0$cap⁰;
160161
//│ private val x¹;
161162
//│ private val y²;
162-
//│ private val scope0$cap⁰;
163163
//│ constructor Good²(scope0$cap, x, y) {
164164
//│ set scope0$cap⁰ = scope0$cap;
165165
//│ set x¹ = x;

0 commit comments

Comments
 (0)