Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/Term.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ sealed trait ResolvableImpl:
* `duplicate` method if it appears in its own expansion.
*
* This method is only supposed to be called by Resolver.
*
* The expansion term inherits all flow-resolved information from this term.
*/
private[semantics] def expand(expansion: Opt[Term]): this.type =
// `expansion.isDefined`: Ideally, if a term is already expanded,
Expand All @@ -151,6 +153,14 @@ sealed trait ResolvableImpl:
lastWords(s"Cannot expand the term ${this.showDbg} multiple times (to different expansions ${expansion.get.showDbg}).")

this.expansion = S(expansion)

expansion match
case S(r: Resolvable) =>
// Propagate flow-resolved information to the expansion
r.ictx = this.ictx
r.resolvedContextuals = this.resolvedContextuals
case _ => ()

this

def resolve: this.type = expand(N)
Expand Down
74 changes: 56 additions & 18 deletions hkmc2/shared/src/main/scala/hkmc2/semantics/flow/FlowAnalysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
constrainContextualCall(t).foreach: c =>
collectedConstraints += ((src = t, c = c))
Comment on lines +70 to +72
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same pattern of code is duplicated in three locations (lines 70-72, 161-163, and 194-196). This code checks if the term is resolvable, constrains contextual calls, and collects constraints. This duplication violates the DRY (Don't Repeat Yourself) principle and makes the code harder to maintain. Consider extracting this logic into a helper method.

Copilot uses AI. Check for mistakes.
P.Flow(ts.bms.get.flow)
// typeProd(trm)

case Ref(sym) =>
sym match
Expand Down Expand Up @@ -157,10 +156,8 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
P.Flow(sym)

case sel @ Sel(pre, nme) =>
// selsToExpand += sel
t.asResolvable.foreach: t =>
constrainContextualCall(t).foreach: c =>
collectedConstraints += ((src = t, c = c))
constrainContextualCall(sel).foreach: c =>
collectedConstraints += ((src = sel, c = c))
log(s"Selection ${sel.showDbg} ${sel.typ}")
checkLDS(pre): pre_t =>
sel.resolvedSym match
Expand Down Expand Up @@ -191,9 +188,8 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
P.Ctor(sym, args_t)(t)

case app @ App(lhs, rhs) =>
t.asResolvable.foreach: t =>
constrainContextualCall(t).foreach: c =>
collectedConstraints += ((src = t, c = c))
constrainContextualCall(app).foreach: c =>
collectedConstraints += ((src = app, c = c))
checkLDS(lhs): pre_t =>
val sym = app.resSym
val c = C.Fun(typeProd(rhs), C.Flow(sym))
Expand Down Expand Up @@ -277,12 +273,12 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
sel.resolvedTargets match
case ObjectMember(sym) :: Nil =>
assert(sel.sym.isEmpty)
sel.expansion = S(S(sel.copy()(sym = S(sym), sel.typ, sel.originalCtx)))
sel.expand(S(sel.copy()(sym = S(sym), sel.typ, sel.originalCtx)))
case CompanionMember(comp, sym) :: Nil =>
val base = Sel(comp, Tree.Ident(sym.nme))(S(sym), N, N)
val app = App(base, Tup(sel.prefix :: Nil)(Tree.DummyTup))(Tree.DummyApp, N, FlowSymbol.app())
log(s"Expansion: ${app.showDbg}")
sel.expansion = S(S(app))
sel.expand(S(app))
case Nil =>
// FIXME: actually allow that in dead code (use floodfill constraints from exported members to detect)
if !sel.isErroneous then raise:
Expand All @@ -302,24 +298,29 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
case CompanionMember(comp, sym) :: Nil =>
val base = Sel(comp, Tree.Ident(sym.nme))(S(sym), N, N)
log(s"Leading dot expansion: ${base.showDbg}")
sel.expansion = S(S(base))
sel.expand(S(base))
case Nil =>
// FIXME: actually allow that in dead code (use floodfill constraints from exported members to detect)
sel.expansion = S(S(Error))
sel.expand(S(Error))
raise:
ErrorReport:
msg"Cannot resolve leading dot selection" -> sel.toLoc :: Nil
case targets => sel.expansion = S(S(Error)); raise:
case targets => sel.expand(S(Error)); raise:
ErrorReport:
msg"Ambiguous selection with multiple apparent targets:" -> sel.toLoc
:: targets.map:
case CompanionMember(_, sym) => msg"companion member ${sym.nme}" -> sym.toLoc
contextualCallsToExpand.foreach: t =>
expandContextualCall(t.expanded.asResolvable.getOrElse(die))

Comment on lines +314 to +315
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to .getOrElse(die) at line 314 will crash if t.expanded.asResolvable returns N. This could happen if the expanded term is not a Resolvable. Since t is already added to contextualCallsToExpand buffer during constrainContextualCall, it's guaranteed to be a Resolvable, but after expansion it might change type. This should be handled more gracefully, either by filtering out non-resolvable expansions or by proper error handling.

Suggested change
expandContextualCall(t.expanded.asResolvable.getOrElse(die))
t.expanded.asResolvable match
case Some(resolvable) =>
expandContextualCall(resolvable)
case None =>
log(s"Warning: expanded term for ${t.showDbg} is not a Resolvable, skipping expansion.")
// Optionally, raise an error or handle as needed

Copilot uses AI. Check for mistakes.
def constrainContextualCall(t: Resolvable): Ls[Constraint] = t.resolvedSym match
case S(sym: TermSymbol) =>
/**
* For a possibly call to a contextual function, create a list of constraints to ensure that the
* contextual parameters are properly supplied.
*/
def constrainContextualCall(t: Resolvable): Ls[Constraint] =
def constrain(sym: TermSymbol): Ls[Constraint] =
val defn = sym.defn.getOrElse(die)
// TODO: This checks only the head param list. Check all param lists.
defn.params.headOption match
case S(ps) if ps.flags.ctx =>
log(s"Constraining contextual call ${t.showDbg}")
Expand All @@ -336,9 +337,43 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
val cons = C.Typ(typ)
Constraint(prod, cons)
constraints
case _ =>
case _ => Nil

log(s"Attempting to constrain contextual call: ${t.showDbg}")
// If t is already resolved by the basic resolution phase,
// simply use the resolved symbol; otherwise, use the flow information.
t.resolvedSym match
case S(sym: TermSymbol) => constrain(sym)
case S(sym) => Nil

case N => t match // use flow info

case t: Sel => t.resolvedTargets match
case target :: Nil =>
log(s"Resolved contextual call resolution for ${t.showDbg} to target ${target}")
// TODO: It is really odd that SelectionTarget carries a MemberSymbol instead of a DefinitionSymbol...
target match
case SelectionTarget.ObjectMember(sym: TermSymbol) =>
constrain(sym)
case SelectionTarget.ObjectMember(sym: BlockMemberSymbol) =>
sym.asTrm.map(constrain(_)).getOrElse(Nil)
case SelectionTarget.ObjectMember(sym) =>
Nil
case SelectionTarget.CompanionMember(t, sym: TermSymbol) =>
constrain(sym)
case SelectionTarget.CompanionMember(t, sym: BlockMemberSymbol) =>
sym.asTrm.map(constrain(_)).getOrElse(Nil)
case SelectionTarget.CompanionMember(t, sym) =>
Nil
case target :: targets => // ambiguous targets? but does it raise error?
log(s"Unresolved contextual call resolution for ${t.showDbg} due to ambiguous targets ${targets.mkString(", ")}")
Nil // TODO
case Nil => // insufficient targets
log(s"Unresolved contextual call resolution for ${t.showDbg} due to insufficient targets")
Nil

case t => // unsupported form
Nil
case _ => die

Comment on lines 322 to 377
Copy link

Copilot AI Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constrainContextualCall method uses multiple .getOrElse(die) calls (lines 318, 324) which will crash with generic "Internal Error" messages if the expected values are not present. For example, if sym.defn is N or p.signType is N, this could happen in legitimate error scenarios during type checking. Consider handling these cases more gracefully with proper error reporting rather than crashing.

Suggested change
val defn = sym.defn.getOrElse(die)
defn.params.headOption match
case S(ps) if ps.flags.ctx =>
log(s"Constraining contextual call ${t.showDbg}")
contextualCallsToExpand += t
val placeholders = ps.params.map: p =>
val sig = p.signType.getOrElse(die)
val sym = FlowSymbol(s"using-${p.sym.name}-flow")
val placeholder = ContextualPlaceholder(sym)
(sig, placeholder)
t.resolvedContextuals = S(placeholders)
val constraints = placeholders.map:
case (typ, placeholder) =>
val prod = P.Flow(placeholder.sym)
val cons = C.Typ(typ)
Constraint(prod, cons)
constraints
case _ =>
Nil
case _ => die
sym.defn match
case Some(defn) =>
defn.params.headOption match
case S(ps) if ps.flags.ctx =>
log(s"Constraining contextual call ${t.showDbg}")
contextualCallsToExpand += t
val placeholders = ps.params.map: p =>
p.signType match
case Some(sig) =>
val sym = FlowSymbol(s"using-${p.sym.name}-flow")
val placeholder = ContextualPlaceholder(sym)
(sig, placeholder)
case None =>
reportError(s"Missing signType for parameter ${p.sym.name} in contextual call: ${t.showDbg}")
// Return a dummy placeholder with a dummy type, or skip this parameter
// Here, we skip this parameter
null
val filteredPlaceholders = placeholders.filter(_ != null)
t.resolvedContextuals = S(filteredPlaceholders)
val constraints = filteredPlaceholders.map:
case (typ, placeholder) =>
val prod = P.Flow(placeholder.sym)
val cons = C.Typ(typ)
Constraint(prod, cons)
constraints
case _ =>
Nil
case None =>
reportError(s"Missing definition for symbol ${sym.name} in contextual call: ${t.showDbg}")
Nil
case _ =>
reportError(s"Expected TermSymbol in contextual call, found: ${t.resolvedSym}")
Nil
// Helper method for error reporting
private def reportError(msg: String): Unit =
// Replace this with the project's error reporting mechanism as appropriate
println(s"[FlowAnalysis Error] $msg")

Copilot uses AI. Check for mistakes.
def expandContextualCall(t: Resolvable): Unit = t.resolvedContextuals match
case S(cs) =>
Expand All @@ -351,7 +386,7 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
cs.map:
case (typ, placeholder) => PlainFld(placeholder.solution.get)
)(Tree.DummyTup))(Tree.DummyApp, N, FlowSymbol.app())))
case N => ()
case N => die

