Skip to content

Commit

Permalink
close #906: lazy evaluation of default in Option.getOrElse and Coll.g…
Browse files Browse the repository at this point in the history
…etOrElse
  • Loading branch information
kushti committed Jun 11, 2024
1 parent dd62bd7 commit aaef77e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 17 deletions.
43 changes: 33 additions & 10 deletions data/shared/src/main/scala/sigma/ast/transformers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import sigma.eval.ErgoTreeEvaluator.DataEnv
import sigma.serialization.CoreByteWriter.ArgInfo
import sigma.serialization.OpCodes
import sigma.serialization.ValueCodes.OpCode
import sigma.{Box, Coll, Evaluation}
import sigma.{Box, Coll, Evaluation, VersionContext}

// TODO refactor: remove this trait as it doesn't have semantic meaning

Expand Down Expand Up @@ -258,10 +258,22 @@ case class ByIndex[V <: SType](input: Value[SCollection[V]],
val indexV = index.evalTo[Int](env)
default match {
case Some(d) =>
val dV = d.evalTo[V#WrappedType](env)
Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
addCost(ByIndex.costKind)
inputV.getOrElse(indexV, dV)
if (VersionContext.current.isV6SoftForkActivated) {
// lazy evaluation of default in 6.0
addCost(ByIndex.costKind)
if (inputV.isDefinedAt(indexV)) {
inputV.apply(indexV)
} else {
val dV = d.evalTo[V#WrappedType](env)
Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
inputV.getOrElse(indexV, dV)
}
} else {
val dV = d.evalTo[V#WrappedType](env)
Value.checkType(d, dV) // necessary because cast to V#WrappedType is erased
addCost(ByIndex.costKind)
inputV.getOrElse(indexV, dV)
}
case _ =>
addCost(ByIndex.costKind)
inputV.apply(indexV)
Expand Down Expand Up @@ -613,11 +625,22 @@ case class OptionGetOrElse[V <: SType](input: Value[SOption[V]], default: Value[
override val opType = SFunc(IndexedSeq(input.tpe, tpe), tpe)
override def tpe: V = input.tpe.elemType
protected final override def eval(env: DataEnv)(implicit E: ErgoTreeEvaluator): Any = {
val inputV = input.evalTo[Option[V#WrappedType]](env)
val dV = default.evalTo[V#WrappedType](env) // TODO v6.0: execute lazily (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/906)
Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
addCost(OptionGetOrElse.costKind)
inputV.getOrElse(dV)
if(VersionContext.current.isV6SoftForkActivated) {
// lazy evaluation of default in 6.0
val inputV = input.evalTo[Option[V#WrappedType]](env)
addCost(OptionGetOrElse.costKind)
inputV.getOrElse {
val dV = default.evalTo[V#WrappedType](env)
Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
dV
}
} else {
val inputV = input.evalTo[Option[V#WrappedType]](env)
val dV = default.evalTo[V#WrappedType](env)
Value.checkType(default, dV) // necessary because cast to V#WrappedType is erased
addCost(OptionGetOrElse.costKind)
inputV.getOrElse(dV)
}
}
}
object OptionGetOrElse extends ValueCompanion with FixedCostValueCompanion {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ class BasicOpsSpecification extends CompilerTestingCommons
"""{
| getVar[Int](1).getOrElse(getVar[Int](44).get) > 0
|}
|
|""".stripMargin,
null
)
Expand All @@ -179,15 +178,12 @@ class BasicOpsSpecification extends CompilerTestingCommons
}

property("Lazy evaluation of default in Coll.getOrElse") {
val customExt = Map (
1.toByte -> IntConstant(5)
).toSeq
def optTest() = test("getOrElse", env, customExt,
def optTest() = test("getOrElse", env, ext,
"""{
| val c = Coll[Int](1)
| c.getOrElse(0, getVar[Int](44).get) > 0
| c.getOrElse(0, getVar[Int](44).get) > 0 &&
| c.getOrElse(1, c.getOrElse(0, getVar[Int](44).get)) > 0
|}
|
|""".stripMargin,
null
)
Expand Down

0 comments on commit aaef77e

Please sign in to comment.