fix(compiler): Do not restrict stream args when ability is present [fixes LNG-233] (#902)

Add test
This commit is contained in:
InversionSpaces 2023-09-18 16:43:22 +02:00 committed by GitHub
parent bba6645e7a
commit 54ddcc8b62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 14 deletions

View File

@ -4,17 +4,22 @@ import aqua.parser.expr.func.ArrowExpr
import aqua.parser.lexer.{BasicTypeToken, Name} import aqua.parser.lexer.{BasicTypeToken, Name}
import aqua.raw.Raw import aqua.raw.Raw
import aqua.raw.arrow.ArrowRaw import aqua.raw.arrow.ArrowRaw
import aqua.raw.ops.{FuncOp, RawTag, ReturnTag, SeqTag} import aqua.raw.ops.*
import aqua.raw.value.LiteralRaw import aqua.raw.value.LiteralRaw
import aqua.semantics.expr.func.ArrowSem import aqua.semantics.expr.func.ArrowSem
import aqua.semantics.rules.types.TypesState
import aqua.types.* import aqua.types.*
import aqua.types.ScalarType.*
import cats.Id import cats.Id
import cats.data.{NonEmptyList, State} import cats.syntax.applicative.*
import cats.data.{NonEmptyList, NonEmptyMap, State}
import org.scalatest.EitherValues import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers import org.scalatest.matchers.should.Matchers
import org.scalatest.Inside
class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues { class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues with Inside {
import Utils.{given, *} import Utils.{given, *}
@ -27,21 +32,19 @@ class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues {
sem.program[State[CompilerState[Id], *]] sem.program[State[CompilerState[Id], *]]
} }
"sem" should "create empty model" in { "ArrowSem" should "create empty model" in {
val model = getModel(program("(a: string, b: u32) -> u8")) val model = getModel(program("(a: string, b: u32) -> u8"))
model shouldBe (Raw.Empty("Invalid arrow body")) model shouldBe (Raw.Empty("Invalid arrow body"))
} }
"sem" should "create error model" ignore { it should "create error model" ignore {
val model = getModel(RawTag.empty.toFuncOp)(program("(a: string, b: u32) -> u8")) val model = getModel(RawTag.empty.toFuncOp)(program("(a: string, b: u32) -> u8"))
model shouldBe Raw.Empty( model shouldBe Raw.Empty(
"Return type is defined for the arrow, but nothing returned. Use `<- value, ...` as the last expression inside function body." "Return type is defined for the arrow, but nothing returned. Use `<- value, ...` as the last expression inside function body."
) )
} }
import aqua.types.ScalarType.* it should "create right model for arrow without return type" ignore {
"arrow without return type" should "create right model" ignore {
val model = getModel(RawTag.empty.toFuncOp)(program("(a: string, b: u32)")) val model = getModel(RawTag.empty.toFuncOp)(program("(a: string, b: u32)"))
model shouldBe ArrowRaw( model shouldBe ArrowRaw(
ArrowType(labelled("a", string, labelled("b", u32)), NilType), ArrowType(labelled("a", string, labelled("b", u32)), NilType),
@ -50,7 +53,7 @@ class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues {
) )
} }
"arrow with return type and correct state" should "create correct model" ignore { it should "create correct model for arrow with return type and correct state" ignore {
val returnValue = LiteralRaw("123", string) val returnValue = LiteralRaw("123", string)
val returnTag = FuncOp(ReturnTag(NonEmptyList.one(returnValue)).wrap(RawTag.empty)) val returnTag = FuncOp(ReturnTag(NonEmptyList.one(returnValue)).wrap(RawTag.empty))
val model = getModel(returnTag)(program("(a: string, b: u32) -> string")) val model = getModel(returnTag)(program("(a: string, b: u32) -> string"))
@ -60,7 +63,7 @@ class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues {
model shouldBe resultModel model shouldBe resultModel
} }
"arrow with return type and seq inside" should "create correct model" ignore { it should "create correct model for arrow with return type and seq inside" ignore {
val returnValue = LiteralRaw("123", string) val returnValue = LiteralRaw("123", string)
val seq = FuncOp(SeqTag.wrap(RawTag.empty, ReturnTag(NonEmptyList.one(returnValue)).leaf)) val seq = FuncOp(SeqTag.wrap(RawTag.empty, ReturnTag(NonEmptyList.one(returnValue)).leaf))
val model = getModel(seq)(program("(a: string, b: u32) -> string")) val model = getModel(seq)(program("(a: string, b: u32) -> string"))
@ -70,7 +73,7 @@ class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues {
model shouldBe resultModel model shouldBe resultModel
} }
"different types in return type and return value" should "create error model" ignore { it should "create error model for different types in return type and return value" ignore {
val returnValue = LiteralRaw("123", string) val returnValue = LiteralRaw("123", string)
val seq = FuncOp( val seq = FuncOp(
SeqTag.wrap( SeqTag.wrap(
@ -86,4 +89,74 @@ class ArrowSemSpec extends AnyFlatSpec with Matchers with EitherValues {
) )
} }
it should "not restrict stream arguments" in {
val body =
PushToStreamTag(
LiteralRaw.quote("a"),
Call.Export("s", StreamType(ScalarType.string))
).leaf
def test(
abilityArgs: List[String],
args: List[String],
initState: CompilerState[Id]
) = {
val abilityPart =
if (abilityArgs.isEmpty) ""
else abilityArgs.mkString("{", ",", "}")
val argsPart = args.appended("s: *string").mkString("(", ",", ")")
val expr = abilityPart + argsPart
val (state, raw) = program(expr).apply(body.toFuncOp.pure).run(initState).value
state.errors shouldBe empty
inside(raw) { case ArrowRaw(_, Nil, bodyRes) =>
bodyRes shouldBe body
}
}
val structType = StructType(
"TestStruct",
NonEmptyMap.one(
"field",
ScalarType.string
)
)
val abilityType = AbilityType(
"TestAbility",
NonEmptyMap.one(
"field",
ScalarType.string
)
)
val state: CompilerState[Id] = CompilerState(
types = TypesState(
strict = Map(
"FirstAbility" -> abilityType,
"SecondAbility" -> abilityType,
"DataStruct" -> structType
)
)
)
val abilityArgs = List(
"FirstAbility",
"SecondAbility"
)
val args = List(
"a: string",
"callback: u32 -> string",
"data: DataStruct"
)
for {
abilityArgs <- abilityArgs.toSet.subsets()
args <- args.toSet.subsets()
} test(abilityArgs.toList, args.toList, state)
}
} }

View File

@ -74,9 +74,10 @@ sealed trait ProductType extends Type {
} }
lazy val labelledData: List[(String, DataType)] = this match { lazy val labelledData: List[(String, DataType)] = this match {
case LabeledConsType(label, t: DataType, pt) => (label -> t) :: pt.labelledData case LabeledConsType(label, t: DataType, pt) =>
case LabeledConsType(label, t: ArrowType, pt) => pt.labelledData (label -> t) :: pt.labelledData
case UnlabeledConsType(_, pt) => pt.labelledData case ConsType(_, pt) =>
pt.labelledData
case _ => Nil case _ => Nil
} }
} }