diff --git a/docs.daml.com b/docs.daml.com new file mode 160000 index 000000000000..de038f35e2cd --- /dev/null +++ b/docs.daml.com @@ -0,0 +1 @@ +Subproject commit de038f35e2cd6dde57969176dd08d4c68c2f3d54 diff --git a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/admin/PackageUpgradeValidator.scala b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/admin/PackageUpgradeValidator.scala index 4fe8894ce9d1..500ac009bac3 100644 --- a/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/admin/PackageUpgradeValidator.scala +++ b/sdk/canton/community/ledger/ledger-api-core/src/main/scala/com/digitalasset/canton/platform/apiserver/services/admin/PackageUpgradeValidator.scala @@ -13,29 +13,68 @@ import com.digitalasset.canton.platform.apiserver.services.admin.ApiPackageManag import com.digitalasset.daml.lf.archive.DamlLf.Archive import com.digitalasset.daml.lf.archive.Decode import com.digitalasset.daml.lf.data.Ref -import com.digitalasset.daml.lf.language.Ast +import com.digitalasset.daml.lf.language.Util.dependenciesInTopologicalOrder +import com.digitalasset.canton.platform.apiserver.services.admin.PackageUpgradeValidator.PackageMap +import com.digitalasset.daml.lf.language.{Ast, LanguageVersion} import com.digitalasset.daml.lf.validation.{TypecheckUpgrades, UpgradeError} +import com.digitalasset.canton.util.EitherTUtil import scalaz.std.either.* import scalaz.std.option.* import scalaz.std.scalaFuture.futureInstance import scalaz.syntax.traverse.* import scala.concurrent.{ExecutionContext, Future} +import scala.math.Ordering.Implicits.infixOrderingOps + +object PackageUpgradeValidator { + type PackageMap = Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)] +} class PackageUpgradeValidator( - getPackageMap: LoggingContextWithTrace => Map[ - Ref.PackageId, - (Ref.PackageName, Ref.PackageVersion), - ], + getPackageMap: LoggingContextWithTrace => PackageMap, getLfArchive: LoggingContextWithTrace => Ref.PackageId => Future[Option[Archive]], val loggerFactory: NamedLoggerFactory, )(implicit executionContext: ExecutionContext) extends NamedLogging { - def validateUpgrade(uploadedPackage: (Ref.PackageId, Ast.Package))(implicit + def validateUpgrade( + upgradingPackages: List[(Ref.PackageId, Ast.Package)] + )(implicit loggingContext: LoggingContextWithTrace ): EitherT[Future, DamlError, Unit] = { + val upgradingPackagesMap = upgradingPackages.toMap + val packagesInTopologicalOrder = + dependenciesInTopologicalOrder(upgradingPackages.map(_._1), upgradingPackagesMap) val packageMap = getPackageMap(loggingContext) + + def go( + packageMap: PackageMap, + deps: List[Ref.PackageId], + ): EitherT[Future, DamlError, PackageMap] = deps match { + case Nil => EitherT.pure[Future, DamlError](packageMap) + case pkgId :: rest => + val pkg = upgradingPackagesMap(pkgId) + val supportsUpgrades = LanguageVersion.supportsPackageUpgrades(pkg.languageVersion) && !pkg.isUtilityPackage + for { + _ <- EitherTUtil.ifThenET(supportsUpgrades)( + // This check will look for the closest neighbors of pkgId for the package versioning ordering and + // will load them from the DB and decode them. If one were to upload many packages that upgrade each + // other, we will end up decoding the same package many times. Some of these cases could be sped up + // by a cache depending on the order in which the packages are uploaded. + validatePackageUpgrade((pkgId, pkg), packageMap) + ) + res <- go(packageMap + ((pkgId, (pkg.metadata.name, pkg.metadata.version))), rest) + } yield res + } + go(packageMap, packagesInTopologicalOrder).map(_ => ()) + } + + private def validatePackageUpgrade( + uploadedPackage: (Ref.PackageId, Ast.Package), + packageMap: PackageMap, + )(implicit + loggingContext: LoggingContextWithTrace + ): EitherT[Future, DamlError, Unit] = { val (uploadedPackageId, uploadedPackageAst) = uploadedPackage val optUpgradingDar = Some(uploadedPackage) logger.info( @@ -49,6 +88,9 @@ class PackageUpgradeValidator( ) EitherT.rightT[Future, DamlError](()) } else { + logger.info( + s"Bad version of package $uploadedPackageId as it has been previously uploaded $existingPackageId" + ) EitherT.leftT[Future, Unit]( Validation.UpgradeVersion .Error( @@ -69,6 +111,7 @@ class PackageUpgradeValidator( ) _ <- typecheckUpgrades( TypecheckUpgrades.MaximalDarCheck, + packageMap, optUpgradingDar, optMaximalDar, ) @@ -77,6 +120,7 @@ class PackageUpgradeValidator( ) _ <- typecheckUpgrades( TypecheckUpgrades.MinimalDarCheck, + packageMap, optMinimalDar, optUpgradingDar, ) @@ -144,6 +188,7 @@ class PackageUpgradeValidator( private def strictTypecheckUpgrades( phase: TypecheckUpgrades.UploadPhaseCheck, + packageMap: PackageMap, optNewDar1: Option[(Ref.PackageId, Ast.Package)], oldPkgId2: Ref.PackageId, optOldPkg2: Option[Ast.Package], @@ -161,7 +206,7 @@ class PackageUpgradeValidator( EitherT( Future( TypecheckUpgrades - .typecheckUpgrades((newPkgId1, newPkg1), oldPkgId2, optOldPkg2) + .typecheckUpgrades(packageMap, (newPkgId1, newPkg1), oldPkgId2, optOldPkg2) .toEither ) ).leftMap[DamlError] { @@ -183,6 +228,7 @@ class PackageUpgradeValidator( private def typecheckUpgrades( typecheckPhase: TypecheckUpgrades.UploadPhaseCheck, + packageMap: PackageMap, optNewDar1: Option[(Ref.PackageId, Ast.Package)], optOldDar2: Option[(Ref.PackageId, Ast.Package)], )(implicit @@ -195,6 +241,7 @@ class PackageUpgradeValidator( case (Some((newPkgId1, newPkg1)), Some((oldPkgId2, oldPkg2))) => strictTypecheckUpgrades( typecheckPhase, + packageMap, Some((newPkgId1, newPkg1)), oldPkgId2, Some(oldPkg2), diff --git a/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/admin/PackageUploader.scala b/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/admin/PackageUploader.scala index 1becb013b215..ed6d172abdaa 100644 --- a/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/admin/PackageUploader.scala +++ b/sdk/canton/community/participant/src/main/scala/com/digitalasset/canton/participant/admin/PackageUploader.scala @@ -36,8 +36,9 @@ import com.digitalasset.canton.{LedgerSubmissionId, LfPackageId} import com.digitalasset.daml.lf.archive.{DamlLf, Dar as LfDar, DarParser, Decode} import com.digitalasset.daml.lf.data.Ref import com.digitalasset.daml.lf.engine.Engine -import com.digitalasset.daml.lf.language.Ast +import com.digitalasset.daml.lf.language.{Ast, LanguageVersion} import com.google.protobuf.ByteString +import scala.math.Ordering.Implicits.infixOrderingOps import java.nio.file.Paths import java.util.zip.ZipInputStream @@ -88,7 +89,7 @@ class PackageUploader( dependencies <- dar.dependencies.parTraverse(archive => catchUpstreamErrors(Decode.decodeArchive(archive)) ) - _ <- validatePackages(mainPackage, dependencies) + _ <- validatePackages(mainPackage :: dependencies) } yield hash } @@ -98,7 +99,7 @@ class PackageUploader( submissionId: LedgerSubmissionId, )(implicit traceContext: TraceContext - ): EitherT[FutureUnlessShutdown, DamlError, (List[Ref.PackageId], Hash)] = + ): EitherT[FutureUnlessShutdown, DamlError, (List[LfPackageId], Hash)] = performUnlessClosingEitherUSF("upload DAR") { val darNameO = fileNameO.map(fn => PathUtils.getFilenameWithoutExtension(Paths.get(fn).getFileName)) @@ -118,12 +119,12 @@ class PackageUploader( dependencies <- dar.dependencies.parTraverse(archive => catchUpstreamErrors(Decode.decodeArchive(archive)).map(archive -> _) ) + allPackages = mainPackage :: dependencies hash <- EitherT( uploadDarExecutionQueue.executeUS( uploadDarSequentialStep( darPayload = darPayload, - mainPackage = mainPackage, - dependencies = dependencies, + packages = allPackages, // TODO(#17635): Allow more generic source descriptions or rename source description to DAR name lengthValidatedDarName = lengthValidatedNameO, submissionId = submissionId, @@ -131,7 +132,7 @@ class PackageUploader( description = "store DAR", ) ) - } yield (mainPackage._2._1 :: dependencies.map(_._2._1)) -> hash + } yield allPackages.map(_._2._1) -> hash } // This stage must be run sequentially to exclude the possibility @@ -139,8 +140,7 @@ class PackageUploader( // is happening concurrently with an update of the package metadata view. private def uploadDarSequentialStep( darPayload: ByteString, - mainPackage: (DamlLf.Archive, (LfPackageId, Ast.Package)), - dependencies: List[(DamlLf.Archive, (LfPackageId, Ast.Package))], + packages: List[(DamlLf.Archive, (LfPackageId, Ast.Package))], lengthValidatedDarName: Option[String255], submissionId: LedgerSubmissionId, )(implicit traceContext: TraceContext): FutureUnlessShutdown[Either[DamlError, Hash]] = { @@ -165,7 +165,9 @@ class PackageUploader( s"Managed to upload one or more archives for submissionId $submissionId" ) _ = allPackages.foreach { case (_, (pkgId, pkg)) => - packageMetadataView.update(PackageMetadata.from(pkgId, pkg)) + if (pkg.languageVersion >= LanguageVersion.Features.packageUpgrades && !pkg.isUtilityPackage) { + packageMetadataView.update(PackageMetadata.from(pkgId, pkg)) + } } } yield () @@ -178,10 +180,8 @@ class PackageUploader( DarDescriptor(hash, persistedDarName), darPayload.toByteArray, ) - validatePackages(mainPackage._2, dependencies.map(_._2)) - .semiflatMap { _ => - val allPackages = mainPackage :: dependencies - val result = persist(darDescriptor, uploadTime, allPackages) + validatePackages(packages.map(_._2)).semiflatMap { _ => + val result = persist(darDescriptor, uploadTime, packages) handleUploadResult(result, submissionId) } .map(_ => hash) @@ -213,15 +213,14 @@ class PackageUploader( } private def validatePackages( - mainPackage: (LfPackageId, Ast.Package), - dependencies: List[(LfPackageId, Ast.Package)], + packages: List[(LfPackageId, Ast.Package)] )(implicit traceContext: TraceContext ): EitherT[FutureUnlessShutdown, DamlError, Unit] = for { _ <- EitherT.fromEither[FutureUnlessShutdown]( engine - .validatePackages((mainPackage :: dependencies).toMap) + .validatePackages(packages.toMap) .leftMap( PackageServiceErrors.Validation.handleLfEnginePackageError(_): DamlError ) @@ -229,10 +228,12 @@ class PackageUploader( _ <- if (enableUpgradeValidation) { packageUpgradeValidator - .validateUpgrade(mainPackage)(LoggingContextWithTrace(loggerFactory)) + .validateUpgrade(packages)(LoggingContextWithTrace(loggerFactory)) .mapK(FutureUnlessShutdown.outcomeK) } else { - logger.info(s"Skipping upgrade validation for package ${mainPackage._1}.") + logger.info( + s"Skipping upgrade validation for packages ${packages.map(_._1).sorted.mkString(", ")}" + ) EitherT.pure[FutureUnlessShutdown, DamlError](()) } } yield () diff --git a/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/InferSerializability.hs b/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/InferSerializability.hs index 0b9ca107347c..619dacce616b 100644 --- a/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/InferSerializability.hs +++ b/sdk/compiler/daml-lf-tools/src/DA/Daml/LF/InferSerializability.hs @@ -15,21 +15,30 @@ import DA.Daml.LF.Ast import DA.Daml.LF.TypeChecker.Serializability (CurrentModule(..), serializabilityConditionsDataType) inferModule :: World -> Module -> Either String Module -inferModule world0 mod0 = do - let modName = moduleName mod0 - let dataTypes = moduleDataTypes mod0 - let interfaces = NM.namesSet (moduleInterfaces mod0) - let eqs = - [ (dataTypeCon dataType, serializable, deps) - | dataType <- NM.toList dataTypes - , let (serializable, deps) = - case serializabilityConditionsDataType world0 (Just $ CurrentModule modName interfaces) dataType of - Left _ -> (False, []) - Right deps0 -> (True, HS.toList deps0) - ] - case leastFixedPointBy (&&) eqs of - Left name -> throwError ("Reference to unknown data type: " ++ show name) - Right serializabilities -> do - let updateDataType dataType = - dataType{dataSerializable = IsSerializable (HMS.lookupDefault False (dataTypeCon dataType) serializabilities)} - pure mod0{moduleDataTypes = NM.map updateDataType dataTypes} +inferModule world0 mod0 = + case moduleName mod0 of + -- Unstable parts of stdlib mustn't contain serializable types, because if they are + -- serializable, then the upgrading checks run on the datatypes and this causes problems. + -- Therefore, we mark the datatypes as not-serializable, so that upgrades checks don't trigger. + -- For more information on this issue, refer to issue + -- https://github.com/digital-asset/daml/issues/19338issues/19338 + ModuleName ["GHC", "Stack", "Types"] -> pure mod0 + ModuleName ["DA", "Numeric"] -> pure mod0 + _ -> do + let modName = moduleName mod0 + let dataTypes = moduleDataTypes mod0 + let interfaces = NM.namesSet (moduleInterfaces mod0) + let eqs = + [ (dataTypeCon dataType, serializable, deps) + | dataType <- NM.toList dataTypes + , let (serializable, deps) = + case serializabilityConditionsDataType world0 (Just $ CurrentModule modName interfaces) dataType of + Left _ -> (False, []) + Right deps0 -> (True, HS.toList deps0) + ] + case leastFixedPointBy (&&) eqs of + Left name -> throwError ("Reference to unknown data type: " ++ show name) + Right serializabilities -> do + let updateDataType dataType = + dataType{dataSerializable = IsSerializable (HMS.lookupDefault False (dataTypeCon dataType) serializabilities)} + pure mod0{moduleDataTypes = NM.map updateDataType dataTypes} diff --git a/sdk/compiler/damlc/tests/BUILD.bazel b/sdk/compiler/damlc/tests/BUILD.bazel index 4f4e5dbca9d2..0d264d8fe32b 100644 --- a/sdk/compiler/damlc/tests/BUILD.bazel +++ b/sdk/compiler/damlc/tests/BUILD.bazel @@ -470,7 +470,7 @@ da_haskell_test( "//test-common:upgrades-FailsWhenOldFieldIsDeletedFromTemplate-files", "//test-common:upgrades-FailsWhenOldFieldIsDeletedFromTemplateChoice-files", "//test-common:upgrades-FailsWhenTemplateAddsKeyType-files", - "//test-common:upgrades-FailsWhenTemplateChangesKeyType-files", + "//test-common:upgrades-FailsWhenTemplateChangesKeyTypeSuperficially-files", "//test-common:upgrades-FailsWhenTemplateChoiceChangesItsReturnType-files", "//test-common:upgrades-FailsWhenTemplateRemovesKeyType-files", "//test-common:upgrades-FailsWhenTwoDeeplyNestedTypeSynonymsResolveToDifferentDatatypes-files", diff --git a/sdk/compiler/damlc/tests/platform-independence.dar-hash b/sdk/compiler/damlc/tests/platform-independence.dar-hash index a0bc87a27741..960552346432 100644 --- a/sdk/compiler/damlc/tests/platform-independence.dar-hash +++ b/sdk/compiler/damlc/tests/platform-independence.dar-hash @@ -1,34 +1,34 @@ -6e3151a58988ce314600f15cd6456c85a988ee3209f73df04d6217e090c484dc META-INF/MANIFEST.MF -af53bfb744c41db01eb8066a4f2485bab8af7444206202213be5a37dc0e2f36d platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/compiler/damlc/tests/PlatformIndependence.daml -0000000000000000000000000000000000000000000000000000000000000000 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/compiler/damlc/tests/PlatformIndependence.hi -0000000000000000000000000000000000000000000000000000000000000000 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/compiler/damlc/tests/PlatformIndependence.hie -bb828ccb15d06cf91985c5be842b0d66f35349064319ce658d64b5fd7b492910 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-2857149df3c364fa3c3fc677d2a40c693b1a1d106a16ba5325f247b1a76c7f38.dalf -5b367b37fe8430dbc1cffc69c24f48d43e6c11ed16c2a48d0e775be6c3cd3fa2 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Exception-ArithmeticError-ee33fb70918e7aaa3d3fc44d64a399fb2bf5bcefc54201b1690ecd448551ba88.dalf -98c16c8dfd84c1241922d7fa93d5860b87ee93c7d0346c87bf7c76710cf5fd2d platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Exception-AssertionFailed-6da1f43a10a179524e840e7288b47bda213339b0552d92e87ae811e52f59fc0e.dalf -aed72dfe7eb325ad9aaafa1a19ba7f34bf93992d62fe78e7c8a27432546ea56e platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Exception-GeneralError-f181cd661f7af3a60bdaae4b0285a2a67beb55d6910fc8431dbae21a5825ec0f.dalf -cc51cb400519000f2dc3a2bd893dcc269546f42c2ff2e04aa0293f9595ffb099 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Exception-PreconditionFailed-91e167fa7a256f21f990c526a0a0df840e99aeef0e67dc1f5415b0309486de74.dalf -2f671fa9f93604a9cd7520e6f343a56a8f58b038195fe9dd8fa2bf7fca4a8118 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Internal-Erased-0e4a572ab1fb94744abb02243a6bbed6c78fc6e3c8d3f60c655f057692a62816.dalf -67930dd5a0bd139c344935939d9903c5d6d93a326f7bec248f3a1180eff682e7 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Internal-NatSyn-e5411f3d75f072b944bd88e652112a14a3d409c491fd9a51f5f6eede6d3a3348.dalf -a260a743f3732429f294092f0b36703f28739e471d8da367e6178b636e815b53 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Internal-PromotedText-ab068e2f920d0e06347975c2a342b71f8b8e3b4be0f02ead9442caac51aa8877.dalf -bef5523d20b5bb3e608423caf03bb62b5c40ba759a646e0055d93bdc80a166a3 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-DA-Types-5aee9b21b8e9a4c4975b5f4c4198e6e6e8469df49e2010820e792f393db870f4.dalf -bac571bea0ef93a7c34eb2ff9c2de98aa035d04b65c8d01f7cf5ae911fbe91ca platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-GHC-Prim-fcee8dfc1b81c449b421410edd5041c16ab59c45bbea85bcb094d1b17c3e9df7.dalf -a857d76904ee3a8344ecc739edae5bb5ae93373a1a3bb777454afcd5006b5e7a platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-GHC-Tuple-19f0df5fdaf5a96e137b6ea885fdb378f37bd3166bd9a47ee11518e33fa09a20.dalf -a298eed9572d98da051d99f4b1b522dbbfea5665cee948ff450a0487be2aeddd platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-prim-GHC-Types-e7e0adfa881e7dbbb07da065ae54444da7c4bccebcb8872ab0cb5dcf9f3761ce.dalf -7e08880fce5eafc90a5b6ccb2cb7923a55478919c6449c94e3a95ef79def45e9 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-0.0.0-ff9cf6dabd1fc0deabf5534c1ded7fdc3d565fccf34e52dc74a108d8a358a589.dalf -4619339c51f1069ca6a07474bcb0f8ecb9c4b77bf5ca7d6a246712d636c0c796 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Action-State-Type-a1fa18133ae48cbb616c4c148e78e661666778c3087d099067c7fe1868cbb3a1.dalf -4fc3e91abda9caf95390da16fa7267803e88d52540513078a3e87d1a56639fa6 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Date-Types-fa79192fe1cce03d7d8db36471dde4cf6c96e6d0f07e1c391dd49e355af9b38c.dalf -db6bf950ebba81f55305bb0cc09dfa6d9d226fcb116dfea087a8c8c4afc0841a platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Internal-Any-6f8e6085f5769861ae7a40dccd618d6f747297d59b37cab89b93e2fa80b0c024.dalf -8713e809627225804d9ec8cf5f244f696a682c909760762d5543431002a2db69 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Internal-Down-86d888f34152dae8729900966b44abcb466b9c111699678de58032de601d2b04.dalf -eda925616a15f843a6f04bd677377b07efe48e75fcdde7cfb16e611c7a913cd9 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Internal-Interface-AnyView-Types-c280cc3ef501d237efa7b1120ca3ad2d196e089ad596b666bed59a85f3c9a074.dalf -d16cc72b5fa04d1ceade89a65fd5e5e26cabb7b271254548cd1f4d2164812d87 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Internal-Template-9e70a8b3510d617f8a136213f33d6a903a10ca0eeec76bb06ba55d1ed9680f69.dalf -4c6edf633b367a196e0d8f3749626206e65bd3134e5331fae41b726e50b9d5df platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Logic-Types-cae345b5500ef6f84645c816f88b9f7a85a9f3c71697984abdf6849f81e80324.dalf -e969d7b1a5c1271e8113d4cab7794bae3be678f53748fe93ff688df0343c584c platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Monoid-Types-52854220dc199884704958df38befd5492d78384a032fd7558c38f00e3d778a2.dalf -288ad8f4dd0d8971d6c0fd120edcd611a89ecad955c5ac9d7a06e77f80a2b6ea platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-NonEmpty-Types-bde4bd30749e99603e5afa354706608601029e225d4983324d617825b634253a.dalf -91b712f0940ada408419f785ab47901886a431075e2f3a9178dd8058dc17499d platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Random-Types-bfda48f9aa2c89c895cde538ec4b4946c7085959e031ad61bde616b9849155d7.dalf -a593b782fca59f9b86ecd526c1e679ea28866e472081b0c68795dfcfdc9ec5e7 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Semigroup-Types-d095a2ccf6dd36b2415adc4fa676f9191ba63cd39828dc5207b36892ec350cbc.dalf -5fe3810e2722629fb251fa813ed98ee539f90733055ca573a0ecf5f7cc435317 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Set-Types-c3bb0c5d04799b3f11bad7c3c102963e115cf53da3e4afcbcfd9f06ebd82b4ff.dalf -b0c108d8863653cfecfc2442321ac6092a0945654a7d7c8343f7c16fd56a8081 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Stack-Types-60c61c542207080e97e378ab447cc355ecc47534b3a3ebbff307c4fb8339bc4d.dalf -d1951ee045378e8b874a4a3aa5466d810f5ca6a60cb3e8f49d28338f1bea6f2c platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Time-Types-b70db8369e1c461d5c70f1c86f526a29e9776c655e6ffc2560f95b05ccb8b946.dalf -e311651bb4bfd90d1555c47488d4d02ac7f9774062bcf90ef097faff60b11481 platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/daml-stdlib-DA-Validation-Types-3cde94fe9be5c700fc1d9a8ad2277e2c1214609f8c52a5b4db77e466875b8cb7.dalf -8a3d04a48d3cd7e3e1f689ec6e241eb61502182cd8088b7d59597cd923f1d45b platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/data/platform-independence-1.0.0.conf -8cdeaca6743756e03570d0a8168d57b14fff6f3a616e9658d3341a03ac30aeec platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb/platform-independence-1.0.0-7a1437395c79e9b7648b9cbb135f8f0290880fdb1ed0ef6c99b885405df7eabb.dalf +d437ea94d68765e6d072e55d55232140c75f3d0cd2704fd5d138492eddf6f15f META-INF/MANIFEST.MF +af53bfb744c41db01eb8066a4f2485bab8af7444206202213be5a37dc0e2f36d platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/compiler/damlc/tests/PlatformIndependence.daml +0000000000000000000000000000000000000000000000000000000000000000 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/compiler/damlc/tests/PlatformIndependence.hi +0000000000000000000000000000000000000000000000000000000000000000 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/compiler/damlc/tests/PlatformIndependence.hie +f449ec0bad9cadcaa79224e1ac15d9851968e6d4d73754fd0e2adce768f72056 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-315cb5676675c14e71453d4a9a2a58900e5b50d6665cba4cdf21f58b22abff83.dalf +6458feec418d71e834dfa5b56a32b640f0595d1cf9bef29c3456cf9eac1c921e platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Exception-ArithmeticError-cb0552debf219cc909f51cbb5c3b41e9981d39f8f645b1f35e2ef5be2e0b858a.dalf +ce477181ed187d31fb71e2819cd8af24b3bee3ff55b02950c23363849cf86a47 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Exception-AssertionFailed-3f4deaf145a15cdcfa762c058005e2edb9baa75bb7f95a4f8f6f937378e86415.dalf +a5dafa3128e153955c2360201cb700b09d170914847b184184e4413be848cecb platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Exception-GeneralError-86828b9843465f419db1ef8a8ee741d1eef645df02375ebf509cdc8c3ddd16cb.dalf +9ec4a0044ebf1002e47c5119b06c8650535f0bd841d8a0c7189455a3720169f3 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Exception-PreconditionFailed-f20de1e4e37b92280264c08bf15eca0be0bc5babd7a7b5e574997f154c00cb78.dalf +9a6861aa98233c2fd6a446edd4255c2891ab3db5eec355955381f35088956a23 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Internal-Erased-76bf0fd12bd945762a01f8fc5bbcdfa4d0ff20f8762af490f8f41d6237c6524f.dalf +e66c79fc41a6bd6350ab265ee3bd15c0a6d5cd1748757194577448c89ce9e6a7 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Internal-NatSyn-38e6274601b21d7202bb995bc5ec147decda5a01b68d57dda422425038772af7.dalf +608e8efb2ed17a67eae9ddb74ca235a848195da170f47bf4d18d33bc7e96cc44 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Internal-PromotedText-d58cf9939847921b2aab78eaa7b427dc4c649d25e6bee3c749ace4c3f52f5c97.dalf +42105a59d0c9c7088a8860693f6da3d60ca62da5ccac1b9cf0dde8f975b984a5 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-DA-Types-40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7.dalf +12906f0e43060e26f823f03c2bbfe4d541db833d370db4caae2c66f38acae440 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-GHC-Prim-e491352788e56ca4603acc411ffe1a49fefd76ed8b163af86cf5ee5f4c38645b.dalf +bdc8c66d0511eff0262d3a133269e655bf47ba742e98ced5bc76a3fcd0211a73 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-GHC-Tuple-6839a6d3d430c569b2425e9391717b44ca324b88ba621d597778811b2d05031d.dalf +e99c27f6b9d297aaf747b572356e08376ce8d7a994ff00242749978b8a8a9ab0 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-prim-GHC-Types-518032f41fd0175461b35ae0c9691e08b4aea55e62915f8360af2cc7a1f2ba6c.dalf +08a841ff213451e925c9c544b5c990c5499ac70471bd6114dacab4d7678b300a platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-0.0.0-b81cc36228f1cbf48969c312905bdd13fecb3af020b7017867a4c8e9b819e6c1.dalf +dc4bd12915aea953a4ae6fb5e3b31fd3ec99605ae402c8b6350035ed9bbdeda7 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Action-State-Type-10e0333b52bba1ff147fc408a6b7d68465b157635ee230493bd6029b750dcb05.dalf +6d9d1309c57dab98cb34fda6b26d3c6d5b2e5fb1357333bce2c0b26c262fc372 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Date-Types-bfcd37bd6b84768e86e432f5f6c33e25d9e7724a9d42e33875ff74f6348e733f.dalf +acb729cf88297d61a52ba5852019326077f682e914052449d75142447b89b964 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Internal-Any-cc348d369011362a5190fe96dd1f0dfbc697fdfd10e382b9e9666f0da05961b7.dalf +5625ab94e607b99fd03cfb3a618c3ec8227cf35dc917cc310d12c34691d10c9d platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Internal-Down-057eed1fd48c238491b8ea06b9b5bf85a5d4c9275dd3f6183e0e6b01730cc2ba.dalf +fb97292e2989cf6b046d0c07355a86741ba327231b13596e646f6aed3c65b726 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Internal-Interface-AnyView-Types-6df2d1fd8ea994ed048a79587b2722e3a887ac7592abf31ecf46fe09ac02d689.dalf +e6817a705c974eea0b05051e919e18cab97df616f3d8c8e590b41cde1147b7bf platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Internal-Template-d14e08374fc7197d6a0de468c968ae8ba3aadbf9315476fd39071831f5923662.dalf +542ba5ef4d1707d77dbaa2c457adc06f28bad394968bae25635a982b7b1f6916 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Logic-Types-c1f1f00558799eec139fb4f4c76f95fb52fa1837a5dd29600baa1c8ed1bdccfd.dalf +a70854a646e926e98a102a6d332c67872b4bc5978700bf946ce58dfc94ba993c platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Monoid-Types-6c2c0667393c5f92f1885163068cd31800d2264eb088eb6fc740e11241b2bf06.dalf +e80bf135b35aa8a1eca973e1b57b95b2ff3c6f9b1039be8b0a8e6a1810bfc613 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-NonEmpty-Types-e22bce619ae24ca3b8e6519281cb5a33b64b3190cc763248b4c3f9ad5087a92c.dalf +77210bf43703a6883586997dfab07154c988f294b144337d056f99ba14fa6150 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Random-Types-e4cc67c3264eba4a19c080cac5ab32d87551578e0f5f58b6a9460f91c7abc254.dalf +aea033031e908d0a9b7c4701bc4a563c5f25b0f626ab3abb11725fe6525d4f79 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Semigroup-Types-8a7806365bbd98d88b4c13832ebfa305f6abaeaf32cfa2b7dd25c4fa489b79fb.dalf +41970cee0963cbf25ffb1d35601b4200631aedf794f80ab22f999416b48d8531 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Set-Types-97b883cd8a2b7f49f90d5d39c981cf6e110cf1f1c64427a28a6d58ec88c43657.dalf +e198664748ca9a14de3cf197a0bac3aec6deb3d4097db73dfbf300bb97e30b9a platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Stack-Types-5921708ce82f4255deb1b26d2c05358b548720938a5a325718dc69f381ba47ff.dalf +826cad481a81e8e1fd7151a0f9c3bf5c14cc14e2983e1abc143387dafe4b8282 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Time-Types-733e38d36a2759688a4b2c4cec69d48e7b55ecc8dedc8067b815926c917a182a.dalf +348c6f5fcd6b3b2753a8418cdb980b3a8c73fcc37ff1ffc63c0a9625159ca067 platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/daml-stdlib-DA-Validation-Types-99a2705ed38c1c26cbb8fe7acf36bbf626668e167a33335de932599219e0a235.dalf +c0ee8933aa71d974733d3a902430a66c774ab14302a5f84d9fff398f8d94d60c platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/data/platform-independence-1.0.0.conf +f2de19ae3b4212dc81c4ae005bf574e0d324be87895ef708d60eac489784550e platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc/platform-independence-1.0.0-cc970409d01aa851d1d61ba77865520cd6df798508181c5af579d3995232e5fc.dalf diff --git a/sdk/compiler/damlc/tests/src/DA/Test/DamlcUpgrades.hs b/sdk/compiler/damlc/tests/src/DA/Test/DamlcUpgrades.hs index 9e8e37b8cc5f..2ee7ac47a184 100644 --- a/sdk/compiler/damlc/tests/src/DA/Test/DamlcUpgrades.hs +++ b/sdk/compiler/damlc/tests/src/DA/Test/DamlcUpgrades.hs @@ -87,7 +87,7 @@ tests damlc = False setUpgradeField , test - "FailsWhenTemplateChangesKeyType" + "FailsWhenTemplateChangesKeyTypeSuperficially" (FailWithError "\ESC\\[0;91merror type checking template Main.A key:\n The upgraded template A cannot change its key type.") contractKeysMinVersion NoDependencies diff --git a/sdk/compiler/damlc/tests/src/DA/Test/UnstableTypes.hs b/sdk/compiler/damlc/tests/src/DA/Test/UnstableTypes.hs index da2ef2f27826..75f53369e7ba 100644 --- a/sdk/compiler/damlc/tests/src/DA/Test/UnstableTypes.hs +++ b/sdk/compiler/damlc/tests/src/DA/Test/UnstableTypes.hs @@ -6,7 +6,6 @@ module DA.Test.UnstableTypes (main) where {- HLINT ignore "locateRunfiles/package_app" -} -import Data.Bifunctor import Control.Monad.Extra import DA.Bazel.Runfiles import qualified DA.Daml.LF.Ast as LF @@ -41,9 +40,9 @@ main = do , LF.getIsSerializable (LF.dataSerializable ty) ] if | "daml-prim" == takeBaseName dalf -> - serializableTypes @?= sort damlPrimTypes + serializableTypes @?= [] | "daml-stdlib" `isPrefixOf` takeBaseName dalf -> - serializableTypes @?= sort damlStdlibTypes + serializableTypes @?= [] | otherwise -> assertFailure ("Unknown package: " <> show dalf) pure () diff --git a/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV1.scala b/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV1.scala index e16dca548451..476a9f84ddc1 100644 --- a/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV1.scala +++ b/sdk/daml-lf/archive/src/main/scala/com/digitalasset/daml/lf/archive/DecodeV1.scala @@ -1057,47 +1057,7 @@ private[archive] class DecodeV1(minor: LV.Minor) { private[lf] object DecodeV1 { - object Features { - import LV._ - val default = v1_6 - val internedPackageId = v1_6 - val internedStrings = v1_7 - val internedDottedNames = v1_7 - val numeric = v1_7 - val anyType = v1_7 - val typeRep = v1_7 - val typeSynonyms = v1_8 - val packageMetadata = v1_8 - val genComparison = v1_11 - val genMap = v1_11 - val scenarioMustFailAtMsg = v1_11 - val contractIdTextConversions = v1_11 - val exerciseByKey = v1_11 - val internedTypes = v1_11 - val choiceObservers = v1_11 - val bigNumeric = v1_13 - val exceptions = v1_14 - val basicInterfaces = v1_15 - val choiceFuncs = v1_dev - val choiceAuthority = v1_dev - val natTypeErasure = v1_dev - val packageUpgrades = v1_dev - val dynamicExercise = v1_dev - val sharedKeys = v1_dev - - /** TYPE_REP_TYCON_NAME builtin */ - val templateTypeRepToText = v1_dev - - /** Guards in interfaces */ - val extendedInterfaces = v1_dev - - /** Unstable, experimental features. This should stay in x.dev forever. - * Features implemented with this flag should be moved to a separate - * feature flag once the decision to add them permanently has been made. - */ - val unstable = v1_dev - - } + val Features = LV.FeaturesV1 private def eitherToParseError[A](x: Either[String, A]): A = x.fold(err => throw Error.Parsing(err), identity) diff --git a/sdk/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/DecodeV1Spec.scala b/sdk/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/DecodeV1Spec.scala index 2d522d109d0c..f055bce337ec 100644 --- a/sdk/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/DecodeV1Spec.scala +++ b/sdk/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/DecodeV1Spec.scala @@ -72,11 +72,12 @@ class DecodeV1Spec private[this] val lfVersions = LV.AllV1 - private[this] def forEveryVersionSuchThat[U](cond: LV => Boolean)(f: LV => U): Unit = + private[this] def forEveryVersionSuchThat[U](cond: LV => Boolean)(f: LV => U): Unit = { lfVersions.foreach { version => if (cond(version)) f(version) () } + } private[this] def forEveryVersion[U]: (LV => U) => Unit = forEveryVersionSuchThat(_ => true) @@ -753,7 +754,7 @@ class DecodeV1Spec } "decode PackageMetadata if lf version >= 1.8" in { - forEveryVersionSuchThat(_ >= Features.packageMetadata) { version => + forEveryVersionSuchThat(_ >= Features.packageMetadata) { (version: LV) => val decoder = new DecodeV1(version.minor) val pkgId = Ref.PackageId.assertFromString( "0000000000000000000000000000000000000000000000000000000000000000" @@ -769,13 +770,16 @@ class DecodeV1Spec .addInternedStrings("0.0.0") .setMetadata(metadata) .build() - inside(decoder.decodePackage(pkgId, pkg, false)) { case Right(pkg) => - pkg.metadata shouldBe - Ast.PackageMetadata( - Ref.PackageName.assertFromString("foobar"), - Ref.PackageVersion.assertFromString("0.0.0"), - None, - ) + inside(decoder.decodePackage(pkgId, pkg, false)) { + case Right(pkg) => + pkg.metadata shouldBe + Ast.PackageMetadata( + Ref.PackageName.assertFromString("foobar"), + Ref.PackageVersion.assertFromString("0.0.0"), + None, + ) + case Left(Error.Internal(_, _, Some(err))) => throw err + case Left(err) => throw err } } } diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala index 247bed605ce1..612f42333fe0 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala @@ -1233,11 +1233,21 @@ object Ast { directDeps: Set[PackageId], languageVersion: LanguageVersion, metadata: PackageMetadata, + // Packages that do not define any serializable types are referred to as utility packages + // in the context of upgrades. They will not be considered for upgrade checks. + isUtilityPackage: Boolean, ) { + // package Name if the package support upgrade + // TODO: https://github.com/digital-asset/daml/issues/17965 + // drop that in daml-3 + private[lf] val name: Option[Ref.PackageName] = + if (LanguageVersion.supportsPackageUpgrades(languageVersion) && !isUtilityPackage) + Some(metadata.name) + else + None private[lf] def pkgName: Ref.PackageName = metadata.name private[lf] def pkgVersion: Option[Ref.PackageVersion] = { - import Ordering.Implicits._ - if (languageVersion < LanguageVersion.Features.persistedPackageVersion) + if (LanguageVersion.supportsPersistedPackageVersion(languageVersion)) None else Some(metadata.version) @@ -1254,8 +1264,10 @@ object Ast { directDeps: Iterable[PackageId], languageVersion: LanguageVersion, metadata: PackageMetadata, + // Packages that do not define any serializable types are referred to as utility packages + // in the context of upgrades. They will not be considered for upgrade checks. ): GenPackage[E] = - GenPackage( + apply( modules = toMapWithoutDuplicate( modules.view.map(m => m.name -> m), (modName: ModuleName) => PackageError(s"Collision on module name ${modName.toString}"), @@ -1269,13 +1281,24 @@ object Ast { directDeps: Set[PackageId], languageVersion: LanguageVersion, metadata: PackageMetadata, - ): GenPackage[E] = + ): GenPackage[E] = { + val isUtilityPackage = + modules.values.forall(mod => + mod.templates.isEmpty && + mod.interfaces.isEmpty && + mod.definitions.values.forall { + case DDataType(serializable, _, _) => !serializable + case _ => true + } + ) GenPackage( modules = modules, directDeps = directDeps, languageVersion = languageVersion, metadata = metadata, + isUtilityPackage = isUtilityPackage, ) + } def unapply(arg: GenPackage[E]): Some[ ( diff --git a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala index 37509cd937b4..2928eaa19c59 100644 --- a/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala +++ b/sdk/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala @@ -49,6 +49,36 @@ object LanguageVersion { @deprecated("use AllV2", since = "3.1.0") val All = AllV2 + private def supportsV1AndV2( + lv: LanguageVersion, + minorV2: Option[Minor], + minorV1: Option[Minor], + ): Boolean = { + import scala.math.Ordering.Implicits._ + lv.major match { + case Major.V2 => + minorV2 match { + case Some(minorV2) => lv >= LanguageVersion(Major.V2, minorV2) + case None => false + } + case Major.V1 => + minorV1 match { + case Some(minorV1) => lv >= LanguageVersion(Major.V1, minorV1) + case None => false + } + } + } + + def supportsPackageUpgrades(lv: LanguageVersion): Boolean = + supportsV1AndV2( + lv, + Some(Features.packageUpgrades.minor), + Some(FeaturesV1.packageUpgrades.minor), + ) + + def supportsPersistedPackageVersion(lv: LanguageVersion): Boolean = + supportsV1AndV2(lv, Some(Features.persistedPackageVersion.minor), None) + object Features { val default = v2_1 val exceptions = v2_1 @@ -82,6 +112,47 @@ object LanguageVersion { } + object FeaturesV1 { + val default = v1_6 + val internedPackageId = v1_6 + val internedStrings = v1_7 + val internedDottedNames = v1_7 + val numeric = v1_7 + val anyType = v1_7 + val typeRep = v1_7 + val typeSynonyms = v1_8 + val packageMetadata = v1_8 + val genComparison = v1_11 + val genMap = v1_11 + val scenarioMustFailAtMsg = v1_11 + val contractIdTextConversions = v1_11 + val exerciseByKey = v1_11 + val internedTypes = v1_11 + val choiceObservers = v1_11 + val bigNumeric = v1_13 + val exceptions = v1_14 + val basicInterfaces = v1_15 + val choiceFuncs = v1_dev + val choiceAuthority = v1_dev + val natTypeErasure = v1_dev + val packageUpgrades = v1_dev + val dynamicExercise = v1_dev + val sharedKeys = v1_dev + + /** TYPE_REP_TYCON_NAME builtin */ + val templateTypeRepToText = v1_dev + + /** Guards in interfaces */ + val extendedInterfaces = v1_dev + + /** Unstable, experimental features. This should stay in x.dev forever. + * Features implemented with this flag should be moved to a separate + * feature flag once the decision to add them permanently has been made. + */ + val unstable = v1_dev + + } + private[lf] def notSupported(majorLanguageVersion: LanguageMajorVersion) = throw new IllegalArgumentException(s"${majorLanguageVersion.pretty} not supported") diff --git a/sdk/daml-lf/validation/BUILD.bazel b/sdk/daml-lf/validation/BUILD.bazel index cba5087fb32b..d1a91e07a939 100644 --- a/sdk/daml-lf/validation/BUILD.bazel +++ b/sdk/daml-lf/validation/BUILD.bazel @@ -152,6 +152,24 @@ da_scala_test_suite( "//test-common:upgrades-TemplateChangedKeyType-v2.dar", "//test-common:upgrades-ValidUpgrade-v1.dar", "//test-common:upgrades-ValidUpgrade-v2.dar", + "//test-common:upgrades-EmptyProject-v21.dar", + "//test-common:upgrades-EmptyProject-v2dev.dar", + "//test-common:upgrades-ValidParameterizedTypesUpgrade-v1.dar", + "//test-common:upgrades-ValidParameterizedTypesUpgrade-v2.dar", + "//test-common:upgrades-ValidKeyTypeEquality-v1.dar", + "//test-common:upgrades-ValidKeyTypeEquality-v2.dar", + "//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgrades-v1.dar", + "//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgrades-v2.dar", + "//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v1.dar", + "//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v2.dar", + "//test-common:upgrades-UploadFailsWhenDepsAreInvalidUpgrades-v1.dar", + "//test-common:upgrades-UploadFailsWhenDepsAreInvalidUpgrades-v2.dar", + "//test-common:upgrades-SucceedsWhenNonSerializableTypesAreIncompatible-v1.dar", + "//test-common:upgrades-SucceedsWhenNonSerializableTypesAreIncompatible-v2.dar", + "//test-common:upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-v1.dar", + "//test-common:upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-v2.dar", + "//test-common:upgrades-FailsWhenUpgradedFieldPackagesAreNotUpgradable-v1.dar", + "//test-common:upgrades-FailsWhenUpgradedFieldPackagesAreNotUpgradable-v2.dar", # Ported from DamlcUpgrades.hs "//test-common:upgrades-FailsWhenExistingFieldInTemplateChoiceIsChanged-v1.dar", @@ -251,7 +269,20 @@ da_scala_test_suite( scalacopts = lf_scalacopts, deps = [ ":upgrade-test-lib", + "//:sdk-version-scala-lib", + "//bazel_tools/runfiles:scala_runfiles", + "//canton:community_admin-api", + "//canton:community_ledger_ledger-common", + "//canton:community_util-logging", + "//canton:ledger_api_proto_scala", + "//daml-lf/archive:daml_lf_archive_proto_java", + "//daml-lf/archive:daml_lf_archive_reader", + "//daml-lf/archive/encoder", "//daml-lf/data", + "//daml-lf/encoder", + "//daml-lf/language", + "//daml-lf/parser", + "//libs-scala/crypto", "//libs-scala/ledger-resources", "//libs-scala/resources", "//libs-scala/rs-grpc-bridge", diff --git a/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Upgrading.scala b/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Upgrading.scala index 9960bbb1f48b..f8e4fdef5b95 100644 --- a/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Upgrading.scala +++ b/sdk/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Upgrading.scala @@ -4,12 +4,13 @@ package com.digitalasset.daml.lf package validation -import com.digitalasset.daml.lf.data.Ref -import com.digitalasset.daml.lf.language.Ast import scala.util.{Try, Success, Failure} -import com.digitalasset.daml.lf.validation.AlphaEquiv -import com.digitalasset.daml.lf.data.ImmArray -import com.digitalasset.daml.lf.language.LanguageVersion +import com.digitalasset.daml.lf.data.Ref.TypeConName +import com.digitalasset.daml.lf.data.{ImmArray, Ref} +import com.digitalasset.daml.lf.language.Ast._ +import com.digitalasset.daml.lf.language.{Ast, LanguageVersion, PackageInterface} + +import scala.annotation.tailrec case class Upgrading[A](past: A, present: A) { def map[B](f: A => B): Upgrading[B] = Upgrading(f(past), f(present)) @@ -168,17 +169,6 @@ object UpgradeError { s"The upgraded $origin has changed the order of its variants - any new variant must be added at the end of the enum." } - final case class TriedToUpgradeIface(iface: Ref.DottedName) extends Error { - override def message: String = - s"Tried to upgrade interface $iface, but interfaces cannot be upgraded. They should be removed in any upgrading package." - } - - final case class MissingImplementation(tpl: Ref.DottedName, iface: Ref.TypeConName) - extends Error { - override def message: String = - s"Implementation of interface $iface by template $tpl appears in package that is being upgraded, but does not appear in this package." - } - final case class DependencyHasLowerVersionDespiteUpgrade( depName: Ref.PackageName, depPresentVersion: Ref.PackageVersion, @@ -195,6 +185,17 @@ object UpgradeError { override def message: String = s"The upgraded package uses an older LF version (${presentVersion.pretty} < ${pastVersion.pretty})" } + + final case class TriedToUpgradeIface(iface: Ref.DottedName) extends Error { + override def message: String = + s"Tried to upgrade interface $iface, but interfaces cannot be upgraded. They should be removed in any upgrading package." + } + + final case class MissingImplementation(tpl: Ref.DottedName, iface: Ref.TypeConName) + extends Error { + override def message: String = + s"Implementation of interface $iface by template $tpl appears in package that is being upgraded, but does not appear in this package." + } } sealed abstract class UpgradedRecordOrigin @@ -272,6 +273,25 @@ final case class ModuleWithMetadata(module: Ast.Module) { } +private case class Env( + currentDepth: Int = 0, + binderDepth: Map[TypeVarName, Int] = Map.empty, +) { + def extend(varNames: ImmArray[TypeVarName]): Env = { + varNames.foldLeft(this) { case (env, varName) => + env.extend(varName) + } + } + + def extend(varName: TypeVarName): Env = Env( + currentDepth + 1, + binderDepth.updated(varName, currentDepth), + ) +} + +/** A datatype closing over the free type variables of [[value]] with [[env]]. */ +private case class Closure[A](env: Env, value: A) + object TypecheckUpgrades { sealed abstract class UploadPhaseCheck @@ -331,48 +351,200 @@ object TypecheckUpgrades { Try(t.map(f(_).get).toSeq) def typecheckUpgrades( + packageMap: Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)], present: ( Ref.PackageId, Ast.Package, - Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)], ), pastPackageId: Ref.PackageId, - mbPastPkg: Option[(Ast.Package, Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)])], + mbPastPkg: Option[Ast.Package], ): Try[Unit] = { mbPastPkg match { case None => fail(UpgradeError.CouldNotResolveUpgradedPackageId(Upgrading(pastPackageId, present._1))); - case Some((pastPkg, pastPkgDeps)) => - val tc = TypecheckUpgrades(Upgrading((pastPackageId, pastPkg, pastPkgDeps), present)) + case Some(pastPkg) => + val (presentPackageId, presentPkg) = present + val tc = TypecheckUpgrades( + packageMap + + (presentPackageId -> (presentPkg.pkgName, presentPkg.metadata.version)) + + (pastPackageId -> (pastPkg.pkgName, pastPkg.metadata.version)), + Upgrading((pastPackageId, pastPkg), present), + ) tc.check() } } - - def typecheckUpgrades( - present: ( - Ref.PackageId, - Ast.Package, - ), - pastPackageId: Ref.PackageId, - mbPastPkg: Option[Ast.Package], - ): Try[Unit] = { - val emptyPackageMap: Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)] = Map.empty - val presentWithNoDeps = (present._1, present._2, emptyPackageMap) - val mbPastPkgWithNoDeps = mbPastPkg.map((_, emptyPackageMap)) - TypecheckUpgrades.typecheckUpgrades(presentWithNoDeps, pastPackageId, mbPastPkgWithNoDeps) - } } case class TypecheckUpgrades( + packageMap: Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)], packages: Upgrading[ - (Ref.PackageId, Ast.Package, Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)]) - ] + (Ref.PackageId, Ast.Package) + ], ) { import TypecheckUpgrades._ + private lazy val packageId: Upgrading[Ref.PackageId] = packages.map(_._1) private lazy val `package`: Upgrading[Ast.Package] = packages.map(_._2) - private lazy val dependencies - : Upgrading[Map[Ref.PackageId, (Ref.PackageName, Ref.PackageVersion)]] = packages.map(_._3) + + private val packageInterface: Upgrading[PackageInterface] = + packages.map { case (pkgId, pkgAst) => PackageInterface(Map(pkgId -> pkgAst)) } + + /** The set of type constructors whose definitions are structurally equal between the + * past and present packages. It is built by building the largest fixed point of + * [[genStructurallyEqualTyConsStep]], which removes type constructors whose definitions + * are not structurally equal from a set. The set is seeded with the qualified names of + * all type constructors present in both packages and whose definitions are serializable. + */ + private lazy val structurallyEqualTyCons: Set[Ref.QualifiedName] = { + def tyCons(pkg: Ast.Package): Set[Ref.QualifiedName] = { + pkg.modules.flatMap { case (moduleName, module) => + module.definitions.collect { + case (name, dt: DDataType) if dt.serializable => + Ref.QualifiedName(moduleName, name) + } + }.toSet + } + val commonTyCons = tyCons(`package`.past).intersect(tyCons(`package`.present)) + genStructurallyEqualTyCons(commonTyCons) + } + + /** Computes the fixed point of genStructurallyEqualTyConsStep. + */ + @tailrec + private def genStructurallyEqualTyCons(tyCons: Set[Ref.QualifiedName]): Set[Ref.QualifiedName] = { + val newTyCOns = genStructurallyEqualTyConsStep(tyCons) + if (newTyCOns == tyCons) tyCons + else genStructurallyEqualTyCons(newTyCOns) + } + + /** For each type constructor name in [[tyCons]], checks that the definition of [[tyCons]] in + * the past and present packages are structurally equal, assuming that the type constructors + * in [[tyCons]] are structurally equal. Removes those that aren't. + */ + def genStructurallyEqualTyConsStep(tyCons: Set[Ref.QualifiedName]): Set[Ref.QualifiedName] = { + tyCons.filter { name => + val pastTypeConName = TypeConName(packageId.past, name) + val presentTypeConName = TypeConName(packageId.present, name) + structurallyEqualDataTypes( + tyCons, + Util.handleLookup( + Context.DefDataType(pastTypeConName), + packageInterface.past + .lookupDataType(pastTypeConName), + ), + Util.handleLookup( + Context.DefDataType(presentTypeConName), + packageInterface.present + .lookupDataType(presentTypeConName), + ), + ) + } + } + + /** Checks that [[pastDataType]] and [[presentDataType]] are structurally equal, assuming that + * the type constructors in [[tyCons]] are structurally equal. + */ + def structurallyEqualDataTypes( + tyCons: Set[Ref.QualifiedName], + pastDataType: DDataType, + presentDataType: DDataType, + ): Boolean = + structurallyEqualDataCons( + tyCons, + Closure(Env().extend(pastDataType.params.map(_._1)), pastDataType.cons), + Closure(Env().extend(presentDataType.params.map(_._1)), presentDataType.cons), + ) + + /** Checks that [[pastCons]] and [[presentCons]] are structurally equal, assuming that + * the type constructors in [[tyCons]] are structurally equal. + */ + private def structurallyEqualDataCons( + tyCons: Set[Ref.QualifiedName], + pastCons: Closure[DataCons], + presentCons: Closure[DataCons], + ): Boolean = + (pastCons.value, presentCons.value) match { + case (DataRecord(pastFields), DataRecord(presentFields)) => + pastFields.length == presentFields.length && + pastFields.iterator.zip(presentFields.iterator).forall { + case ((pastFieldName, pastType), (presentFieldName, presentType)) => + pastFieldName == presentFieldName && + structurallyEqualTypes( + tyCons, + Closure(pastCons.env, pastType), + Closure(presentCons.env, presentType), + ) + } + case (DataVariant(pastVariants), DataVariant(presentVariants)) => + pastVariants.length == presentVariants.length && + pastVariants.iterator.zip(presentVariants.iterator).forall { + case ((pastVariantName, pastType), (presentVariantName, presentType)) => + pastVariantName == presentVariantName && + structurallyEqualTypes( + tyCons, + Closure(pastCons.env, pastType), + Closure(presentCons.env, presentType), + ) + } + case (DataEnum(pastConstructors), DataEnum(presentConstructors)) => + pastConstructors.length == presentConstructors.length && + pastConstructors.iterator.zip(presentConstructors.iterator).forall { + case (pastCtor, presentCtor) => pastCtor == presentCtor + } + case _ => + false + } + + /** Checks that [[pastType]] and [[presentType]] are structurally equal, assuming that + * the type constructors in [[tyCons]] are structurally equal. + */ + private def structurallyEqualTypes( + tyCons: Set[Ref.QualifiedName], + pastType: Closure[Ast.Type], + presentType: Closure[Ast.Type], + ): Boolean = + structurallyEqualTypes( + tyCons, + pastType.env, + presentType.env, + List((pastType.value, presentType.value)), + ) + + /** A stack-safe version of [[structurallyEqualTypes]] that uses a work list. + */ + @tailrec + private def structurallyEqualTypes( + tyCons: Set[Ref.QualifiedName], + envPast: Env, + envPresent: Env, + trips: List[(Type, Type)], + ): Boolean = { + trips match { + case Nil => true + case (t1, t2) :: trips => + (t1, t2) match { + case (TVar(x1), TVar(x2)) => + envPast.binderDepth(x1) == envPresent.binderDepth(x2) && + structurallyEqualTypes(tyCons, envPast, envPresent, trips) + case (TNat(n1), TNat(n2)) => + n1 == n2 && structurallyEqualTypes(tyCons, envPast, envPresent, trips) + case (TTyCon(c1), TTyCon(c2)) => + // Either c1 and c2 are the same type constructor from the exact same package (e.g. Tuple2), + // or they must have the same qualified name and be structurally equal by co-induction + // hypothesis. + (c1 == c2 || + (c1.qualifiedName == c2.qualifiedName && + tyCons.contains(c1.qualifiedName))) && + structurallyEqualTypes(tyCons, envPast, envPresent, trips) + case (TApp(f1, a1), TApp(f2, a2)) => + structurallyEqualTypes(tyCons, envPast, envPresent, (f1, f2) :: (a1, a2) :: trips) + case (TBuiltin(b1), TBuiltin(b2)) => + b1 == b2 && structurallyEqualTypes(tyCons, envPast, envPresent, trips) + case _ => + false + } + } + } private def check(): Try[Unit] = { for { @@ -382,28 +554,10 @@ case class TypecheckUpgrades( `package`.map(_.modules), (name: Ref.ModuleName, _: Ast.Module) => UpgradeError.MissingModule(name), ) - _ <- checkDeps() _ <- tryAll(upgradedModules.values, checkModule(_)) } yield () } - private def checkDeps(): Try[Unit] = { - val (_deleted @ _, existing, _new @ _) = extractDelExistNew(dependencies.map(_.values.toMap)) - tryAll(existing, checkDep).map(_ => ()) - } - - private def checkDep(dep: (Ref.PackageName, Upgrading[Ref.PackageVersion])): Try[Unit] = { - val (depName, depVersions) = dep - failIf( - depVersions.present < depVersions.past, - UpgradeError.DependencyHasLowerVersionDespiteUpgrade( - depName, - depVersions.present, - depVersions.past, - ), - ) - } - private def splitModuleDts( module: Ast.Module ): ( @@ -416,7 +570,7 @@ case class TypecheckUpgrades( val (ifaces, other) = datatypes.partitionMap({ case (tcon, dt) => lookupInterface(module, tcon, dt) }) - (ifaces.toMap, other.toMap) + (ifaces.toMap, other.filter(_._2.serializable).toMap) } private def lookupInterface( @@ -504,16 +658,50 @@ case class TypecheckUpgrades( } yield () } - private def checkType(typ: Upgrading[Ast.Type]): Boolean = { - AlphaEquiv.alphaEquiv(unifyTypes(typ.past), unifyTypes(typ.present)) + private def checkIdentifiers(past: Ref.Identifier, present: Ref.Identifier): Boolean = { + val compatibleNames = past.qualifiedName == present.qualifiedName + val compatiblePackages = + (packageMap.get(past.packageId), packageMap.get(present.packageId)) match { + // The two packages have LF versions < 1.16. + // They must be the exact same package as LF < 1.16 don't support upgrades. + case (None, None) => past.packageId == present.packageId + // The two packages have LF versions >= 1.16. + // The present package must be a valid upgrade of the past package. Since we validate uploaded packages in + // topological order, the package version ordering is a proxy for the "upgrades" relationship. + case (Some((pastName, pastVersion)), Some((presentName, presentVersion))) => + pastName == presentName && pastVersion <= presentVersion + // LF versions < 1.16 and >= 1.16 are not comparable. + case (_, _) => false + } + compatibleNames && compatiblePackages + } + + @tailrec + private def checkTypeList(envPast: Env, envPresent: Env, trips: List[(Type, Type)]): Boolean = + trips match { + case Nil => true + case (t1, t2) :: trips => + (t1, t2) match { + case (TVar(x1), TVar(x2)) => + envPast.binderDepth(x1) == envPresent.binderDepth(x2) && + checkTypeList(envPast, envPresent, trips) + case (TNat(n1), TNat(n2)) => + n1 == n2 && checkTypeList(envPast, envPresent, trips) + case (TTyCon(c1), TTyCon(c2)) => + checkIdentifiers(c1, c2) && checkTypeList(envPast, envPresent, trips) + case (TApp(f1, a1), TApp(f2, a2)) => + checkTypeList(envPast, envPresent, (f1, f2) :: (a1, a2) :: trips) + case (TBuiltin(b1), TBuiltin(b2)) => + b1 == b2 && checkTypeList(envPast, envPresent, trips) + case _ => + false + } + } + + private def checkType(typ: Upgrading[Closure[Ast.Type]]): Boolean = { + checkTypeList(typ.past.env, typ.present.env, List((typ.past.value, typ.present.value))) } - // TODO: https://github.com/digital-asset/daml/pull/18377 - // For simplicity's sake, we check all names against one another as if they - // are in the same package, because package ids do not tell us the package - // name - in the future we should resolve package ids to their package names - // so that we can rule out upgrades between packages that don't have the same - // name. private def unifyIdentifier(id: Ref.Identifier): Ref.Identifier = Ref.Identifier(Ref.PackageId.assertFromString("0"), id.qualifiedName) @@ -528,19 +716,6 @@ case class TypecheckUpgrades( TopLevel(datatype) } - private def unifyTypes(typ: Ast.Type): Ast.Type = { - typ match { - case Ast.TNat(n) => Ast.TNat(n) - case Ast.TSynApp(n, args) => Ast.TSynApp(unifyIdentifier(n), args.map(unifyTypes(_))) - case Ast.TVar(n) => Ast.TVar(n) - case Ast.TTyCon(con) => Ast.TTyCon(unifyIdentifier(con)) - case Ast.TBuiltin(bt) => Ast.TBuiltin(bt) - case Ast.TApp(fun, arg) => Ast.TApp(unifyTypes(fun), unifyTypes(arg)) - case Ast.TForall(v, body) => Ast.TForall(v, unifyTypes(body)) - case Ast.TStruct(fields) => Ast.TStruct(fields.mapValues(unifyTypes(_))) - } - } - private def checkKey( templateName: Ref.DottedName, key: Upgrading[Option[Ast.TemplateKey]], @@ -548,9 +723,15 @@ case class TypecheckUpgrades( key match { case Upgrading(None, None) => Success(()); case Upgrading(Some(pastKey), Some(presentKey)) => { - val key = Upgrading(pastKey.typ, presentKey.typ) - if (!checkType(key)) - fail(UpgradeError.TemplateChangedKeyType(templateName, key)) + val keyPastPresent = Upgrading(pastKey.typ, presentKey.typ) + if ( + !structurallyEqualTypes( + structurallyEqualTyCons, + Closure(Env(), pastKey.typ), + Closure(Env(), presentKey.typ), + ) + ) + fail(UpgradeError.TemplateChangedKeyType(templateName, keyPastPresent)) else Success(()) } @@ -563,7 +744,7 @@ case class TypecheckUpgrades( private def checkChoice(choice: Upgrading[Ast.TemplateChoice]): Try[Unit] = { val returnType = choice.map(_.returnType) - if (checkType(returnType)) { + if (checkType(returnType.map(Closure(Env(), _)))) { Success(()) } else { fail(UpgradeError.ChoiceChangedReturnType(choice.present.name, returnType)) @@ -579,9 +760,13 @@ case class TypecheckUpgrades( if (unifyUpgradedRecordOrigin(origin.present) != unifyUpgradedRecordOrigin(origin.past)) { fail(UpgradeError.RecordChangedOrigin(name, origin)) } else { + val env = datatype.map(dt => Env().extend(dt.params.map(_._1))) datatype.map(_.cons) match { case Upgrading(past: Ast.DataRecord, present: Ast.DataRecord) => - checkFields(origin.present, Upgrading(past, present)) + checkFields( + origin.present, + Upgrading(Closure(env.past, past), Closure(env.present, present)), + ) case Upgrading(past: Ast.DataVariant, present: Ast.DataVariant) => val upgrade = Upgrading(past, present) val variants: Upgrading[Map[Ast.VariantConName, Ast.Type]] = @@ -593,7 +778,9 @@ case class TypecheckUpgrades( UpgradeError.VariantRemovedVariant(origin.present), ) - changedTypes = existing.filter { case (field @ _, typ) => !checkType(typ) } + changedTypes = existing.filter { case (field @ _, typ) => + !checkType(env.zip(typ, Closure.apply _)) + } _ <- if (changedTypes.nonEmpty) fail(UpgradeError.VariantChangedVariantType(origin.present)) @@ -639,10 +826,11 @@ case class TypecheckUpgrades( private def checkFields( origin: UpgradedRecordOrigin, - records: Upgrading[Ast.DataRecord], + recordClosures: Upgrading[Closure[Ast.DataRecord]], ): Try[Unit] = { + val env = recordClosures.map(_.env) val fields: Upgrading[Map[Ast.FieldName, Ast.Type]] = - records.map(rec => Map.from(rec.fields.iterator)) + recordClosures.map(rec => Map.from(rec.value.fields.iterator)) def fieldTypeOptional(typ: Ast.Type): Boolean = typ match { case Ast.TApp(Ast.TBuiltin(Ast.BTOptional), _) => true @@ -655,7 +843,9 @@ case class TypecheckUpgrades( _ <- failIf(_deleted.nonEmpty, UpgradeError.RecordFieldsMissing(origin, _deleted)) // Then we check for changed types - changedTypes = _existing.filter { case (field @ _, typ) => !checkType(typ) } + changedTypes = _existing.filter { case (field @ _, typ) => + !checkType(env.zip(typ, Closure.apply _)) + } _ <- failIf( changedTypes.nonEmpty, UpgradeError.RecordFieldsExistingChanged(origin, changedTypes), @@ -677,7 +867,8 @@ case class TypecheckUpgrades( // Finally, reordered field names changedFieldNames: ImmArray[(Ast.FieldName, Ast.FieldName)] = { - val fieldNames: Upgrading[ImmArray[Ast.FieldName]] = records.map(_.fields.map(_._1)) + val fieldNames: Upgrading[ImmArray[Ast.FieldName]] = + recordClosures.map(_.value.fields.map(_._1)) fieldNames.past.zip(fieldNames.present).filter { case (past, present) => past != present } } _ <- failIf(changedFieldNames.nonEmpty, UpgradeError.RecordFieldsOrderChanged(origin)) diff --git a/sdk/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/upgrade/UpgradesSpecBase.scala b/sdk/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/upgrade/UpgradesSpecBase.scala index 4138f582f00c..9733f15ec00f 100644 --- a/sdk/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/upgrade/UpgradesSpecBase.scala +++ b/sdk/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/upgrade/UpgradesSpecBase.scala @@ -101,6 +101,16 @@ trait LongTests { this: UpgradesSpec => ) } + s"uploading the standard library twice for two different LF versions succeeds ($suffix)" in { + for { + result1 <- uploadPackage("test-common/upgrades-EmptyProject-v21.dar") + result2 <- uploadPackage("test-common/upgrades-EmptyProject-v2dev.dar") + } yield { + // We expect both results to be error-free + assert(result1._2.isEmpty && result2._2.isEmpty) + } + } + s"uploads against the same package name must be version unique ($suffix)" in { testPackagePair( "test-common/upgrades-CommonVersionFailure-v1a.dar", @@ -111,6 +121,7 @@ trait LongTests { this: UpgradesSpec => ), ) } + s"report no upgrade errors for valid upgrade ($suffix)" in { testPackagePair( "test-common/upgrades-ValidUpgrade-v1.dar", @@ -118,6 +129,20 @@ trait LongTests { this: UpgradesSpec => assertPackageUpgradeCheck(None), ) } + s"report no upgrade errors for valid upgrades of parameterized data types ($suffix)" in { + testPackagePair( + "test-common/upgrades-ValidParameterizedTypesUpgrade-v1.dar", + "test-common/upgrades-ValidParameterizedTypesUpgrade-v2.dar", + assertPackageUpgradeCheck(None), + ) + } + s"report no upgrade errors for alpha-equivalent complex key types ($suffix)" in { + testPackagePair( + "test-common/upgrades-ValidKeyTypeEquality-v1.dar", + "test-common/upgrades-ValidKeyTypeEquality-v2.dar", + assertPackageUpgradeCheck(None), + ) + } s"report error when module is missing in upgrading package ($suffix)" in { testPackagePair( "test-common/upgrades-MissingModule-v1.dar", @@ -624,6 +649,58 @@ trait LongTests { this: UpgradesSpec => mkTrivialPkg("-decreasing-lf-version-", "2.0.0", LanguageVersion.v2_1), assertPackageUpgradeCheck(Some("The upgraded package uses an older LF version")), ) + + "Succeeds when v2 depends on v2dep which is a valid upgrade of v1dep" in + testPackagePair( + "test-common/upgrades-UploadSucceedsWhenDepsAreValidUpgrades-v1.dar", + "test-common/upgrades-UploadSucceedsWhenDepsAreValidUpgrades-v2.dar", + assertPackageDependenciesUpgradeCheck( + "test-common/upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v1.dar", + "test-common/upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v2.dar", + None, + ), + ) + + "report upgrade errors when v2 depends on v2dep which is an invalid upgrade of v1dep" in + testPackagePair( + "test-common/upgrades-UploadFailsWhenDepsAreInvalidUpgrades-v1.dar", + "test-common/upgrades-UploadFailsWhenDepsAreInvalidUpgrades-v2.dar", + assertPackageDependenciesUpgradeCheck( + "test-common/upgrades-FailsWhenExistingFieldInTemplateIsChanged-v1.dar", + "test-common/upgrades-FailsWhenExistingFieldInTemplateIsChanged-v2.dar", + Some("The upgraded template A has changed the types of some of its original fields."), + ), + ) + + "Succeeds even when non-serializable types are incompatible" in { + testPackagePair( + "test-common/upgrades-SucceedsWhenNonSerializableTypesAreIncompatible-v1.dar", + "test-common/upgrades-SucceedsWhenNonSerializableTypesAreIncompatible-v2.dar", + assertPackageUpgradeCheck( + None + ), + ) + } + + "Fails when comparing types from packages with different names" in { + testPackagePair( + "test-common/upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-v1.dar", + "test-common/upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-v2.dar", + assertPackageUpgradeCheck( + Some("The upgraded data type A has changed the types of some of its original fields.") + ), + ) + } + + "Fails when comparing type constructors from other packages that resolve to incompatible types" in { + testPackagePair( + "test-common/upgrades-FailsWhenUpgradedFieldPackagesAreNotUpgradable-v1.dar", + "test-common/upgrades-FailsWhenUpgradedFieldPackagesAreNotUpgradable-v2.dar", + assertPackageUpgradeCheck( + Some("The upgraded data type T has changed the types of some of its original fields.") + ), + ) + } } } @@ -691,11 +768,11 @@ abstract class UpgradesSpec(val suffix: String) val (testPackageV1Id, uploadV1Result) = v1 val (testPackageV2Id, uploadV2Result) = v2 if (disableUpgradeValidation) { - filterLog(cantonLogSrc, testPackageV1Id) should include( - s"Skipping upgrade validation for package $testPackageV1Id" + filterLog(cantonLogSrc, testPackageV1Id) should include regex ( + s"Skipping upgrade validation for packages .*$testPackageV1Id".r ) - filterLog(cantonLogSrc, testPackageV2Id) should include( - s"Skipping upgrade validation for package $testPackageV2Id" + filterLog(cantonLogSrc, testPackageV2Id) should include regex ( + s"Skipping upgrade validation for packages .*$testPackageV2Id".r ) filterLog(cantonLogSrc, testPackageV2Id) should not include regex( s"The DAR contains a package which claims to upgrade another package, but basic checks indicate the package is not a valid upgrade." @@ -874,6 +951,21 @@ abstract class UpgradesSpec(val suffix: String) ) { a => a } } + def assertPackageDependenciesUpgradeCheck( + v1dep: String, + v2dep: String, + failureMessage: Option[String], + )( + v1: (PackageId, Option[Throwable]), + v2: (PackageId, Option[Throwable]), + )(cantonLogSrc: String): Assertion = { + val v1depId = loadPackageIdAndBS(v1dep)._1 + val v2depId = loadPackageIdAndBS(v2dep)._1 + assertPackageUpgradeCheckGeneral(failureMessage)((v1depId, v1._2), (v2depId, v2._2), true)( + cantonLogSrc + ) + } + def filterLog(log: String, str: String): String = log.split("\n").view.filter(_.contains(str)).mkString("\n") } diff --git a/sdk/test-common/BUILD.bazel b/sdk/test-common/BUILD.bazel index 801849a10c6c..1f922fbeb206 100644 --- a/sdk/test-common/BUILD.bazel +++ b/sdk/test-common/BUILD.bazel @@ -8,9 +8,12 @@ load( load( "//daml-lf/language:daml-lf.bzl", "lf_version_configuration", + "mangle_for_damlc", "version_in", ) load("//test-common:test-common.bzl", "da_scala_dar_resources_library") +load("//rules_daml:daml.bzl", "daml_compile", "default_damlc_opts") +load("//daml-lf/language:daml-lf.bzl", "mangle_for_java") alias( name = "dar-files", @@ -67,99 +70,45 @@ da_scala_dar_resources_library( visibility = ["//visibility:public"], ) +# Compiles FailsWhenUpgradedFieldFromDifferentPackageName/dep/Dep.daml to two packages with different names. +[ + daml_compile( + name = "upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-dep-{}".format(project_name), + srcs = glob(["src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/dep/Dep.daml"]), + project_name = project_name, + target = "2.dev", + version = "1.0.0", + visibility = ["//visibility:public"], + ) + for project_name in [ + "name1", + "name2", + ] +] + [ [ filegroup( - name = "upgrades-{}-files".format(identifier), + name = "upgrades-{}-dep-files".format(identifier), srcs = glob(["src/main/daml/upgrades/{}/*/*.daml".format(identifier)]), visibility = ["//visibility:public"], ), daml_compile( - name = "upgrades-{}-v1".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/v1/*.daml".format(identifier)]), + name = "upgrades-{}-dep".format(identifier), + srcs = glob(["src/main/daml/upgrades/{}/dep/*.daml".format(identifier)]), dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], enable_interfaces = True, ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], - project_name = "upgrades-example-{}".format(identifier), + project_name = "upgrades-example-{}-dep".format(identifier), target = "2.dev", version = "1.0.0", visibility = ["//visibility:public"], ), - daml_compile( - name = "upgrades-{}-v2".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/v2/*.daml".format(identifier)]), - dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], - enable_interfaces = True, - ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], - project_name = "upgrades-example-{}".format(identifier), - target = "2.dev", - # We want to check the validity of this upgrade on the ledger - # client, not during compilation - typecheck_upgrades = False, - upgrades = "//test-common:upgrades-{}-v1.dar".format(identifier), - version = "2.0.0", - visibility = ["//visibility:public"], - ), ] for identifier in [ - "MissingModule", - "MissingTemplate", - "MissingDataCon", - "MissingChoice", - "RecordFieldsNewNonOptional", - "TemplateChangedKeyType", - "ValidUpgrade", - - # Ported from DamlcUpgrades.hs - "FailsWhenExistingFieldInTemplateChoiceIsChanged", - "FailsWhenExistingFieldInTemplateIsChanged", - "FailsWhenNewFieldIsAddedToTemplateChoiceWithoutOptionalType", - "FailsWhenNewFieldIsAddedToTemplateWithoutOptionalType", - "FailsWhenOldFieldIsDeletedFromTemplate", - "FailsWhenOldFieldIsDeletedFromTemplateChoice", - "FailsWhenTemplateAddsKeyType", - "FailsWhenTemplateChangesKeyType", - "FailsWhenTemplateChoiceChangesItsReturnType", - "FailsWhenTemplateRemovesKeyType", - "SucceedsWhenNewFieldWithOptionalTypeIsAddedToTemplate", - "SucceedsWhenNewFieldWithOptionalTypeIsAddedToTemplateChoice", - "SucceedsWhenTemplateChoiceInputArgumentHasChanged", - "SucceedsWhenTemplateChoiceReturnsATemplateWhichHasChanged", - - # More tests ported from DamlcUpgrades.hs - "SucceedsWhenATopLevelEnumChanges", - "FailsWhenATopLevelRecordAddsANonOptionalField", - "FailsWhenATopLevelRecordAddsAnOptionalFieldBeforeTheEnd", - "FailsWhenATopLevelVariantAddsAFieldToAVariantsType", - "FailsWhenATopLevelVariantAddsAVariant", - "FailsWhenATopLevelVariantRemovesAVariant", - "FailsWhenTwoDeeplyNestedTypeSynonymsResolveToDifferentDatatypes", - "SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd", - "SucceedsWhenATopLevelTypeSynonymChanges", - "SucceedsWhenTwoDeeplyNestedTypeSynonymsResolveToTheSameDatatypes", - - # More more tests ported from DamlcUpgrades.hs - "FailWhenATopLevelEnumChangesChangesTheOrderOfItsVariants", - "FailWhenATopLevelVariantChangesChangesTheOrderOfItsVariants", - # More more more tests ported from DamlcUpgrades.hs - "FailsWhenAnInterfaceIsDefinedInAnUpgradingPackageWhenItWasAlreadyInThePriorPackage", - "SucceedsWhenAnInterfaceIsOnlyDefinedInTheInitialPackage", - "SucceedWhenATopLevelEnumAddsAField", - "SucceedsWhenATopLevelVariantAddsAVariant", - "SucceedsWhenATopLevelVariantAddsAnOptionalFieldToAVariantsType", - "WarnsWhenAnInterfaceAndATemplateAreDefinedInTheSamePackage", - "WarnsWhenAnInterfaceIsUsedInThePackageThatItsDefinedIn", - "WarnsWhenControllersOfTemplateChoiceAreChanged", - "WarnsWhenObserversOfTemplateChoiceAreChanged", - "WarnsWhenTemplateChangesEnsure", - "WarnsWhenTemplateChangesKeyExpression", - "WarnsWhenTemplateChangesKeyMaintainers", - "WarnsWhenTemplateChangesObservers", - "WarnsWhenTemplateChangesSignatories", - "FailsWithSynonymReturnTypeChange", - "FailsOnlyInModuleNotInReexports", - "FailsWhenDatatypeChangesVariety", + "FailsWhenAnInstanceIsDropped", + "SucceedsWhenAnInstanceIsAddedSeparateDep", ] ] @@ -173,6 +122,7 @@ da_scala_dar_resources_library( daml_compile( name = "upgrades-{}-v1".format(identifier), srcs = glob(["src/main/daml/upgrades/{}/v1/*.daml".format(identifier)]), + data_dependencies = v1deps, dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], enable_interfaces = True, ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], @@ -184,7 +134,7 @@ da_scala_dar_resources_library( daml_compile( name = "upgrades-{}-v2".format(identifier), srcs = glob(["src/main/daml/upgrades/{}/v2/*.daml".format(identifier)]), - data_dependencies = ["//test-common:upgrades-{}-v1.dar".format(identifier)], + data_dependencies = v2deps, dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], enable_interfaces = True, ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], @@ -198,10 +148,135 @@ da_scala_dar_resources_library( visibility = ["//visibility:public"], ), ] - for identifier in [ + for (identifier, v1deps, v2deps) in [ + ("MissingModule", [], []), + ("MissingTemplate", [], []), + ("MissingDataCon", [], []), + ("MissingChoice", [], []), + ("RecordFieldsNewNonOptional", [], []), + ("TemplateChangedKeyType", [], []), + ("ValidUpgrade", [], []), + ("ValidParameterizedTypesUpgrade", [], []), + ("ValidKeyTypeEquality", [], []), + ( + "UploadSucceedsWhenDepsAreValidUpgrades", + ["//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v1.dar"], + ["//test-common:upgrades-UploadSucceedsWhenDepsAreValidUpgradesDep-v2.dar"], + ), + ("UploadSucceedsWhenDepsAreValidUpgradesDep", [], []), + ( + "UploadFailsWhenDepsAreInvalidUpgrades", + ["//test-common:upgrades-FailsWhenExistingFieldInTemplateIsChanged-v1.dar"], + ["//test-common:upgrades-FailsWhenExistingFieldInTemplateIsChanged-v2.dar"], + ), + + # Ported from DamlcUpgrades.hs + ("FailsWhenExistingFieldInTemplateChoiceIsChanged", [], []), + ("FailsWhenExistingFieldInTemplateIsChanged", [], []), + ("FailsWhenNewFieldIsAddedToTemplateChoiceWithoutOptionalType", [], []), + ("FailsWhenNewFieldIsAddedToTemplateWithoutOptionalType", [], []), + ("FailsWhenOldFieldIsDeletedFromTemplate", [], []), + ("FailsWhenOldFieldIsDeletedFromTemplateChoice", [], []), + ("FailsWhenTemplateAddsKeyType", [], []), + ("FailsWhenTemplateChangesKeyType", [], []), + ("FailsWhenTemplateChangesKeyTypeSuperficially", [], []), + ("FailsWhenTemplateChoiceChangesItsReturnType", [], []), + ("FailsWhenTemplateRemovesKeyType", [], []), + ("SucceedsWhenNewFieldWithOptionalTypeIsAddedToTemplate", [], []), + ("SucceedsWhenNewFieldWithOptionalTypeIsAddedToTemplateChoice", [], []), + ("SucceedsWhenTemplateChoiceInputArgumentHasChanged", [], []), + ("SucceedsWhenTemplateChoiceReturnsATemplateWhichHasChanged", [], []), + ("SucceedsWhenNonSerializableTypesAreIncompatible", [], []), + ( + "FailsWhenUpgradedFieldFromDifferentPackageName", + ["//test-common:upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-dep-name1.dar"], + ["//test-common:upgrades-FailsWhenUpgradedFieldFromDifferentPackageName-dep-name2.dar"], + ), + ( + "FailsWhenUpgradedFieldPackagesAreNotUpgradable", + ["//test-common:upgrades-SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd-v2.dar"], + ["//test-common:upgrades-SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd-v1.dar"], + ), + + # More tests ported from DamlcUpgrades.hs + ("SucceedsWhenATopLevelEnumChanges", [], []), + ("FailsWhenATopLevelRecordAddsANonOptionalField", [], []), + ("FailsWhenATopLevelRecordAddsAnOptionalFieldBeforeTheEnd", [], []), + ("FailsWhenATopLevelVariantAddsAFieldToAVariantsType", [], []), + ("FailsWhenATopLevelVariantAddsAVariant", [], []), + ("FailsWhenATopLevelVariantRemovesAVariant", [], []), + ("FailsWhenTwoDeeplyNestedTypeSynonymsResolveToDifferentDatatypes", [], []), + ("SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd", [], []), + ("SucceedsWhenATopLevelTypeSynonymChanges", [], []), + ("SucceedsWhenTwoDeeplyNestedTypeSynonymsResolveToTheSameDatatypes", [], []), + + # More more tests ported from DamlcUpgrades.hs + ("FailWhenATopLevelEnumChangesChangesTheOrderOfItsVariants", [], []), + ("FailWhenATopLevelVariantChangesChangesTheOrderOfItsVariants", [], []), + # More more more tests ported from DamlcUpgrades.hs - "SucceedsWhenAnInstanceIsAddedUpgradedPackage", - "WarnsWhenAnInterfaceIsDefinedAndThenUsedInAPackageThatUpgradesIt", + ("FailsWhenAnInterfaceIsDefinedInAnUpgradingPackageWhenItWasAlreadyInThePriorPackage", [], []), + ("SucceedsWhenAnInterfaceIsOnlyDefinedInTheInitialPackage", [], []), + ("SucceedWhenATopLevelEnumAddsAField", [], []), + ("SucceedsWhenATopLevelVariantAddsAVariant", [], []), + ("SucceedsWhenATopLevelVariantAddsAnOptionalFieldToAVariantsType", [], []), + ("WarnsWhenAnInterfaceAndATemplateAreDefinedInTheSamePackage", [], []), + ("WarnsWhenAnInterfaceIsUsedInThePackageThatItsDefinedIn", [], []), + ("WarnsWhenControllersOfTemplateChoiceAreChanged", [], []), + ("WarnsWhenObserversOfTemplateChoiceAreChanged", [], []), + ("WarnsWhenTemplateChangesEnsure", [], []), + ("WarnsWhenTemplateChangesKeyExpression", [], []), + ("WarnsWhenTemplateChangesKeyMaintainers", [], []), + ("WarnsWhenTemplateChangesObservers", [], []), + ("WarnsWhenTemplateChangesSignatories", [], []), + ("FailsWithSynonymReturnTypeChange", [], []), + ("FailsOnlyInModuleNotInReexports", [], []), + ("FailsWhenDatatypeChangesVariety", [], []), + ( + "SucceedsWhenAnInstanceIsAddedUpgradedPackage", + [], + [ + "//test-common:upgrades-SucceedsWhenAnInstanceIsAddedUpgradedPackage-v1.dar", + ], + ), + ( + "WarnsWhenAnInterfaceIsDefinedAndThenUsedInAPackageThatUpgradesIt", + [], + [ + "//test-common:upgrades-WarnsWhenAnInterfaceIsDefinedAndThenUsedInAPackageThatUpgradesIt-v1.dar", + ], + ), + ( + "FailsWhenAnInstanceIsDropped", + ["//test-common:upgrades-FailsWhenAnInstanceIsDropped-dep.dar"], + ["//test-common:upgrades-FailsWhenAnInstanceIsDropped-dep.dar"], + ), + ( + "SucceedsWhenAnInstanceIsAddedSeparateDep", + ["//test-common:upgrades-SucceedsWhenAnInstanceIsAddedSeparateDep-dep.dar"], + ["//test-common:upgrades-SucceedsWhenAnInstanceIsAddedSeparateDep-dep.dar"], + ), + ] +] + +# Two dars with an empty main module whose only point is to depend on the standard library. +# They are compiled to to two different LF versions: 1.16 and 1.dev, which means they +# embark two different versions of the standard library: 1.16 and 1.dev. The packages have +# different names on purpose: the goal is not to check that they are valid upgrades of each +# other, but rather to check that the package upgrade map is not confused when trying to +# compare the different versions of the standard library that they embark upon uploading. +[ + daml_compile( + name = "upgrades-EmptyProject-{}".format(mangle_for_damlc(lf_version)), + srcs = glob(["src/main/daml/upgrades/EmptyProject/*.daml"]), + project_name = "upgrades-EmptyProject-{}".format(mangle_for_damlc(lf_version)), + target = lf_version, + version = "1.0.0", + visibility = ["//visibility:public"], + ) + for lf_version in [ + "2.1", + "2.dev", ] ] @@ -287,60 +362,6 @@ da_scala_dar_resources_library( ] ] -[ - [ - filegroup( - name = "upgrades-{}-files".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/*/*.daml".format(identifier)]), - visibility = ["//visibility:public"], - ), - daml_compile( - name = "upgrades-{}-dep".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/dep/*.daml".format(identifier)]), - dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], - enable_interfaces = True, - ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], - project_name = "upgrades-example-{}-dep".format(identifier), - target = "2.dev", - version = "1.0.0", - visibility = ["//visibility:public"], - ), - daml_compile( - name = "upgrades-{}-v1".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/v1/*.daml".format(identifier)]), - data_dependencies = ["//test-common:upgrades-{}-dep.dar".format(identifier)], - dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], - enable_interfaces = True, - ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], - project_name = "upgrades-example-{}".format(identifier), - target = "2.dev", - version = "1.0.0", - visibility = ["//visibility:public"], - ), - daml_compile( - name = "upgrades-{}-v2".format(identifier), - srcs = glob(["src/main/daml/upgrades/{}/v2/*.daml".format(identifier)]), - data_dependencies = ["//test-common:upgrades-{}-dep.dar".format(identifier)], - dependencies = ["//daml-script/daml:daml-script-2.dev.dar"], - enable_interfaces = True, - ghc_options = default_damlc_opts + ["--ghc-option=-Wno-unused-imports"], - project_name = "upgrades-example-{}".format(identifier), - target = "2.dev", - # We want to check the validity of this upgrade on the ledger - # client, not during compilation - typecheck_upgrades = False, - upgrades = "//test-common:upgrades-{}-v1.dar".format(identifier), - version = "2.0.0", - visibility = ["//visibility:public"], - ), - ] - for identifier in [ - # More more more tests ported from DamlcUpgrades.hs - "FailsWhenAnInstanceIsDropped", - "SucceedsWhenAnInstanceIsAddedSeparateDep", - ] -] - [ [ filegroup( diff --git a/sdk/test-common/src/main/daml/upgrades/EmptyProject/Main.daml b/sdk/test-common/src/main/daml/upgrades/EmptyProject/Main.daml new file mode 100644 index 000000000000..0d9fabaee1a3 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/EmptyProject/Main.daml @@ -0,0 +1,7 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +-- This module is deliberately empty. +-- The only purpose of this package is to depend on the standard library. diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v1/Main.daml index e4305a3f69c4..ab9be080a584 100644 --- a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v1/Main.daml +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v1/Main.daml @@ -2,11 +2,14 @@ -- SPDX-License-Identifier: Apache-2.0 module Main where + +data T = T with + i : Int + template A with p : Party q : Party where signatory p - key (p, "text") : (Party, Text) + key (p, T 0) : (Party, T) maintainer (fst key) - diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v2/Main.daml index 0aebd3329f2c..c9bdb424afd3 100644 --- a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v2/Main.daml +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyType/v2/Main.daml @@ -2,11 +2,16 @@ -- SPDX-License-Identifier: Apache-2.0 module Main where + +data T = T with + i : Int + j : Optional Int + template A with p : Party q : Party where signatory p - key (p, 1) : (Party, Int) + key (p, T 0 None) : (Party, T) maintainer (fst key) diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v1/Main.daml new file mode 100644 index 000000000000..8494506284c5 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v1/Main.daml @@ -0,0 +1,12 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +template A with + p : Party + q : Party + where + signatory p + key (p, 1) : (Party, Int) + maintainer (fst key) diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v2/Main.daml new file mode 100644 index 000000000000..16c09cdf9730 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenTemplateChangesKeyTypeSuperficially/v2/Main.daml @@ -0,0 +1,13 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +template A with + p : Party + q : Party + where + signatory p + key (p, "text") : (Party, Text) + maintainer (fst key) + diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/dep/Dep.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/dep/Dep.daml new file mode 100644 index 000000000000..955a7e3dc06f --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/dep/Dep.daml @@ -0,0 +1,6 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Dep where + +data T = MkT diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v1/Main.daml new file mode 100644 index 000000000000..a18a9b6d518e --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v1/Main.daml @@ -0,0 +1,9 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +import qualified Dep + +data A = A { x : Dep.T } + diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v2/Main.daml new file mode 100644 index 000000000000..7c9c9b0aa747 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldFromDifferentPackageName/v2/Main.daml @@ -0,0 +1,10 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +import qualified Dep + +-- This definition is identical to v1:A, but "Dep" is from package with a +-- different name that the one imported by v1:Main. +data A = A { x : Dep.T } diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v1/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v1/ProjectMain.daml new file mode 100644 index 000000000000..cbd87257e909 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v1/ProjectMain.daml @@ -0,0 +1,10 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +-- Imported from SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd v2 +import qualified Main + +data T = T { x: Main.A } + diff --git a/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v2/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v2/ProjectMain.daml new file mode 100644 index 000000000000..76445ba6ebda --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/FailsWhenUpgradedFieldPackagesAreNotUpgradable/v2/ProjectMain.daml @@ -0,0 +1,16 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +-- Imported from SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd v1 +import qualified Main + +-- This Main.A refers to SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd-v1.Main.A, +-- while the T.x field in v1 of this package refers to +-- SucceedsWhenATopLevelRecordAddsAnOptionalFieldAtTheEnd-v2.Main.A. +-- Thus in both versions 1 and 2 of this package, the T.x field have types that: +-- - have the same package name, +-- - have the same qualified name, +-- - and come from two packages that are in an upgrade relationship, but in the wrong order +data T = T { x: Main.A } diff --git a/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Main.daml index 5f88aa189e2b..a6f9529da91b 100644 --- a/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Main.daml +++ b/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Main.daml @@ -4,3 +4,8 @@ module Main where import qualified Other + +useOther : Other.Dummy -> () +useOther _ = () + +data Dummy = Dummy {} diff --git a/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Other.daml b/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Other.daml index f4fa58717388..b92b6a719573 100644 --- a/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Other.daml +++ b/sdk/test-common/src/main/daml/upgrades/MissingModule/v1/Other.daml @@ -2,3 +2,5 @@ -- SPDX-License-Identifier: Apache-2.0 module Other where + +data Dummy = Dummy {} diff --git a/sdk/test-common/src/main/daml/upgrades/MissingModule/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/MissingModule/v2/Main.daml index a7636046e676..2c8a5b33f71c 100644 --- a/sdk/test-common/src/main/daml/upgrades/MissingModule/v2/Main.daml +++ b/sdk/test-common/src/main/daml/upgrades/MissingModule/v2/Main.daml @@ -2,3 +2,5 @@ -- SPDX-License-Identifier: Apache-2.0 module Main where + +data Dummy = Dummy {} diff --git a/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v1/Main.daml new file mode 100644 index 000000000000..9ddfda10fce5 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v1/Main.daml @@ -0,0 +1,9 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +-- v1:A is not serializable and should not be compared to v2:A +data A = A { f : Int -> Int } + +data Dummy = Dummy {} diff --git a/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v2/Main.daml new file mode 100644 index 000000000000..45cda587b64c --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/SucceedsWhenNonSerializableTypesAreIncompatible/v2/Main.daml @@ -0,0 +1,9 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +-- v2:A is serializable, but v1:A is not and thus they should not be compared +data A = A { x : Int } + +data Dummy = Dummy {} diff --git a/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v1/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v1/ProjectMain.daml new file mode 100644 index 000000000000..b4d5ff6edd78 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v1/ProjectMain.daml @@ -0,0 +1,12 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +import qualified Main + +template Foo with + p: Party + dep: ContractId Main.A + where + signatory p diff --git a/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v2/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v2/ProjectMain.daml new file mode 100644 index 000000000000..b4d5ff6edd78 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadFailsWhenDepsAreInvalidUpgrades/v2/ProjectMain.daml @@ -0,0 +1,12 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +import qualified Main + +template Foo with + p: Party + dep: ContractId Main.A + where + signatory p diff --git a/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v1/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v1/ProjectMain.daml new file mode 100644 index 000000000000..b5c9016e41a4 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v1/ProjectMain.daml @@ -0,0 +1,12 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +import qualified Main + +template Foo with + p: Party + dep: ContractId Main.T + where + signatory p diff --git a/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v2/ProjectMain.daml b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v2/ProjectMain.daml new file mode 100644 index 000000000000..b5c9016e41a4 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgrades/v2/ProjectMain.daml @@ -0,0 +1,12 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module ProjectMain where + +import qualified Main + +template Foo with + p: Party + dep: ContractId Main.T + where + signatory p diff --git a/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v1/Main.daml new file mode 100644 index 000000000000..d4beca6008a6 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v1/Main.daml @@ -0,0 +1,15 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +data TKey1 = TKey1 { p : Party } + +template T with + p: Party + where + signatory p + key (TKey1 p) : TKey1 + maintainer key.p + +data D = D { t : Text } diff --git a/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v2/Main.daml new file mode 100644 index 000000000000..fdb078a9218c --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/UploadSucceedsWhenDepsAreValidUpgradesDep/v2/Main.daml @@ -0,0 +1,30 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +module Main where + +data TKey1 = TKey1 with + p : Party + +template T with + p: Party + where + signatory p + key (TKey1 p) : TKey1 + maintainer key.p + +data TKey2 = TKey2 with + p : Party + +template U with + p: Party + where + signatory p + key (TKey2 p) : TKey2 + maintainer key.p + +data D = D with + t : Text + u : Optional Text +data E = E with + t : Text diff --git a/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v1/Main.daml new file mode 100644 index 000000000000..a40a061da9e3 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v1/Main.daml @@ -0,0 +1,17 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +-- CoTyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- STDX-License-Identifier: ATache-2.0 + +module Main where + +data TKey a = TKey { p : Party, q : NonUniform a } +data NonUniform a = Nil | NonUniform (TKey (a, a)) + +template T with + p: Party + where + signatory p + key (TKey p Nil) : TKey Int + maintainer key.p diff --git a/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v2/Main.daml new file mode 100644 index 000000000000..85b2c3e5c4ab --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/ValidKeyTypeEquality/v2/Main.daml @@ -0,0 +1,19 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +-- CoTyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- STDX-License-Identifier: ATache-2.0 + +module Main where + +-- alpha-equivalent to v1 after synonym normalization +data TKey b = TKey { p : Party, q : NonUniformSyn b } +type NonUniformSyn c = NonUniform c +data NonUniform d = Nil | NonUniform (TKey (d, d)) + +template T with + p: Party + where + signatory p + key (TKey p Nil) : TKey Int + maintainer key.p diff --git a/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v1/Main.daml b/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v1/Main.daml new file mode 100644 index 000000000000..f1d8f466ae21 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v1/Main.daml @@ -0,0 +1,15 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +-- CoTyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- STDX-License-Identifier: ATache-2.0 + +module Main where + +data T1 a = T1 { x : a } + +data T2 a b = C1 a | C2 b + +-- A mutually polymorphic recursive data type +data T3 a = T3 (T4 a) +data T4 a = T4 (T3 (a, a)) diff --git a/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v2/Main.daml b/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v2/Main.daml new file mode 100644 index 000000000000..6add64054f36 --- /dev/null +++ b/sdk/test-common/src/main/daml/upgrades/ValidParameterizedTypesUpgrade/v2/Main.daml @@ -0,0 +1,17 @@ +-- Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- SPDX-License-Identifier: Apache-2.0 + +-- CoTyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. +-- STDX-License-Identifier: ATache-2.0 + +module Main where + +-- Alpha-equivalent to v1 + a new optional field +data T1 c = T1 { x : c, y : Optional c } + +-- Alpha-equivalent to v1 + a new variant +data T2 c d = C1 c | C2 d | C3 (c, d) + +-- Alpha-equivalent to v1 +data T3 b = T3 (T4 b) +data T4 c = T4 (T3 (c, c))