def getCompanionMember(name: Str, oc: Opt[Ctx], sym: Symbol): Opt[(Term, BlockMemberSymbol)] = sym match
case ms: ModuleOrObjectSymbol => ms.defn.flatMap: d =>
Expand Down Expand Up @@ -454,6 +489,7 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
sel.trm.resolvedTargets ::= SelectionTarget.CompanionMember(path, memb)
log(s"Found member ${memb}")
toSolve.push(Constraint(P.Flow(memb.flow), C.Flow(trm.resSym)))
constrainContextualCall(sel.trm).foreach(toSolve.push(_))
case _ =>
log(s"Could not find member ${trm.nme.name} in ${sym}")
case _ => log("Unhandled RHS for leading dot selections")
Expand All @@ -469,6 +505,7 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
sel.trm.resolvedTargets ::= SelectionTarget.ObjectMember(memb)
log(s"Found immediate member ${memb}")
toSolve.push(Constraint(P.Flow(memb.flow), sel.res))
constrainContextualCall(sel.trm).foreach(toSolve.push(_))
case S(memb) => TODO(memb)
case N =>
d.moduleCompanion match
Expand All @@ -488,6 +525,7 @@ class FlowAnalysis(using tl: TraceLogger)(using Raise, State, Ctx):
case memb: BlockMemberSymbol => P.Flow(memb.flow)
case _ => TODO(memb)
toSolve.push(Constraint(newlhs, C.Fun(P.Tup((N, lhs) :: Nil), sel.res)))
constrainContextualCall(sel.trm).foreach(toSolve.push(_))
case N => raise:
sel.trm.isErroneous = true
ErrorReport:
Expand Down
176 changes: 88 additions & 88 deletions hkmc2/shared/src/test/mlscript/flows/Contextuals.mls
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,11 @@


