LF: Clean up Ast (#11786)

- rename non-default builders `apply` to `build`
  * avoid confusing both
  * make explicit the build can crash

- make interfaceId and templateId fields consitent

- use when possible named arguments

- check for non-repetition of inherited choices

CHANGELOG_BEGIN
CHANGELOG_END
This commit is contained in:
Remy 2021-11-19 15:40:28 +01:00 committed by GitHub
parent 25e5bbb753
commit cbe9c922ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 311 additions and 269 deletions

View File

@ -241,7 +241,7 @@ class ReplService(
): Unit = {
val lfVer = LanguageVersion(LanguageVersion.Major.V1, LanguageVersion.Minor(req.getMinor))
val mod = archive.moduleDecoder(lfVer, homePackageId).assertFromByteString(req.getDamlLf1)
val pkg = Package((mainModules + (mod.name -> mod)).values, Seq(), lfVer, None)
val pkg = Package(mainModules.updated(mod.name, mod), Set.empty, lfVer, None)
// TODO[AH] Provide daml-script package id from REPL client.
val Some(scriptPackageId) = this.signatures.collectFirst {
case (pkgId, pkg) if pkg.modules.contains(DottedName.assertFromString("Daml.Script")) => pkgId

View File

@ -64,7 +64,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
val internedTypes = decodeInternedTypes(env0, lfPackage)
val env = env0.copy(internedTypes = internedTypes)
Package(
Package.build(
modules = lfPackage.getModulesList.asScala.map(env.decodeModule(_)),
directDeps = dependencyTracker.getDependencies,
languageVersion = languageVersion,
@ -289,7 +289,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
}
}
Module(
Module.build(
moduleName,
defs,
templates,
@ -583,16 +583,14 @@ private[archive] class DecodeV1(minor: LV.Minor) {
lfTempl.getParamInternedStr,
"DefTemplate.param.param",
)
Template(
Template.build(
param = paramName,
precond = if (lfTempl.hasPrecond) decodeExpr(lfTempl.getPrecond, s"$tpl:ensure") else ETrue,
signatories = decodeExpr(lfTempl.getSignatories, s"$tpl.signatory"),
agreementText = decodeExpr(lfTempl.getAgreement, s"$tpl:agreement"),
choices = lfTempl.getChoicesList.asScala
.map(decodeChoice(tpl, _))
.map(ch => (ch.name, ch)),
choices = lfTempl.getChoicesList.asScala.view.map(decodeChoice(tpl, _)),
observers = decodeExpr(lfTempl.getObservers, s"$tpl:observer"),
implements = lfImplements.map(decodeTemplateImplements).map(impl => (impl.interface, impl)),
implements = lfImplements.view.map(decodeTemplateImplements),
key =
if (lfTempl.hasKey) Some(decodeTemplateKey(tpl, lfTempl.getKey, paramName))
else None,
@ -602,21 +600,19 @@ private[archive] class DecodeV1(minor: LV.Minor) {
private[this] def decodeTemplateImplements(
lfImpl: PLF.DefTemplate.Implements
): TemplateImplements =
TemplateImplements(
interface = decodeTypeConName(lfImpl.getInterface),
methods = lfImpl.getMethodsList.asScala
.map(decodeTemplateImplementsMethod)
.map(method => (method.name, method)),
inheritedChoices = lfImpl.getInheritedChoiceInternedNamesList.asScala
.map(getInternedName(_, "TemplateImplements.inheritedChoices"))
.toSet,
TemplateImplements.build(
interfaceId = decodeTypeConName(lfImpl.getInterface),
methods = lfImpl.getMethodsList.asScala.view.map(decodeTemplateImplementsMethod),
inheritedChoices = lfImpl.getInheritedChoiceInternedNamesList.asScala.view
.map(getInternedName(_, "TemplateImplements.inheritedChoices")),
)
private[this] def decodeTemplateImplementsMethod(
lfMethod: PLF.DefTemplate.ImplementsMethod
): TemplateImplementsMethod =
TemplateImplementsMethod(
name = getInternedName(lfMethod.getMethodInternedName, "TemplateImplementsMethod.name"),
methodName =
getInternedName(lfMethod.getMethodInternedName, "TemplateImplementsMethod.name"),
value = decodeExpr(lfMethod.getValue, "TemplateImplementsMethod.value"),
)
@ -669,14 +665,10 @@ private[archive] class DecodeV1(minor: LV.Minor) {
id: DottedName,
lfInterface: PLF.DefInterface,
): DefInterface =
DefInterface(
DefInterface.build(
param = getInternedName(lfInterface.getParamInternedStr, "DefInterface.param"),
fixedChoices = lfInterface.getFixedChoicesList.asScala.view
.map(decodeChoice(id, _))
.map(choice => choice.name -> choice),
methods = lfInterface.getMethodsList.asScala.view
.map(decodeInterfaceMethod)
.map(method => method.name -> method),
fixedChoices = lfInterface.getFixedChoicesList.asScala.view.map(decodeChoice(id, _)),
methods = lfInterface.getMethodsList.asScala.view.map(decodeInterfaceMethod),
precond = decodeExpr(lfInterface.getPrecond, s"$id:ensure"),
)
@ -1126,8 +1118,8 @@ private[archive] class DecodeV1(minor: LV.Minor) {
assertSince(LV.Features.interfaces, "Expr.to_interface")
val toInterface = lfExpr.getToInterface
EToInterface(
iface = decodeTypeConName(toInterface.getInterfaceType),
tpl = decodeTypeConName(toInterface.getTemplateType),
interfaceId = decodeTypeConName(toInterface.getInterfaceType),
templateId = decodeTypeConName(toInterface.getTemplateType),
value = decodeExpr(toInterface.getTemplateExpr, definition),
)
@ -1135,8 +1127,8 @@ private[archive] class DecodeV1(minor: LV.Minor) {
assertSince(LV.Features.interfaces, "Expr.from_interface")
val fromInterface = lfExpr.getFromInterface
EFromInterface(
iface = decodeTypeConName(fromInterface.getInterfaceType),
tpl = decodeTypeConName(fromInterface.getTemplateType),
interfaceId = decodeTypeConName(fromInterface.getInterfaceType),
templateId = decodeTypeConName(fromInterface.getTemplateType),
value = decodeExpr(fromInterface.getInterfaceExpr, definition),
)
@ -1144,8 +1136,9 @@ private[archive] class DecodeV1(minor: LV.Minor) {
assertSince(LV.Features.interfaces, "Expr.call_interface")
val callInterface = lfExpr.getCallInterface
ECallInterface(
iface = decodeTypeConName(callInterface.getInterfaceType),
method = getInternedName(callInterface.getMethodInternedName, "ECallInterface.method"),
interfaceId = decodeTypeConName(callInterface.getInterfaceType),
methodName =
getInternedName(callInterface.getMethodInternedName, "ECallInterface.method"),
value = decodeExpr(callInterface.getInterfaceExpr, definition),
)
@ -1283,7 +1276,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
case PLF.Update.SumCase.CREATE_INTERFACE =>
val create = lfUpdate.getCreateInterface
UpdateCreateInterface(
interface = decodeTypeConName(create.getInterface),
interfaceId = decodeTypeConName(create.getInterface),
arg = decodeExpr(create.getExpr, definition),
)
@ -1307,7 +1300,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
assertSince(LV.Features.interfaces, "exerciseInterface")
val exercise = lfUpdate.getExerciseInterface
UpdateExerciseInterface(
interface = decodeTypeConName(exercise.getInterface),
interfaceId = decodeTypeConName(exercise.getInterface),
choice = handleInternedName(exercise.getChoiceInternedStr),
cidE = decodeExpr(exercise.getCid, definition),
argE = decodeExpr(exercise.getArg, definition),
@ -1340,7 +1333,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
assertSince(LV.Features.interfaces, "fetchInterface")
val fetch = lfUpdate.getFetchInterface
UpdateFetchInterface(
interface = decodeTypeConName(fetch.getInterface),
interfaceId = decodeTypeConName(fetch.getInterface),
contractId = decodeExpr(fetch.getCid, definition),
)

View File

@ -70,7 +70,7 @@ private[daml] object DamlLfEncoder extends App {
} else None
val pkg =
Ast.Package(modules, Set.empty[PackageId], parserParameters.languageVersion, metadata)
Ast.Package.build(modules, Set.empty[PackageId], parserParameters.languageVersion, metadata)
val pkgs = PackageInterface(Map(pkgId -> pkg))
Validation.checkPackage(pkgs, pkgId, pkg).left.foreach(e => error(e.pretty))

View File

@ -2106,12 +2106,7 @@ class EngineTest
val pkgId = Ref.PackageId.assertFromString("-pkg-")
def pkg(version: LV) =
language.Ast.Package(
Iterable.empty,
Iterable.empty,
version,
None,
)
language.Ast.Package(Map.empty, Set.empty, version, None)
"reject disallow packages" in {
val negativeTestCases = Table(

View File

@ -170,7 +170,7 @@ class InterfaceReaderSpec extends AnyWordSpec with Matchers with Inside {
"Package metadata should be extracted if present" in {
def pkg(metadata: Option[Ast.PackageMetadata]) =
Ast.Package(
modules = Seq.empty,
modules = Map.empty,
directDeps = Set.empty,
languageVersion = LanguageVersion.default,
metadata = metadata,

View File

@ -377,10 +377,10 @@ private[lf] final class Compiler(
addDef(compileSignatories(identifier, tmpl))
addDef(compileObservers(identifier, tmpl))
tmpl.implements.values.foreach { impl =>
addDef(compileCreateByInterface(identifier, tmpl, impl.interface))
addDef(compileImplements(identifier, impl.interface))
addDef(compileCreateByInterface(identifier, tmpl, impl.interfaceId))
addDef(compileImplements(identifier, impl.interfaceId))
impl.methods.values.foreach(method =>
addDef(compileImplementsMethod(identifier, impl.interface, method))
addDef(compileImplementsMethod(identifier, impl.interfaceId, method))
)
}

View File

@ -188,9 +188,9 @@ class InterpreterTest extends AnyWordSpec with Matchers with TableDrivenProperty
PureCompiledPackages.assertBuild(
Map(
dummyPkg ->
Package(
Package.build(
List(
Module(
Module.build(
name = modName,
definitions = Map(
DottedName.assertFromString("bar") ->
@ -211,14 +211,14 @@ class InterpreterTest extends AnyWordSpec with Matchers with TableDrivenProperty
val pkgs3 = PureCompiledPackages.assertBuild(
Map(
dummyPkg ->
Package(
Package.build(
List(
Module(
name = modName,
definitions = Map.empty,
templates = Map.empty,
exceptions = Map.empty,
interfaces = List.empty,
interfaces = Map.empty,
featureFlags = FeatureFlags.default,
)
),

View File

@ -156,13 +156,16 @@ object Ast {
final case class EFromAnyException(typ: Type, value: Expr) extends Expr
/** Convert template payload to interface it implements */
final case class EToInterface(iface: TypeConName, tpl: TypeConName, value: Expr) extends Expr
final case class EToInterface(interfaceId: TypeConName, templateId: TypeConName, value: Expr)
extends Expr
/** Convert interface back to template payload if possible */
final case class EFromInterface(iface: TypeConName, tpl: TypeConName, value: Expr) extends Expr
final case class EFromInterface(interfaceId: TypeConName, templateId: TypeConName, value: Expr)
extends Expr
/** Invoke an interface method */
final case class ECallInterface(iface: TypeConName, method: MethodName, value: Expr) extends Expr
final case class ECallInterface(interfaceId: TypeConName, methodName: MethodName, value: Expr)
extends Expr
//
// Kinds
@ -487,9 +490,9 @@ object Ast {
final case class UpdatePure(t: Type, expr: Expr) extends Update
final case class UpdateBlock(bindings: ImmArray[Binding], body: Expr) extends Update
final case class UpdateCreate(templateId: TypeConName, arg: Expr) extends Update
final case class UpdateCreateInterface(interface: TypeConName, arg: Expr) extends Update
final case class UpdateCreateInterface(interfaceId: TypeConName, arg: Expr) extends Update
final case class UpdateFetch(templateId: TypeConName, contractId: Expr) extends Update
final case class UpdateFetchInterface(interface: TypeConName, contractId: Expr) extends Update
final case class UpdateFetchInterface(interfaceId: TypeConName, contractId: Expr) extends Update
final case class UpdateExercise(
templateId: TypeConName,
choice: ChoiceName,
@ -497,7 +500,7 @@ object Ast {
argE: Expr,
) extends Update
final case class UpdateExerciseInterface(
interface: TypeConName,
interfaceId: TypeConName,
choice: ChoiceName,
cidE: Expr,
argE: Expr,
@ -587,7 +590,7 @@ object Ast {
final class GenDValueCompanion[E] private[Ast] {
def apply(typ: Type, noPartyLiterals: Boolean, body: E, isTest: Boolean): GenDValue[E] =
GenDValue(typ, noPartyLiterals, body, isTest)
GenDValue(typ = typ, noPartyLiterals = noPartyLiterals, body = body, isTest = isTest)
def unapply(arg: GenDValue[E]): Some[(Type, Boolean, E, Boolean)] =
Some((arg.typ, arg.noPartyLiterals, arg.body, arg.isTest))
@ -626,7 +629,7 @@ object Ast {
final class GenTemplateKeyCompanion[E] private[Ast] {
def apply(typ: Type, body: E, maintainers: E): GenTemplateKey[E] =
GenTemplateKey(typ, body, maintainers)
GenTemplateKey(typ = typ, body = body, maintainers = maintainers)
def unapply(arg: GenTemplateKey[E]): Some[(Type, E, E)] =
Some((arg.typ, arg.body, arg.maintainers))
@ -646,22 +649,32 @@ object Ast {
)
final class GenDefInterfaceCompanion[E] {
def apply(
@throws[PackageError]
def build(
param: ExprVarName, // Binder for template argument.
fixedChoices: Iterable[(ChoiceName, GenTemplateChoice[E])],
methods: Iterable[(MethodName, InterfaceMethod)],
fixedChoices: Iterable[GenTemplateChoice[E]],
methods: Iterable[InterfaceMethod],
precond: E,
): GenDefInterface[E] = {
val fixedChoiceMap = toMapWithoutDuplicate(
fixedChoices,
(name: ChoiceName) => throw PackageError(s"collision on interface choice name $name"),
fixedChoices.view.map(c => c.name -> c),
(name: ChoiceName) => PackageError(s"collision on interface choice name $name"),
)
val methodMap = toMapWithoutDuplicate(
methods,
(name: MethodName) => throw PackageError(s"collision on interface method name $name"),
methods.view.map(c => c.name -> c),
(name: MethodName) => PackageError(s"collision on interface method name $name"),
)
GenDefInterface(param, fixedChoiceMap, methodMap, precond)
}
def apply(
param: ExprVarName,
fixedChoices: Map[ChoiceName, GenTemplateChoice[E]],
methods: Map[MethodName, InterfaceMethod],
precond: E,
): GenDefInterface[E] =
GenDefInterface(param, fixedChoices, methods, precond)
def unapply(arg: GenDefInterface[E]): Some[
(
ExprVarName,
@ -709,54 +722,55 @@ object Ast {
}
final class GenTemplateCompanion[E] private[Ast] {
@throws[PackageError]
def build(
param: ExprVarName,
precond: E,
signatories: E,
agreementText: E,
choices: Iterable[GenTemplateChoice[E]],
observers: E,
key: Option[GenTemplateKey[E]],
implements: Iterable[GenTemplateImplements[E]],
): GenTemplate[E] =
GenTemplate[E](
param = param,
precond = precond,
signatories = signatories,
agreementText = agreementText,
choices = toMapWithoutDuplicate(
choices.view.map(c => c.name -> c),
(choiceName: ChoiceName) => PackageError(s"collision on choice name $choiceName"),
),
observers = observers,
key = key,
implements = toMapWithoutDuplicate(
implements.map(i => i.interfaceId -> i),
(ifaceId: TypeConName) =>
PackageError(s"repeated interface implementation ${ifaceId.toString}"),
),
)
def apply(
param: ExprVarName,
precond: E,
signatories: E,
agreementText: E,
choices: Iterable[(ChoiceName, GenTemplateChoice[E])],
choices: Map[ChoiceName, GenTemplateChoice[E]],
observers: E,
key: Option[GenTemplateKey[E]],
implements: Iterable[(TypeConName, GenTemplateImplements[E])],
): GenTemplate[E] = {
val choiceMap = toMapWithoutDuplicate(
choices,
(choiceName: ChoiceName) => throw PackageError(s"collision on choice name $choiceName"),
implements: Map[TypeConName, GenTemplateImplements[E]],
) = GenTemplate(
param = param,
precond = precond,
signatories = signatories,
agreementText = agreementText,
choices = choices,
observers = observers,
key = key,
implements = implements,
)
val implementsMap = toMapWithoutDuplicate(
implements,
(ifaceName: TypeConName) =>
throw PackageError(s"repeated interface implementation ${ifaceName.toString}"),
)
GenTemplate[E](
param,
precond,
signatories,
agreementText,
choiceMap,
observers,
key,
implementsMap,
)
}
def apply(arg: GenTemplate[E]): Option[
(
ExprVarName,
E,
E,
E,
Map[ChoiceName, GenTemplateChoice[E]],
E,
Option[GenTemplateKey[E]],
Map[TypeConName, GenTemplateImplements[E]],
)
] = GenTemplate.unapply(arg)
def unapply(arg: GenTemplate[E]): Some[
(
ExprVarName,
@ -811,14 +825,14 @@ object Ast {
update: E,
): GenTemplateChoice[E] =
GenTemplateChoice(
name,
consuming,
controllers,
choiceObservers,
selfBinder,
argBinder,
returnType,
update,
name = name,
consuming = consuming,
controllers = controllers,
choiceObservers = choiceObservers,
selfBinder = selfBinder,
argBinder = argBinder,
returnType = returnType,
update = update,
)
def unapply(
@ -845,36 +859,41 @@ object Ast {
val TemplateChoiceSignature = new GenTemplateChoiceCompanion[Unit]
final case class GenTemplateImplements[E](
interface: TypeConName,
interfaceId: TypeConName,
methods: Map[MethodName, GenTemplateImplementsMethod[E]],
inheritedChoices: Set[ChoiceName],
)
final class GenTemplateImplementsCompanion[E] private[Ast] {
def apply(
interface: TypeConName,
methods: Iterable[(MethodName, GenTemplateImplementsMethod[E])],
@throws[PackageError]
def build(
interfaceId: TypeConName,
methods: Iterable[GenTemplateImplementsMethod[E]],
inheritedChoices: Iterable[ChoiceName],
): GenTemplateImplements[E] = {
val methodMap = toMapWithoutDuplicate(
methods,
(methodName: MethodName) =>
throw PackageError(s"repeated method implementation $methodName"),
): GenTemplateImplements[E] =
new GenTemplateImplements[E](
interfaceId = interfaceId,
methods = toMapWithoutDuplicate(
methods.map(m => m.name -> m),
(name: MethodName) => PackageError(s"repeated method implementation $name"),
),
inheritedChoices = toSetWithoutDuplicate(
inheritedChoices,
(name: ChoiceName) => PackageError(s"repeated inherited Choices $name"),
),
)
new GenTemplateImplements[E](interface, methodMap, inheritedChoices.toSet)
}
def apply(
interface: TypeConName,
interfaceId: TypeConName,
methods: Map[MethodName, GenTemplateImplementsMethod[E]],
inheritedChoices: Set[ChoiceName],
): GenTemplateImplements[E] =
GenTemplateImplements[E](interface, methods, inheritedChoices)
GenTemplateImplements[E](interfaceId, methods, inheritedChoices)
def unapply(
arg: GenTemplateImplements[E]
): Some[(TypeConName, Map[MethodName, GenTemplateImplementsMethod[E]], Set[ChoiceName])] =
Some((arg.interface, arg.methods, arg.inheritedChoices))
Some((arg.interfaceId, arg.methods, arg.inheritedChoices))
}
type TemplateImplements = GenTemplateImplements[Expr]
@ -889,11 +908,8 @@ object Ast {
)
final class GenTemplateImplementsMethodCompanion[E] {
def apply(
name: MethodName,
value: E,
): GenTemplateImplementsMethod[E] =
GenTemplateImplementsMethod[E](name, value)
def apply(methodName: MethodName, value: E): GenTemplateImplementsMethod[E] =
GenTemplateImplementsMethod[E](methodName, value)
def unapply(
arg: GenTemplateImplementsMethod[E]
@ -911,10 +927,10 @@ object Ast {
final class GenDefExceptionCompanion[E] private[Ast] {
def apply(message: E): GenDefException[E] =
GenDefException(message)
GenDefException(message = message)
def unapply(arg: GenDefException[E]): Some[E] =
Some((arg.message))
Some(arg.message)
}
type DefException = GenDefException[Expr]
@ -964,53 +980,73 @@ object Ast {
private[this] def toMapWithoutDuplicate[Key, Value](
xs: Iterable[(Key, Value)],
error: Key => Nothing,
error: Key => PackageError,
): Map[Key, Value] =
xs.foldLeft[Map[Key, Value]](Map.empty[Key, Value]) { case (acc, (key, value)) =>
if (acc.contains(key)) {
error(key)
} else {
xs.foldLeft(Map.empty[Key, Value]) { case (acc, (key, value)) =>
if (acc.contains(key))
throw error(key)
else
acc.updated(key, value)
}
}
private[this] def toSetWithoutDuplicate[X](
xs: Iterable[X],
error: X => PackageError,
): Set[X] =
xs.foldLeft(Set.empty[X])((acc, x) =>
if (acc.contains(x))
throw error(x)
else
acc + x
)
final class GenModuleCompanion[E] private[Ast] {
def apply(
@throws[PackageError]
def build(
name: ModuleName,
definitions: Iterable[(DottedName, GenDefinition[E])],
templates: Iterable[(DottedName, GenTemplate[E])],
exceptions: Iterable[(DottedName, GenDefException[E])],
interfaces: Iterable[(DottedName, GenDefInterface[E])],
featureFlags: FeatureFlags,
): GenModule[E] = {
val definitionMap =
toMapWithoutDuplicate(
): GenModule[E] =
GenModule(
name = name,
definitions = toMapWithoutDuplicate(
definitions,
(name: DottedName) => throw PackageError(s"Collision on definition name ${name.toString}"),
)
val templateMap =
toMapWithoutDuplicate(
(name: DottedName) => PackageError(s"Collision on definition name ${name.toString}"),
),
templates = toMapWithoutDuplicate(
templates,
(name: DottedName) => throw PackageError(s"Collision on template name ${name.toString}"),
)
val exceptionMap =
toMapWithoutDuplicate(
(name: DottedName) => PackageError(s"Collision on template name ${name.toString}"),
),
exceptions = toMapWithoutDuplicate(
exceptions,
(name: DottedName) => throw PackageError(s"Collision on exception name ${name.toString}"),
)
val interfaceMap =
toMapWithoutDuplicate(
(name: DottedName) => PackageError(s"Collision on exception name ${name.toString}"),
),
interfaces = toMapWithoutDuplicate(
interfaces,
(name: DottedName) => throw PackageError(s"Collision on interface name ${name.toString}"),
(name: DottedName) => PackageError(s"Collision on interface name ${name.toString}"),
),
featureFlags = featureFlags,
)
GenModule(name, definitionMap, templateMap, exceptionMap, interfaceMap, featureFlags)
}
def apply(
name: ModuleName,
definitions: Map[DottedName, GenDefinition[E]],
templates: Map[DottedName, GenTemplate[E]],
exceptions: Map[DottedName, GenDefException[E]],
interfaces: Map[DottedName, GenDefInterface[E]],
featureFlags: FeatureFlags,
) =
GenModule(
name = name,
definitions = definitions,
templates = templates,
exceptions = exceptions,
interfaces = interfaces,
featureFlags = featureFlags,
)
def unapply(arg: GenModule[E]): Some[
(
@ -1042,34 +1078,33 @@ object Ast {
)
final class GenPackageCompanion[E] private[Ast] {
def apply(
@throws[PackageError]
def build(
modules: Iterable[GenModule[E]],
directDeps: Iterable[PackageId],
languageVersion: LanguageVersion,
metadata: Option[PackageMetadata],
): GenPackage[E] = {
val modulesWithNames = modules.map(m => m.name -> m)
val moduleMap =
toMapWithoutDuplicate(
modulesWithNames,
(modName: ModuleName) =>
throw PackageError(s"Collision on module name ${modName.toString}"),
): GenPackage[E] =
GenPackage(
modules = toMapWithoutDuplicate(
modules.view.map(m => m.name -> m),
(modName: ModuleName) => PackageError(s"Collision on module name ${modName.toString}"),
),
directDeps = directDeps.toSet,
languageVersion = languageVersion,
metadata = metadata,
)
this(moduleMap, directDeps.toSet, languageVersion, metadata)
}
def apply(
modules: Map[ModuleName, GenModule[E]],
directDeps: Set[PackageId],
languageVersion: LanguageVersion,
metadata: Option[PackageMetadata],
) =
): GenPackage[E] =
GenPackage(
modules: Map[ModuleName, GenModule[E]],
directDeps: Set[PackageId],
languageVersion: LanguageVersion,
metadata: Option[PackageMetadata],
modules = modules,
directDeps = directDeps,
languageVersion = languageVersion,
metadata = metadata,
)
def unapply(arg: GenPackage[E]): Some[
@ -1079,7 +1114,17 @@ object Ast {
LanguageVersion,
Option[PackageMetadata],
)
] = Some((arg.modules, arg.directDeps, arg.languageVersion, arg.metadata))
] = {
Some(
(
arg.modules,
arg.directDeps,
arg.languageVersion,
arg.metadata,
)
)
}
}
type Package = GenPackage[Expr]

View File

@ -18,24 +18,24 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
private def defaultVersion = LanguageVersion.defaultV1
"Package.apply" should {
"Package.build" should {
"catch module name collisions" in {
Package(
Package.build(
List(
Module(modName1, List.empty, List.empty, List.empty, List.empty, FeatureFlags.default),
Module(modName2, List.empty, List.empty, List.empty, List.empty, FeatureFlags.default),
Module(modName1, Map.empty, Map.empty, Map.empty, Map.empty, FeatureFlags.default),
Module(modName2, Map.empty, Map.empty, Map.empty, Map.empty, FeatureFlags.default),
),
Set.empty,
defaultVersion,
None,
)
a[PackageError] shouldBe thrownBy(
Package(
Package.build(
List(
Module(modName1, List.empty, List.empty, List.empty, List.empty, FeatureFlags.default),
Module(modName1, List.empty, List.empty, List.empty, List.empty, FeatureFlags.default),
Module(modName1, Map.empty, Map.empty, Map.empty, Map.empty, FeatureFlags.default),
Module(modName1, Map.empty, Map.empty, Map.empty, Map.empty, FeatureFlags.default),
),
Set.empty,
defaultVersion,
@ -47,7 +47,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
}
"Module.apply" should {
"Module.build" should {
val template = Template(
param = Name.assertFromString("x"),
@ -57,7 +57,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
choices = Map.empty,
observers = eParties,
key = None,
implements = List.empty,
implements = Map.empty,
)
def exception = DefException(
message = eText
@ -70,7 +70,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
"catch definition name collisions" in {
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("def1") -> recordDef,
@ -85,7 +85,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
a[PackageError] shouldBe thrownBy(
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("def1") -> recordDef,
@ -104,7 +104,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
"catch template collisions" in {
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -119,7 +119,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
a[PackageError] shouldBe thrownBy(
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -137,7 +137,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
}
"catch exception collisions" in {
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -152,7 +152,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
a[PackageError] shouldBe thrownBy(
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -170,7 +170,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
}
"catch collisions between exception and template" in {
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -187,7 +187,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
a[PackageError] shouldBe thrownBy(
Module.apply(
Module.build(
name = modName1,
definitions = List(
defName("defName1") -> recordDef,
@ -207,14 +207,12 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
}
"Template.apply" should {
"Template.build" should {
def builder(name: ChoiceName, typ: Type, expr: Expr) = TemplateChoice(
name = name,
consuming = true,
controllers = eParties,
// TODO https://github.com/digital-asset/daml/issues/7709
// need test for the Some case
choiceObservers = None,
selfBinder = Name.assertFromString("self"),
argBinder = Name.assertFromString("arg") -> TUnit,
@ -225,17 +223,22 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
val List(choice1, choice2, choice3) =
List("choice1", "choice2", "choice3").map(Name.assertFromString)
"catch implements interface repetition " ignore {
// TODO https://github.com/digital-asset/daml/issues/10917
// implement
}
"catch choice name collisions" in {
Template(
Template.build(
param = Name.assertFromString("x"),
precond = ETrue,
signatories = eParties,
agreementText = eText,
choices = List(
choice1 -> builder(choice1, TUnit, EUnit),
choice2 -> builder(choice2, TBool, ETrue),
choice3 -> builder(choice3, TText, eText),
builder(choice1, TUnit, EUnit),
builder(choice2, TBool, ETrue),
builder(choice3, TText, eText),
),
observers = eParties,
key = None,
@ -243,15 +246,15 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
)
a[PackageError] shouldBe thrownBy(
Template(
Template.build(
param = Name.assertFromString("x"),
precond = ETrue,
signatories = eParties,
agreementText = eText,
choices = List(
choice1 -> builder(choice1, TUnit, EUnit),
choice2 -> builder(choice2, TBool, ETrue),
choice1 -> builder(choice1, TText, eText),
builder(choice1, TUnit, EUnit),
builder(choice2, TBool, ETrue),
builder(choice1, TText, eText),
),
observers = eParties,
key = None,
@ -261,6 +264,17 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
}
}
"GenDefInterface.build " should {
"catch duplicate choices" ignore {
// TODO https://github.com/digital-asset/daml/issues/10917
// implement
}
"catch duplicate method" ignore {
// TODO https://github.com/digital-asset/daml/issues/10917
// implement
}
}
private val modName1 = DottedName.assertFromString("Mod1")
private val modName2 = DottedName.assertFromString("Mod2")

View File

@ -4,8 +4,7 @@
package com.daml.lf
package testing.parser
import com.daml.lf.data.ImmArray
import com.daml.lf.data.Ref.{ChoiceName, DottedName, Name}
import com.daml.lf.data.{ImmArray, Ref}
import com.daml.lf.language.Ast._
import com.daml.lf.testing.parser.Parsers._
import com.daml.lf.testing.parser.Token._
@ -19,9 +18,9 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
import exprParser.{expr, expr0}
private def split(defs: Seq[Def]) = {
val definitions = Seq.newBuilder[(DottedName, Definition)]
val templates = Seq.newBuilder[(DottedName, Template)]
val exceptions = Seq.newBuilder[(DottedName, DefException)]
val definitions = Seq.newBuilder[(Ref.DottedName, Definition)]
val templates = Seq.newBuilder[(Ref.DottedName, Template)]
val exceptions = Seq.newBuilder[(Ref.DottedName, DefException)]
defs.foreach {
case DataDef(name, defn) =>
definitions += name -> defn
@ -36,7 +35,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, parameters.languageVersion, metadata)
Package.build(modules, List.empty, parameters.languageVersion, metadata)
}
private lazy val metadata: Parser[PackageMetadata] =
@ -49,13 +48,13 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
case _ ~ modTag ~ modName ~ _ ~ defs =>
val (definitions, templates, exceptions) = split(defs)
val flags = FeatureFlags(forbidPartyLiterals = modTag(noPartyLitsTag))
Module(modName, definitions, templates, exceptions, List.empty, flags)
Module.build(modName, definitions, templates, exceptions, List.empty, flags)
}
private lazy val definition: Parser[Def] =
synDefinition | recDefinition | variantDefinition | enumDefinition | valDefinition | templateDefinition | exceptionDefinition
private def tags(allowed: Set[Name]): Parser[Set[Name]] = Parser { in =>
private def tags(allowed: Set[Ref.Name]): Parser[Set[Ref.Name]] = Parser { in =>
val parser = rep(`@` ~> id) ^^ { tags =>
tags.foreach { t =>
if (!allowed(t))
@ -69,7 +68,7 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
parser(in)
}
private lazy val binder: Parser[(Name, Type)] =
private lazy val binder: Parser[(Ref.Name, Type)] =
id ~ `:` ~ typ ^^ { case id ~ _ ~ typ => id -> typ }
private lazy val synDefinition: Parser[DataDef] =
@ -138,7 +137,7 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
key =>
TemplDef(
tycon,
Template(x, precon, signatories, agreement, choices, observers, key, List.empty),
Template.build(x, precon, signatories, agreement, choices, observers, key, List.empty),
)
}
@ -147,20 +146,20 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
case tycon ~ _ ~ _ ~ message => ExcepDef(tycon, DefException(message))
}
private lazy val choiceParam: Parser[(Name, Type)] =
private lazy val choiceParam: Parser[(Ref.Name, Type)] =
`(` ~> id ~ `:` ~ typ <~ `)` ^^ { case name ~ _ ~ typ => name -> typ }
private lazy val selfBinder: Parser[Name] =
private lazy val selfBinder: Parser[Ref.Name] =
`(` ~> id <~ `)`
private lazy val templateChoice: Parser[(ChoiceName, TemplateChoice)] =
private lazy val templateChoice: Parser[TemplateChoice] =
Id("choice") ~> tags(templateChoiceTags) ~ id ~ selfBinder ~ choiceParam ~
(`:` ~> typ) ~
(`,` ~> Id("controllers") ~> expr) ~
opt(`,` ~> Id("observers") ~> expr) ~
(`to` ~> expr) ^^ {
case choiceTags ~ name ~ self ~ param ~ retTyp ~ controllers ~ choiceObservers ~ update =>
name -> TemplateChoice(
TemplateChoice(
name,
!choiceTags(nonConsumingTag),
controllers,
@ -172,10 +171,10 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
)
}
private val serializableTag = Name.assertFromString("serializable")
private val noPartyLitsTag = Name.assertFromString("noPartyLiterals")
private val isTestTag = Name.assertFromString("isTest")
private val nonConsumingTag = Name.assertFromString("nonConsuming")
private val serializableTag = Ref.Name.assertFromString("serializable")
private val noPartyLitsTag = Ref.Name.assertFromString("noPartyLiterals")
private val isTestTag = Ref.Name.assertFromString("isTest")
private val nonConsumingTag = Ref.Name.assertFromString("nonConsuming")
private val dataDefTags = Set(serializableTag)
private val templateChoiceTags = Set(nonConsumingTag)
@ -188,8 +187,8 @@ object ModParser {
private sealed trait Def extends Product with Serializable
private final case class DataDef(name: DottedName, defn: Definition) extends Def
private final case class TemplDef(name: DottedName, defn: Template) extends Def
private final case class ExcepDef(name: DottedName, defn: DefException) extends Def
private final case class DataDef(name: Ref.DottedName, defn: Definition) extends Def
private final case class TemplDef(name: Ref.DottedName, defn: Template) extends Def
private final case class ExcepDef(name: Ref.DottedName, defn: DefException) extends Def
}

View File

@ -475,7 +475,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
parseModules(p) shouldBe Right(
List(
Module(
Module.build(
name = modName,
definitions = List(
DottedName.assertFromSegments(ImmArray("Tree", "Node").toSeq) -> recDef,
@ -510,10 +510,10 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
List(
Module(
name = modName,
definitions = List(DottedName.assertFromString("fact") -> valDef),
templates = List.empty,
exceptions = List.empty,
interfaces = List.empty,
definitions = Map(DottedName.assertFromString("fact") -> valDef),
templates = Map.empty,
exceptions = Map.empty,
interfaces = Map.empty,
featureFlags = FeatureFlags.default,
)
)
@ -553,13 +553,13 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
"""
val template =
Template(
Template.build(
param = n"this",
precond = e"True",
signatories = e"Cons @Party [person] (Nil @Party)",
agreementText = e""" "Agreement" """,
choices = Map(
n"Sleep" -> TemplateChoice(
choices = List(
TemplateChoice(
name = n"Sleep",
consuming = true,
controllers = e"Cons @Party [person] (Nil @Party)",
@ -569,7 +569,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
returnType = t"ContractId Mod:Person",
update = e"upure @(ContractId Mod:Person) self",
),
n"Nap" -> TemplateChoice(
TemplateChoice(
name = n"Nap",
consuming = false,
controllers = e"Cons @Party [person] (Nil @Party)",
@ -579,7 +579,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
returnType = t"Int64",
update = e"upure @Int64 i",
),
n"PowerNap" -> TemplateChoice(
TemplateChoice(
name = n"PowerNap",
consuming = false,
controllers = e"Cons @Party [person] (Nil @Party)",
@ -605,10 +605,10 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
List(
Module(
name = modName,
definitions = List(name -> recDef),
templates = List(name -> template),
exceptions = List.empty,
interfaces = List.empty,
definitions = Map(name -> recDef),
templates = Map(name -> template),
exceptions = Map.empty,
interfaces = Map.empty,
featureFlags = FeatureFlags.default,
)
)
@ -635,12 +635,12 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
"""
val template =
Template(
Template.build(
param = n"this",
precond = e"True",
signatories = e"Nil @Unit",
agreementText = e""" "Agreement" """,
choices = Map.empty,
choices = List.empty,
observers = e"Nil @Unit",
key = None,
implements = List.empty,
@ -656,10 +656,10 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
List(
Module(
name = modName,
definitions = List(name -> recDef),
templates = List(name -> template),
exceptions = List.empty,
interfaces = List.empty,
definitions = Map(name -> recDef),
templates = Map(name -> template),
exceptions = Map.empty,
interfaces = Map.empty,
featureFlags = FeatureFlags.default,
)
)
@ -693,10 +693,10 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
List(
Module(
name = modName,
definitions = List(name -> recDef),
templates = List.empty,
exceptions = List(name -> exception),
interfaces = List.empty,
definitions = Map(name -> recDef),
templates = Map.empty,
exceptions = Map(name -> exception),
interfaces = Map.empty,
featureFlags = FeatureFlags.default,
)
)

View File

@ -474,13 +474,13 @@ private[validation] object Typing {
def checkIfaceImplementation(tplTcon: TypeConName, impl: TemplateImplements): Unit = {
val DefInterfaceSignature(_, fixedChoices, methods, _) =
handleLookup(ctx, interface.lookupInterface(impl.interface))
handleLookup(ctx, interface.lookupInterface(impl.interfaceId))
val fixedChoiceSet = fixedChoices.keys.toSet
val fixedChoiceSet = fixedChoices.keySet
if (impl.inheritedChoices != fixedChoiceSet) {
throw EBadInheritedChoices(
ctx,
impl.interface,
impl.interfaceId,
tplTcon,
fixedChoiceSet,
impl.inheritedChoices,
@ -489,12 +489,12 @@ private[validation] object Typing {
methods.values.foreach { (method: InterfaceMethod) =>
if (!impl.methods.contains(method.name))
throw EMissingInterfaceMethod(ctx, tplTcon, impl.interface, method.name)
throw EMissingInterfaceMethod(ctx, tplTcon, impl.interfaceId, method.name)
}
impl.methods.values.foreach { (tplMethod: TemplateImplementsMethod) =>
methods.get(tplMethod.name) match {
case None =>
throw EUnknownInterfaceMethod(ctx, tplTcon, impl.interface, tplMethod.name)
throw EUnknownInterfaceMethod(ctx, tplTcon, impl.interfaceId, tplMethod.name)
case Some(method) =>
checkExpr(tplMethod.value, TFun(TTyCon(tplTcon), method.returnType))
}
@ -502,8 +502,7 @@ private[validation] object Typing {
}
def checkDefException(excepName: TypeConName, defException: DefException): Unit = {
val DefException(message) = defException
checkExpr(message, TTyCon(excepName) ->: TText)
checkExpr(defException.message, TTyCon(excepName) ->: TText)
()
}

View File

@ -187,10 +187,7 @@ private[validation] object ExprIterable {
private[iterable] def iterator(x: TemplateImplementsMethod): Iterator[Expr] =
x match {
case TemplateImplementsMethod(
name @ _,
value,
) =>
case TemplateImplementsMethod(name @ _, value) =>
Iterator(value)
}

View File

@ -31,7 +31,7 @@ class DependencyVersionSpec extends AnyWordSpec with TableDrivenPropertyChecks w
) = {
val (pkgId, modName) = ref
val mod = Module(
val mod = Module.build(
name = modName,
definitions = (u -> DValue(TUnit, true, EUnit, false)) +:
depRefs.map { case (depPkgId, depModName) =>

View File

@ -1221,7 +1221,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
"reject ill formed type record definitions" in {
def checkModule(mod: Module) = {
val pkg = Package.apply(List(mod), List.empty, defaultLanguageVersion, None)
val pkg = Package.build(List(mod), List.empty, defaultLanguageVersion, None)
Typing.checkModule(PackageInterface(Map(defaultPackageId -> pkg)), defaultPackageId, mod)
}
@ -1244,7 +1244,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
"reject ill formed type variant definitions" in {
def checkModule(mod: Module) = {
val pkg = Package.apply(List(mod), List.empty, defaultLanguageVersion, None)
val pkg = Package.build(List(mod), List.empty, defaultLanguageVersion, None)
Typing.checkModule(PackageInterface(Map(defaultPackageId -> pkg)), defaultPackageId, mod)
}
@ -1267,7 +1267,7 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher
"reject ill formed type synonym definitions" in {
def checkModule(mod: Module) = {
val pkg = Package.apply(List(mod), List.empty, defaultLanguageVersion, None)
val pkg = Package.build(List(mod), List.empty, defaultLanguageVersion, None)
Typing.checkModule(PackageInterface(Map(defaultPackageId -> pkg)), defaultPackageId, mod)
}