From 2ba5a4fb7f50424a2a2395ceb08b43726c54785a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 8 Oct 2024 14:57:32 +0300 Subject: [PATCH] PropertyCallSerializer fix, explicitTypeArgs fix, more tests --- .../src/main/scala/sigma/ast/methods.scala | 6 ++- .../PropertyCallSerializer.scala | 27 ++++++++++- .../sigma/compiler/ir/GraphBuilding.scala | 3 ++ .../ir/wrappers/sigma/impl/SigmaDslImpl.scala | 12 ++--- .../utxo/BasicOpsSpecification.scala | 45 ++++++++++++++++++- 5 files changed, 82 insertions(+), 11 deletions(-) diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala index 74ca9cdd3f..62a8691eec 100644 --- a/data/shared/src/main/scala/sigma/ast/methods.scala +++ b/data/shared/src/main/scala/sigma/ast/methods.scala @@ -1844,8 +1844,10 @@ case object SGlobalMethods extends MonoTypeMethods { ArgInfo("value", "value to be serialized")) lazy val noneMethod = SMethod(this, "none", - SFunc(Array(SGlobal, tT), SOption(tT), Array(paramT)), 9, FixedCost(JitCost(5))) // todo: cost - .withIRInfo(MethodCallIrBuilder) + SFunc(Array(SGlobal), SOption(tT), Array(paramT)), 9, FixedCost(JitCost(5)), Seq(tT)) // todo: cost + .withIRInfo(MethodCallIrBuilder, + javaMethodOf[SigmaDslBuilder, RType[_]]("none"), + { mtype => Array(mtype.tRange) }) .withInfo(MethodCall, "") protected override def getMethods() = super.getMethods() ++ { diff --git a/data/shared/src/main/scala/sigma/serialization/PropertyCallSerializer.scala b/data/shared/src/main/scala/sigma/serialization/PropertyCallSerializer.scala index 10411e21ce..072e7a7ed5 100644 --- a/data/shared/src/main/scala/sigma/serialization/PropertyCallSerializer.scala +++ b/data/shared/src/main/scala/sigma/serialization/PropertyCallSerializer.scala @@ -5,6 +5,10 @@ import sigma.serialization.CoreByteWriter.{ArgInfo, DataInfo} import sigma.ast._ import sigma.ast.syntax.SValue import SigmaByteWriter._ +import debox.cfor +import sigma.util.safeNewArray + +import scala.collection.compat.immutable.ArraySeq case class PropertyCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[SType]], STypeSubst) => Value[SType]) extends ValueSerializer[MethodCall] { @@ -17,6 +21,10 @@ case class PropertyCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value w.put(mc.method.objType.typeId, typeCodeInfo) w.put(mc.method.methodId, methodCodeInfo) w.putValue(mc.obj, objInfo) + mc.method.explicitTypeArgs.foreach { a => + val tpe = mc.typeSubst(a) // existence is checked in MethodCall constructor + w.putType(tpe) + } } override def parse(r: SigmaByteReader): Value[SType] = { @@ -24,7 +32,22 @@ case class PropertyCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value val methodId = r.getByte() val obj = r.getValue() val method = SMethod.fromIds(typeId, methodId) - val specMethod = method.specializeFor(obj.tpe, SType.EmptySeq) - cons(obj, specMethod, Value.EmptySeq, EmptySubst) + + val (explicitTypeSubst: Map[STypeVar, SType], specMethod: SMethod) = if (method.hasExplicitTypeArgs) { + val nTypes = method.explicitTypeArgs.length + val res = safeNewArray[SType](nTypes) + cfor(0)(_ < nTypes, _ + 1) { i => + res(i) = r.getType() + } + val explicitTypes = ArraySeq.unsafeWrapArray(res) + val explicitTypeSubst = method.explicitTypeArgs.zip(explicitTypes).toMap + val specMethod = method.withConcreteTypes(explicitTypeSubst) + (explicitTypeSubst, specMethod) + } else { + val specMethod = method.specializeFor(obj.tpe, SType.EmptySeq) + (EmptySubst, specMethod) + } + + cons(obj, specMethod, Value.EmptySeq, explicitTypeSubst) } } diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala index c1d1db40a2..b1c6f9de88 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala @@ -1178,6 +1178,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext => val value = asRep[tT.WrappedType](argsV(0)) val cT = stypeToElem(typeSubst.apply(tT)).asInstanceOf[Elem[tT.WrappedType]] g.some(value)(cT) + case SGlobalMethods.noneMethod.name => + val cT = stypeToElem(typeSubst.apply(tT)).asInstanceOf[Elem[tT.WrappedType]] + g.none()(cT) case _ => throwError() } case (x: Ref[tNum], _: SNumericTypeMethods) => method.name match { diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala index de4370da50..7e5de4bd3b 100644 --- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala +++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala @@ -1974,22 +1974,22 @@ object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") { override def fromBigEndianBytes[T](bytes: Ref[Coll[Byte]])(implicit cT: Elem[T]): Ref[T] = { asRep[T](mkMethodCall(self, SigmaDslBuilderClass.getMethod("fromBigEndianBytes", classOf[Sym], classOf[Elem[T]]), - Array[AnyRef](bytes, cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType))), - true, false, cT)) + Array[AnyRef](bytes, cT), + true, false, cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType)))) } override def some[T](value: Ref[T])(implicit cT: Elem[T]): Ref[WOption[T]] = { asRep[WOption[T]](mkMethodCall(self, SigmaDslBuilderClass.getMethod("some", classOf[Sym], classOf[Elem[T]]), - Array[AnyRef](value, cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType))), - true, false, element[WOption[T]])) + Array[AnyRef](value, cT), + true, false, element[WOption[T]], Map(tT -> Evaluation.rtypeToSType(cT.sourceType)))) } override def none[T]()(implicit cT: Elem[T]): Ref[WOption[T]] = { asRep[WOption[T]](mkMethodCall(self, SigmaDslBuilderClass.getMethod("none", classOf[Elem[T]]), - Array[AnyRef](cT, Map(tT -> Evaluation.rtypeToSType(cT.sourceType))), - true, false, element[WOption[T]])) + Array[AnyRef](cT), + true, false, element[WOption[T]], Map(tT -> Evaluation.rtypeToSType(cT.sourceType)))) } } diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala index 16817e08ae..1ae52d0971 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala @@ -989,7 +989,6 @@ class BasicOpsSpecification extends CompilerTestingCommons } } - // todo: failing, needs for Header (de)serialization support from https://github.com/ScorexFoundation/sigmastate-interpreter/pull/972 property("serialize - collection of collection of headers") { val td = new SigmaTestingData {} val h1 = td.TestData.h1 @@ -1755,4 +1754,48 @@ class BasicOpsSpecification extends CompilerTestingCommons } } + property("Global.some - computable value") { + val ext: Seq[VarBinding] = Seq( + (intVar1, IntConstant(0)) + ) + def someTest(): Assertion = { + test("some", env, ext, + """{ + | val i = getVar[Int](1) + | val xo = Global.some[Int](i.get) + | xo == i + |}""".stripMargin, + null + ) + } + + if (VersionContext.current.isV6SoftForkActivated) { + someTest() + } else { + an[Exception] should be thrownBy someTest() + } + } + + property("Global.none") { + val ext: Seq[VarBinding] = Seq( + (intVar1, IntConstant(0)) + ) + def someTest(): Assertion = { + test("some", env, ext, + """{ + | val xo = Global.some[Long](5L) + | val xn = Global.none[Long]() + | xn.isDefined == false && xn != xo + |}""".stripMargin, + null + ) + } + + if (VersionContext.current.isV6SoftForkActivated) { + someTest() + } else { + an[Exception] should be thrownBy someTest() + } + } + }