Skip to content

Commit

Permalink
merging w. 6.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Sep 17, 2024
2 parents a8f1d66 + d284f79 commit 3f6f8d5
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 75 deletions.
3 changes: 1 addition & 2 deletions core/shared/src/main/scala/sigma/ast/SType.scala
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypePa
}

object SFunc {
final val FuncTypeCode: TypeCode = TypeCodes.FirstFuncType
final val FuncTypeCode: TypeCode = TypeCodes.FuncType
def apply(tDom: SType, tRange: SType): SFunc = SFunc(Array(tDom), tRange) // HOTSPOT:
val identity = { x: Any => x }
}
Expand Down Expand Up @@ -654,7 +654,6 @@ object SOption extends STypeCompanion {
def apply[T <: SType](implicit elemType: T, ov: Overloaded1): SOption[T] = SOption(elemType)
}


/** Base class for descriptors of `Coll[T]` ErgoTree type for some elemType T. */
trait SCollection[T <: SType] extends SProduct with SGenericType {
def elemType: T
Expand Down
14 changes: 3 additions & 11 deletions core/shared/src/main/scala/sigma/ast/STypeParam.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,10 @@ package sigma.ast

/** Represents a type parameter in a type system.
*
* @param ident The identifier for this type parameter.
* @param upperBound The upper bound of this type parameter, if exists.
* @param lowerBound The lower bound of this type parameter, if exists.
* @note Type parameters with bounds are currently not supported.
* @param ident The identifier for this type parameter
*/
case class STypeParam(
ident: STypeVar,
upperBound: Option[SType] = None,
lowerBound: Option[SType] = None) {
assert(upperBound.isEmpty && lowerBound.isEmpty, s"Type parameters with bounds are not supported, but found $this")

override def toString = ident.toString + upperBound.fold("")(u => s" <: $u") + lowerBound.fold("")(l => s" >: $l")
case class STypeParam(ident: STypeVar) {
override def toString = ident.toString
}

object STypeParam {
Expand Down
6 changes: 2 additions & 4 deletions core/shared/src/main/scala/sigma/ast/TypeCodes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ object TypeCodes {

val LastDataType : TypeCode = TypeCode @@ 111.toByte

/** SFunc types occupy remaining space of byte values [FirstFuncType .. 255] */
val FirstFuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte

val LastFuncType : TypeCode = TypeCode @@ 255.toByte
/** SFunc type */
val FuncType: TypeCode = TypeCode @@ (LastDataType + 1).toByte

/** We use optimized encoding of constant values to save space in serialization.
* Since Box registers are stored as Constant nodes we save 1 byte for each register.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigma.serialization

import debox.cfor
import sigma.VersionContext
import sigma.ast.SCollectionType.{CollectionTypeCode, NestedCollectionTypeCode}
import sigma.ast._
import sigma.serialization.{CoreByteReader, CoreByteWriter, InvalidTypePrefix}
Expand Down Expand Up @@ -101,6 +102,17 @@ class TypeSerializer {
// `Tuple` type with more than 4 items `(Int, Byte, Box, Boolean, Int)`
serializeTuple(tup, w)
}
case SFunc(tDom, tRange, tpeParams) =>
w.put(SFunc.FuncTypeCode)
w.putUByte(tDom.length)
tDom.foreach { st =>
serialize(st, w)
}
serialize(tRange, w)
w.putUByte(tpeParams.length)
tpeParams.foreach { tp =>
serialize(tp.ident, w)
}
case typeIdent: STypeVar => {
w.put(typeIdent.typeCode)
val bytes = typeIdent.name.getBytes(StandardCharsets.UTF_8)
Expand Down Expand Up @@ -189,7 +201,24 @@ class TypeSerializer {
case SHeader.typeCode => SHeader
case SPreHeader.typeCode => SPreHeader
case SGlobal.typeCode => SGlobal
case SFunc.FuncTypeCode if VersionContext.current.isV6SoftForkActivated =>
val tdLength = r.getUByte()

val tDom = (1 to tdLength).map { _ =>
deserialize(r)
}
val tRange = deserialize(r)
val tpeParamsLength = r.getUByte()
val tpeParams = (1 to tpeParamsLength).map { _ =>
val ident = deserialize(r)
require(ident.isInstanceOf[STypeVar])
STypeParam(ident.asInstanceOf[STypeVar])
}
SFunc(tDom, tRange, tpeParams)
// todo: serialize tParams
case _ =>
// todo: 6.0: replace 1008 check with identical behavior but other opcode, to activate
// ReplacedRule(1008 -> new opcode) during 6.0 activation
CheckTypeCode(c.toByte)
NoType
}
Expand Down
37 changes: 31 additions & 6 deletions data/shared/src/main/scala/sigma/ast/methods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1052,7 +1052,7 @@ case object SBoxMethods extends MonoTypeMethods {
| identifier followed by box index in the transaction outputs.
""".stripMargin ) // see ExtractCreationInfo

lazy val getRegMethod = SMethod(this, "getReg",
lazy val getRegMethodV5 = SMethod(this, "getReg",
SFunc(Array(SBox, SInt), SOption(tT), Array(paramT)), 7, ExtractRegisterAs.costKind)
.withInfo(ExtractRegisterAs,
""" Extracts register by id and type.
Expand All @@ -1061,23 +1061,49 @@ case object SBoxMethods extends MonoTypeMethods {
""".stripMargin,
ArgInfo("regId", "zero-based identifier of the register."))

lazy val getRegMethodV6 = SMethod(this, "getReg",
SFunc(Array(SBox, SInt), SOption(tT), Array(paramT)), 7, ExtractRegisterAs.costKind, Seq(tT))
.withIRInfo(MethodCallIrBuilder,
javaMethodOf[Box, Int, RType[_]]("getReg"),
{ mtype => Array(mtype.tRange.asOption[SType].elemType) })
.withInfo(MethodCall, """ Extracts register by id and type.
| Type param \lst{T} expected type of the register.
| Returns \lst{Some(value)} if the register is defined and has given type and \lst{None} otherwise
""".stripMargin,
ArgInfo("regId", "zero-based identifier of the register."))

lazy val tokensMethod = SMethod(
this, "tokens", SFunc(SBox, ErgoBox.STokensRegType), 8, FixedCost(JitCost(15)))
.withIRInfo(MethodCallIrBuilder)
.withInfo(PropertyCall, "Secondary tokens")


// should be lazy to solve recursive initialization
protected override def getMethods() = super.getMethods() ++ Array(
lazy val commonBoxMethods = super.getMethods() ++ Array(
ValueMethod, // see ExtractAmount
PropositionBytesMethod, // see ExtractScriptBytes
BytesMethod, // see ExtractBytes
BytesWithoutRefMethod, // see ExtractBytesWithNoRef
IdMethod, // see ExtractId
creationInfoMethod,
getRegMethod,
tokensMethod
) ++ registers(8)

lazy val v5Methods = commonBoxMethods ++ Array(
getRegMethodV5
)

lazy val v6Methods = commonBoxMethods ++ Array(
getRegMethodV6
)

// should be lazy to solve recursive initialization
protected override def getMethods() = {
if (VersionContext.current.isV6SoftForkActivated) {
v6Methods
} else {
v5Methods
}
}

}

/** Type descriptor of `AvlTree` type of ErgoTree. */
Expand Down Expand Up @@ -1523,7 +1549,6 @@ case object SGlobalMethods extends MonoTypeMethods {
lazy val deserializeToMethod = SMethod(
this, "deserializeTo", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 3, deserializeCostKind, Seq(tT))
.withIRInfo(MethodCallIrBuilder, desJava)
// .copy(irInfo = MethodIRInfo(None, Some(desJava), None))
.withInfo(MethodCall, "Byte-wise XOR of two collections of bytes", // todo: desc
ArgInfo("left", "left operand"), ArgInfo("right", "right operand"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,6 @@ case class MethodCallSerializer(cons: (Value[SType], SMethod, IndexedSeq[Value[S
types
}

methodTemplate.specializeFor(obj.tpe, argTypes)
method.specializeFor(obj.tpe, argTypes)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import org.scalacheck.Arbitrary._
import org.scalacheck.Gen.{choose, frequency}
import org.scalacheck.util.Buildable
import org.scalacheck.{Arbitrary, Gen}
import sigma.data._
import scorex.crypto.authds.{ADDigest, ADKey}
import scorex.util.encode.{Base58, Base64}
import scorex.util.{ModifierId, bytesToId}
Expand All @@ -27,6 +26,7 @@ import sigma.util.Extensions.EcpOps
import sigma.validation.{ChangedRule, DisabledRule, EnabledRule, ReplacedRule, RuleStatus}
import sigma.validation.ValidationRules.FirstRuleId
import ErgoTree.ZeroHeader
import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CBox, CHeader, COR, CTHRESHOLD, Digest32Coll, ProveDHTuple, ProveDlog, RType, SigmaBoolean}
import sigma.eval.Extensions.{EvalIterableOps, SigmaBooleanOps}
import sigma.eval.SigmaDsl
import sigma.interpreter.{ContextExtension, ProverResult}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ object SigmaPPrint extends PPrinter {
s"SOption[${typeName(ot.elemType)}]"
case _: STuple =>
"STuple"
case _: SFunc =>
s"SFunc"
case _ =>
sys.error(s"Cannot get typeName($tpe)")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sigma.compiler.ir
import org.ergoplatform._
import sigma.ast.SCollection.SByteArray
import sigma.{SigmaException, VersionContext, ast}
import sigma.ast.SType.tT
import sigma.ast.TypeCodes.LastConstantCode
import sigma.ast.Value.Typed
import sigma.ast.syntax.{SValue, ValueOps}
Expand Down Expand Up @@ -1041,6 +1042,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case (box: Ref[Box]@unchecked, SBoxMethods) => method.name match {
case SBoxMethods.tokensMethod.name =>
box.tokens
case SBoxMethods.getRegMethodV6.name if VersionContext.current.isV6SoftForkActivated =>
val c1 = asRep[Int](argsV(0))
val c2 = stypeToElem(typeSubst.apply(tT))
box.getReg(c1)(c2)
case _ => throwError
}
case (ctx: Ref[Context]@unchecked, SContextMethods) => method.name match {
Expand Down
2 changes: 1 addition & 1 deletion sc/shared/src/main/scala/sigma/compiler/ir/IRContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ trait IRContext
override def invokeUnlifted(e: Elem[_], mc: MethodCall, dataEnv: DataEnv): Any = e match {
case _: CollElem[_,_] => mc match {
case CollMethods.map(_, f) =>
val newMC = mc.copy(args = mc.args :+ f.elem.eRange)(mc.resultType, mc.isAdapterCall)
val newMC = mc.copy(args = mc.args :+ f.elem.eRange)(mc.resultType, mc.isAdapterCall, mc.typeSubst)
super.invokeUnlifted(e, newMC, dataEnv)
case _ =>
super.invokeUnlifted(e, mc, dataEnv)
Expand Down
16 changes: 12 additions & 4 deletions sc/shared/src/main/scala/sigma/compiler/ir/MethodCalls.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sigma.compiler.ir

import debox.{cfor, Buffer => DBuffer}
import sigma.ast.{SType, STypeVar}
import sigma.compiler.DelayInvokeException
import sigma.reflection.RMethod
import sigma.util.CollectionUtil.TraversableOps
Expand All @@ -26,7 +27,9 @@ trait MethodCalls extends Base { self: IRContext =>
* given `method`.
*/
case class MethodCall private[MethodCalls](receiver: Sym, method: RMethod, args: Seq[AnyRef], neverInvoke: Boolean)
(val resultType: Elem[Any], val isAdapterCall: Boolean = false) extends Def[Any] {
(val resultType: Elem[Any],
val isAdapterCall: Boolean = false,
val typeSubst: Map[STypeVar, SType]) extends Def[Any] {

override def mirror(t: Transformer): Ref[Any] = {
val len = args.length
Expand Down Expand Up @@ -99,9 +102,14 @@ trait MethodCalls extends Base { self: IRContext =>
}

/** Creates new MethodCall node and returns its node ref. */
def mkMethodCall(receiver: Sym, method: RMethod, args: Seq[AnyRef],
neverInvoke: Boolean, isAdapterCall: Boolean, resultElem: Elem[_]): Sym = {
reifyObject(MethodCall(receiver, method, args, neverInvoke)(asElem[Any](resultElem), isAdapterCall))
def mkMethodCall(receiver: Sym,
method: RMethod,
args: Seq[AnyRef],
neverInvoke: Boolean,
isAdapterCall: Boolean,
resultElem: Elem[_],
typeSubst: Map[STypeVar, SType] = Map.empty): Sym = {
reifyObject(MethodCall(receiver, method, args, neverInvoke)(asElem[Any](resultElem), isAdapterCall, typeSubst))
}

@tailrec
Expand Down
16 changes: 7 additions & 9 deletions sc/shared/src/main/scala/sigma/compiler/ir/TreeBuilding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,10 @@ trait TreeBuilding extends Base { IR: IRContext =>
mkExtractAmount(box.asBox)
case BoxM.propositionBytes(In(box)) =>
mkExtractScriptBytes(box.asBox)
case BoxM.getReg(In(box), regId, _) =>
case BoxM.getReg(In(box), regId, _) if regId.isConst =>
val tpe = elemToSType(s.elem).asOption
if (regId.isConst)
mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(valueFromRep(regId)), tpe)
else
error(s"Non constant expressions (${regId.node}) are not supported in getReg")
case BoxM.creationInfo(In(box)) =>
mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(valueFromRep(regId)), tpe)
case BoxM.creationInfo(In(box)) =>
mkExtractCreationInfo(box.asBox)
case BoxM.id(In(box)) =>
mkExtractId(box.asBox)
Expand Down Expand Up @@ -404,13 +401,14 @@ trait TreeBuilding extends Base { IR: IRContext =>
mkMultiplyGroup(obj.asGroupElement, arg.asGroupElement)

// Fallback MethodCall rule: should be the last in this list of cases
case Def(MethodCall(objSym, m, argSyms, _)) =>
case Def(mc @ MethodCall(objSym, m, argSyms, _)) =>
val obj = recurse[SType](objSym)
val args = argSyms.collect { case argSym: Sym => recurse[SType](argSym) }
MethodsContainer.getMethod(obj.tpe, m.getName) match {
case Some(method) =>
val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe))
builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, Map())
val typeSubst = mc.typeSubst
val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe)).withConcreteTypes(typeSubst)
builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, typeSubst)
case None =>
error(s"Cannot find method ${m.getName} in object $obj")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import sigma.compiler.ir.wrappers.sigma.impl.SigmaDslDefs
import scala.collection.compat.immutable.ArraySeq

package impl {
import sigma.Evaluation
import sigma.ast.SType.tT
import sigma.compiler.ir.meta.ModuleInfo
import sigma.compiler.ir.wrappers.sigma.SigmaDsl
import sigma.compiler.ir.{Base, GraphIRReflection, IRContext}
Expand Down Expand Up @@ -620,10 +622,11 @@ object Box extends EntityObject("Box") {
}

override def getReg[T](i: Ref[Int])(implicit cT: Elem[T]): Ref[WOption[T]] = {
val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(self,
BoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](i, cT),
true, false, element[WOption[T]]))
true, false, element[WOption[T]], Map(tT -> st) ))
}

override def tokens: Ref[Coll[(Coll[Byte], Long)]] = {
Expand Down Expand Up @@ -695,10 +698,11 @@ object Box extends EntityObject("Box") {
}

def getReg[T](i: Ref[Int])(implicit cT: Elem[T]): Ref[WOption[T]] = {
val st = Evaluation.rtypeToSType(cT.sourceType)
asRep[WOption[T]](mkMethodCall(source,
BoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
Array[AnyRef](i, cT),
true, true, element[WOption[T]]))
true, true, element[WOption[T]], Map(tT -> st)))
}

def tokens: Ref[Coll[(Coll[Byte], Long)]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class SigmaTyper(val builder: SigmaBuilder,
case Apply(ApplyTypes(sel @ Select(obj, n, _), Seq(rangeTpe)), args) =>
val newObj = assignType(env, obj)
val newArgs = args.map(assignType(env, _))
obj.tpe match {
newObj.tpe match {
case SGlobal =>
SGlobalMethods.method(n) match {
case Some(method) =>
Expand Down Expand Up @@ -173,10 +173,10 @@ class SigmaTyper(val builder: SigmaBuilder,
case Some(method) =>
error(s"Don't know how to handle method $method in obj $p", sel.sourceContext)
case None =>
throw new MethodNotFound(s"Cannot find method '$n' in in the object $obj of Product type $p", obj.sourceContext.toOption)
throw new MethodNotFound(s"Cannot find method '$n' in in the object $newObj of Product type $p", newObj.sourceContext.toOption)
}
case _ =>
error(s"Cannot get field '$n' in in the object $obj of non-product type ${obj.tpe}", sel.sourceContext)
error(s"Cannot get field '$n' in in the object $newObj of non-product type ${newObj.tpe}", sel.sourceContext)
}

case app @ Apply(sel @ Select(obj, n, _), args) =>
Expand Down
24 changes: 0 additions & 24 deletions sc/shared/src/test/scala/sigma/LanguageSpecificationV5.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9823,30 +9823,6 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite =>
}
}

property("higher order lambdas") {
val f = existingFeature(
{ (xs: Coll[Int]) =>
val inc = { (x: Int) => x + 1 }

def apply(in: (Int => Int, Int)) = in._1(in._2)

xs.map { (x: Int) => apply((inc, x)) }
},
"""{(xs: Coll[Int]) =>
| val inc = { (x: Int) => x + 1 }
| def apply(in: (Int => Int, Int)) = in._1(in._2)
| xs.map { (x: Int) => apply((inc, x)) }
| }
|""".stripMargin
)

// TODO v6.0: Add support of SFunc in TypeSerializer (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/847)
assertExceptionThrown(
f.verifyCase(Coll[Int](), Expected(Success(Coll[Int]()), 0)),
exceptionLike[MatchError]("(SInt$) => SInt$ (of class sigma.ast.SFunc)")
)
}

override protected def afterAll(): Unit = {
printDebug(CErgoTreeEvaluator.DefaultProfiler.generateReport)
printDebug("==========================================================")
Expand Down
Loading

0 comments on commit 3f6f8d5

Please sign in to comment.