LF: move language version from modules to packages (#7064)

CHANGELOG_BEGIN
CHANGELOG_END
This commit is contained in:
Remy 2020-08-10 11:26:58 +02:00 committed by GitHub
parent 015b3b6534
commit 17926c5a8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 118 additions and 174 deletions

View File

@ -202,7 +202,7 @@ class ReplService(
// For now we only include the module of the current line
// we probably need to extend this to merge the
// modules from each line.
val pkg = Package(Seq(mod), Seq(), None)
val pkg = Package(Seq(mod), Seq(), lfVer, None)
// TODO[AH] Provide daml-script package id from REPL client.
val (scriptPackageId, _) = packages.find {
case (_, pkg) => pkg.modules.contains(DottedName.assertFromString("Daml.Script"))

View File

@ -148,7 +148,7 @@ class Context(val contextId: Context.ContextId, languageVersion: LanguageVersion
}
def allPackages: Map[PackageId, Ast.Package] = synchronized {
extPackages + (homePackageId -> Ast.Package(modules, extPackages.keySet, None))
extPackages + (homePackageId -> Ast.Package(modules, extPackages.keySet, languageVersion, None))
}
// We use a fix Hash and fix time to seed the contract id, so we get reproducible run.

View File

@ -62,6 +62,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
_,
onlySerializableDataDefs).decode),
directDeps = dependencyTracker.getDependencies,
languageVersion = languageVersion,
metadata = metadata,
)
@ -238,7 +239,7 @@ private[archive] class DecodeV1(minor: LV.Minor) extends Decode.OfPackage[PLF.Pa
templates += ((defName, decodeTemplate(defn)))
}
Module(moduleName, defs, templates, languageVersion, decodeFeatureFlags(lfModule.getFlags))
Module(moduleName, defs, templates, decodeFeatureFlags(lfModule.getFlags))
}
// -----------------------------------------------------------------------

View File

@ -66,7 +66,11 @@ private[daml] object DamlLfEncoder extends App {
Ref.PackageVersion.assertFromString("1.0.0")))
} else None
val pkgs = Map(pkgId -> Ast.Package(modules, Set.empty[Ref.PackageId], metadata))
val pkgs =
Map(
pkgId ->
Ast.Package(modules, Set.empty[Ref.PackageId], parserParameters.languageVersion, metadata)
)
Validation.checkPackage(pkgs, pkgId).left.foreach(e => error(e.pretty))

View File

@ -173,7 +173,7 @@ class EncodeV1Spec extends WordSpec with Matchers with TableDrivenPropertyChecks
PackageName.assertFromString("encodespec"),
PackageVersion.assertFromString("1.0.0")))
} else None
val pkg = Package(parseModules(text).right.get, Set.empty, metadata)
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)

View File

@ -9,8 +9,6 @@ import java.util.concurrent.ConcurrentHashMap
import com.daml.lf.data.Ref.PackageId
import com.daml.lf.engine.ConcurrentCompiledPackages.AddPackageState
import com.daml.lf.language.Ast.Package
import com.daml.lf.language.LanguageVersion
import com.daml.lf.speedy
import com.daml.lf.speedy.Compiler
import scala.collection.JavaConverters._
@ -28,16 +26,11 @@ final class ConcurrentCompiledPackages extends MutableCompiledPackages {
new ConcurrentHashMap()
private[this] var _profilingMode: speedy.Compiler.ProfilingMode = speedy.Compiler.NoProfile
private[this] var _stackTraceMode: speedy.Compiler.StackTraceMode = speedy.Compiler.FullStackTrace
private[this] val _packagesLanguageVersions: ConcurrentMap[PackageId, LanguageVersion] =
new ConcurrentHashMap().asScala
override def getPackage(pId: PackageId): Option[Package] = _packages.get(pId)
override def getDefinition(dref: speedy.SExpr.SDefinitionRef): Option[speedy.SExpr] =
Option(_defns.get(dref))
override def packageLanguageVersion: PartialFunction[PackageId, LanguageVersion] =
_packagesLanguageVersions
override def profilingMode: Compiler.ProfilingMode = _profilingMode
def profilingMode_=(profilingMode: speedy.Compiler.ProfilingMode) = {
@ -121,14 +114,6 @@ final class ConcurrentCompiledPackages extends MutableCompiledPackages {
pkgId,
pkg
)
// update the packageMaxLanguageVersions
// If the package is empty, no update
pkg.modules.values.headOption
.foreach(
mod =>
// all modules of a package are compiled to the same LF version
_packagesLanguageVersions.update(pkgId, mod.languageVersion))
}
}
}