fun f(using x: Int) = x + 1
//│ FAILURE: Unexpected exception
//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached an unexpected state.
//│ at: mlscript.utils.package$.lastWords(package.scala:230)
//│ at: mlscript.utils.package$.die(package.scala:229)
//│ at: hkmc2.semantics.flow.FlowAnalysis.constrainContextualCall(FlowAnalysis.scala:337)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3$$anonfun$10(FlowAnalysis.scala:195)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
//│ at: scala.Option.foreach(Option.scala:437)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3(FlowAnalysis.scala:194)
//│ at: hkmc2.utils.TraceLogger.trace(TraceLogger.scala:17)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl(FlowAnalysis.scala:217)
//│ Flowed:
//│ fun f⁰ctx (x⁰: Int⁰{ ~> Int⁰ }) ‹flow:f⁰› = +(x⁰, 1)‹app⁰›
//│ where
//│ x⁰ <~ type Int
//│ flow:f⁰ <~ ((type Int) -> app⁰)

using Int = 42
//│ Flowed:
Expand All @@ -34,103 +27,110 @@ f
//│ Typing producer: { member:f }
//│ | Typing producer: member:f‹term:f›
//│ | | Typing producer: member:f
//│ | | : flow:f‹729›
//│ | | : flow:f‹555›
//│ | | Attempting to constrain contextual call: member:f‹term:f›
//│ | | Constraining contextual call member:f‹term:f›
//│ | : flow:f‹729
//│ : flow:f‹729
//│ Handling constraint: using-x-flow‹730› <: type class:Int (from member:f‹term:f›)
//│ | Solving: using-x-flow‹730› <: type class:Int (Flow, Typ)
//│ | : flow:f‹555
//│ : flow:f‹555
//│ Handling constraint: using-x-flow‹566› <: type class:Int (from member:f‹term:f›)
//│ | Solving: using-x-flow‹566› <: type class:Int (Flow, Typ)
//│ | New flow using-x-flow ~> Typ(Ref(class:Int,List()))
//│ Flowed:
//│ f⁰{ ~> f⁰(instance$Ident(Int)⁰)‹app› }
//│ f⁰{ ~> f⁰(instance$Ident(Int)⁰)‹app¹› }
//│ where
//│
//│ FAILURE: Unexpected compilation error
//│ FAILURE LOCATION: lookup_! (Scope.scala:120)
//│ FAILURE INFO: Tuple2:
//│ _1 = Tuple2:
//│ _1 = member:f
//│ _2 = class hkmc2.semantics.BlockMemberSymbol
//│ _2 = Scope:
//│ parentOrCfg = Left of Cfg:
//│ escapeChars = true
//│ useSuperscripts = false
//│ includeZero = false
//│ curThis = S of S of globalThis:globalThis
//│ bindings = HashMap(member:instance$Ident(Int) -> instance$Ident$_Int$_, member:Predef -> Predef, $runtime -> runtime, $block$res -> block$res1, $definitionMetadata -> definitionMetadata, $prettyPrint -> prettyPrint, $block$res -> block$res, $Term -> Term, $Block -> Block, $Shape -> Shape, $block$res -> block$res2)
//│ ╔══[COMPILATION ERROR] No definition found in scope for member 'f'
//│ ║ l.33: f
//│ ║ ^
//│ ╟── which references the symbol introduced here
//│ ║ l.11: fun f(using x: Int) = x + 1
//│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^
//│ FAILURE: Unexpected runtime error
//│ FAILURE LOCATION: mkQuery (JSBackendDiffMaker.scala:159)
//│ ═══[RUNTIME ERROR] ReferenceError: f is not defined
//│ at REPL13:1:28
//│ at ContextifyScript.runInThisContext (node:vm:137:12)
//│ at REPLServer.defaultEval (node:repl:593:22)
//│ at bound (node:domain:433:15)
//│ at REPLServer.runBound [as eval] (node:domain:444:12)
//│ at REPLServer.onLine (node:repl:922:10)
//│ at REPLServer.emit (node:events:518:28)
//│ at REPLServer.emit (node:domain:489:12)
//│ at [_onLine] [as _onLine] (node:internal/readline/interface:419:12)
//│ at [_normalWrite] [as _normalWrite] (node:internal/readline/interface:613:22)
//│ = 43

