fix(compiler): Code generate wrong stream name in AIR [LNG-276] (#958)

This commit is contained in:
Dima 2023-11-02 20:13:25 +07:00 committed by GitHub
parent 6e6b567f8e
commit a1576efad9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 155 additions and 35 deletions

View File

@ -317,7 +317,7 @@ object ArrowInliner extends Logging {
) )
defineRenames <- Mangler[S].findAndForbidNames(defineNames) defineRenames <- Mangler[S].findAndForbidNames(defineNames)
renaming = ( renaming =
data.renames ++ data.renames ++
streamRenames ++ streamRenames ++
arrowRenames ++ arrowRenames ++
@ -325,7 +325,6 @@ object ArrowInliner extends Logging {
capturedValues.renames ++ capturedValues.renames ++
capturedArrows.renames ++ capturedArrows.renames ++
defineRenames defineRenames
)
/** /**
* TODO: Optimize resolve. * TODO: Optimize resolve.

View File

@ -39,34 +39,45 @@ object TagInliner extends Logging {
* *
* @param prefix Previous instructions * @param prefix Previous instructions
*/ */
enum TagInlined(prefix: Option[OpModel.Tree]) { enum TagInlined[T](prefix: Option[OpModel.Tree]) {
/** /**
* Tag inlining emitted nothing * Tag inlining emitted nothing
*/ */
case Empty( case Empty[S](
prefix: Option[OpModel.Tree] = None prefix: Option[OpModel.Tree] = None
) extends TagInlined(prefix) ) extends TagInlined[S](prefix)
/** /**
* Tag inlining emitted one parent model * Tag inlining emitted one parent model
* *
* @param model Model which will wrap children * @param model Model which will wrap children
*/ */
case Single( case Single[S](
model: OpModel, model: OpModel,
prefix: Option[OpModel.Tree] = None prefix: Option[OpModel.Tree] = None
) extends TagInlined(prefix) ) extends TagInlined[S](prefix)
/** /**
* Tag inling emitted complex transformation * Tag inling emitted complex transformation
* *
* @param toModel Function from children results to result of this tag * @param toModel Function from children results to result of this tag
*/ */
case Mapping( case Mapping[S](
toModel: Chain[OpModel.Tree] => OpModel.Tree, toModel: Chain[OpModel.Tree] => OpModel.Tree,
prefix: Option[OpModel.Tree] = None prefix: Option[OpModel.Tree] = None
) extends TagInlined(prefix) ) extends TagInlined[S](prefix)
/**
* Tag inlining emitted computation
* that should be executed after children
*
* @param model computation producing model
*/
case After[S](
model: State[S, OpModel],
prefix: Option[OpModel.Tree] = None
) extends TagInlined[S](prefix)
/** /**
* Finalize inlining, construct a tree * Finalize inlining, construct a tree
@ -74,23 +85,34 @@ object TagInliner extends Logging {
* @param children Children results * @param children Children results
* @return Result of inlining * @return Result of inlining
*/ */
def build(children: Chain[OpModel.Tree]): OpModel.Tree = { def build(children: Chain[OpModel.Tree]): State[T, OpModel.Tree] = {
val inlined = this match { def toSeqModel(tree: OpModel.Tree | Chain[OpModel.Tree]): State[T, OpModel.Tree] = {
case Empty(_) => children val treeChain = tree match {
case c: Chain[OpModel.Tree] => c
case t: OpModel.Tree => Chain.one(t)
}
State.pure(SeqModel.wrap(Chain.fromOption(prefix) ++ treeChain))
}
this match {
case Empty(_) =>
toSeqModel(children)
case Single(model, _) => case Single(model, _) =>
Chain.one(model.wrap(children)) toSeqModel(model.wrap(children))
case Mapping(toModel, _) => case Mapping(toModel, _) =>
Chain.one(toModel(children)) toSeqModel(toModel(children))
case After(model, _) =>
model.flatMap(m => toSeqModel(m.wrap(children)))
} }
SeqModel.wrap(Chain.fromOption(prefix) ++ inlined)
} }
} }
private def pure[S](op: OpModel): State[S, TagInlined] = private def pure[S](op: OpModel): State[S, TagInlined[S]] =
TagInlined.Single(model = op).pure TagInlined.Single(model = op).pure
private def none[S]: State[S, TagInlined] = private def none[S]: State[S, TagInlined[S]] =
TagInlined.Empty().pure TagInlined.Empty().pure
private def combineOpsWithSeq(l: Option[OpModel.Tree], r: Option[OpModel.Tree]) = private def combineOpsWithSeq(l: Option[OpModel.Tree], r: Option[OpModel.Tree]) =
@ -174,7 +196,7 @@ object TagInliner extends Logging {
*/ */
def tagToModel[S: Mangler: Arrows: Exports]( def tagToModel[S: Mangler: Arrows: Exports](
tag: RawTag tag: RawTag
): State[S, TagInlined] = ): State[S, TagInlined[S]] =
tag match { tag match {
case OnTag(peerId, via, strategy) => case OnTag(peerId, via, strategy) =>
for { for {
@ -371,7 +393,17 @@ object TagInliner extends Logging {
} yield model.fold(TagInlined.Empty())(m => TagInlined.Single(model = m)) } yield model.fold(TagInlined.Empty())(m => TagInlined.Single(model = m))
case RestrictionTag(name, typ) => case RestrictionTag(name, typ) =>
pure(RestrictionModel(name, typ)) // Rename restriction after children are inlined with new exports
TagInlined
.After(
for {
exps <- Exports[S].exports
model = exps.get(name).collect { case VarModel(n, _, _) =>
RestrictionModel(n, typ)
}
} yield model.getOrElse(RestrictionModel(name, typ))
)
.pure
case DeclareStreamTag(value) => case DeclareStreamTag(value) =>
value match value match
@ -438,13 +470,14 @@ object TagInliner extends Logging {
private def traverseS[S]( private def traverseS[S](
cf: RawTag.Tree, cf: RawTag.Tree,
f: RawTag => State[S, TagInlined] f: RawTag => State[S, TagInlined[S]]
): State[S, OpModel.Tree] = ): State[S, OpModel.Tree] =
for { for {
headInlined <- f(cf.head) headInlined <- f(cf.head)
tail <- StateT.liftF(cf.tail) tail <- StateT.liftF(cf.tail)
children <- tail.traverse(traverseS[S](_, f)) children <- tail.traverse(traverseS[S](_, f))
} yield headInlined.build(children) inlined <- headInlined.build(children)
} yield inlined
def handleTree[S: Exports: Mangler: Arrows]( def handleTree[S: Exports: Mangler: Arrows](
tree: RawTag.Tree tree: RawTag.Tree

View File

@ -183,6 +183,96 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside {
} }
/**
* func returnNil() -> *string:
* someStr: *string
* <- someStr
*
* func newFunc() -> []string:
* stream <- returnNil()
* stream <<- "asd"
* <- stream
*/
it should "rename restricted stream correctly" in {
val streamType = StreamType(ScalarType.string)
val someStr = VarRaw("someStr", streamType)
val returnStreamArrowType = ArrowType(
ProductType(Nil),
ProductType(streamType :: Nil)
)
val returnNil = FuncArrow(
"returnNil",
SeqTag.wrap(
DeclareStreamTag(someStr).leaf,
ReturnTag(
NonEmptyList.one(someStr)
).leaf
),
returnStreamArrowType,
List(someStr),
Map.empty,
Map.empty,
None
)
val streamVar = VarRaw("stream", streamType)
val canonStreamVar = VarRaw(
s"-${streamVar.name}-canon-0",
CanonStreamType(ScalarType.string)
)
val flatStreamVar = VarRaw(
s"-${streamVar.name}-flat-0",
ArrayType(ScalarType.string)
)
val newFunc = FuncArrow(
"newFunc",
RestrictionTag(streamVar.name, streamType).wrap(
SeqTag.wrap(
CallArrowRawTag
.func(
returnNil.funcName,
Call(Nil, Call.Export(streamVar.name, streamType) :: Nil)
)
.leaf,
PushToStreamTag(
LiteralRaw.quote("asd"),
Call.Export(streamVar.name, streamVar.`type`)
).leaf,
CanonicalizeTag(
streamVar,
Call.Export(canonStreamVar.name, canonStreamVar.`type`)
).leaf,
FlattenTag(
canonStreamVar,
flatStreamVar.name
).leaf,
ReturnTag(
NonEmptyList.one(flatStreamVar)
).leaf
)
),
ArrowType(
ProductType(Nil),
ProductType(ArrayType(ScalarType.string) :: Nil)
),
List(flatStreamVar),
Map(returnNil.funcName -> returnNil),
Map.empty,
None
)
val model = callFuncModel(newFunc)
val restrictionName = model.collect {
case RestrictionModel(name, _) => name
}.headOption
restrictionName shouldBe Some(someStr.name)
}
/** /**
* func returnStream() -> *string: * func returnStream() -> *string:
* stream: *string * stream: *string

View File

@ -1,12 +1,10 @@
package aqua.model.transform.pre package aqua.model.transform.pre
import aqua.model.FuncArrow import aqua.model.{ArgsCall, FuncArrow}
import aqua.model.ArgsCall import aqua.raw.ops.*
import aqua.raw.ops.{Call, CallArrowRawTag, RawTag, SeqTag, TryTag} import aqua.raw.value.VarRaw
import aqua.raw.value.{ValueRaw, VarRaw}
import aqua.types.* import aqua.types.*
import cats.syntax.show.*
import cats.syntax.option.* import cats.syntax.option.*
/** /**
@ -47,7 +45,7 @@ case class FuncPreTransformer(
* @return FuncArrow that can be called and delegates the call to a client-registered callback * @return FuncArrow that can be called and delegates the call to a client-registered callback
*/ */
private def arrowToCallback(name: String, arrowType: ArrowType): FuncArrow = { private def arrowToCallback(name: String, arrowType: ArrowType): FuncArrow = {
val (args, call, ret) = ArgsCall.arrowToArgsCallRet(arrowType) val (_, call, ret) = ArgsCall.arrowToArgsCallRet(arrowType)
FuncArrow( FuncArrow(
arrowCallbackPrefix + name, arrowCallbackPrefix + name,
callback(name, call), callback(name, call),

View File

@ -3,15 +3,15 @@ package aqua.semantics.rules.names
import aqua.parser.lexer.{Name, Token} import aqua.parser.lexer.{Name, Token}
import aqua.semantics.Levenshtein import aqua.semantics.Levenshtein
import aqua.semantics.rules.StackInterpreter import aqua.semantics.rules.StackInterpreter
import aqua.semantics.rules.report.ReportAlgebra
import aqua.semantics.rules.locations.LocationsAlgebra import aqua.semantics.rules.locations.LocationsAlgebra
import aqua.types.{AbilityType, ArrowType, StreamType, Type} import aqua.semantics.rules.report.ReportAlgebra
import aqua.types.{ArrowType, StreamType, Type}
import cats.data.{OptionT, State} import cats.data.{OptionT, State}
import cats.syntax.all.*
import cats.syntax.applicative.*
import cats.syntax.flatMap.* import cats.syntax.flatMap.*
import cats.syntax.functor.* import cats.syntax.functor.*
import cats.syntax.applicative.*
import cats.syntax.all.*
import monocle.Lens import monocle.Lens
import monocle.macros.GenLens import monocle.macros.GenLens
@ -160,7 +160,7 @@ class NamesInterpreter[S[_], X](using
mapStackHead(Map.empty) { frame => mapStackHead(Map.empty) { frame =>
frame -> frame.names.collect { case (n, st @ StreamType(_)) => frame -> frame.names.collect { case (n, st @ StreamType(_)) =>
n -> st n -> st
}.toMap }
} }
override def beginScope(token: Token[S]): SX[Unit] = override def beginScope(token: Token[S]): SX[Unit] =