View File

@ -9,7 +9,7 @@ import com.daml.lf.data.ImmArray
import com.daml.lf.data.ImmArray.ImmArraySeq
import com.daml.lf.data.Ref
import com.daml.lf.data.Ref.{DottedName, QualifiedName}
import com.daml.lf.language.{Ast, LanguageVersion}
import com.daml.lf.language.Ast
import org.scalatest.{Inside, Matchers, WordSpec}
import scala.language.implicitConversions
@ -151,8 +151,8 @@ class InterfaceReaderSpec extends WordSpec with Matchers with Inside {
moduleName,
Map(dataName -> dfn),
Map.empty,
LanguageVersion.defaultV1,
Ast.FeatureFlags.default)
Ast.FeatureFlags.default,
)
private def dottedName(segments: Iterable[String]): DottedName =
DottedName.assertFromSegments(segments)

View File

@ -21,7 +21,8 @@ abstract class CompiledPackages {
def definitions: PartialFunction[SDefinitionRef, SExpr] =
Function.unlift(this.getDefinition)
def packageLanguageVersion: PartialFunction[PackageId, LanguageVersion]
def packageLanguageVersion: PartialFunction[PackageId, LanguageVersion] =
packages andThen (_.languageVersion)
def stackTraceMode: Compiler.StackTraceMode
def profilingMode: Compiler.ProfilingMode
@ -40,13 +41,6 @@ final class PureCompiledPackages private (
override def getDefinition(dref: SDefinitionRef): Option[SExpr] = defns.get(dref)
override def stackTraceMode = stacktracing
override def profilingMode = profiling
override val packageLanguageVersion: Map[PackageId, LanguageVersion] =
packages.foldLeft(Map.empty[PackageId, LanguageVersion]) {
case (acc, (pkgId, pkg)) =>
// all modules of a package are compiled to the same LF version
pkg.modules.values.headOption.fold(acc)(mod => acc.updated(pkgId, mod.languageVersion))
}
}
object PureCompiledPackages {

View File

@ -197,11 +197,11 @@ class InterpreterTest extends WordSpec with Matchers with TableDrivenPropertyChe
DottedName.assertFromString("bar") ->
DValue(TBuiltin(BTBool), true, ETrue, false),
),
LanguageVersion.default,
FeatureFlags.default,
),
),
Set.empty[PackageId],
LanguageVersion.default,
None,
),
),
@ -214,11 +214,11 @@ class InterpreterTest extends WordSpec with Matchers with TableDrivenPropertyChe
Module(
modName,
Map.empty,
LanguageVersion.default,
FeatureFlags.default,
),
),
Set.empty[PackageId],
LanguageVersion.default,
None,
),
),

View File

