Drop support for Daml-LF party literals from the Scala side (#11922)

* Drop support for Daml-LF party literals from the Scala side

This PR enforces that forbidPartyLiterals is always `true` and drops
the corresponding literals from the AST. Haskell side is in #11930

fixes #11581

changelog_begin
changelog_end

* Update daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ComparisonSBuiltinTest.scala

Co-authored-by: Remy <remy.haemmerle@daml.com>

* Revert "Update daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ComparisonSBuiltinTest.scala"

This reverts commit 55e542ce4e3a7fd15544ee703de3277ffc309b17.

Co-authored-by: Remy <remy.haemmerle@daml.com>
This commit is contained in:
Moritz Kiefer 2021-12-01 11:37:42 +01:00 committed by GitHub
parent 18dc85680a
commit 8179c73763
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 354 additions and 458 deletions

View File

@ -1636,12 +1636,8 @@ message DefValue {
Expr expr = 2;
// If true, the value must not contain any party literals and not reference
// values which contain party literals.
// This flag is used to simplify package validation by not requiring an
// inference but only a check. Such a check must validate that this flag is
// set correctly and that templates do not reference values which have this
// flag set to false.
// Always true for SDK > 1.18. Setting it to false
// will result in the package being rejected.
bool no_party_literals = 3;
bool is_test = 4;

View File

@ -349,19 +349,17 @@ private[archive] class DecodeV1(minor: LV.Minor) {
getInternedDottedName(internedDName)
}
private[this] def decodeFeatureFlags(flags: PLF.FeatureFlags): FeatureFlags = {
private[lf] def decodeFeatureFlags(flags: PLF.FeatureFlags): FeatureFlags = {
// NOTE(JM, #157): We disallow loading packages with these flags because they impact the Ledger API in
// ways that would currently make it quite complicated to support them.
if (
!flags.getDontDivulgeContractIdsInCreateArguments || !flags.getDontDiscloseNonConsumingChoicesToObservers
!flags.getDontDivulgeContractIdsInCreateArguments || !flags.getDontDiscloseNonConsumingChoicesToObservers || !flags.getForbidPartyLiterals
) {
throw Error.Parsing(
"Deprecated feature flag settings detected, refusing to parse package"
)
}
FeatureFlags(
forbidPartyLiterals = flags.getForbidPartyLiterals
)
FeatureFlags.default
}
private[this] def decodeDefDataType(lfDataType: PLF.DefDataType): DDataType = {
@ -472,7 +470,10 @@ private[archive] class DecodeV1(minor: LV.Minor) {
"EnumConstructors.constructors",
)
private[this] def decodeDefValue(lfValue: PLF.DefValue): DValue = {
private[lf] def decodeDefValue(lfValue: PLF.DefValue): DValue = {
if (!lfValue.getNoPartyLiterals) {
throw Error.Parsing("DefValue must have no_party_literals set to true")
}
val name = handleDottedName(
lfValue.getNameWithType.getNameDnameList.asScala,
lfValue.getNameWithType.getNameInternedDname,
@ -480,7 +481,6 @@ private[archive] class DecodeV1(minor: LV.Minor) {
)
DValue(
typ = decodeType(lfValue.getNameWithType.getType),
noPartyLiterals = lfValue.getNoPartyLiterals,
body = decodeExpr(lfValue.getExpr, name.toString),
isTest = lfValue.getIsTest,
)
@ -1462,9 +1462,6 @@ private[archive] class DecodeV1(minor: LV.Minor) {
case PLF.PrimLit.SumCase.TEXT_STR =>
assertUntil(LV.Features.internedStrings, "PrimLit.text_str")
PLText(lfPrimLit.getTextStr)
case PLF.PrimLit.SumCase.PARTY_STR =>
assertUntil(LV.Features.internedStrings, "PrimLit.party_str")
toPLParty(lfPrimLit.getPartyStr)
case PLF.PrimLit.SumCase.TIMESTAMP =>
val t = Time.Timestamp.fromLong(lfPrimLit.getTimestamp)
t.fold(e => throw Error.Parsing("error decoding timestamp: " + e), PLTimestamp)
@ -1477,12 +1474,11 @@ private[archive] class DecodeV1(minor: LV.Minor) {
case PLF.PrimLit.SumCase.NUMERIC_INTERNED_STR =>
assertSince(LV.Features.numeric, "PrimLit.numeric")
toPLNumeric(getInternedStr(lfPrimLit.getNumericInternedStr))
case PLF.PrimLit.SumCase.PARTY_INTERNED_STR =>
assertSince(LV.Features.internedStrings, "PrimLit.party_interned_str")
toPLParty(getInternedStr(lfPrimLit.getPartyInternedStr))
case PLF.PrimLit.SumCase.ROUNDING_MODE =>
assertSince(LV.Features.bigNumeric, "Expr.rounding_mode")
PLRoundingMode(java.math.RoundingMode.valueOf(lfPrimLit.getRoundingModeValue))
case PLF.PrimLit.SumCase.PARTY_STR | PLF.PrimLit.SumCase.PARTY_INTERNED_STR =>
throw Error.Parsing("Party literals are not supported")
case PLF.PrimLit.SumCase.SUM_NOT_SET =>
throw Error.Parsing("PrimLit.SUM_NOT_SET")
}
@ -1515,9 +1511,6 @@ private[archive] class DecodeV1(minor: LV.Minor) {
private[this] def toPLDecimal(s: String) =
PLNumeric(eitherToParseError(Decimal.fromString(s)))
private[this] def toPLParty(s: String) =
PLParty(eitherToParseError(Party.fromString(s)))
// maxVersion excluded
private[this] def assertUntil(maxVersion: LV, description: => String): Unit =
if (!versionIsOlderThan(maxVersion))

View File

@ -956,9 +956,8 @@ class DecodeV1Spec
pkg
.modules(Ref.DottedName.assertFromString("DarReaderTest"))
.definitions(Ref.DottedName.assertFromString("reverseCopy"))
) {
case Ast.DValue(_, _, Ast.ELocation(_, Ast.EVal(Ref.Identifier(resolvedExtId, _))), _) =>
(resolvedExtId: String) should ===(extId: String)
) { case Ast.DValue(_, Ast.ELocation(_, Ast.EVal(Ref.Identifier(resolvedExtId, _))), _) =>
(resolvedExtId: String) should ===(extId: String)
}
}
}
@ -1244,4 +1243,40 @@ class DecodeV1Spec
}
}
s"reject DefValue with no_party_literals = false" in {
val defValue =
DamlLf1.DefValue
.newBuilder()
.setNoPartyLiterals(false)
.build()
forEveryVersion { version =>
val decoder = moduleDecoder(version)
val ex = the[Error.Parsing] thrownBy decoder.decodeDefValue(defValue)
ex.msg shouldBe "DefValue must have no_party_literals set to true"
}
}
s"reject Feature flags set to false" in {
def featureFlags(
forbidPartyLits: Boolean,
dontDivulgeCids: Boolean,
dontDiscloseNonConsuming: Boolean,
) = DamlLf1.FeatureFlags
.newBuilder()
.setForbidPartyLiterals(forbidPartyLits)
.setDontDivulgeContractIdsInCreateArguments(dontDivulgeCids)
.setDontDiscloseNonConsumingChoicesToObservers(dontDiscloseNonConsuming)
.build()
forEveryVersion { version =>
val decoder = moduleDecoder(version)
decoder.decodeFeatureFlags(featureFlags(true, true, true)) shouldBe Ast.FeatureFlags.default
Seq(
featureFlags(false, true, true),
featureFlags(true, false, true),
featureFlags(true, true, false),
).foreach { flags =>
an[Error.Parsing] shouldBe thrownBy(decoder.decodeFeatureFlags(flags))
}
}
}
}

View File

@ -92,7 +92,7 @@ private[daml] class EncodeV1(minor: LV.Minor) {
builder.setFlags(
PLF.FeatureFlags
.newBuilder()
.setForbidPartyLiterals(module.featureFlags.forbidPartyLiterals)
.setForbidPartyLiterals(true)
.setDontDivulgeContractIdsInCreateArguments(true)
.setDontDiscloseNonConsumingChoicesToObservers(true)
)
@ -467,8 +467,6 @@ private[daml] class EncodeV1(minor: LV.Minor) {
setString(value, builder.setTextStr, builder.setTextInternedStr)
case PLTimestamp(value) =>
builder.setTimestamp(value.micros)
case PLParty(party) =>
setString(party, builder.setPartyStr, builder.setPartyInternedStr)
case PLDate(date) =>
builder.setDate(date.days)
case PLRoundingMode(rounding) =>
@ -772,7 +770,7 @@ private[daml] class EncodeV1(minor: LV.Minor) {
.newBuilder()
.setNameWithType(dottedName -> value.typ)
.setExpr(value.body)
.setNoPartyLiterals(value.noPartyLiterals)
.setNoPartyLiterals(true)
.setIsTest(value.isTest)
.build()
}

View File

@ -12,19 +12,19 @@ module DecimalMod {
agreement "Agreement for DecimalMod:Box";
};
val build0: DecimalMod:Box = DecimalMod:Box {
val build0: Party -> DecimalMod:Box = \(p : Party) -> DecimalMod:Box {
x = 0.0000000000 ,
party = 'Alice'
party = p
};
val buildMax: DecimalMod:Box = DecimalMod:Box {
val buildMax: Party -> DecimalMod:Box = \(p : Party) -> DecimalMod:Box {
x = 9999999999999999999999999999.9999999999 ,
party = 'Alice'
party = p
};
val buildMin: DecimalMod:Box = DecimalMod:Box {
val buildMin: Party -> DecimalMod:Box = \(p : Party) -> DecimalMod:Box {
x = -9999999999999999999999999999.9999999999 ,
party = 'Alice'
party = p
};
}

View File

@ -15,7 +15,10 @@ module EnumMod {
};
val createColoredContract: EnumMod:Color -> Scenario (ContractId EnumMod:Box) = \ (color: EnumMod:Color) ->
commit @(ContractId EnumMod:Box) 'Bob' (create @EnumMod:Box (EnumMod:Box { x = color, party = 'Bob' }));
sbind
bob : Party <- sget_party "Bob"
in
commit @(ContractId EnumMod:Box) bob (create @EnumMod:Box (EnumMod:Box { x = color, party = bob }));
enum Nothing = ;

View File

@ -26,7 +26,10 @@ module GenMapMod {
GenMap (RecordMod:Pair Int64 (Numeric 10)) (VariantMod:Either Int64 (Numeric 10))->
Scenario (ContractId GenMapMod:Box)
= \ (x: GenMap (RecordMod:Pair Int64 (Numeric 10)) (VariantMod:Either Int64 (Numeric 10))) ->
commit @(ContractId GenMapMod:Box) 'Bob' (create @GenMapMod:Box (GenMapMod:Box { x = x, party = 'Bob' }));
sbind
bob : Party <- sget_party "Bob"
in
commit @(ContractId GenMapMod:Box) bob (create @GenMapMod:Box (GenMapMod:Box { x = x, party = bob }));
val map0: GenMap (RecordMod:Pair Int64 (Numeric 10)) (VariantMod:Either Int64 (Numeric 10)) =
GENMAP_EMPTY @(RecordMod:Pair Int64 (Numeric 10)) @(VariantMod:Either Int64 (Numeric 10));

View File

@ -18,28 +18,28 @@ module NumericMod {
agreement "Agreement for NumericMod:Box";
};
val build0: NumericMod:Box = NumericMod:Box {
val build0: Party -> NumericMod:Box = \(p : Party) -> NumericMod:Box {
x0 = 0. ,
x10 = 0.0000000000 ,
x17 = 0.00000000000000000 ,
x37 = 0.0000000000000000000000000000000000000 ,
party = 'Alice'
party = p
};
val buildMax: NumericMod:Box = NumericMod:Box {
val buildMax: Party -> NumericMod:Box = \(p : Party) -> NumericMod:Box {
x0 = 99999999999999999999999999999999999999. ,
x10 = 9999999999999999999999999999.9999999999 ,
x17 = 999999999999999999999.99999999999999999 ,
x37 = 9.9999999999999999999999999999999999999 ,
party = 'Alice'
party = p
};
val buildMin: NumericMod:Box = NumericMod:Box {
val buildMin: Party -> NumericMod:Box = \(p : Party) -> NumericMod:Box {
x0 = -99999999999999999999999999999999999999. ,
x10 = -9999999999999999999999999999.9999999999 ,
x17 = -999999999999999999999.99999999999999999 ,
x37 = -9.9999999999999999999999999999999999999 ,
party = 'Alice'
party = p
};
}

View File

@ -12,7 +12,7 @@ module PartyMod {
agreement "Agreement for PartyMod:Box";
};
val @noPartyLiterals one: Party -> List Party =
val one: Party -> List Party =
\(x: Party) -> Cons @Party [x] (Nil @Party);
}

View File

@ -18,7 +18,10 @@ module RecordMod {
RecordMod:Pair Int64 (Numeric 10)->
Scenario (ContractId RecordMod:Box)
= \ (x: RecordMod:Pair Int64 (Numeric 10)) ->
commit @(ContractId RecordMod:Box) 'Bob' (create @RecordMod:Box (RecordMod:Box { x = x, party = 'Bob' }));
sbind
bob : Party <- sget_party "Bob"
in
commit @(ContractId RecordMod:Box) bob (create @RecordMod:Box (RecordMod:Box { x = x, party = bob }));
val pair1: RecordMod:Pair Int64 (Numeric 10) =
RecordMod:Pair @Int64 @(Numeric 10) {

View File

@ -12,9 +12,10 @@ module TextMod {
agreement "Agreement for TextMod:Box";
};
val build: TextMod:Box = TextMod:Box {
x = "some text",
party = 'Alice'
};
val build: Party -> TextMod:Box = \(p : Party) ->
TextMod:Box {
x = "some text",
party = p
};
}

View File

@ -18,7 +18,10 @@ module VariantMod {
VariantMod:Either Int64 (Numeric 10)->
Scenario (ContractId VariantMod:Box)
= \ (x: VariantMod:Either Int64 (Numeric 10)) ->
commit @(ContractId VariantMod:Box) 'Bob' (create @VariantMod:Box (VariantMod:Box { x = x, party = 'Bob' }));
sbind
bob : Party <- sget_party "Bob"
in
commit @(ContractId VariantMod:Box) bob (create @VariantMod:Box (VariantMod:Box { x = x, party = bob }));
val either1: VariantMod:Either Int64 (Numeric 10) =
VariantMod:Either:Left @Int64 @(Numeric 10) 0;

View File

@ -70,7 +70,6 @@ class EncodeV1Spec extends AnyWordSpec with Matchers with TableDrivenPropertyChe
val aDecimal: Numeric 10 = 2.2000000000;
val aDate: Date = 1879-03-14;
val aTimestamp: Timestamp = 1970-01-01T00:00:00.000001Z;
val aParty: Party = 'party';
val aString: Text = "a string";
val aStruct: forall (a:*) (b:*). a -> b -> < x1: a, x2: b > = /\ (a:*) (b:*). \ (x1: a) (x2: b) ->
<x1 = x1, x2 = x2>;

View File

@ -41,11 +41,11 @@ class ValueEnricherSpec extends AnyWordSpec with Matchers with TableDrivenProper
cids: List (ContractId Mod:Contract)
};
val @noPartyLiterals keyParties: (Mod:Key -> List Party) =
val keyParties: (Mod:Key -> List Party) =
\(key: Mod:Key) ->
Cons @Party [Mod:Key {party} key] (Nil @Party);
val @noPartyLiterals contractParties : (Mod:Contract -> List Party) =
val contractParties : (Mod:Contract -> List Party) =
\(contract: Mod:Contract) ->
Mod:keyParties (Mod:Contract {key} contract);

View File

@ -376,7 +376,7 @@ private[lf] final class Compiler(
}
module.definitions.foreach {
case (defName, DValue(_, _, body, _)) =>
case (defName, DValue(_, body, _)) =>
val ref = t.LfDefRef(Identifier(pkgId, QualifiedName(module.name, defName)))
builder += (ref -> SDefinition(withLabelT(ref, unsafeCompile(body))))
case _ =>
@ -724,7 +724,6 @@ private[lf] final class Compiler(
case PLNumeric(d) => SNumeric(d)
case PLText(t) => SText(t)
case PLTimestamp(ts) => STimestamp(ts)
case PLParty(p) => SParty(p)
case PLDate(d) => SDate(d)
case PLRoundingMode(roundingMode) => SInt64(roundingMode.ordinal.toLong)
})

View File

@ -114,7 +114,9 @@ class ComparisonSBuiltinTest extends AnyWordSpec with Matchers with TableDrivenP
e"1970-01-01T00:00:00.000000Z",
e"2020-02-02T20:20:02.020000Z",
),
t"Party" -> List(e"'alice'", e"'bob'", e"'carol'"),
// Parties cannot be built from expressions.
// We map at runtime the `party1`, `party2` and, `party3` two 3 party IDS in increasing order.
t"Party" -> List(e"party1", e"party2", e"party3"),
t"Mod:Color" -> List(e"Mod:Color:Red", e"Mod:Color:Green", e"Mod:Color:Blue"),
t"Mod:MyUnit" -> List(e"Mod:MyUnit {}"),
// Contract IDs cannot be built from expressions.
@ -619,37 +621,69 @@ class ComparisonSBuiltinTest extends AnyWordSpec with Matchers with TableDrivenP
private[this] val compiledPackages =
PureCompiledPackages.assertBuild(Map(pkgId1 -> pkg1, pkgId2 -> pkg2))
private[this] val binderType = {
private[this] val cidBinderType = {
implicit def parserParameters: ParserParameters[this.type] = parserParameters1
t"ContractId Mod:Template"
}
private[this] val binder1 = Ref.Name.assertFromString("cid1") -> binderType
private[this] val binder2 = Ref.Name.assertFromString("cid2") -> binderType
private[this] val binder3 = Ref.Name.assertFromString("cid3") -> binderType
private[this] val partyBinderType = {
implicit def parserParameters: ParserParameters[this.type] = parserParameters1
t"Party"
}
private[this] val cidBinder1 = Ref.Name.assertFromString("cid1") -> cidBinderType
private[this] val cidBinder2 = Ref.Name.assertFromString("cid2") -> cidBinderType
private[this] val cidBinder3 = Ref.Name.assertFromString("cid3") -> cidBinderType
private[this] val partyBinder1 = Ref.Name.assertFromString("party1") -> partyBinderType
private[this] val partyBinder2 = Ref.Name.assertFromString("party2") -> partyBinderType
private[this] val partyBinder3 = Ref.Name.assertFromString("party3") -> partyBinderType
private[this] val contractIds =
Array(
Seq(
ContractId.V1.assertFromString("00" * 32 + "0000"),
ContractId.V1.assertFromString("00" * 32 + "0001"),
ContractId.V1.assertFromString("00" + "ff" * 32),
).map(cid => SEValue(SValue.SContractId(cid)): SExpr)
private[this] val parties =
Seq(
Ref.Party.assertFromString("alice"),
Ref.Party.assertFromString("bob"),
Ref.Party.assertFromString("carol"),
).map(p => SEValue(SValue.SParty(p)): SExpr)
private[this] def eval(bi: Ast.BuiltinFunction, t: Ast.Type, x: Ast.Expr, y: Ast.Expr) = {
final case class Goodbye(e: SError) extends RuntimeException("", null, false, false)
val sexpr = compiledPackages.compiler.unsafeCompile(
Ast.EAbs(
binder1,
partyBinder1,
Ast.EAbs(
binder2,
Ast.EAbs(binder3, Ast.EApp(Ast.EApp(Ast.ETyApp(Ast.EBuiltin(bi), t), x), y), None),
partyBinder2,
Ast.EAbs(
partyBinder3,
Ast.EAbs(
cidBinder1,
Ast.EAbs(
cidBinder2,
Ast.EAbs(
cidBinder3,
Ast.EApp(Ast.EApp(Ast.ETyApp(Ast.EBuiltin(bi), t), x), y),
None,
),
None,
),
None,
),
None,
),
None,
),
None,
)
)
val machine =
Speedy.Machine.fromPureSExpr(compiledPackages, SEApp(sexpr, contractIds))
Speedy.Machine.fromPureSExpr(compiledPackages, SEApp(sexpr, (parties ++ contractIds).toArray))
try {
machine.run() match {
case SResult.SResultFinalValue(v) => Right(v)

View File

@ -12,7 +12,8 @@ import com.daml.lf.language.{LanguageVersion, PackageInterface}
import com.daml.lf.speedy.Compiler.FullStackTrace
import com.daml.lf.speedy.SResult.{SResultError, SResultFinalValue}
import com.daml.lf.speedy.SError.SErrorDamlException
import com.daml.lf.speedy.SValue.SUnit
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue.{SUnit, SParty}
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.testing.parser.ParserParameters
import com.daml.lf.validation.Validation
@ -24,6 +25,11 @@ import org.scalatest.wordspec.AnyWordSpec
// TEST_EVIDENCE: Semantics: Exceptions, throw/catch.
class ExceptionTest extends AnyWordSpec with Matchers with TableDrivenPropertyChecks {
private def applyToParty(pkgs: CompiledPackages, e: Expr, p: Party): SExpr = {
val se = pkgs.compiler.unsafeCompile(e)
SEApp(se, Array(SEValue(SParty(p))))
}
"unhandled throw" should {
// Behaviour when no handler catches a throw:
@ -464,12 +470,14 @@ class ExceptionTest extends AnyWordSpec with Matchers with TableDrivenPropertyCh
"rollback of creates" should {
val party = Party.assertFromString("Alice")
val example: Expr = EApp(e"M:causeRollback", EPrimLit(PLParty(party)))
val example: Expr = e"M:causeRollback"
def transactionSeed: crypto.Hash = crypto.Hash.hashPrivateKey("transactionSeed")
"works as expected for a contract version POST-dating exceptions" in {
val pkgs = mkPackagesAtVersion(LanguageVersion.v1_dev)
val res = Speedy.Machine.fromUpdateExpr(pkgs, transactionSeed, example, party).run()
val res = Speedy.Machine
.fromUpdateSExpr(pkgs, transactionSeed, applyToParty(pkgs, example, party), party)
.run()
res shouldBe SResultFinalValue(SUnit)
}
@ -482,7 +490,9 @@ class ExceptionTest extends AnyWordSpec with Matchers with TableDrivenPropertyCh
IE.UnhandledException(TTyCon(tyCon), ValueRecord(Some(tyCon), data.ImmArray.Empty))
val pkgs = mkPackagesAtVersion(LanguageVersion.v1_11)
val res = Speedy.Machine.fromUpdateExpr(pkgs, transactionSeed, example, party).run()
val res = Speedy.Machine
.fromUpdateSExpr(pkgs, transactionSeed, applyToParty(pkgs, example, party), party)
.run()
res shouldBe SResultError(SErrorDamlException(anException))
}
@ -683,22 +693,23 @@ class ExceptionTest extends AnyWordSpec with Matchers with TableDrivenPropertyCh
def transactionSeed: crypto.Hash = crypto.Hash.hashPrivateKey("transactionSeed")
val causeRollback: Expr = EApp(e"NewM:causeRollback", EPrimLit(PLParty(party)))
val causeUncatchable: Expr = EApp(e"NewM:causeUncatchable", EPrimLit(PLParty(party)))
val causeUncatchable2: Expr = EApp(e"NewM:causeUncatchable2", EPrimLit(PLParty(party)))
val causeRollback: SExpr = applyToParty(pkgs, e"NewM:causeRollback", party)
val causeUncatchable: SExpr = applyToParty(pkgs, e"NewM:causeUncatchable", party)
val causeUncatchable2: SExpr = applyToParty(pkgs, e"NewM:causeUncatchable2", party)
"create rollback when old contacts are not within try-catch context" in {
val res = Speedy.Machine.fromUpdateExpr(pkgs, transactionSeed, causeRollback, party).run()
val res = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, causeRollback, party).run()
res shouldBe SResultFinalValue(SUnit)
}
"causes uncatchable exception when an old contract is within a new-exercise within a try-catch" in {
val res = Speedy.Machine.fromUpdateExpr(pkgs, transactionSeed, causeUncatchable, party).run()
val res = Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, causeUncatchable, party).run()
res shouldBe SResultError(SErrorDamlException(anException))
}
"causes uncatchable exception when an old contract is within a new-exercise which aborts" in {
val res = Speedy.Machine.fromUpdateExpr(pkgs, transactionSeed, causeUncatchable2, party).run()
val res =
Speedy.Machine.fromUpdateSExpr(pkgs, transactionSeed, causeUncatchable2, party).run()
res shouldBe SResultError(SErrorDamlException(anException))
}

View File

@ -194,7 +194,7 @@ class InterpreterTest extends AnyWordSpec with Matchers with TableDrivenProperty
name = modName,
definitions = Map(
DottedName.assertFromString("bar") ->
DValue(TBuiltin(BTBool), true, ETrue, false)
DValue(TBuiltin(BTBool), ETrue, false)
),
templates = Map.empty,
exceptions = Map.empty,

View File

@ -8,6 +8,7 @@ import com.daml.lf.data._
import com.daml.lf.language.Ast._
import com.daml.lf.speedy.PartialTransaction._
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue._
import com.daml.lf.speedy.SResult._
import com.daml.lf.testing.parser.Implicits._
@ -66,10 +67,9 @@ class ProfilerTest extends AnyWordSpec with Matchers with ScalaCheckDrivenProper
def profile(e: Expr): Seq[(Boolean, Profile.Label)] = {
val transactionSeed: crypto.Hash = crypto.Hash.hashPrivateKey("foobar")
val party = Ref.Party.assertFromString("Alice")
val lit: PrimLit = PLParty(party)
val arg: Expr = EPrimLit(lit)
val example: Expr = EApp(e, arg)
val machine = Speedy.Machine.fromUpdateExpr(compiledPackages, transactionSeed, example, party)
val se = compiledPackages.compiler.unsafeCompile(e)
val example: SExpr = SEApp(se, Array(SEValue(SParty(party))))
val machine = Speedy.Machine.fromUpdateSExpr(compiledPackages, transactionSeed, example, party)
val res = machine.run()
res match {
case _: SResultFinalValue =>

View File

@ -7,11 +7,13 @@ package speedy
import com.daml.lf.data.ImmArray
import com.daml.lf.data.Ref
import com.daml.lf.data.Ref.Party
import com.daml.lf.language.Ast.{Package, Expr, PrimLit, PLParty, EPrimLit, EApp}
import com.daml.lf.language.Ast.{Package, Expr}
import com.daml.lf.language.{LanguageVersion, PackageInterface}
import com.daml.lf.speedy.Compiler.FullStackTrace
import com.daml.lf.speedy.PartialTransaction.{CompleteTransaction, IncompleteTransaction}
import com.daml.lf.speedy.SResult.SResultFinalValue
import com.daml.lf.speedy.SExpr._
import com.daml.lf.speedy.SValue._
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.testing.parser.ParserParameters
import com.daml.lf.transaction.Node
@ -47,7 +49,9 @@ class RollbackTest extends AnyWordSpec with Matchers with TableDrivenPropertyChe
pkgs1: PureCompiledPackages
)(e: Expr, party: Party): SubmittedTransaction = {
def transactionSeed: crypto.Hash = crypto.Hash.hashPrivateKey("RollbackTest.scala")
val machine = Speedy.Machine.fromUpdateExpr(pkgs1, transactionSeed, e, party)
val se = pkgs1.compiler.unsafeCompile(e)
val example = SEApp(se, Array(SEValue(SParty(party))))
val machine = Speedy.Machine.fromUpdateSExpr(pkgs1, transactionSeed, example, party)
val res = machine.run()
res match {
case _: SResultFinalValue =>
@ -237,10 +241,7 @@ class RollbackTest extends AnyWordSpec with Matchers with TableDrivenPropertyChe
forEvery(testCases) { (exp: String, expected: List[Tree]) =>
s"""$exp, contracts expected: $expected """ in {
val party = Party.assertFromString("Alice")
val lit: PrimLit = PLParty(party)
val arg: Expr = EPrimLit(lit)
val example: Expr = EApp(e"M:$exp", arg)
val tx: SubmittedTransaction = runUpdateExprGetTx(pkgs)(example, party)
val tx: SubmittedTransaction = runUpdateExprGetTx(pkgs)(e"M:$exp", party)
val ids: List[Tree] = shapeOfTransaction(tx)
ids shouldBe expected
}

View File

@ -731,8 +731,10 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe
"EQUAL @ContractId" - {
"works as expected" in {
eval(e"EQUAL @(ContractId Mod:T) 'contract1' 'contract1'") shouldBe Right(SBool(true))
eval(e"EQUAL @(ContractId Mod:T) 'contract1' 'contract2'") shouldBe Right(SBool(false))
val cid1 = SContractId(Value.ContractId.assertFromString("#contract1"))
val cid2 = SContractId(Value.ContractId.assertFromString("#contract2"))
evalApp(e"EQUAL @(ContractId Mod:T)", Array(cid1, cid1)) shouldBe Right(SBool(true))
evalApp(e"EQUAL @(ContractId Mod:T)", Array(cid1, cid2)) shouldBe Right(SBool(false))
}
}
@ -1213,11 +1215,17 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe
"Text Operations" - {
"PARTY_TO_QUOTED_TEXT single quotes" in {
eval(e"PARTY_TO_QUOTED_TEXT 'alice'") shouldBe Right(SText("'alice'"))
evalApp(
e"PARTY_TO_QUOTED_TEXT",
Array(SParty(Ref.Party.assertFromString("alice"))),
) shouldBe Right(SText("'alice'"))
}
"PARTY_TO_TEXT does not single quote" in {
eval(e"PARTY_TO_TEXT 'alice'") shouldBe Right(SText("alice"))
evalApp(
e"PARTY_TO_TEXT",
Array(SParty(Ref.Party.assertFromString("alice"))),
) shouldBe Right(SText("alice"))
}
"TEXT_TO_PARTY" - {
@ -1615,7 +1623,11 @@ object SBuiltinTest {
evalSExpr(compiledPackages.compiler.unsafeCompile(e), onLedger)
}
private def evalApp(e: Expr, args: Array[SValue], onLedger: Boolean): Either[SError, SValue] = {
private def evalApp(
e: Expr,
args: Array[SValue],
onLedger: Boolean = true,
): Either[SError, SValue] = {
evalSExpr(SEApp(compiledPackages.compiler.unsafeCompile(e), args.map(SEValue(_))), onLedger)
}

View File

@ -172,13 +172,19 @@ class SpeedyTest extends AnyWordSpec with Matchers {
val anyPkgs = typeAndCompile(anyPkg)
private val alice = SParty(Party.assertFromString("Alice"))
"to_any" should {
"succeed on Int64" in {
eval(e"""to_any @Int64 1""", anyPkgs) shouldEqual Right(SAny(TBuiltin(BTInt64), SInt64(1)))
}
"succeed on record type without parameters" in {
eval(e"""to_any @Test:T1 (Test:T1 {party = 'Alice'})""", anyPkgs) shouldEqual
evalApp(
e"""\ (p: Party) -> to_any @Test:T1 (Test:T1 {party = p})""",
Array(alice),
anyPkgs,
) shouldEqual
Right(
SAny(
TTyCon(Identifier(pkgId, QualifiedName.assertFromString("Test:T1"))),
@ -191,7 +197,11 @@ class SpeedyTest extends AnyWordSpec with Matchers {
)
}
"succeed on record type with parameters" in {
eval(e"""to_any @(Test:T3 Int64) (Test:T3 @Int64 {party = 'Alice'})""", anyPkgs) shouldEqual
evalApp(
e"""\ (p : Party) -> to_any @(Test:T3 Int64) (Test:T3 @Int64 {party = p})""",
Array(alice),
anyPkgs,
) shouldEqual
Right(
SAny(
TApp(
@ -205,7 +215,11 @@ class SpeedyTest extends AnyWordSpec with Matchers {
),
)
)
eval(e"""to_any @(Test:T3 Text) (Test:T3 @Text {party = 'Alice'})""", anyPkgs) shouldEqual
evalApp(
e"""\ (p : Party) -> to_any @(Test:T3 Text) (Test:T3 @Text {party = p})""",
Array(alice),
anyPkgs,
) shouldEqual
Right(
SAny(
TApp(
@ -229,8 +243,9 @@ class SpeedyTest extends AnyWordSpec with Matchers {
}
"return Some(tpl) if template type matches" in {
eval(
e"""from_any @Test:T1 (to_any @Test:T1 (Test:T1 {party = 'Alice'}))""",
evalApp(
e"""\(p : Party) -> from_any @Test:T1 (to_any @Test:T1 (Test:T1 {party = p}))""",
Array(alice),
anyPkgs,
) shouldEqual
Right(
@ -247,16 +262,18 @@ class SpeedyTest extends AnyWordSpec with Matchers {
}
"return None if template type does not match" in {
eval(
e"""from_any @Test:T2 (to_any @Test:T1 (Test:T1 {party = 'Alice'}))""",
evalApp(
e"""\(p : Party) -> from_any @Test:T2 (to_any @Test:T1 (Test:T1 {party = p}))""",
Array(alice),
anyPkgs,
) shouldEqual Right(
SOptional(None)
)
}
"return Some(v) if type parameter is the same" in {
eval(
e"""from_any @(Test:T3 Int64) (to_any @(Test:T3 Int64) (Test:T3 @Int64 {party = 'Alice'}))""",
evalApp(
e"""\(p : Alice) -> from_any @(Test:T3 Int64) (to_any @(Test:T3 Int64) (Test:T3 @Int64 {party = p}))""",
Array(alice),
anyPkgs,
) shouldEqual Right(
SOptional(
@ -271,8 +288,9 @@ class SpeedyTest extends AnyWordSpec with Matchers {
)
}
"return None if type parameter is different" in {
eval(
e"""from_any @(Test:T3 Int64) (to_any @(Test:T3 Text) (Test:T3 @Int64 {party = 'Alice'}))""",
evalApp(
e"""\ (p : Party) -> from_any @(Test:T3 Int64) (to_any @(Test:T3 Text) (Test:T3 @Int64 {party = p}))""",
Array(alice),
anyPkgs,
) shouldEqual Right(SOptional(None))
}
@ -489,8 +507,11 @@ class SpeedyTest extends AnyWordSpec with Matchers {
object SpeedyTest {
private def eval(e: Expr, packages: PureCompiledPackages): Either[SError, SValue] = {
val machine = Speedy.Machine.fromPureExpr(packages, e)
private def eval(e: Expr, packages: PureCompiledPackages): Either[SError, SValue] =
evalSExpr(packages.compiler.unsafeCompile(e), packages)
private def evalSExpr(e: SExpr, packages: PureCompiledPackages): Either[SError, SValue] = {
val machine = Speedy.Machine.fromPureSExpr(packages, e)
final case class Goodbye(e: SError) extends RuntimeException("", null, false, false)
try {
val value = machine.run() match {
@ -504,6 +525,15 @@ object SpeedyTest {
}
}
private def evalApp(
e: Expr,
args: Array[SValue],
packages: PureCompiledPackages,
): Either[SError, SValue] = {
val se = packages.compiler.unsafeCompile(e)
evalSExpr(SEApp(se, args.map(SEValue(_))), packages)
}
@SuppressWarnings(Array("org.wartremover.warts.Any"))
private implicit def resultEq: Equality[Either[SError, SValue]] = {
case (Right(v1: SValue), Right(v2: SValue)) => svalue.Equality.areEqual(v1, v2)

View File

@ -330,7 +330,6 @@ object Ast {
// Text should be treated as Utf8, data.Utf8 provide emulation functions for that
final case class PLText(override val value: String) extends PrimLit
final case class PLTimestamp(override val value: Time.Timestamp) extends PrimLit
final case class PLParty(override val value: Party) extends PrimLit
final case class PLDate(override val value: Time.Date) extends PrimLit
final case class PLRoundingMode(override val value: java.math.RoundingMode) extends PrimLit
@ -591,17 +590,16 @@ object Ast {
final case class GenDValue[E](
typ: Type,
noPartyLiterals: Boolean,
body: E,
isTest: Boolean,
) extends GenDefinition[E]
final class GenDValueCompanion[E] private[Ast] {
def apply(typ: Type, noPartyLiterals: Boolean, body: E, isTest: Boolean): GenDValue[E] =
GenDValue(typ = typ, noPartyLiterals = noPartyLiterals, body = body, isTest = isTest)
def apply(typ: Type, body: E, isTest: Boolean): GenDValue[E] =
GenDValue(typ = typ, body = body, isTest = isTest)
def unapply(arg: GenDValue[E]): Some[(Type, Boolean, E, Boolean)] =
Some((arg.typ, arg.noPartyLiterals, arg.body, arg.isTest))
def unapply(arg: GenDValue[E]): Some[(Type, E, Boolean)] =
Some((arg.typ, arg.body, arg.isTest))
}
type DValue = GenDValue[Expr]
@ -947,25 +945,10 @@ object Ast {
type DefExceptionSignature = GenDefException[Unit]
val DefExceptionSignature = GenDefException(())
final case class FeatureFlags(
forbidPartyLiterals: Boolean // If set to true, party literals are not allowed to appear in daml-lf packages.
/*
These flags are present in Daml-LF, but our ecosystem does not support them anymore:
dontDivulgeContractIdsInCreateArguments: Boolean, // If set to true, arguments to creates are not divulged.
// Instead target contract id's of exercises are divulged
// and fetches are authorized.
dontDiscloseNonConsumingChoicesToObservers: Boolean // If set to true, exercise nodes of
// non-consuming choices are only
// disclosed to the signatories and
// controllers of the target contract/choice
// and not to the observers of the target contract.
*/
)
final case class FeatureFlags()
object FeatureFlags {
val default = FeatureFlags(
forbidPartyLiterals = false
)
val default = FeatureFlags()
}
//

View File

@ -64,7 +64,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
val recordDef = DDataType(true, ImmArray.Empty, DataRecord(ImmArray.Empty))
val variantDef = DDataType(true, ImmArray.Empty, DataVariant(ImmArray.Empty))
val valDef = DValue(TUnit, false, EUnit, false)
val valDef = DValue(TUnit, EUnit, false)
def defName(s: String) = DottedName.assertFromSegments(Iterable(s))

View File

@ -227,8 +227,8 @@ private[daml] class AstRewriter(
x
case DDataType(serializable @ _, params @ _, DataInterface) =>
x
case DValue(typ, noPartyLiterals, body, isTest) =>
DValue(apply(typ), noPartyLiterals, apply(body), isTest)
case DValue(typ, body, isTest) =>
DValue(apply(typ), apply(body), isTest)
case DTypeSyn(params @ _, typ @ _) =>
throw new RuntimeException("TODO #3616,AstRewriter,DTypeSyn")

View File

@ -4,7 +4,7 @@
package com.daml.lf.testing.parser
import com.daml.lf.data.Ref.{Location, Name}
import com.daml.lf.data.{ImmArray, Ref}
import com.daml.lf.data.ImmArray
import com.daml.lf.language.Ast._
import com.daml.lf.testing.parser.Parsers._
import com.daml.lf.testing.parser.Token._
@ -73,13 +73,6 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) {
acceptMatch("Text", { case Text(s) => PLText(s) }) |
acceptMatch("Timestamp", { case Timestamp(l) => PLTimestamp(l) }) |
acceptMatch("Date", { case Date(l) => PLDate(l) }) |
acceptMatch(
"Party",
{
case SimpleString(s) if Ref.Party.fromString(s).isRight =>
PLParty(Ref.Party.assertFromString(s))
},
) |
(id ^? roundingModes) ^^ PLRoundingMode
private lazy val primCon =

View File

@ -48,11 +48,10 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
}
lazy val mod: Parser[Module] =
Id("module") ~! tags(modTags) ~ dottedName ~ `{` ~ rep(definition <~ `;`) <~ `}` ^^ {
case _ ~ modTag ~ modName ~ _ ~ defs =>
Id("module") ~! dottedName ~ `{` ~ rep(definition <~ `;`) <~ `}` ^^ {
case _ ~ modName ~ _ ~ defs =>
val (definitions, templates, exceptions, interfaces) = split(defs)
val flags = FeatureFlags(forbidPartyLiterals = modTag(noPartyLitsTag))
Module.build(modName, definitions, templates, exceptions, interfaces, flags)
Module.build(modName, definitions, templates, exceptions, interfaces, FeatureFlags.default)
}
private lazy val definition: Parser[Def] =
@ -115,7 +114,7 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
private lazy val valDefinition: Parser[DataDef] =
Id("val") ~>! tags(valDefTags) ~ dottedName ~ `:` ~ typ ~ `=` ~ expr ^^ {
case defTags ~ id ~ _ ~ typ ~ _ ~ expr =>
DataDef(id, DValue(typ, defTags(noPartyLitsTag), expr, defTags(isTestTag)))
DataDef(id, DValue(typ, expr, defTags(isTestTag)))
}
private lazy val templateKey: Parser[TemplateKey] =
@ -223,14 +222,12 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
}
private val serializableTag = Ref.Name.assertFromString("serializable")
private val noPartyLitsTag = Ref.Name.assertFromString("noPartyLiterals")
private val isTestTag = Ref.Name.assertFromString("isTest")
private val nonConsumingTag = Ref.Name.assertFromString("nonConsuming")
private val dataDefTags = Set(serializableTag)
private val templateChoiceTags = Set(nonConsumingTag)
private val valDefTags = Set(noPartyLitsTag, isTestTag)
private val modTags = Set(noPartyLitsTag)
private val valDefTags = Set(isTestTag)
}

View File

@ -152,8 +152,6 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
"1970-01-02" -> PLDate(Time.Date.assertFromDaysSinceEpoch(1)),
"1970-01-01T00:00:00.000001Z" -> PLTimestamp(Time.Timestamp.assertFromLong(1)),
"1970-01-01T00:00:01Z" -> PLTimestamp(Time.Timestamp.assertFromLong(1000000)),
"'party'" -> PLParty(Party.assertFromString("party")),
""" ' aB0-_ ' """ -> PLParty(Party.assertFromString(" aB0-_ ")),
"ROUNDING_UP" -> PLRoundingMode(java.math.RoundingMode.UP),
)
@ -517,13 +515,13 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
"""
module Mod {
val @noPartyLiterals fact : Int64 -> Int64 = \(x: Int64) -> ERROR @INT64 "not implemented";
val fact : Int64 -> Int64 = \(x: Int64) -> ERROR @INT64 "not implemented";
}
"""
val valDef =
DValue(t"Int64 -> Int64", true, e"""\(x: Int64) -> ERROR @INT64 "not implemented"""", false)
DValue(t"Int64 -> Int64", e"""\(x: Int64) -> ERROR @INT64 "not implemented"""", false)
parseModules(p) shouldBe Right(
List(
@ -551,7 +549,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
template (this : Person) = {
precondition True;
signatories Cons @Party [person] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
observers Cons @Party [Mod:Person {person} this] (Nil @Party);
agreement "Agreement";
choice Sleep (self) (u:Unit) : ContractId Mod:Person
, controllers Cons @Party [person] (Nil @Party)
@ -622,7 +620,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
update = e"upure @Int64 i",
),
),
observers = e"Cons @Party ['Alice'] (Nil @Party)",
observers = e"Cons @Party [Mod:Person {person} this] (Nil @Party)",
key = Some(TemplateKey(t"Party", e"(Mod:Person {name} this)", e"""\ (p: Party) -> p""")),
implements = Map(
human ->

View File

@ -326,7 +326,7 @@ object Repl {
defn match {
case DTypeSyn(_, _) => "<type synonym>" // FIXME: pp this
case DDataType(_, _, _) => "<data type>" // FIXME(JM): pp this
case DValue(typ, _, _, _) => prettyType(typ, pkgId, modId)
case DValue(typ, _, _) => prettyType(typ, pkgId, modId)
}
def prettyQualified(pkgId: PackageId, modId: ModuleName, m: Identifier): String = {
@ -464,7 +464,7 @@ object Repl {
case None =>
println("Error: definition '" + id + "' not found. Try :list.")
usage()
case Some(DValue(_, _, body, _)) =>
case Some(DValue(_, body, _)) =>
val expr = argExprs.foldLeft(body)((e, arg) => EApp(e, arg))
val compiledPackages = PureCompiledPackages.assertBuild(state.packages)
@ -503,7 +503,7 @@ object Repl {
case None =>
println("Error: " + id + " not found.")
None
case Some(DValue(_, _, body, true)) =>
case Some(DValue(_, body, true)) =>
val argExprs = args.map(s => assertRight(parser.parseExpr(s)))
Some(argExprs.foldLeft(body)((e, arg) => EApp(e, arg)))
case Some(_) =>
@ -542,7 +542,7 @@ object Repl {
(modName, mod) = module
definition <- mod.definitions
(dfnName, dfn) = definition
bodyTest <- List(dfn).collect { case DValue(TScenario(_), _, body, true) => body }
bodyTest <- List(dfn).collect { case DValue(TScenario(_), body, true) => body }
} yield QualifiedName(modName, dfnName).toString -> bodyTest
var failures = 0
var successes = 0

View File

@ -174,7 +174,7 @@ object ScenarioRunner {
scenarioDef: Ast.Definition,
): Ast.Expr = {
scenarioDef match {
case Ast.DValue(_, _, body, _) => body
case Ast.DValue(_, body, _) => body
case _: Ast.DTypeSyn =>
throw new RuntimeException(
s"Requested scenario $scenarioRef is a type synonym, not a definition"

View File

@ -1,42 +0,0 @@
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.lf.validation
import com.daml.lf.data.Ref.PackageId
import com.daml.lf.language.Ast._
import com.daml.lf.language.PackageInterface
import com.daml.lf.validation.iterable.ExprIterable
private[validation] object PartyLiterals {
import Util.handleLookup
@throws[EForbiddenPartyLiterals]
def checkModule(interface: PackageInterface, pkgId: PackageId, module: Module): Unit = {
module.definitions.foreach {
case (defName, DValue(typ @ _, noPartyLiterals, body, isTest @ _)) =>
def context = ContextDefValue(pkgId, module.name, defName)
if (noPartyLiterals)
checkExpr(interface, context, body)
else if (module.featureFlags.forbidPartyLiterals)
throw EForbiddenPartyLiterals(context, ValRefWithPartyLiterals(context.ref))
case _ =>
}
module.templates.foreach { case (defName, template) =>
def context = ContextDefValue(pkgId, module.name, defName)
ExprIterable(template).foreach(checkExpr(interface, context, _))
}
}
private def checkExpr(interface: PackageInterface, context: => Context, expr: Expr): Unit =
expr match {
case EPrimLit(party: PLParty) =>
throw EForbiddenPartyLiterals(context, PartyLiteral(party.value))
case EVal(valRef) if !handleLookup(context, interface.lookupValue(valRef)).noPartyLiterals =>
throw EForbiddenPartyLiterals(context, ValRefWithPartyLiterals(valRef))
case otherwise =>
ExprIterable(otherwise).foreach(checkExpr(interface, context, _))
}
}

View File

@ -39,7 +39,6 @@ private[validation] object Typing {
case PLNumeric(s) => TNumeric(TNat(Numeric.scale(s)))
case PLText(_) => TText
case PLTimestamp(_) => TTimestamp
case PLParty(_) => TParty
case PLDate(_) => TDate
case PLRoundingMode(_) => TRoundingMode
}
@ -383,7 +382,7 @@ private[validation] object Typing {
}
def checkDValue(dfn: DValue): Unit = dfn match {
case DValue(typ, _, body, isTest) =>
case DValue(typ, body, isTest) =>
checkType(typ, KStar)
checkExpr(body, typ)
if (isTest) {

View File

@ -67,6 +67,5 @@ object Validation {
): Unit = {
Typing.checkModule(interface, pkgId, mod)
Serializability.checkModule(interface, pkgId, mod)
PartyLiterals.checkModule(interface, pkgId, mod)
}
}

View File

@ -129,7 +129,7 @@ private[validation] object ExprIterable {
x match {
case DTypeSyn(params @ _, typ @ _) => Iterator.empty
case DDataType(serializable @ _, params @ _, dataCons @ _) => Iterator.empty
case DValue(typ @ _, noPartyLiterals @ _, body, isTest @ _) =>
case DValue(typ @ _, body, isTest @ _) =>
Iterator(body)
}

View File

@ -175,7 +175,7 @@ private[validation] object TypeIterable {
Iterator.empty
case DDataType(serializable @ _, params @ _, DataInterface) =>
Iterator.empty
case DValue(typ, noPartyLiterals @ _, body, isTest @ _) =>
case DValue(typ, body, isTest @ _) =>
Iterator(typ) ++ iterator(body)
}

View File

@ -33,11 +33,10 @@ class DependencyVersionSpec extends AnyWordSpec with TableDrivenPropertyChecks w
val mod = Module.build(
name = modName,
definitions = (u -> DValue(TUnit, true, EUnit, false)) +:
definitions = (u -> DValue(TUnit, EUnit, false)) +:
depRefs.map { case (depPkgId, depModName) =>
depModName -> DValue(
TUnit,
true,
EVal(Identifier(depPkgId, QualifiedName(depModName, u))),
false,
)

View File

@ -1,155 +0,0 @@
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.lf
package validation
import com.daml.lf.data.Ref.DottedName
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.testing.parser.defaultPackageId
import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
class PartyLiteralsSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
import PartyLiterals._
"Party Literals validation" should {
"disallows bad party literals" in {
val pkg =
p"""
module Mod {
record R = {};
val isAlice: Party -> Bool = EQUAL_PARTY 'Alice';
val @noPartyLiterals v: Unit = ();
}
// a well-formed module
module NegativeTestCase {
val @noPartyLiterals v: Unit = Mod:v;
val @noPartyLiterals isAlice: Party -> Bool =
\ (party: Party) -> EQUAL_TEXT (PARTY_TO_TEXT party) "'Alice'";
record R = { party: Party };
template (this : R) = {
precondition True;
signatories Cons @Party [party] (Nil @Party);
observers Cons @Party [party] (Nil @Party);
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers party to
upure @Unit ();
};
}
module PositiveTestCase1 {
val @noPartyLiterals bob : Party = 'Bob'; // disallowed party literal 'Bob'
}
module PositiveTestCase2 {
val @noPartyLiterals isAlice : Party -> Bool =
Mod:isAlice; // disallowed value ref `Mod:isAllice`
}
module PositiveTestCase3 {
record R = { party: Party };
template (this : R) = {
precondition EQUAL_PARTY party 'Alice'; // disallowed party literal 'Alice'
signatories Cons @Party [party] (Nil @Party);
observers Cons @Party [party] (Nil @Party);
agreement "Agreement";
choice Ch (self) (i : Mod:R): Unit, controllers party to
upure @Unit ();
} ;
}
module PositiveTestCase4 {
record R = { party: Party };
template (this : R) = {
precondition True;
signatories Cons @Party ['Alice'] (Nil @Party); // disallowed party literal 'Alice'
observers Cons @Party [party] (Nil @Party);
agreement "Agreement";
choice Ch (self) (i : Mod:R): Unit, controllers party to
upure @Unit ();
} ;
}
module PositiveTestCase5 {
record R = { party: Party };
template (this : R) = {
precondition True;
signatories Cons @Party [party] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party); // disallowed party literal 'Alice'
agreement "Agreement";
choice Ch (self) (i : Mod:R): Unit, controllers 'Alice' to
upure @Unit ();
} ;
}
module PositiveTestCase6 {
record R = { party: Party };
template (this : R) = {
precondition True;
signatories Cons @Party [party] (Nil @Party);
observers Cons @Party [party] (Nil @Party);
agreement PARTY_TO_TEXT 'Alice'; // disallowed party literal 'Alice'
choice Ch (self) (i : Mod:R): Unit, controllers 'Alice' to
upure @Unit ();
} ;
}
module PositiveTestCase7 {
record R = { party: Party };
template (this : R) = {
precondition True;
signatories Cons @Party [party] (Nil @Party);
observers Cons @Party [party] (Nil @Party);
agreement "Agreement";
choice Ch (self) (i : Mod:R): Party, controllers party to
upure @Party 'Alice'; // disallowed party literal 'Alice'
} ;
}
module @noPartyLiterals PositiveTestCase8 {
val bob : Party = Error "not implememted"; // disallowed value ref
}
"""
val positiveTestCases = Table(
"module",
"PositiveTestCase1",
"PositiveTestCase2",
"PositiveTestCase3",
"PositiveTestCase4",
"PositiveTestCase5",
"PositiveTestCase6",
"PositiveTestCase7",
"PositiveTestCase8",
)
val interface = language.PackageInterface(Map(defaultPackageId -> pkg))
checkModule(
interface,
defaultPackageId,
pkg.modules(DottedName.assertFromString("NegativeTestCase")),
)
forEvery(positiveTestCases) { modName =>
an[EForbiddenPartyLiterals] should be thrownBy
checkModule(
interface,
defaultPackageId,
pkg.modules(DottedName.assertFromString(modName)),
)
}
}
}
}

View File

@ -149,19 +149,21 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
// well-formed module
module NegativeTestCase {
record @serializable SerializableRecord = {};
record @serializable SerializableRecord = { alice: Party };
template (this : SerializableRecord) = {
precondition True;
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Mod:SerializableType) : Mod:SerializableType, controllers $partiesAlice to upure @Mod:SerializableType (Mod:SerializableType {});
choice Ch (self) (i : Mod:SerializableType) : Mod:SerializableType, controllers ${partiesAlice(
"NegativeTestCase:SerializableRecord"
)} to upure @Mod:SerializableType (Mod:SerializableType {});
} ;
}
module PositiveTestCase1 {
record UnserializableRecord = {};
record UnserializableRecord = { alice: Party };
template (this : UnserializableRecord) = { // disallowed unserializable type
precondition True;
@ -169,13 +171,15 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Mod:SerializableType) :
Mod:SerializableType, controllers $partiesAlice
Mod:SerializableType, controllers ${partiesAlice(
"PositiveTestCase1:UnserializableRecord"
)}
to upure @Mod:SerializableType (Mod:SerializableType {});
} ;
}
module PositiveTestCase2 {
record @serializable SerializableRecord = {};
record @serializable SerializableRecord = { alice: Party };
template (this : SerializableRecord) = {
precondition True;
@ -183,13 +187,13 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Mod:UnserializableType) : // disallowed unserializable type
Unit, controllers $partiesAlice to
Unit, controllers ${partiesAlice("PositiveTestCase2:SerializableRecord")} to
upure @Unit ();
} ;
}
module PositiveTestCase3 {
record @serializable SerializableRecord = {};
record @serializable SerializableRecord = { alice: Party };
template (this : SerializableRecord) = {
precondition True;
@ -197,7 +201,9 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Mod:SerializableType) :
Mod:UnserializableType, controllers $partiesAlice to // disallowed unserializable type
Mod:UnserializableType, controllers ${partiesAlice(
"PositiveTestCase3:SerializableRecord"
)} to // disallowed unserializable type
upure @Mod:UnserializableType (Mod:UnserializableType {});
} ;
}
@ -321,13 +327,13 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
record R (a: *) (b: *) = {f: a -> b };
record @serializable T = {};
record @serializable T = {alice: Party, bob: Party};
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Cons @Party [bob] (Nil @Party);
observers Cons @Party [alice] (Nil @Party);
agreement "Agreement";
choice Ch (self) (x: Int64) : Decimal, controllers 'Bob' to upure @Int64 (DECIMAL_TO_INT64 x);
choice Ch (self) (x: Int64) : Decimal, controllers bob to upure @Int64 (DECIMAL_TO_INT64 x);
} ;
val f : Int64 -> Int64 = ERROR @(Int64 -> Int64) "not implemented";
@ -346,6 +352,6 @@ class SerializabilitySpec extends AnyWordSpec with TableDrivenPropertyChecks wit
Serializability.checkModule(w, defaultPackageId, mod)
}
private val partiesAlice = "(Cons @Party ['Alice'] (Nil @Party))"
private def partiesAlice(r: String) = s"(Cons @Party [$r {alice} this] (Nil @Party))"
}

View File

@ -158,8 +158,6 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
E"(( 1879-03-14 ))" -> T"(( Date ))",
//ExpLitTimestamp
E"(( 1969-07-20T20:17:00.000000Z ))" -> T"(( Timestamp ))",
//ExpLitParty
E"(( 'party' ))" -> T"(( Party ))",
//TextMap
E"Λ (τ : ⋆) . (( TEXTMAP_EMPTY @τ ))" -> T"∀ (τ : ⋆) . (( TextMap τ ))",
//GenMap
@ -364,7 +362,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
T"ContractId Mod:I → (( Update Mod:I ))",
E"λ (e: Party) → (( fetch_by_key @Mod:T e ))" ->
T"Party → (( Update (⟨ contract: Mod:T, contractId: ContractId Mod:T ⟩) ))",
E"λ (e: Party) → (( lookup_by_key @Mod:T 'Bob' ))" ->
E"λ (e: Party) → (( lookup_by_key @Mod:T e ))" ->
T"Party → (( Update (Option (ContractId Mod:T)) ))",
E"(( uget_time ))" ->
T"(( Update Timestamp ))",
@ -955,26 +953,26 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch1 (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
to upure @Unit ();
choice Ch2 (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
, observers Nil @Party
to upure @Unit ();
choice Ch3 (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, observers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
, observers Nil @Party
to upure @Unit ();
implements Mod:I {
method getParties = \(self: NegativeTestCase:T) -> Cons @Party [NegativeTestCase:T {person} self] (Nil @Party);
};
key @Mod:Key
(Mod:Key { person = (NegativeTestCase:T {name} this), party = (NegativeTestCase:T {person} this) })
(\ (key: Mod:Key) -> Cons @Party [(Mod:Key {party} key), 'Alice'] (Nil @Party) );
(\ (key: Mod:Key) -> Cons @Party [(Mod:Key {party} key)] (Nil @Party) );
} ;
}
@ -985,8 +983,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
// in the next line, T should be of type *.
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
};
}
@ -997,8 +995,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
// in the next line, V should be of record.
template (this : V) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
};
}
@ -1007,8 +1005,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
// template without data type
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
} ;
}
@ -1018,8 +1016,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition (); // precondition should be a boolean
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
} ;
}
@ -1030,9 +1028,9 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories (); // should be of (type List Party)
observers Cons @Party ['Alice'] (Nil @Party);
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
} ;
}
@ -1041,10 +1039,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
signatories Nil @Party;
observers (); // should be of type (List Party)
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
} ;
}
@ -1053,8 +1051,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Bob'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit
, controllers () // should be of type (List Party)
@ -1067,11 +1065,11 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Bob'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
, observers () // should be of type (List Party)
to upure @Unit ();
} ;
@ -1082,10 +1080,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement (); // should be of type Text
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
} ;
}
@ -1094,11 +1092,11 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : List) : Unit // the type of i (here List) should be of kind * (here it is * -> *)
, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
, controllers Nil @Party to upure @Unit ();
} ;
}
@ -1107,11 +1105,11 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : List // the return type (here List) should be of kind * (here it is * -> *)
, controllers Cons @Party ['Alice'] (Nil @Party) to upure @(List) (/\ (tau : *). Nil @tau);
, controllers Nil @Party to upure @(List) (/\ (tau : *). Nil @tau);
} ;
}
@ -1121,17 +1119,17 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
key @Mod:Key
// In the next line, the declared type do not match body
(PositiveTestCase_KeyBodyShouldBeProperType:Key {
person = (PositiveTestCase_KeyBodyShouldBeProperType:T {name} this),
party = (PositiveTestCase_KeyBodyShouldBeProperType:T {person} this)
})
(\ (key: Mod:Key) -> Cons @Party [(Mod:Key {party} key), 'Alice'] (Nil @Party) );
(\ (key: Mod:Key) -> Cons @Party [(Mod:Key {party} key)] (Nil @Party) );
} ;
}
@ -1142,10 +1140,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
key @Mod:Key
// In the next line, the declared type do not match body
(Mod:Key {
@ -1153,7 +1151,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
party = (PositiveTestCase_MaintainersShouldBeProperType:T {person} this)
})
(\ (key: PositiveTestCase_MaintainersShouldBeProperType:Key) ->
Cons @Party [(PositiveTestCase_MaintainersShouldBeProperType:Key {party} key), 'Alice'] (Nil @Party) );
Cons @Party [(PositiveTestCase_MaintainersShouldBeProperType:Key {party} key)] (Nil @Party) );
} ;
}
@ -1163,10 +1161,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
key @Mod:Key
// In the next line, the declared type do not match body
(Mod:Key {
@ -1183,10 +1181,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit, controllers Cons @Party ['Alice'] (Nil @Party) to upure @Unit ();
choice Ch (self) (i : Unit) : Unit, controllers Nil @Party to upure @Unit ();
key @PositiveTestCase_MaintainersShouldNotUseThis:TBis
(PositiveTestCase_MaintainersShouldNotUseThis:TBis {
person = (PositiveTestCase_MaintainersShouldNotUseThis:T {name} this),
@ -1194,7 +1192,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
})
// In the next line, cannot use `this`
(\ (key: PositiveTestCase_MaintainersShouldNotUseThis:TBis) ->
Cons @Party [(PositiveTestCase_MaintainersShouldNotUseThis:T {person} this), 'Alice'] (Nil @Party) );
Cons @Party [(PositiveTestCase_MaintainersShouldNotUseThis:T {person} this)] (Nil @Party) );
};
}
@ -1203,11 +1201,11 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
to upure @Unit ();
implements Mod:I {
method getParties = \(self: PositiveCase_InterfaceMethodShouldBeProperType:T) -> (); // should Be of type
@ -1220,11 +1218,11 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
to upure @Unit ();
implements Mod:I {
};
@ -1236,15 +1234,15 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] (Nil @Party);
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (i : Unit) : Unit
, controllers Cons @Party ['Alice'] (Nil @Party)
, controllers Nil @Party
to upure @Unit ();
implements Mod:I {
method getParties = \(self: PositiveCase_ImplementsShouldOverrideOnlyMethods:T) ->
Cons @Party [(PositiveCase_ImplementsShouldOverrideOnlyMethods:T {person} this), 'Alice'] (Nil @Party);
Cons @Party [(PositiveCase_ImplementsShouldOverrideOnlyMethods:T {person} this)] (Nil @Party);
method getName = \(self: PositiveCase_ImplementsShouldOverrideOnlyMethods:T) ->
PositiveCase_ImplementsShouldOverrideOnlyMethods:T {name} this;
};
@ -1317,7 +1315,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
precondition True;
method getParties: List Party;
choice Ch1 (self) (i : Unit) : Unit,
controllers Cons @Party ['Alice'] (Nil @Party)
controllers Nil @Party
to upure @Unit ();
choice Ch2 (self) (i : Unit) : Unit,
controllers call_method @NegativeTestCase:I getParties this,
@ -1662,18 +1660,18 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
record @serializable T = { person: Party, name: Text };
template (this : T) = {
precondition True;
signatories Cons @Party ['Bob'] Nil @Party;
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice Ch (self) (x: Int64) : Decimal, controllers 'Bob' to upure @INT64 (DECIMAL_TO_INT64 x);
key @Party (Mod:Person {person} this) (\ (p: Party) -> Cons @Party ['Alice', p] (Nil @Party));
choice Ch (self) (x: Int64) : Decimal, controllers Nil @Party to upure @INT64 (DECIMAL_TO_INT64 x);
key @Party (Mod:Person {person} this) (\ (p: Party) -> Cons @Party [p] (Nil @Party));
};
interface (this : I) = {
precondition True;
method getParties: List Party;
choice ChIface (self) (x: Int64) : Decimal,
controllers 'Bob'
controllers Nil @Party
to upure @INT64 (DECIMAL_TO_INT64 x);
};
@ -1684,10 +1682,10 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
record @serializable Ti = { person: Party, name: Text };
template (this: Ti) = {
precondition True;
signatories Cons @Party ['Bob'] Nil @Party;
observers Cons @Party ['Alice'] (Nil @Party);
signatories Nil @Party;
observers Nil @Party;
agreement "Agreement";
choice ChTmpl (self) (x: Int64) : Decimal, controllers 'Bob' to upure @INT64 (DECIMAL_TO_INT64 x);
choice ChTmpl (self) (x: Int64) : Decimal, controllers Nil @Party to upure @INT64 (DECIMAL_TO_INT64 x);
implements Mod:I {
method getParties = Cons @Party [(Mod:Ti {person} this)] (Nil @Party);
};

View File

@ -190,11 +190,11 @@ object Script {
def getScriptIds(ty: Type): Either[String, ScriptIds] =
ScriptIds.fromType(ty).toRight(s"Expected type 'Daml.Script.Script a' but got $ty")
script.flatMap {
case GenDValue(TApp(TApp(TBuiltin(BTArrow), param), result), _, _, _) =>
case GenDValue(TApp(TApp(TBuiltin(BTArrow), param), result), _, _) =>
for {
scriptIds <- getScriptIds(result)
} yield Script.Function(scriptExpr, param, scriptIds)
case GenDValue(ty, _, _, _) =>
case GenDValue(ty, _, _) =>
for {
scriptIds <- getScriptIds(ty)
} yield Script.Action(scriptExpr, scriptIds)

View File

@ -29,7 +29,7 @@
- ensure correct privacy for rollback subtree: [BlindingSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/BlindingSpec.scala#L201)
## Semantics:
- Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L24)
- Exceptions, throw/catch.: [ExceptionTest.scala](daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/ExceptionTest.scala#L25)
- contract key behaviour (non-unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L383)
- contract key behaviour (unique mode): [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L389)
- contract keys must have a non-empty set of maintainers: [ContractKeySpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/ContractKeySpec.scala#L218)
@ -44,21 +44,21 @@
- ensure expression forms have the correct type: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L107)
- ill-formed create command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L133)
- ill-formed create-and-exercise command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L154)
- ill-formed exception definitions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1417)
- ill-formed exception definitions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1415)
- ill-formed exercise command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L138)
- ill-formed exercise-by-key command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L145)
- ill-formed expressions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L422)
- ill-formed expressions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L420)
- ill-formed fetch command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L167)
- ill-formed fetch-by-key command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L170)
- ill-formed interfaces are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1310)
- ill-formed interfaces are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1308)
- ill-formed kinds are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L19)
- ill-formed lookup command is rejected: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L175)
- ill-formed records are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1559)
- ill-formed templates are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L938)
- ill-formed type synonyms applications are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1538)
- ill-formed type synonyms definitions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1605)
- ill-formed records are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1557)
- ill-formed templates are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L936)
- ill-formed type synonyms applications are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1536)
- ill-formed type synonyms definitions are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1603)
- ill-formed types are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L99)
- ill-formed variants are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1582)
- ill-formed variants are rejected: [TypingSpec.scala](daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala#L1580)
- well formed create command is accepted: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L79)
- well formed create-and-exercise command is accepted: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L98)
- well formed exercise command is accepted: [CommandPreprocessorSpec.scala](daml-lf/engine/src/test/scala/com/digitalasset/daml/lf/engine/CommandPreprocessorSpec.scala#L84)

View File

@ -173,9 +173,9 @@ object Trigger extends StrictLogging {
for {
definition <- compiledPackages.interface.lookupDefinition(triggerId).left.map(_.pretty)
expr <- definition match {
case GenDValue(TApp(TTyCon(tcon), stateTy), _, _, _) =>
case GenDValue(TApp(TTyCon(tcon), stateTy), _, _) =>
detectTriggerType(tcon, stateTy)
case GenDValue(ty, _, _, _) => Left(s"$ty is not a valid type for a trigger")
case GenDValue(ty, _, _) => Left(s"$ty is not a valid type for a trigger")
case _ => Left(s"Trigger must points to a value but points to $definition")
}
triggerIds = TriggerIds(expr.ty.tycon.packageId)

View File

@ -30,7 +30,7 @@ object RunnerMain {
for ((modName, mod) <- dar.main._2.modules) {
for ((defName, defVal) <- mod.definitions) {
defVal match {
case DValue(TApp(TTyCon(tcon), _), _, _, _) => {
case DValue(TApp(TTyCon(tcon), _), _, _) => {
val triggerIds = TriggerIds(tcon.packageId)
if (
tcon == triggerIds.damlTrigger("Trigger")