fun id(x) = x
//│ Flowed:
//│ fun id⁰(x) ‹flow:id⁰› = x
//│ fun id⁰(x¹) ‹flow:id⁰› = x¹
//│ where
//│ flow:id⁰ <~ ((x) -> x)
//│ flow:id⁰ <~ ((x¹) -> x¹)

class Foo with
fun f(using x: Int) = x + 1
//│ FAILURE: Unexpected exception
//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached an unexpected state.
//│ at: mlscript.utils.package$.lastWords(package.scala:230)
//│ at: mlscript.utils.package$.die(package.scala:229)
//│ at: hkmc2.semantics.flow.FlowAnalysis.constrainContextualCall(FlowAnalysis.scala:337)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3$$anonfun$10(FlowAnalysis.scala:195)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
//│ at: scala.Option.foreach(Option.scala:437)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3(FlowAnalysis.scala:194)
//│ at: hkmc2.utils.TraceLogger.trace(TraceLogger.scala:17)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl(FlowAnalysis.scala:217)
//│ Flowed:
//│ class Foo {
//│ fun f¹ctx (x²: Int⁰{ ~> Int⁰ }) ‹flow:f¹› = +(x², 1)‹app²›
//│ }
//│ where
//│ x² <~ type Int
//│ flow:f¹ <~ ((type Int) -> app²)