@ -603,7 +603,6 @@ object Ast {
case class Module private (
name: ModuleName,
definitions: Map[DottedName, Definition],
languageVersion: LanguageVersion,
featureFlags: FeatureFlags
)
@ -615,16 +614,14 @@ object Ast {
def apply(
name: ModuleName,
definitions: Traversable[(DottedName, Definition)],
languageVersion: LanguageVersion,
featureFlags: FeatureFlags
): Module =
Module(name, definitions, List.empty, languageVersion, featureFlags)
Module(name, definitions, List.empty, featureFlags)
def apply(
name: ModuleName,
definitions: Traversable[(DottedName, Definition)],
templates: Traversable[(DottedName, Template)],
languageVersion: LanguageVersion,
featureFlags: FeatureFlags
): Module = {
@ -649,7 +646,7 @@ object Ast {
}
}
new Module(name, defsMap ++ updatedRecords, languageVersion, featureFlags)
new Module(name, defsMap ++ updatedRecords, featureFlags)
}
}
@ -658,7 +655,8 @@ object Ast {
case class Package(
modules: Map[ModuleName, Module],
directDeps: Set[PackageId],
metadata: Option[PackageMetadata]
languageVersion: LanguageVersion,
metadata: Option[PackageMetadata],
) {
def lookupIdentifier(identifier: QualifiedName): Either[String, Definition] = {
this.modules.get(identifier.module) match {
@ -681,12 +679,14 @@ object Ast {
def apply(
modules: Traversable[Module],
directDeps: Traversable[PackageId],
metadata: Option[PackageMetadata]): Package = {
languageVersion: LanguageVersion,
metadata: Option[PackageMetadata],
): Package = {
val modulesWithNames = modules.map(m => m.name -> m)
findDuplicate(modulesWithNames).foreach { modName =>
throw PackageError(s"Collision on module name ${modName.toString}")
}
Package(modulesWithNames.toMap, directDeps.toSet, metadata)
Package(modulesWithNames.toMap, directDeps.toSet, languageVersion, metadata)
}
}

View File

@ -20,17 +20,21 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
Package(
List(
Module(modName1, List.empty, List.empty, defaultVersion, FeatureFlags.default),
Module(modName2, List.empty, List.empty, defaultVersion, FeatureFlags.default)),
Module(modName1, List.empty, List.empty, FeatureFlags.default),
Module(modName2, List.empty, List.empty, FeatureFlags.default),
),
Set.empty,
defaultVersion,
None
)
a[PackageError] shouldBe thrownBy(
Package(
List(
Module(modName1, List.empty, List.empty, defaultVersion, FeatureFlags.default),
Module(modName1, List.empty, List.empty, defaultVersion, FeatureFlags.default)),
Module(modName1, List.empty, List.empty, FeatureFlags.default),
Module(modName1, List.empty, List.empty, FeatureFlags.default),
),
Set.empty,
defaultVersion,
None
))
@ -69,7 +73,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
defName("def4") -> valDef
),
templates = List.empty,
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
)
@ -83,7 +86,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
defName("def1") -> valDef
),
templates = List.empty,
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
))
@ -100,7 +102,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
templates = List(
defName("defName1") -> template,
),
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
)
@ -115,7 +116,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
defName("defName1") -> template,
defName("defName1") -> template,
),
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
))
}
@ -131,7 +131,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
templates = List(
defName("defName1") -> template,
),
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
)
@ -145,7 +144,6 @@ class AstSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
templates = List(
defName("defName3") -> template,
),
languageVersion = defaultVersion,
featureFlags = FeatureFlags.default,
))
}

View File

@ -18,31 +18,10 @@ private[daml] class AstRewriter(
import AstRewriter._
def apply(pkg: Package): Package =
Package(
ImmArray(pkg.modules)
.transform { (_, x) =>
apply(x)
}
.toSeq
.toMap,
Set.empty[PackageId],
pkg.metadata,
)
pkg.copy(modules = pkg.modules.transform((_, x) => apply(x)))
def apply(module: Module): Module =
module match {
case Module(name, definitions, languageVersion, featureFlags) =>
Module(
name,
ImmArray(definitions)
.transform { (_, x) =>
apply(x)
}
.toSeq
.toMap,
languageVersion,
featureFlags)
}
module.copy(definitions = module.definitions.transform((_, x) => apply(x)))
def apply(identifier: Identifier): Identifier =
if (identifierRule.isDefinedAt(identifier))

View File

@ -29,7 +29,7 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
lazy val pkg: Parser[Package] =
opt(metadata) ~ rep(mod) ^^ {
case metadata ~ modules => Package(modules, Set.empty, metadata)
case metadata ~ modules => Package(modules, Set.empty, parameters.languageVersion, metadata)
}
private lazy val metadata: Parser[PackageMetadata] =
@ -44,7 +44,7 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
val flags = FeatureFlags(
forbidPartyLiterals = modTag(noPartyLitsTag)
)
Module(modName, definitions, templates, parameters.languageVersion, flags)
Module(modName, definitions, templates, flags)
}
private lazy val definition: Parser[Def] =

View File

