mirror of
https://github.com/digital-asset/daml.git
synced 2024-11-10 10:46:11 +03:00
LF: Scala serializability checker handle exceptions (#8363)
This is part of #8020. CHANGELOG_BEGIN CHANGELOG_END
This commit is contained in:
parent
2083f74cf2
commit
425fca6541
@ -62,7 +62,9 @@ private[validation] object Serializability {
|
||||
checkType(targ)
|
||||
case TBuiltin(builtinType) =>
|
||||
builtinType match {
|
||||
case BTInt64 | BTText | BTTimestamp | BTDate | BTParty | BTBool | BTUnit =>
|
||||
case BTInt64 | BTText | BTTimestamp | BTDate | BTParty | BTBool | BTUnit |
|
||||
BTAnyException | BTGeneralError | BTArithmeticError | BTContractError =>
|
||||
()
|
||||
case BTNumeric =>
|
||||
unserializable(URNumeric)
|
||||
case BTList =>
|
||||
@ -85,9 +87,6 @@ private[validation] object Serializability {
|
||||
unserializable(URAny)
|
||||
case BTTypeRep =>
|
||||
unserializable(URTypeRep)
|
||||
case BTAnyException | BTArithmeticError | BTContractError | BTGeneralError =>
|
||||
// TODO https://github.com/digital-asset/daml/issues/8020
|
||||
sys.error("exceptions not supported")
|
||||
}
|
||||
case TForall(_, _) =>
|
||||
unserializable(URForall)
|
||||
@ -135,6 +134,15 @@ private[validation] object Serializability {
|
||||
template.key.foreach(k => Env(version, world, context, SRKey, k.typ).checkType())
|
||||
}
|
||||
|
||||
def checkException(
|
||||
version: LanguageVersion,
|
||||
world: World,
|
||||
tyCon: TTyCon,
|
||||
): Unit = {
|
||||
val context = ContextDefException(tyCon.tycon)
|
||||
Env(version, world, context, SRExceptionArg, tyCon).checkType()
|
||||
}
|
||||
|
||||
def checkModule(world: World, pkgId: PackageId, module: Module): Unit = {
|
||||
val version = world.lookupPackage(NoContext, pkgId).languageVersion
|
||||
module.definitions.foreach {
|
||||
@ -148,5 +156,9 @@ private[validation] object Serializability {
|
||||
val tyCon = TTyCon(Identifier(pkgId, QualifiedName(module.name, defName)))
|
||||
checkTemplate(version, world, tyCon, template)
|
||||
}
|
||||
module.exceptions.keys.foreach { defName =>
|
||||
val tyCon = TTyCon(Identifier(pkgId, QualifiedName(module.name, defName)))
|
||||
checkException(version, world, tyCon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ private[validation] object Typing {
|
||||
mod.templates.foreach {
|
||||
case (dfnName, template) =>
|
||||
val tyConName = TypeConName(pkgId, QualifiedName(mod.name, dfnName))
|
||||
val env = Env(languageVersion, world, ContextTemplate(pkgId, mod.name, dfnName), Map.empty)
|
||||
val env = Env(languageVersion, world, ContextTemplate(tyConName), Map.empty)
|
||||
world.lookupDataType(env.ctx, tyConName) match {
|
||||
case DDataType(_, ImmArray(), DataRecord(_)) =>
|
||||
env.checkTemplate(tyConName, template)
|
||||
|
@ -55,13 +55,13 @@ final case class ContextDefDataType(tycon: TypeConName) extends Context {
|
||||
def pretty: String = s"data type ${tycon.qualifiedName}"
|
||||
}
|
||||
final case class ContextTemplate(tycon: TypeConName) extends Context {
|
||||
def pretty: String = s"data type ${tycon.qualifiedName}"
|
||||
def pretty: String = s"template definition ${tycon.qualifiedName}"
|
||||
}
|
||||
final case class ContextDefException(tycon: TypeConName) extends Context {
|
||||
def pretty: String = s"exception type ${tycon.qualifiedName}"
|
||||
def pretty: String = s"exception definition ${tycon.qualifiedName}"
|
||||
}
|
||||
final case class ContextDefValue(ref: ValueRef) extends Context {
|
||||
def pretty: String = s"value type ${ref.qualifiedName}"
|
||||
def pretty: String = s"value definition ${ref.qualifiedName}"
|
||||
}
|
||||
final case class ContextLocation(loc: Location) extends Context {
|
||||
def pretty: String =
|
||||
@ -101,6 +101,9 @@ case object SRTemplateArg extends SerializabilityRequirement {
|
||||
case object SRChoiceArg extends SerializabilityRequirement {
|
||||
def pretty: String = "choice argument"
|
||||
}
|
||||
case object SRExceptionArg extends SerializabilityRequirement {
|
||||
def pretty: String = "exception argument"
|
||||
}
|
||||
case object SRChoiceRes extends SerializabilityRequirement {
|
||||
def pretty: String = "choice result"
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ import org.scalatest.prop.TableDrivenPropertyChecks
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
import scala.util.Try
|
||||
|
||||
class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
|
||||
"Serializability checking" should {
|
||||
@ -164,53 +162,52 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
|
||||
}
|
||||
|
||||
module PositiveTestCase1 {
|
||||
record UnserializableRecord = {};
|
||||
|
||||
template (this : UnserializableRecord) = { // disallowed unserializable type
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:SerializableType) :
|
||||
Mod:SerializableType, controllers $partiesAlice
|
||||
to upure @Mod:SerializableType (Mod:SerializableType {})
|
||||
}
|
||||
} ;
|
||||
}
|
||||
record UnserializableRecord = {};
|
||||
|
||||
template (this : UnserializableRecord) = { // disallowed unserializable type
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:SerializableType) :
|
||||
Mod:SerializableType, controllers $partiesAlice
|
||||
to upure @Mod:SerializableType (Mod:SerializableType {})
|
||||
}
|
||||
} ;
|
||||
}
|
||||
|
||||
module PositiveTestCase2 {
|
||||
record @serializable SerializableRecord = {};
|
||||
record @serializable SerializableRecord = {};
|
||||
|
||||
template (this : SerializableRecord) = {
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:UnserializableType) : // disallowed unserializable type
|
||||
Unit, controllers $partiesAlice to
|
||||
upure @Unit ()
|
||||
}
|
||||
} ;
|
||||
}
|
||||
template (this : SerializableRecord) = {
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:UnserializableType) : // disallowed unserializable type
|
||||
Unit, controllers $partiesAlice to
|
||||
upure @Unit ()
|
||||
}
|
||||
} ;
|
||||
}
|
||||
|
||||
module PositiveTestCase3 {
|
||||
record @serializable SerializableRecord = {};
|
||||
record @serializable SerializableRecord = {};
|
||||
|
||||
template (this : SerializableRecord) = {
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:SerializableType) :
|
||||
Mod:UnserializableType, controllers $partiesAlice to // disallowed unserializable type
|
||||
upure @Mod:UnserializableType (Mod:UnserializableType {})
|
||||
}
|
||||
} ;
|
||||
}
|
||||
template (this : SerializableRecord) = {
|
||||
precondition True,
|
||||
signatories Nil @Party,
|
||||
observers Nil @Party,
|
||||
agreement "Agreement",
|
||||
choices {
|
||||
choice Ch (self) (i : Mod:SerializableType) :
|
||||
Mod:UnserializableType, controllers $partiesAlice to // disallowed unserializable type
|
||||
upure @Mod:UnserializableType (Mod:UnserializableType {})
|
||||
}
|
||||
} ;
|
||||
}
|
||||
"""
|
||||
|
||||
val positiveTestCases = Table(
|
||||
@ -227,6 +224,33 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
|
||||
|
||||
}
|
||||
|
||||
"reject unserializable exception definitions" in {
|
||||
|
||||
val pkg =
|
||||
p"""
|
||||
// well-formed module
|
||||
module NegativeTestCase {
|
||||
record @serializable SerializableRecord = { message: Text } ;
|
||||
|
||||
exception SerializableRecord = {
|
||||
message \(e: NegativeTestCase:SerializableRecord) -> NegativeTestCase:SerializableRecord {message} e
|
||||
} ;
|
||||
}
|
||||
|
||||
module PositiveTestCase {
|
||||
record UnserializableRecord = { message: Text } ;
|
||||
|
||||
exception UnserializableRecord = {
|
||||
message \(e: PositiveTestCase:UnserializableRecord) -> PositiveTestCase:UnserializableRecord {message} e
|
||||
} ;
|
||||
}
|
||||
"""
|
||||
|
||||
check(pkg, "NegativeTestCase")
|
||||
an[EExpectedSerializableType] shouldBe thrownBy(check(pkg, "PositiveTestCase"))
|
||||
|
||||
}
|
||||
|
||||
"reject unserializable contract id" in {
|
||||
|
||||
val pkg =
|
||||
@ -331,7 +355,7 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
|
||||
val w = world(pkg)
|
||||
val longModName = DottedName.assertFromString(modName)
|
||||
val mod = pkg.modules(longModName)
|
||||
require(Try(Typing.checkModule(w, defaultPackageId, mod)).isSuccess)
|
||||
Typing.checkModule(w, defaultPackageId, mod)
|
||||
Serializability.checkModule(w, defaultPackageId, mod)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user