fix(compiler): Ordering in option inliner [LNG-351] (#1114)

This commit is contained in:
Dima 2024-04-08 12:24:55 +03:00 committed by GitHub
parent 331d497eb5
commit 49729ac40a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 128 additions and 28 deletions

View File

@ -1,8 +1,10 @@
aqua Main aqua Main
import someFunc from "import.aqua" export main
export someFunc func reward(amount: ?u32) -> u32:
result = ?[amount! / 10, 0]
<- result!
func a() -> string: func main(a: u32) -> u32:
<- "srrt" <- reward(?[a])

View File

@ -1,6 +1,6 @@
aqua Option aqua Option
export SomeS, useOptional, returnOptional, returnNone export SomeS, useOptional, returnOptional, returnNone, getDefault, getArg
import "@fluencelabs/aqua-lib/builtin.aqua" import "@fluencelabs/aqua-lib/builtin.aqua"
@ -27,3 +27,13 @@ func returnNone() -> ?string:
result: *string result: *string
Op.noop() Op.noop()
<- result <- result
func reward(amount: ?u32) -> u32:
result = ?[amount! / 10, 42]
<- result!
func getArg(a: u32) -> u32:
<- reward(?[a])
func getDefault() -> u32:
<- reward(?[])

View File

@ -68,6 +68,8 @@ import {
returnNull, returnNull,
returnOptionalCall, returnOptionalCall,
useOptionalCall, useOptionalCall,
getDefaultCall,
getArgCall
} from "../examples/useOptionalCall.js"; } from "../examples/useOptionalCall.js";
import { import {
viaArrCall, viaArrCall,
@ -607,6 +609,14 @@ describe("Testing examples", () => {
expect(noneResult).toBe(null); expect(noneResult).toBe(null);
}); });
it("option.aqua default values LNG-351", async () => {
registerHandlers();
let defaultResult = await getDefaultCall();
let argResult = await getArgCall(1000);
expect(defaultResult).toBe(42);
expect(argResult).toBe(100);
});
it("nestedFuncs.aqua", async () => { it("nestedFuncs.aqua", async () => {
let nestedFuncsResult = await nestedFuncsCall(); let nestedFuncsResult = await nestedFuncsCall();
expect(nestedFuncsResult).toBe("some-str"); expect(nestedFuncsResult).toBe("some-str");

View File

@ -3,6 +3,8 @@ import {
returnOptional, returnOptional,
useOptional, useOptional,
registerSomeS, registerSomeS,
getDefault,
getArg
} from "../compiled/examples/option.js"; } from "../compiled/examples/option.js";
export function registerHandlers(): void { export function registerHandlers(): void {
@ -31,3 +33,11 @@ export async function returnOptionalCall(): Promise<string | null> {
export async function returnNull(): Promise<string | null> { export async function returnNull(): Promise<string | null> {
return await returnNone(); return await returnNone();
} }
export async function getDefaultCall(): Promise<number> {
return await getDefault();
}
export async function getArgCall(num: number): Promise<number> {
return await getArg(num);
}

View File

@ -34,13 +34,9 @@ object CollectionRawInliner extends RawInliner[CollectionRaw] {
.map(Chain.fromSeq) .map(Chain.fromSeq)
// push values to the stream, that is gathering the collection // push values to the stream, that is gathering the collection
vals = valsWithInlines.map { case (v, _) => vals = valsWithInlines.map { case (v, tOp) =>
PushToStreamModel(v, streamExp).leaf val pts = PushToStreamModel(v, streamExp).leaf
} tOp.map(t => SeqModel.wrap(Chain(t, pts))).getOrElse(pts)
// all inlines will be added before pushing values to the stream
inlines = valsWithInlines.flatMap { case (_, t) =>
Chain.fromOption(t)
} }
canonName <- canonName <-
@ -52,18 +48,17 @@ object CollectionRawInliner extends RawInliner[CollectionRaw] {
raw.collectionType match { raw.collectionType match {
case ArrayType(_) => case ArrayType(_) =>
RestrictionModel(streamName, streamType).wrap( RestrictionModel(streamName, streamType).wrap(
SeqModel.wrap(inlines ++ vals :+ CanonicalizeModel(stream, canon).leaf) SeqModel.wrap(vals :+ CanonicalizeModel(stream, canon).leaf)
) )
case OptionType(_) => case OptionType(_) =>
RestrictionModel(streamName, streamType).wrap( RestrictionModel(streamName, streamType).wrap(
SeqModel.wrap( SeqModel.wrap(
SeqModel.wrap(inlines),
XorModel.wrap(vals :+ NullModel.leaf), XorModel.wrap(vals :+ NullModel.leaf),
CanonicalizeModel(stream, canon).leaf CanonicalizeModel(stream, canon).leaf
) )
) )
case _ => case _ =>
SeqModel.wrap(inlines ++ vals) SeqModel.wrap(vals)
} }
) )
} }

View File

@ -4,8 +4,27 @@ import aqua.model.*
import aqua.model.inline.raw.{ApplyIntoCopyRawInliner, CollectionRawInliner} import aqua.model.inline.raw.{ApplyIntoCopyRawInliner, CollectionRawInliner}
import aqua.model.inline.state.InliningState import aqua.model.inline.state.InliningState
import aqua.raw.ops.* import aqua.raw.ops.*
import aqua.raw.value.{CollectionRaw, LiteralRaw, MakeStructRaw, VarRaw} import aqua.raw.value.{
import aqua.types.{CanonStreamType, OptionType, ScalarType, StreamMapType, StreamType, StructType} CallArrowRaw,
CallServiceRaw,
CollectionRaw,
LiteralRaw,
MakeStructRaw,
VarRaw
}
import aqua.types.{
ArrowType,
CanonStreamType,
LiteralType,
NilType,
OptionType,
ProductType,
ScalarType,
StreamMapType,
StreamType,
StructType
}
import cats.data.{NonEmptyList, NonEmptyMap} import cats.data.{NonEmptyList, NonEmptyMap}
import cats.syntax.show.* import cats.syntax.show.*
import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.flatspec.AnyFlatSpec
@ -38,18 +57,28 @@ class CollectionRawInlinerSpec extends AnyFlatSpec with Matchers {
val expected = val expected =
RestrictionModel("option-inline", StreamType(nestedType)).wrap( // create a stream RestrictionModel("option-inline", StreamType(nestedType)).wrap( // create a stream
SeqModel.wrap( SeqModel.wrap(
// create an object
RestrictionModel(streamMapVar.name, streamMapType).wrap(
InsertKeyValueModel(LiteralModel.quote("field1"), LiteralModel.number(3), streamMapVar.name, streamMapType).leaf,
CanonicalizeModel(streamMapVar, CallModel.Export("nested_type_obj", nestedType)).leaf
),
XorModel.wrap( XorModel.wrap(
SeqModel.wrap( SeqModel.wrap(
// push object to the stream // create an object
PushToStreamModel( RestrictionModel(streamMapVar.name, streamMapType).wrap(
VarModel("nested_type_obj", nestedType), InsertKeyValueModel(
CallModel.Export("option-inline", StreamType(nestedType)) LiteralModel.quote("field1"),
).leaf LiteralModel.number(3),
streamMapVar.name,
streamMapType
).leaf,
CanonicalizeModel(
streamMapVar,
CallModel.Export("nested_type_obj", nestedType)
).leaf
),
SeqModel.wrap(
// push object to the stream
PushToStreamModel(
VarModel("nested_type_obj", nestedType),
CallModel.Export("option-inline", StreamType(nestedType))
).leaf
)
), ),
NullModel.leaf NullModel.leaf
), ),
@ -64,4 +93,48 @@ class CollectionRawInlinerSpec extends AnyFlatSpec with Matchers {
tree.get.equalsOrShowDiff(expected) shouldBe true tree.get.equalsOrShowDiff(expected) shouldBe true
} }
"collection inliner" should "unfold option with calculations inside xor (bug LNG-351)" in {
val zero = LiteralRaw("0", ScalarType.u32)
val call = CallServiceRaw(
LiteralRaw.quote("srv"),
"someCall",
ArrowType(NilType, ProductType(ScalarType.u32 :: Nil)),
Nil
)
val raw = CollectionRaw(NonEmptyList.of(call, zero), OptionType(ScalarType.u32))
val (v, tree) =
RawValueInliner.valueToModel[InliningState](raw, false).runA(InliningState()).value
val streamValue = VarModel("option-inline", StreamType(LiteralType.unsigned))
val resultValue = VarModel("option-inline-0", CanonStreamType(LiteralType.unsigned))
v shouldBe resultValue
val expected = RestrictionModel(streamValue.name, streamValue.`type`).wrap(
SeqModel.wrap(
XorModel.wrap(
SeqModel.wrap(
CallServiceModel("srv", "someCall", Nil, VarModel("someCall", ScalarType.u32)).leaf,
PushToStreamModel(
VarModel("someCall", ScalarType.u32),
CallModel.Export(streamValue.name, streamValue.`type`)
).leaf
),
PushToStreamModel(
LiteralModel.number(0),
CallModel.Export(streamValue.name, streamValue.`type`)
).leaf,
NullModel.leaf
),
CanonicalizeModel(streamValue, CallModel.Export(resultValue.name, resultValue.`type`)).leaf
)
)
tree.get.equalsOrShowDiff(expected) shouldBe true
}
} }