fix(compiler): Fix closure call compilation [fixes LNG-193] (#741)

This commit is contained in:
InversionSpaces 2023-06-13 11:56:17 +02:00 committed by GitHub
parent 8c2240d3b1
commit c5534a964c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 226 additions and 67 deletions

View File

@ -222,9 +222,11 @@ object TagInliner extends Logging {
case v =>
valueToModel(v, false)
}).flatMap { case (model, prefix) =>
Exports[S]
.resolved(assignTo, model)
.as(None -> prefix)
for {
// NOTE: Name <assignTo> should not exist yet
_ <- Mangler[S].forbidName(assignTo)
_ <- Exports[S].resolved(assignTo, model)
} yield None -> prefix
}
case ClosureTag(arrow, detach) =>

View File

@ -75,38 +75,29 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
private def resolveArrow[S: Mangler: Exports: Arrows](
funcName: String,
call: Call
): State[S, (List[ValueModel], Inline)] =
Arrows[S].arrows.flatMap(arrows =>
arrows.get(funcName) match {
case Some(fn) =>
resolveFuncArrow(fn, call)
case None =>
Exports[S].exports.flatMap { exps =>
): State[S, (List[ValueModel], Inline)] = for {
arrows <- Arrows[S].arrows
exports <- Exports[S].exports
arrow = arrows
.get(funcName)
.orElse(
// if there is no arrow, check if it is stored in Exports as variable and try to resolve it
exps.get(funcName) match {
case Some(VarModel(name, ArrowType(_, _), _)) =>
Arrows[S].arrows.flatMap(arrows =>
arrows.get(name) match {
case Some(fn) =>
resolveFuncArrow(fn, call)
case _ =>
exports
.get(funcName)
.collect { case VarModel(name, _: ArrowType, _) =>
name
}
.flatMap(arrows.get)
)
result <- arrow.fold {
logger.error(
s"Inlining, cannot find arrow $funcName, available: ${arrows.keys
.mkString(", ")}"
)
State.pure(Nil -> Inline.empty)
}
)
case _ =>
logger.error(
s"Inlining, cannot find arrow $funcName, available: ${arrows.keys
.mkString(", ")}"
)
State.pure(Nil -> Inline.empty)
}
}
}
)
}(resolveFuncArrow(_, call))
} yield result
override def apply[S: Mangler: Exports: Arrows](
raw: CallArrowRaw,

View File

@ -19,6 +19,9 @@ trait Mangler[S] {
def forbid(names: Set[String]): State[S, Unit]
def forbidName(name: String): State[S, Unit] =
forbid(Set(name))
def transformS[R](f: R => S, g: (R, S) => R): Mangler[R] =
new Mangler[R] {

View File

@ -581,21 +581,24 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
}
/**
* func inner(arg: u16) -> u16 -> u16:
* closure = (x: u16) -> u16:
* func innerName(arg: u16) -> u16 -> u16:
* closureName = (x: u16) -> u16:
* retval = x + arg
* <- retval
* <- closure
* <- closureName
*
* func outer() -> u16:
* c <- inner(42)
* retval = 37 + c(1) + c(2)
* <- retval
* outterClosureName <- inner(42)
* <body(outterClosureName.type)>
* <- outterResultName
*/
"arrow inliner" should "leave meta after returned closure inlining" in {
val innerName = "inner"
val closureName = "closure"
def closureReturnModel(
innerName: String,
closureName: String,
outterClosureName: String,
outterResultName: String,
body: (ArrowType) => List[RawTag.Tree]
) = {
val closureArg = VarRaw(
"x",
ScalarType.u16
@ -689,33 +692,13 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
)
).leaf
val closureCall = (i: String) =>
CallArrowRaw(
ability = None,
name = outterClosure.name,
arguments = List(LiteralRaw(i, LiteralType.number)),
baseType = closureType,
serviceId = None
)
val outerBody = SeqTag.wrap(
innerCall,
AssignmentTag(
RawBuilder.add(
RawBuilder.add(
LiteralRaw("37", LiteralType.number),
closureCall("1")
),
closureCall("2")
),
outterRes.name
).leaf,
ReturnTag(
innerCall +: body(closureType) :+ ReturnTag(
NonEmptyList
.one(
outterRes
)
).leaf
).leaf: _*
)
val outer = FuncArrow(
@ -731,13 +714,63 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
capturedTopology = None
)
val model = ArrowInliner
ArrowInliner
.callArrow[InliningState](
outer,
CallModel(Nil, Nil)
)
.runA(InliningState())
.value
}
/**
* func inner(arg: u16) -> u16 -> u16:
* closure = (x: u16) -> u16:
* retval = x + arg
* <- retval
* <- closure
*
* func outer() -> u16:
* c <- inner(42)
* retval = 37 + c(1) + c(2)
* <- retval
*/
"arrow inliner" should "leave meta after returned closure inlining" in {
val innerName = "inner"
val closureName = "closure"
val outterClosureName = "c"
val outterResultName = "retval"
val closureCall = (closureType: ArrowType, i: String) =>
CallArrowRaw(
ability = None,
name = outterClosureName,
arguments = List(LiteralRaw(i, LiteralType.number)),
baseType = closureType,
serviceId = None
)
val body = (closureType: ArrowType) =>
List(
AssignmentTag(
RawBuilder.add(
RawBuilder.add(
LiteralRaw("37", LiteralType.number),
closureCall(closureType, "1")
),
closureCall(closureType, "2")
),
outterResultName
).leaf
)
val model = closureReturnModel(
innerName = innerName,
closureName = closureName,
outterClosureName = outterClosureName,
outterResultName = outterResultName,
body = body
)
val closureCallModel = (x: String, o: VarModel) =>
MetaModel
@ -958,6 +991,136 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
model.equalsOrShowDiff(expected) shouldEqual true
}
/**
* func inner(arg: u16) -> u16 -> u16:
* closure = (x: u16) -> u16:
* retval = x + arg
* <- retval
* <- closure
*
* func outer() -> u16:
* c <- inner(42)
* b = c
* a = b
* retval = 37 + a(1) + b(2) + c{3}
* <- retval
*/
"arrow inliner" should "correctly inline renamed closure [bug LNG-193]" in {
val innerName = "inner"
val closureName = "closure"
val outterClosureName = "c"
val outterResultName = "retval"
val firstRename = "b"
val secondRename = "a"
val closureCall = (name: String, closureType: ArrowType, i: String) =>
CallArrowRaw(
ability = None,
name = name,
arguments = List(LiteralRaw(i, LiteralType.number)),
baseType = closureType,
serviceId = None
)
val body = (closureType: ArrowType) =>
List(
AssignmentTag(
VarRaw(outterClosureName, closureType),
firstRename
).leaf,
AssignmentTag(
VarRaw(firstRename, closureType),
secondRename
).leaf,
AssignmentTag(
RawBuilder
.add(
RawBuilder.add(
RawBuilder.add(
LiteralRaw("37", LiteralType.number),
closureCall(secondRename, closureType, "1")
),
closureCall(firstRename, closureType, "2")
),
closureCall(outterClosureName, closureType, "3")
),
outterResultName
).leaf
)
val model = closureReturnModel(
innerName = innerName,
closureName = closureName,
outterClosureName = outterClosureName,
outterResultName = outterResultName,
body = body
)
val closureCallModel = (x: String, o: VarModel) =>
MetaModel
.CallArrowModel(closureName)
.wrap(
ApplyTopologyModel(closureName)
.wrap(
ModelBuilder
.add(
LiteralModel(x, LiteralType.number),
LiteralModel("42", LiteralType.number)
)(o)
.leaf
)
)
/* WARNING: This naming is unstable */
val tempAdd0 = VarModel("add-0", ScalarType.u16)
val tempAdd1 = VarModel("add-1", ScalarType.u16)
val tempAdd2 = VarModel("add-2", ScalarType.u16)
val tempAdd3 = VarModel("add-3", ScalarType.u16)
val tempAdd4 = VarModel("add-4", ScalarType.u16)
val tempAdd = VarModel("add", ScalarType.u16)
val expected = SeqModel.wrap(
MetaModel
.CallArrowModel(innerName)
.wrap(
CaptureTopologyModel(closureName).leaf
),
SeqModel.wrap(
ParModel.wrap(
SeqModel.wrap(
ParModel.wrap(
SeqModel.wrap(
closureCallModel("1", tempAdd2),
ModelBuilder
.add(
LiteralModel("37", LiteralType.number),
tempAdd2
)(tempAdd1)
.leaf
),
closureCallModel("2", tempAdd3)
),
ModelBuilder
.add(
tempAdd1,
tempAdd3
)(tempAdd0)
.leaf
),
closureCallModel("3", tempAdd4)
),
ModelBuilder
.add(
tempAdd0,
tempAdd4
)(tempAdd)
.leaf
)
)
model.equalsOrShowDiff(expected) shouldEqual true
}
/*
data Prod:
value: string