@ -414,7 +414,6 @@ class ParsersSpec extends WordSpec with TableDrivenPropertyChecks with Matchers
DottedName.assertFromSegments(ImmArray("Color").toSeq) -> enumDef
),
templates = List.empty,
languageVersion = defaultLanguageVersion,
featureFlags = FeatureFlags.default
)))
@ -435,13 +434,13 @@ class ParsersSpec extends WordSpec with TableDrivenPropertyChecks with Matchers
DValue(t"Int64 -> Int64", true, e"""\(x: Int64) -> ERROR @INT64 "not implemented"""", false)
parseModules(p) shouldBe Right(
List(Module(
name = modName,
definitions = List(DottedName.assertFromString("fact") -> valDef),
templates = List.empty,
languageVersion = defaultLanguageVersion,
featureFlags = FeatureFlags.default
)))
List(
Module(
name = modName,
definitions = List(DottedName.assertFromString("fact") -> valDef),
templates = List.empty,
featureFlags = FeatureFlags.default
)))
}
@ -503,13 +502,13 @@ class ParsersSpec extends WordSpec with TableDrivenPropertyChecks with Matchers
DataRecord(ImmArray(n"person" -> t"Party", n"name" -> t"Text"), Some(template))
)
parseModules(p) shouldBe Right(
List(Module(
name = modName,
definitions = List(DottedName.assertFromString("Person") -> recDef),
templates = List.empty,
languageVersion = defaultLanguageVersion,
featureFlags = FeatureFlags.default
)))
List(
Module(
name = modName,
definitions = List(DottedName.assertFromString("Person") -> recDef),
templates = List.empty,
featureFlags = FeatureFlags.default
)))
}
@ -548,13 +547,13 @@ class ParsersSpec extends WordSpec with TableDrivenPropertyChecks with Matchers
DataRecord(ImmArray.empty, Some(template))
)
parseModules(p) shouldBe Right(
List(Module(
name = modName,
definitions = List(DottedName.assertFromString("R") -> recDef),
templates = List.empty,
languageVersion = defaultLanguageVersion,
featureFlags = FeatureFlags.default
)))
List(
Module(
name = modName,
definitions = List(DottedName.assertFromString("R") -> recDef),
templates = List.empty,
featureFlags = FeatureFlags.default
)))
}
}

View File

@ -14,20 +14,15 @@ private[validation] object DependencyVersion {
import VersionTimeline.Implicits._
for {
pkgFirstModule <- pkg.modules.values.take(1)
// all modules of a package are compiled to the same LF version
pkgLangVersion = pkgFirstModule.languageVersion
depPkgId <- pkg.directDeps
depPkg = world.lookupPackage(NoContext, depPkgId)
depFirstModule <- depPkg.modules.values.take(1)
depLangVersion = depFirstModule.languageVersion
} if (pkgLangVersion precedes depLangVersion)
throw EModuleVersionDependencies(
pkgId,
pkgLangVersion,
depPkgId,
depLangVersion
)
if pkg.languageVersion precedes depPkg.languageVersion
} throw EModuleVersionDependencies(
pkgId,
pkg.languageVersion,
depPkgId,
depPkg.languageVersion
)
}
}

View File

