-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[6.0] Lazy default for Option.getOrElse and Coll.getOrElse #1008
Changes from 4 commits
dd62bd7
aaef77e
8f9b549
4c63a60
61f90cd
26809c9
57ba522
8da3575
8f45909
f151e1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7957,77 +7957,81 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => | |
) | ||
) | ||
) | ||
verifyCases( | ||
// (coll, (index, default)) | ||
{ | ||
def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) | ||
Seq( | ||
((Coll[Int](), (0, default)), success(default)), | ||
((Coll[Int](), (-1, default)), success(default)), | ||
((Coll[Int](1), (0, default)), success(1)), | ||
((Coll[Int](1), (1, default)), success(default)), | ||
((Coll[Int](1), (-1, default)), success(default)), | ||
((Coll[Int](1, 2), (0, default)), success(1)), | ||
((Coll[Int](1, 2), (1, default)), success(2)), | ||
((Coll[Int](1, 2), (2, default)), success(default)), | ||
((Coll[Int](1, 2), (-1, default)), success(default)) | ||
) | ||
}, | ||
existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), | ||
"{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", | ||
if (lowerMethodCallsInTests) | ||
FuncValue( | ||
Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), | ||
BlockValue( | ||
Vector( | ||
ValDef( | ||
3, | ||
List(), | ||
SelectField.typed[Value[STuple]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
2.toByte | ||
|
||
if(!VersionContext.current.isV6SoftForkActivated) { | ||
verifyCases( | ||
// (coll, (index, default)) | ||
{ | ||
def success[T](v: T) = Expected(Success(v), 1773, costDetails, 1773) | ||
|
||
Seq( | ||
((Coll[Int](), (0, default)), success(default)), | ||
((Coll[Int](), (-1, default)), success(default)), | ||
((Coll[Int](1), (0, default)), success(1)), | ||
((Coll[Int](1), (1, default)), success(default)), | ||
((Coll[Int](1), (-1, default)), success(default)), | ||
((Coll[Int](1, 2), (0, default)), success(1)), | ||
((Coll[Int](1, 2), (1, default)), success(2)), | ||
((Coll[Int](1, 2), (2, default)), success(default)), | ||
((Coll[Int](1, 2), (-1, default)), success(default)) | ||
) | ||
}, | ||
existingFeature((x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2), | ||
"{ (x: (Coll[Int], (Int, Int))) => x._1.getOrElse(x._2._1, x._2._2) }", | ||
if (lowerMethodCallsInTests) | ||
FuncValue( | ||
Vector((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), | ||
BlockValue( | ||
Vector( | ||
ValDef( | ||
3, | ||
List(), | ||
SelectField.typed[Value[STuple]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
2.toByte | ||
) | ||
) | ||
) | ||
), | ||
ByIndex( | ||
SelectField.typed[Value[SCollection[SInt.type]]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
1.toByte | ||
), | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), | ||
Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) | ||
ByIndex( | ||
SelectField.typed[Value[SCollection[SInt.type]]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
1.toByte | ||
), | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), | ||
Some(SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte)) | ||
) | ||
) | ||
) | ||
) | ||
else | ||
FuncValue( | ||
Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), | ||
BlockValue( | ||
Array( | ||
ValDef( | ||
3, | ||
List(), | ||
SelectField.typed[Value[STuple]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
2.toByte | ||
else | ||
FuncValue( | ||
Array((1, SPair(SCollectionType(SInt), SPair(SInt, SInt)))), | ||
BlockValue( | ||
Array( | ||
ValDef( | ||
3, | ||
List(), | ||
SelectField.typed[Value[STuple]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
2.toByte | ||
) | ||
) | ||
) | ||
), | ||
MethodCall.typed[Value[SInt.type]]( | ||
SelectField.typed[Value[SCollection[SInt.type]]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
1.toByte | ||
), | ||
SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), | ||
Vector( | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) | ||
), | ||
Map() | ||
MethodCall.typed[Value[SInt.type]]( | ||
SelectField.typed[Value[SCollection[SInt.type]]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SPair(SInt, SInt))), | ||
1.toByte | ||
), | ||
SCollectionMethods.getMethodByName("getOrElse").withConcreteTypes(Map(STypeVar("IV") -> SInt)), | ||
Vector( | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 1.toByte), | ||
SelectField.typed[Value[SInt.type]](ValUse(3, SPair(SInt, SInt)), 2.toByte) | ||
), | ||
Map() | ||
) | ||
) | ||
) | ||
) | ||
)) | ||
)) | ||
} | ||
} | ||
|
||
property("Tuple size method equivalence") { | ||
|
@@ -8591,13 +8595,15 @@ class LanguageSpecificationV5 extends LanguageSpecificationBase { suite => | |
"{ (x: Option[Long]) => x.isDefined }", | ||
FuncValue(Vector((1, SOption(SLong))), OptionIsDefined(ValUse(1, SOption(SLong)))))) | ||
|
||
verifyCases( | ||
Seq( | ||
(None -> Expected(Success(1L), 1766, costDetails3, 1766)), | ||
(Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766))), | ||
existingFeature({ (x: Option[Long]) => x.getOrElse(1L) }, | ||
"{ (x: Option[Long]) => x.getOrElse(1L) }", | ||
FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L))))) | ||
if (!VersionContext.current.isV6SoftForkActivated) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above, this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
verifyCases( | ||
Seq( | ||
(None -> Expected(Success(1L), 1766, costDetails3, 1766)), | ||
(Some(10L) -> Expected(Success(10L), 1766, costDetails3, 1766))), | ||
existingFeature({ (x: Option[Long]) => x.getOrElse(1L) }, | ||
"{ (x: Option[Long]) => x.getOrElse(1L) }", | ||
FuncValue(Vector((1, SOption(SLong))), OptionGetOrElse(ValUse(1, SOption(SLong)), LongConstant(1L))))) | ||
} | ||
|
||
verifyCases( | ||
Seq( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
package sigma | ||
|
||
import sigma.ast.{Apply, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, JitCost, OptionGet, SBigInt, SByte, SInt, SLong, SShort, ValUse} | ||
import sigma.ast.{Apply, ArithOp, BlockValue, ByIndex, CompanionDesc, Constant, Downcast, FixedCost, FixedCostItem, FuncValue, GetVar, IntConstant, JitCost, LongConstant, MethodCall, OptionGet, OptionGetOrElse, PerItemCost, SBigInt, SByte, SCollection, SCollectionMethods, SCollectionType, SInt, SLong, SOption, SPair, SShort, STuple, STypeVar, SelectField, ValDef, ValUse, Value} | ||
import sigma.data.{CBigInt, ExactNumeric} | ||
import sigma.eval.SigmaDsl | ||
import sigma.eval.{SigmaDsl, TracedCost} | ||
import sigma.serialization.ValueCodes.OpCode | ||
import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps} | ||
import sigmastate.exceptions.MethodNotFound | ||
|
||
|
@@ -168,7 +169,62 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite => | |
Seq(compareTo, bitOr, bitAnd).foreach(_.checkEquality(x)) | ||
} | ||
} | ||
} | ||
|
||
property("Option.getOrElse with lazy default") { | ||
def getOrElse = newFeature( | ||
{ (x: Option[Long]) => x.getOrElse(1 / 0L) }, | ||
"{ (x: Option[Long]) => x.getOrElse(1 / 0L) }", | ||
FuncValue( | ||
Array((1, SOption(SLong))), | ||
OptionGetOrElse( | ||
ValUse(1, SOption(SLong)), | ||
ArithOp(LongConstant(1L), LongConstant(0L), OpCode @@ (-99.toByte)) | ||
) | ||
) | ||
) | ||
|
||
if (VersionContext.current.isV6SoftForkActivated) { | ||
forAll { x: Option[Long] => | ||
Seq(getOrElse).map(_.checkEquality(x)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check equality is not enough, as it doesn't involve all interpreter components. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please specify what is needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. verifyCases will exercise all the components. |
||
} | ||
} else { | ||
forAll { x: Option[Long] => | ||
if (x.isEmpty) { | ||
Seq(getOrElse).map(_.checkEquality(x)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
property("Coll getOrElse with lazy default") { | ||
def getOrElse = newFeature( | ||
(x: (Coll[Int], Int)) => x._1.toArray.unapply(x._2).getOrElse(1 / 0), | ||
"{ (x: (Coll[Int], Int)) => x._1.getOrElse(x._2, 1 / 0) }", | ||
FuncValue( | ||
Array((1, SPair(SCollectionType(SInt), SInt))), | ||
ByIndex( | ||
SelectField.typed[Value[SCollection[SInt.type]]]( | ||
ValUse(1, SPair(SCollectionType(SInt), SInt)), | ||
1.toByte | ||
), | ||
SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte), | ||
Some(ArithOp(IntConstant(1), IntConstant(0), OpCode @@ (-99.toByte))) | ||
) | ||
) | ||
) | ||
|
||
if (VersionContext.current.isV6SoftForkActivated) { | ||
forAll { x: (Coll[Int], Int) => | ||
Seq(getOrElse).map(_.checkEquality(x)) | ||
} | ||
} else { | ||
forAll { x: (Coll[Int], Int) => | ||
if (x._1.isEmpty) { | ||
Seq(getOrElse).map(_.checkEquality(x)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
property("BigInt methods equivalence (new features)") { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Protocol change like this can be tested using changeFeature (see other tests) in combination with newVersionedResults (also see code). In this case both old and new behaviour will be tested.
In principle this test case can be moved to LSV6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changedFeature is not enough here, you need for versioned verifyCases, as in 6.0 costing trace would be different in some cases due to difference in default evaluation (at the same time, it wouldnt provide higher cost, so the change is secure costing-wise).
Seems like *Feature machinery is overly complex, but still not enough to describe protocol changes, thus I would recommend to decide what it is actually testing (or should test), and then follow simpler approaches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see other examples where changedFeature is used, there are test cases where cost trace depend on the version and you can pass different traces to the constructor of Expected.
The perceived complexity is due to learning curve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changedFeature is tied to V4/V5 switch, see checkExpected in ChangedFeature / checkVerify functions in SigmaDslTesting. So it cant be used in V6 testing without modifications it seems. So it is definitely not about learning curve, changedFeature is just not ready for V6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aslesarenko see #1024 for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done