LF: Simplify Language Version representation (#8258)

We drop the distinction (at the type level) of Dev and Stable language
version.  The two main reason that motivate this choice:
* we never really used this distinction.
* we want to add the concept of "preview" version (which is neither Dev nor Stable)

CHANGELOG_BEGIN
CHANGELOG_END
This commit is contained in:
Remy 2020-12-11 16:21:45 +01:00 committed by GitHub
parent 7dbb3a60ca
commit 009b030463
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 59 additions and 135 deletions

View File

@ -209,9 +209,7 @@ class ReplService(
override def runScript(
req: RunScriptRequest,
respObs: StreamObserver[RunScriptResponse]): Unit = {
val lfVer = LanguageVersion(
LanguageVersion.Major.V1,
LanguageVersion.Minor fromProtoIdentifier req.getMinor)
val lfVer = LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor(req.getMinor))
val dop: Decode.OfPackage[_] = Decode.decoders
.lift(lfVer)
.getOrElse(throw new RuntimeException(s"No decode support for LF ${lfVer.pretty}"))

View File

@ -226,7 +226,7 @@ class ScenarioService(
): Unit = {
val lfVersion = LanguageVersion(
LanguageVersion.Major.V1,
LanguageVersion.Minor.fromProtoIdentifier(req.getLfMinor)
LanguageVersion.Minor(req.getLfMinor)
)
val ctx = Context.newContext(lfVersion)
contexts += (ctx.contextId -> ctx)

View File

@ -77,10 +77,13 @@ abstract class Reader[+Pkg] {
val majorVersion = readArchiveVersion(lf)
val minorVersion = lf.getMinor
val version =
LanguageVersion(majorVersion, LanguageVersion.Minor fromProtoIdentifier minorVersion)
LanguageVersion(majorVersion, LanguageVersion.Minor(minorVersion))
if (!(majorVersion supportsMinorVersion minorVersion)) {
val supportedVersions =
majorVersion.acceptedVersions.map(v => s"$majorVersion.${v.identifier}")
throw ParseError(
s"LF file $majorVersion.$minorVersion unsupported; maximum supported $majorVersion.x is $majorVersion.${majorVersion.maxSupportedStableMinorVersion.toProtoIdentifier: String}")
s"LF $majorVersion.$minorVersion unsupported. Supported LF versions are ${supportedVersions
.mkString(",")}")
}
(readArchivePayloadOfVersion(hash, lf, version), majorVersion)
}

View File

@ -10,8 +10,7 @@ import com.daml.bazeltools.BazelRunfiles._
import com.daml.lf.archive.Reader.ParseError
import com.daml.lf.data.{Decimal, Numeric, Ref}
import com.daml.lf.language.Util._
import com.daml.lf.language.{Ast, LanguageMinorVersion, LanguageVersion => LV}
import LanguageMinorVersion.Implicits._
import com.daml.lf.language.{Ast, LanguageVersion => LV}
import com.daml.lf.data.ImmArray.ImmArraySeq
import com.daml.lf.data.Ref.DottedName
import com.daml.daml_lf_dev.DamlLf1
@ -59,8 +58,7 @@ class DecodeV1Spec
import VersionTimeline.Implicits._
private[this] val lfVersions =
List(LV.Minor.Stable("6"), LV.Minor.Stable("7"), LV.Minor.Stable("8"), LV.Minor.Dev)
.map(LV(LV.Major.V1, _))
List("6", "7", "8", "dev").map(minor => LV(LV.Major.V1, LV.Minor(minor)))
private[this] def forEveryVersionSuchThat[U](cond: LV => Boolean)(f: LV => U): Unit =
lfVersions.foreach { version =>
@ -350,7 +348,7 @@ class DecodeV1Spec
.setPrimLit(DamlLf1.PrimLit.newBuilder().setNumericInternedStr(id))
.build()
val decimalBuiltinTestCases = Table[DamlLf1.BuiltinFunction, LanguageMinorVersion, Ast.Expr](
val decimalBuiltinTestCases = Table[DamlLf1.BuiltinFunction, String, Ast.Expr](
("decimal builtins", "minVersion", "expected output"),
(
DamlLf1.BuiltinFunction.ADD_DECIMAL,
@ -492,8 +490,8 @@ class DecodeV1Spec
forEveryVersionBefore(LV.Features.numeric) { version =>
val decoder = moduleDecoder(version)
forEvery(decimalBuiltinTestCases) { (proto, version, scala) =>
if (LV.Major.V1.minorVersionOrdering.gteq(version, version))
forEvery(decimalBuiltinTestCases) { (proto, versionId, scala) =>
if (LV.Major.V1.minorVersionOrdering.gteq(LV.Minor(versionId), version.minor))
decoder.decodeExpr(toProtoExpr(proto), "test") shouldBe scala
}
}
@ -523,7 +521,7 @@ class DecodeV1Spec
"translate numeric comparison builtins as is if version >= 1.7" in {
val v1_7 = LV.Minor.Stable("7")
val v1_7 = LV.Minor("7")
forEveryVersionSuchThat(version =>
!(version precedes LV.Features.numeric) & (version precedes LV.Features.genComparison)) {
@ -766,7 +764,7 @@ class DecodeV1Spec
}
"decode resolving the interned package ID" in {
val decoder = Decode.decoders(LV(majorVersion, dalfProto.getMinor))
val decoder = Decode.decoders(LV(majorVersion, LV.Minor(dalfProto.getMinor)))
inside(
decoder.decoder
.decodePackage(pkgId, decoder.extract(dalfProto))

View File

@ -135,7 +135,7 @@ private[daml] object DamlLfEncoder extends App {
version.split("""\.""").toSeq match {
case Seq("1", minor)
if LanguageMajorVersion.V1.supportsMinorVersion(minor) || minor == "dev" =>
LanguageVersion(LanguageMajorVersion.V1, minor)
LanguageVersion(LanguageMajorVersion.V1, LanguageVersion.Minor(minor))
case _ =>
error(s"version '$version' not supported")
}

View File

@ -10,7 +10,7 @@ import com.daml.lf.language.Ast._
import com.daml.lf.language.LanguageMajorVersion.V1
import com.daml.lf.language.{Ast, LanguageVersion}
import com.daml.lf.testing.parser.Implicits.SyntaxHelper
import com.daml.lf.testing.parser.{AstRewriter, ParserParameters, parseModules}
import com.daml.lf.testing.parser.{AstRewriter, ParserParameters}
import com.daml.lf.validation.Validation
import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.matchers.should.Matchers
@ -25,7 +25,7 @@ class EncodeV1Spec extends AnyWordSpec with Matchers with TableDrivenPropertyChe
val defaultParserParameters: ParserParameters[this.type] =
ParserParameters(
pkgId,
LanguageVersion(V1, "8")
LanguageVersion(V1, LanguageVersion.Minor("8"))
)
"Encode and Decode" should {
@ -143,44 +143,6 @@ class EncodeV1Spec extends AnyWordSpec with Matchers with TableDrivenPropertyChe
val pkg1 = normalize(decodedPackage, hashCode, pkgId)
pkg shouldBe pkg1
}
"Encoding of function type with different versions should work as expected" in {
val text =
"""
module Mod{
val f : forall (a:*) (b: *) (c: *). a -> b -> c -> Unit =
/\ (a:*) (b: *) (c: *). \ (xa: a) (xb: b) (xc: c) -> ();
}
"""
val versions =
Table(
"minVersion",
LanguageVersion(V1, "6"),
LanguageVersion(V1, "7"),
LanguageVersion(V1, "8"),
LanguageVersion.default)
forEvery(versions) { version =>
implicit val parserParameters: ParserParameters[version.type] =
ParserParameters(pkgId, version)
val metadata =
if (LanguageVersion.ordering.gteq(version, LanguageVersion.Features.packageMetadata)) {
Some(
PackageMetadata(
PackageName.assertFromString("encodespec"),
PackageVersion.assertFromString("1.0.0")))
} else None
val pkg = Package(parseModules(text).right.get, Set.empty, version, metadata)
val archive = Encode.encodeArchive(pkgId -> pkg, version)
val ((hashCode @ _, decodedPackage: Package), _) = Decode.readArchiveAndVersion(archive)
pkg shouldBe normalize(decodedPackage, hashCode, pkgId)
}
}
}
}

View File

@ -6,8 +6,6 @@ package engine
import java.nio.file.Path
import com.daml.lf.language.LanguageVersion
/**
* The Engine configurations describes the versions of language and
* transaction the engine is allowed to read and write together with
@ -65,10 +63,7 @@ object EngineConfig {
)
private[this] def toDev(config: EngineConfig): EngineConfig =
config.copy(
allowedLanguageVersions = config.allowedLanguageVersions.copy(
max = LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor.Dev)),
)
config.copy(allowedLanguageVersions = transaction.VersionTimeline.devLanguageVersions)
/**
* Recommended production configuration.

View File

@ -1955,17 +1955,17 @@ class EngineTest
"reject disallow packages" in {
val negativeTestCases = Table(
("pkg version", "minVersion", "maxVertion"),
(LV.Minor.Stable("6"), LV.Minor.Stable("6"), LV.Minor.Stable("8")),
(LV.Minor.Stable("7"), LV.Minor.Stable("6"), LV.Minor.Stable("8")),
(LV.Minor.Stable("8"), LV.Minor.Stable("6"), LV.Minor.Stable("8")),
(LV.Minor.Dev, LV.Minor.Stable("6"), LV.Minor.Dev),
(LV.Minor("6"), LV.Minor("6"), LV.Minor("8")),
(LV.Minor("7"), LV.Minor("6"), LV.Minor("8")),
(LV.Minor("8"), LV.Minor("6"), LV.Minor("8")),
(LV.Minor("dev"), LV.Minor("6"), LV.Minor("dev")),
)
val positiveTestCases = Table(
("pkg version", "minVersion", "maxVertion"),
(LV.Minor.Stable("6"), LV.Minor.Stable("7"), LV.Minor.Dev),
(LV.Minor.Stable("7"), LV.Minor.Stable("8"), LV.Minor.Stable("8")),
(LV.Minor.Stable("8"), LV.Minor.Stable("6"), LV.Minor.Stable("7")),
(LV.Minor.Dev, LV.Minor.Stable("6"), LV.Minor.Stable("8")),
(LV.Minor("6"), LV.Minor("7"), LV.Minor("dev")),
(LV.Minor("7"), LV.Minor("8"), LV.Minor("8")),
(LV.Minor("8"), LV.Minor("6"), LV.Minor("7")),
(LV.Minor("dev"), LV.Minor("6"), LV.Minor("8")),
)
forEvery(negativeTestCases)((v, min, max) =>

View File

@ -8,18 +8,12 @@ import com.daml.lf.LfVersions
import scalaz.NonEmptyList
// an ADT version of the DAML-LF version
sealed abstract class LanguageMajorVersion(
val pretty: String,
stableAscending: NonEmptyList[String])
extends LfVersions(
stableAscending.map[LanguageMinorVersion](LanguageMinorVersion.Stable) append NonEmptyList(
LanguageMinorVersion.Dev))(_.toProtoIdentifier)
sealed abstract class LanguageMajorVersion(val pretty: String, minorAscending: NonEmptyList[String])
extends LfVersions(minorAscending.map[LanguageMinorVersion](LanguageMinorVersion))(
_.toProtoIdentifier)
with Product
with Serializable {
final val maxSupportedStableMinorVersion: LanguageMinorVersion.Stable =
LanguageMinorVersion.Stable(stableAscending.last)
// do *not* use implicitly unless type `LanguageMinorVersion` becomes
// indexed by the enclosing major version's singleton type --SC
final val minorVersionOrdering: Ordering[LanguageMinorVersion] =
@ -35,7 +29,9 @@ sealed abstract class LanguageMajorVersion(
object LanguageMajorVersion {
case object V1
extends LanguageMajorVersion(pretty = "1", stableAscending = NonEmptyList("6", "7", "8"))
extends LanguageMajorVersion(
pretty = "1",
minorAscending = NonEmptyList("6", "7", "8", "dev"))
val All: List[LanguageMajorVersion] = List(V1)

View File

@ -3,27 +3,6 @@
package com.daml.lf.language
sealed abstract class LanguageMinorVersion extends Product with Serializable {
import LanguageMinorVersion._
def toProtoIdentifier: String = this match {
case Stable(id) => id
case Dev => "dev"
}
}
object LanguageMinorVersion {
final case class Stable(identifier: String) extends LanguageMinorVersion
case object Dev extends LanguageMinorVersion
def fromProtoIdentifier(identifier: String): LanguageMinorVersion = identifier match {
case "dev" => Dev
case _ => Stable(identifier)
}
object Implicits {
import scala.language.implicitConversions
implicit def `LMV from proto identifier`(identifier: String): LanguageMinorVersion =
fromProtoIdentifier(identifier)
}
final case class LanguageMinorVersion(identifier: String) {
def toProtoIdentifier: String = identifier
}

View File

@ -15,14 +15,9 @@ object LanguageVersion {
type Minor = LanguageMinorVersion
val Minor = LanguageMinorVersion
val defaultV1: LanguageVersion =
LanguageVersion(Major.V1, Major.V1.maxSupportedStableMinorVersion)
val defaultV1: LanguageVersion = LanguageVersion(Major.V1, Minor("8"))
private[lf] def apply(major: LanguageMajorVersion, minor: String): LanguageVersion =
apply(major, Minor fromProtoIdentifier minor)
val default: LanguageVersion =
defaultV1
val default: LanguageVersion = defaultV1
final val ordering: Ordering[LanguageVersion] =
(left, right) =>

View File

@ -3,7 +3,7 @@
package com.daml.lf.language
import com.daml.lf.language.{LanguageMajorVersion => LVM, LanguageVersion => LV}
import com.daml.lf.language.{LanguageVersion => LV}
import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
@ -13,9 +13,9 @@ class LanguageVersionSpec extends AnyWordSpec with Matchers with TableDrivenProp
"LanguageVersion.ordering order as expected" in {
val versionInOrder = List(
LV(LVM.V1, "6"),
LV(LVM.V1, "7"),
LV(LVM.V1, "8"),
LV(LV.Major.V1, LV.Minor("6")),
LV(LV.Major.V1, LV.Minor("7")),
LV(LV.Major.V1, LV.Minor("8")),
)
val versionRank = versionInOrder.zipWithIndex.toMap

View File

@ -196,7 +196,7 @@ object Repl {
private val seed = nextSeed()
val (inputValueVersion, outputTransactionVersions) =
if (compilerConfig.allowedLanguageVersions.contains(LV(LV.Major.V1, LV.Minor.Dev)))
if (compilerConfig.allowedLanguageVersions.contains(LV(LV.Major.V1, LV.Minor("dev"))))
(
value.ValueVersions.DevOutputVersions,
transaction.TransactionVersions.DevOutputVersions,

View File

@ -4,7 +4,7 @@
package com.daml.lf
package transaction
import com.daml.lf.language.{LanguageVersion, LanguageMajorVersion => LMV}
import com.daml.lf.language.LanguageVersion
import com.daml.lf.value.ValueVersion
import scalaz.std.map._
import scalaz.syntax.foldable1._
@ -31,7 +31,7 @@ import scala.language.higherKinds
* that same timeline.
*/
object VersionTimeline {
import LanguageVersion.Minor.Dev
import LanguageVersion.{Major, Minor}
import \&/.{Both, That, This}
type AllVersions[:&:[_, _]] = (ValueVersion :&: TransactionVersion) :&: LanguageVersion
@ -43,12 +43,14 @@ object VersionTimeline {
*/
private[lf] val inAscendingOrder: NonEmptyList[Release] =
NonEmptyList(
That(LanguageVersion(LMV.V1, "6")),
Both(This(ValueVersion("6")), LanguageVersion(LMV.V1, "7")),
That(LanguageVersion(LMV.V1, "8")),
That(LanguageVersion(Major.V1, Minor("6"))),
Both(This(ValueVersion("6")), LanguageVersion(Major.V1, Minor("7"))),
That(LanguageVersion(Major.V1, Minor("8"))),
This(That(TransactionVersion("10"))),
// add new versions above this line (but see more notes below)
Both(Both(ValueVersion("dev"), TransactionVersion("dev")), LanguageVersion(LMV.V1, Dev)),
Both(
Both(ValueVersion("dev"), TransactionVersion("dev")),
LanguageVersion(Major.V1, Minor("dev"))),
//
// "dev" versions float through the timeline with little rationale
// due to their ephemeral contents; don't worry too much about their exact
@ -167,11 +169,11 @@ object VersionTimeline {
private[lf] val stableLanguageVersions =
VersionRange(
min = LanguageVersion(LMV.V1, "6"),
max = LanguageVersion(LMV.V1, "8"),
min = LanguageVersion(Major.V1, Minor("6")),
max = LanguageVersion(Major.V1, Minor("8")),
)
private[lf] val devLanguageVersions =
stableLanguageVersions.copy(max = LanguageVersion(LMV.V1, Dev))
stableLanguageVersions.copy(max = LanguageVersion(Major.V1, Minor("dev")))
}

View File

@ -14,11 +14,8 @@ class TransactionVersionSpec extends AnyWordSpec with Matchers with TableDrivenP
"TransactionVersions.assignNodeVersion" should {
val Seq(v1_6, v1_7, v1_8) = Seq("6", "7", "8").map(minor =>
LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor.Stable(minor)))
val v1_dev =
LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor.Dev)
val Seq(v1_6, v1_7, v1_8, v1_dev) = Seq("6", "7", "8", "dev").map(minor =>
LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor(minor)))
val testCases = Table(
"language version" -> "transaction version",

View File

@ -4,7 +4,6 @@
package com.daml.lf
package transaction
import com.daml.lf.language.LanguageMinorVersion.Dev
import com.daml.lf.language._
import value.{ValueVersion, ValueVersions}
@ -74,7 +73,7 @@ class VersionTimelineSpec
inside(inAscendingOrder.last) {
case Both(
Both(ValueVersion("dev"), TransactionVersion("dev")),
LanguageVersion(LanguageVersion.Major.V1, Dev)) =>
LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor("dev"))) =>
}
}
@ -90,7 +89,7 @@ class VersionTimelineSpec
"given a dev version" should {
"never precede another version of same major" in forAll(genDefinedLanguageVersion) { lv =>
compareReleaseTime(lv, lv copy (minor = LanguageVersion.Minor.Dev)) should contain oneOf (LT, EQ)
compareReleaseTime(lv, lv copy (minor = LanguageVersion.Minor("dev"))) should contain oneOf (LT, EQ)
}
}
}

View File

@ -13,9 +13,9 @@ import org.scalatest.wordspec.AnyWordSpec
class DependencyVersionSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
private[this] val v1_6 = LV(LV.Major.V1, LV.Minor.Stable("6"))
private[this] val v1_7 = LV(LV.Major.V1, LV.Minor.Stable("7"))
private[this] val v1_8 = LV(LV.Major.V1, LV.Minor.Stable("8"))
private[this] val v1_6 = LV(LV.Major.V1, LV.Minor("6"))
private[this] val v1_7 = LV(LV.Major.V1, LV.Minor("7"))
private[this] val v1_8 = LV(LV.Major.V1, LV.Minor("8"))
private[this] val A = (PackageId.assertFromString("-pkg1-"), DottedName.assertFromString("A"))
private[this] val B = (PackageId.assertFromString("-pkg2-"), DottedName.assertFromString("B"))
private[this] val E = (PackageId.assertFromString("-pkg3-"), DottedName.assertFromString("E"))