:df
(new Foo).f
//│ Typing producer: { new member:Foo.f }
//│ | Typing producer: new member:Foo.f‹term:class:Foo.f›
//│ | | Typing producer: new member:Foo.f‹member:f›
//│ FAILURE: Unexpected exception
//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached an unexpected state.
//│ at: mlscript.utils.package$.lastWords(package.scala:230)
//│ at: mlscript.utils.package$.die(package.scala:229)
//│ at: hkmc2.semantics.flow.FlowAnalysis.constrainContextualCall(FlowAnalysis.scala:337)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3$$anonfun$5(FlowAnalysis.scala:162)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
//│ at: scala.Option.foreach(Option.scala:437)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3(FlowAnalysis.scala:161)
//│ at: hkmc2.utils.TraceLogger.trace(TraceLogger.scala:17)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl(FlowAnalysis.scala:217)
//│ | | | Attempting to constrain contextual call: new member:Foo.f‹member:f›
//│ | | | Selection new member:Foo.f‹member:f› None
//│ | | | Typing producer: new member:Foo
//│ | | | : Foo
//│ | | | RES f in new member:Foo.f‹member:f›
//│ | | : flow:f‹587›
//│ | | Attempting to constrain contextual call: new member:Foo.f‹term:class:Foo.f›
//│ | | Constraining contextual call new member:Foo.f‹term:class:Foo.f›
//│ | : flow:f‹587›
//│ : flow:f‹587›
//│ Handling constraint: using-x-flow‹594› <: type class:Int (from new member:Foo.f‹term:class:Foo.f›)
//│ | Solving: using-x-flow‹594› <: type class:Int (Flow, Typ)
//│ | New flow using-x-flow ~> Typ(Ref(class:Int,List()))
//│ Flowed:
//│ new Foo⁰.f‹?›{ ~> new Foo⁰.f¹(instance$Ident(Int)⁰)‹app³› }
//│ where
//│
//│ = 43