@ -152,7 +152,7 @@ private[validation] object Serializability {
}
def checkModule(world: World, pkgId: PackageId, module: Module): Unit = {
val version = module.languageVersion
val version = world.lookupPackage(NoContext, pkgId).languageVersion
module.definitions.foreach {
case (defName, DDataType(serializable, params, dataCons)) =>
val tyCon = TTyCon(Identifier(pkgId, QualifiedName(module.name, defName)))

View File

@ -228,11 +228,12 @@ private[validation] object Typing {
case PCUnit => TUnit
}
def checkModule(world: World, pkgId: PackageId, mod: Module): Unit =
def checkModule(world: World, pkgId: PackageId, mod: Module): Unit = {
val languageVersion = world.lookupPackage(NoContext, pkgId).languageVersion
mod.definitions.foreach {
case (dfnName, DDataType(_, params, cons)) =>
val env =
Env(mod.languageVersion, world, ContextTemplate(pkgId, mod.name, dfnName), params.toMap)
Env(languageVersion, world, ContextTemplate(pkgId, mod.name, dfnName), params.toMap)
checkUniq[TypeVarName](params.keys, EDuplicateTypeParam(env.ctx, _))
def tyConName = TypeConName(pkgId, QualifiedName(mod.name, dfnName))
cons match {
@ -248,13 +249,14 @@ private[validation] object Typing {
env.checkEnumType(tyConName, params, values)
}
case (dfnName, dfn: DValue) =>
Env(mod.languageVersion, world, ContextDefValue(pkgId, mod.name, dfnName)).checkDValue(dfn)
Env(languageVersion, world, ContextDefValue(pkgId, mod.name, dfnName)).checkDValue(dfn)
case (dfnName, DTypeSyn(params, replacementTyp)) =>
val env =
Env(mod.languageVersion, world, ContextTemplate(pkgId, mod.name, dfnName), params.toMap)
Env(languageVersion, world, ContextTemplate(pkgId, mod.name, dfnName), params.toMap)
checkUniq[TypeVarName](params.keys, EDuplicateTypeParam(env.ctx, _))
env.checkType(replacementTyp, KStar)
}
}
case class Env(
languageVersion: LanguageVersion,

View File

@ -31,22 +31,23 @@ class DependencyVersionSpec extends WordSpec with TableDrivenPropertyChecks with
val mod = Module(
modName,
(
(u -> DValue(TUnit, true, EUnit, false)) +:
depRefs.map {
case (depPkgId, depModName) =>
depModName -> DValue(
TUnit,
true,
EVal(Identifier(depPkgId, QualifiedName(depModName, u))),
false)
}
),
langVersion,
(u -> DValue(TUnit, true, EUnit, false)) +:
depRefs.map {
case (depPkgId, depModName) =>
depModName -> DValue(
TUnit,
true,
EVal(Identifier(depPkgId, QualifiedName(depModName, u))),
false)
},
FeatureFlags.default
)
pkgId -> Package(Map(modName -> mod), depRefs.iterator.map(_._1).toSet - pkgId, None)
pkgId -> Package(
Map(modName -> mod),
depRefs.iterator.map(_._1).toSet - pkgId,
langVersion,
None)
}
val negativeTestCases = Table(

View File

@ -8,7 +8,6 @@ import com.daml.lf.language.Ast.Package
import com.daml.lf.language.{LanguageMajorVersion, LanguageVersion}
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.testing.parser.defaultPackageId
import com.daml.lf.validation.SpecUtil._
import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.{Matchers, WordSpec}
@ -296,7 +295,7 @@ class SerializabilitySpec extends WordSpec with TableDrivenPropertyChecks with M
)
forEvery(versions) { version =>
val pkg = pkg0.updateVersion(version)
val pkg = pkg0.copy(languageVersion = version)
forEvery(testCases) { (modName: String, shouldFail: LanguageVersion => Boolean) =>
if (shouldFail(version)) {
an[EExpectedSerializableType] shouldBe thrownBy(check(pkg, modName))

View File

@ -3,8 +3,7 @@
package com.daml.lf.validation
import com.daml.lf.language.Ast.{Expr, Kind, Package, Type}
import com.daml.lf.language.LanguageVersion
import com.daml.lf.language.Ast.{Expr, Kind, Type}
import com.daml.lf.testing.parser.Implicits._
import org.scalactic.Equality
@ -46,14 +45,4 @@ private[validation] object SpecUtil {
b.mkString
}
}
implicit class PackageOps(val pkg: Package) extends AnyVal {
def updateVersion(version: LanguageVersion) = {
val modMap = pkg.modules.map {
case (modName, mod) => modName -> mod.copy(languageVersion = version)
}
pkg.copy(modules = modMap)
}
}
}

View File

@ -7,7 +7,7 @@ import com.daml.lf.data.Ref.DottedName
import com.daml.lf.language.Ast._
import com.daml.lf.language.{LanguageMajorVersion => LVM, LanguageVersion => LV}
import com.daml.lf.testing.parser.Implicits._
import com.daml.lf.testing.parser.defaultPackageId
import com.daml.lf.testing.parser.{defaultPackageId, defaultLanguageVersion}
import com.daml.lf.validation.SpecUtil._
import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.{Matchers, WordSpec}
@ -644,8 +644,6 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
}
"""
val world = new World(Map(defaultPackageId -> pkg))
val typeMismatchCases = Table(
"moduleName",
"PositiveTestCase1",
@ -662,7 +660,7 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
)
def checkModule(pkg: Package, modName: String) = Typing.checkModule(
world,
new World(Map(defaultPackageId -> pkg)),
defaultPackageId,
pkg.modules(DottedName.assertFromString(modName))
)
@ -674,7 +672,7 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
forAll(kindMismatchCases)(module =>
an[EKindMismatch] shouldBe thrownBy(checkModule(pkg, module)))
an[EIllegalKeyExpression] shouldBe thrownBy(
checkModule(pkg.updateVersion(version1_3), "PositiveTestCase6"))
checkModule(pkg.copy(languageVersion = version1_3), "PositiveTestCase6"))
checkModule(pkg, "PositiveTestCase6")
an[EUnknownExprVar] shouldBe thrownBy(checkModule(pkg, "PositiveTestCase9"))
an[EExpectedTemplatableType] shouldBe thrownBy(checkModule(pkg, "PositiveTestCase10"))
@ -711,7 +709,7 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
val modName = DottedName.assertFromString("Mod")
forEvery(testCases) { (version: LV, rejected: Boolean) =>
val pkg = pkg0.updateVersion(version)
val pkg = pkg0.copy(languageVersion = version)
val mod = pkg.modules(modName)
val world = new World(Map(defaultPackageId -> pkg))
@ -755,7 +753,7 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
val modName = DottedName.assertFromString("Mod")
forEvery(testCases) { (version: LV, rejected: Boolean) =>
val pkg = pkg0.updateVersion(version)
val pkg = pkg0.copy(languageVersion = version)
val mod = pkg.modules(modName)
val world = new World(Map(defaultPackageId -> pkg))
@ -848,34 +846,34 @@ class TypingSpec extends WordSpec with TableDrivenPropertyChecks with Matchers {
}
"reject ill formed type synonym definitions" in {
val testCases = Table(
"module"
-> "reject",
//Good
m"""module Mod { synonym S = Int64 ; }""" -> false,
m"""module Mod { synonym S a = a ; }""" -> false,
m"""module Mod { synonym S a b = a ; }""" -> false,
m"""module Mod { synonym S (f: *) = f ; }""" -> false,
m"""module Mod { synonym S (f: * -> *) = f Int64; }""" -> false,
//Bad
m"""module Mod { synonym S = a ; }""" -> true,
m"""module Mod { synonym S a = b ; }""" -> true,
m"""module Mod { synonym S a a = a ; }""" -> true,
m"""module Mod { synonym S = List ; }""" -> true,
m"""module Mod { synonym S (f: * -> *) = f ; }""" -> true,
m"""module Mod { synonym S (f: *) = f Int64; }""" -> true,
def checkModule(mod: Module) = {
val pkg = Package.apply(List(mod), List.empty, defaultLanguageVersion, None)
val world = new World(Map(defaultPackageId -> pkg))
Typing.checkModule(world, defaultPackageId, mod)
}
val negativeTestCases = Table(
"valid module",
m"""module Mod { synonym S = Int64 ; }""",
m"""module Mod { synonym S a = a ; }""",
m"""module Mod { synonym S a b = a ; }""",
m"""module Mod { synonym S (f: *) = f ; }""",
m"""module Mod { synonym S (f: * -> *) = f Int64; }""",
)
forEvery(testCases) { (mod: Module, rejected: Boolean) =>
val world = new World(Map())
val positiveTestCases = Table(
"invalid module",
m"""module Mod { synonym S = a ; }""",
m"""module Mod { synonym S a = b ; }""",
m"""module Mod { synonym S a a = a ; }""",
m"""module Mod { synonym S = List ; }""",
m"""module Mod { synonym S (f: * -> *) = f ; }""",
m"""module Mod { synonym S (f: *) = f Int64; }""",
)
if (rejected)
a[ValidationError] should be thrownBy
Typing.checkModule(world, defaultPackageId, mod)
else
Typing.checkModule(world, defaultPackageId, mod)
()
}
forEvery(negativeTestCases)(mod => checkModule(mod))
forEvery(positiveTestCases)(mod => a[ValidationError] should be thrownBy checkModule(mod))
}
private val pkg =