Fix incorrect compilation with arguments duplication (#211)

This commit is contained in:
Dima 2021-07-22 12:08:55 +03:00 committed by GitHub
parent c292ce05d7
commit f683a6b3cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 31 deletions

View File

@ -1,11 +1,8 @@
service OpH("op"): service AquaDHT("aqua-dht"):
get_str(s: string) -> string put_host_value(key: string, value: string, service_id: []string)
get_arr() -> []string
identity: -> ⊥
func registerKeyPutValue(node_id: string) -> []string: func putHostValue(key: string, value: string, service_id: ?string):
nodes <- OpH.get_arr() AquaDHT.put_host_value(key, value, service_id)
for n <- nodes par:
on n: func create_client_util(service_id: string):
OpH.get_str(node_id) putHostValue("client-util", service_id, nil)
<- nodes

View File

@ -1,6 +1,6 @@
package aqua.model.func package aqua.model.func
import aqua.model.func.raw.{AssignmentTag, CallArrowTag, CallServiceTag, FuncOp, RawTag} import aqua.model.func.raw.{AssignmentTag, CallArrowTag, FuncOp, RawTag}
import aqua.model.{Model, ValueModel, VarModel} import aqua.model.{Model, ValueModel, VarModel}
import aqua.types.{ArrowType, Type} import aqua.types.{ArrowType, Type}
import cats.Eval import cats.Eval
@ -47,15 +47,21 @@ case class FuncCallable(
// Collect all arguments: what names are used inside the function, what values are received // Collect all arguments: what names are used inside the function, what values are received
val argsFull = args.call(call) val argsFull = args.call(call)
// DataType arguments // DataType arguments
val argsToData = argsFull.dataArgs val argsToDataRaw = argsFull.dataArgs
// Arrow arguments: expected type is Arrow, given by-name // Arrow arguments: expected type is Arrow, given by-name
val argsToArrows = argsFull.arrowArgs(arrows) val argsToArrowsRaw = argsFull.arrowArgs(arrows)
// Find all duplicates in arguments
val argsShouldRename = findNewNames(forbiddenNames, (argsToDataRaw ++ argsToArrowsRaw).keySet)
val argsToData = argsToDataRaw.map { case (k, v) => argsShouldRename.getOrElse(k, k) -> v }
val argsToArrows = argsToArrowsRaw.map { case (k, v) => argsShouldRename.getOrElse(k, k) -> v }
// Going to resolve arrows: collect them all. Names should never collide: it's semantically checked // Going to resolve arrows: collect them all. Names should never collide: it's semantically checked
val allArrows = capturedArrows ++ argsToArrows val allArrows = capturedArrows ++ argsToArrows
// Substitute arguments (referenced by name and optional lambda expressions) with values // Substitute arguments (referenced by name and optional lambda expressions) with values
val treeWithValues = body.resolveValues(argsToData) // Also rename all renamed arguments in the body
val treeWithValues = body.rename(argsShouldRename).resolveValues(argsToData)
// Function body on its own defines some values; collect their names // Function body on its own defines some values; collect their names
val treeDefines = treeWithValues.definesVarNames.value -- call.exportTo.map(_.name) val treeDefines = treeWithValues.definesVarNames.value -- call.exportTo.map(_.name)
@ -63,8 +69,7 @@ case class FuncCallable(
// We have some names in scope (forbiddenNames), can't introduce them again; so find new names // We have some names in scope (forbiddenNames), can't introduce them again; so find new names
val shouldRename = findNewNames(forbiddenNames, treeDefines) val shouldRename = findNewNames(forbiddenNames, treeDefines)
// If there was a collision, rename exports and usages with new names // If there was a collision, rename exports and usages with new names
val treeRenamed = val treeRenamed = treeWithValues.rename(shouldRename)
if (shouldRename.isEmpty) treeWithValues else treeWithValues.rename(shouldRename)
// Result could be derived from arguments, or renamed; take care about that // Result could be derived from arguments, or renamed; take care about that
val result = ret.map(_._1).map(_.resolveWith(argsToData)).map { val result = ret.map(_._1).map(_.resolveWith(argsToData)).map {

View File

@ -54,22 +54,26 @@ case class FuncOp(tree: Cofree[Chain, RawTag]) extends Model {
def resolveValues(vals: Map[String, ValueModel]): FuncOp = def resolveValues(vals: Map[String, ValueModel]): FuncOp =
FuncOp(tree.map[RawTag](_.mapValues(_.resolveWith(vals)))) FuncOp(tree.map[RawTag](_.mapValues(_.resolveWith(vals))))
def rename(vals: Map[String, String]): FuncOp = def rename(vals: Map[String, String]): FuncOp = {
FuncOp( if (vals.isEmpty)
tree.map[RawTag](op => this
op.mapValues { else
case v: VarModel if vals.contains(v.name) => v.copy(name = vals(v.name)) FuncOp(
case v => v tree.map[RawTag](op =>
} match { op.mapValues {
case c: CallArrowTag => c.copy(call = c.call.mapExport(n => vals.getOrElse(n, n))) case v: VarModel if vals.contains(v.name) => v.copy(name = vals(v.name))
case c: CallServiceTag => c.copy(call = c.call.mapExport(n => vals.getOrElse(n, n))) case v => v
case a: AssignmentTag => a.copy(assignTo = vals.getOrElse(a.assignTo, a.assignTo)) } match {
case t: ForTag if vals.contains(t.item) => t.copy(item = vals(t.item)) case c: CallArrowTag => c.copy(call = c.call.mapExport(n => vals.getOrElse(n, n)))
case t: NextTag if vals.contains(t.item) => t.copy(item = vals(t.item)) case c: CallServiceTag => c.copy(call = c.call.mapExport(n => vals.getOrElse(n, n)))
case t => t case a: AssignmentTag => a.copy(assignTo = vals.getOrElse(a.assignTo, a.assignTo))
} case t: ForTag if vals.contains(t.item) => t.copy(item = vals(t.item))
case t: NextTag if vals.contains(t.item) => t.copy(item = vals(t.item))
case t => t
}
)
) )
) }
def :+:(prev: FuncOp): FuncOp = def :+:(prev: FuncOp): FuncOp =
FuncOp.RightAssocSemi.combine(prev, this) FuncOp.RightAssocSemi.combine(prev, this)