:df
id(new Foo).f
//│ Typing producer: { member:id(new member:Foo).f }
//│ | Typing producer: member:id(new member:Foo).f
//│ FAILURE: Unexpected exception
//│ /!!!\ Uncaught error: java.lang.Exception: Internal Error: Program reached an unexpected state.
//│ at: mlscript.utils.package$.lastWords(package.scala:230)
//│ at: mlscript.utils.package$.die(package.scala:229)
//│ at: hkmc2.semantics.flow.FlowAnalysis.constrainContextualCall(FlowAnalysis.scala:337)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3$$anonfun$5(FlowAnalysis.scala:162)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
//│ at: scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
//│ at: scala.Option.foreach(Option.scala:437)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl$$anonfun$3(FlowAnalysis.scala:161)
//│ at: hkmc2.utils.TraceLogger.trace(TraceLogger.scala:17)
//│ at: hkmc2.semantics.flow.FlowAnalysis.typeProdImpl(FlowAnalysis.scala:217)
//│ | | Attempting to constrain contextual call: member:id(new member:Foo).f
//│ | | Unresolved contextual call resolution for member:id(new member:Foo).f due to insufficient targets
//│ | | Selection member:id(new member:Foo).f None
//│ | | Typing producer: member:id(new member:Foo)
//│ | | | Attempting to constrain contextual call: member:id(new member:Foo)
//│ | | | Typing producer: member:id‹term:id›
//│ | | | | Typing producer: member:id
//│ | | | | : flow:id‹575›
//│ | | | | Attempting to constrain contextual call: member:id‹term:id›
//│ | | | : flow:id‹575›
//│ | | | Typing producer: [new member:Foo]
//│ | | | | Typing producer: new member:Foo
//│ | | | | : Foo
//│ | | | : [Foo]
//│ | | : app‹599›
//│ | : ⋅f‹600›
//│ : ⋅f‹600›
//│ Handling constraint: flow:id‹575› <: ((Foo) -> app‹599›) (from member:id(new member:Foo))
//│ | Solving: flow:id‹575› <: ((Foo) -> app‹599›) (Flow, Fun)
//│ | New flow flow:id ~> Fun(Tup(List((None,Ctor(class:Foo,List())))),Flow(app))
//│ | Solving: ((x‹571›) -> x‹571›) <: ((Foo) -> app‹599›) (Fun, Fun)
//│ | Solving: [Foo] <: [x‹571›] (Tup, Tup)
//│ | Solving: Foo <: x‹571› (Ctor, Flow)
//│ | New flow Ctor(class:Foo,List()) ~> x
//│ | Solving: x‹571› <: app‹599› (Flow, Flow)
//│ | New flow x ~> app
//│ | Solving: Foo <: app‹599› (Ctor, Flow)
//│ | New flow Ctor(class:Foo,List()) ~> app
//│ Handling constraint: app‹599› <: {f: ⋅f‹600›} (from member:id(new member:Foo).f)
//│ | Solving: app‹599› <: {f: ⋅f‹600›} (Flow, Sel)
//│ | New flow app ~> Sel(Ident(f),Flow(⋅f))
//│ | Solving: Foo <: {f: ⋅f‹600›} (Ctor, Sel)
//│ | Found immediate member member:f
//│ | Attempting to constrain contextual call: member:id(new member:Foo).f
//│ | Resolved contextual call resolution for member:id(new member:Foo).f to target ObjectMember(member:f)
//│ | Constraining contextual call member:id(new member:Foo).f
//│ | Solving: using-x-flow‹601› <: type class:Int (Flow, Typ)
//│ | New flow using-x-flow ~> Typ(Ref(class:Int,List()))
//│ | Solving: flow:f‹587› <: ⋅f‹600› (Flow, Flow)
//│ | New flow flow:f ~> ⋅f
//│ | Solving: ((type class:Int) -> app‹584›) <: ⋅f‹600› (Fun, Flow)
//│ | New flow Fun(Tup(List(Typ(Ref(class:Int,List()))),None),Flow(app),List(),false) ~> ⋅f
//│ Resolved targets for member:id(new member:Foo).f: ObjectMember(member:f)
//│ Flowed:
//│ id⁰(new Foo⁰)‹app⁴›.f¹(instance$Ident(Int)⁰)‹app⁵›
//│ where
//│
//│ = 43
Loading
Loading