Skip to content

Commit

Permalink
LF: add interface to scala AST and decoder (digital-asset#10830)
Browse files Browse the repository at this point in the history
this is part of digital-asset#10810

CHANGELOG_BEGIN
CHANGELOG_END
  • Loading branch information
remyhaemmerle-da authored Sep 10, 2021
1 parent 07b72d0 commit e42cd3a
Show file tree
Hide file tree
Showing 20 changed files with 221 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
val defs = mutable.ArrayBuffer[(DottedName, Definition)]()
val templates = mutable.ArrayBuffer[(DottedName, Template)]()
val exceptions = mutable.ArrayBuffer[(DottedName, DefException)]()
val interfaces = mutable.ArrayBuffer[(DottedName, DefInterface)]()

if (versionIsOlderThan(LV.Features.typeSynonyms)) {
assertEmpty(lfModule.getSynonymsList, "Module.synonyms")
Expand Down Expand Up @@ -276,11 +277,29 @@ private[archive] class DecodeV1(minor: LV.Minor) {
lfModule.getExceptionsList.asScala
.foreach { defn =>
val defName = getInternedDottedName(defn.getNameInternedDname)
exceptions += ((defName, decodeException(defName, defn)))
exceptions += (defName -> decodeException(defName, defn))
}
}

Module(moduleName, defs, templates, exceptions, decodeFeatureFlags(lfModule.getFlags))
if (versionIsOlderThan(LV.Features.interfaces)) {
assertEmpty(lfModule.getInterfacesList, "Module.interfaces")
} else {
lfModule.getInterfacesList.asScala.foreach { defn =>
val defName = getInternedDottedName(defn.getTyconInternedDname)
interfaces += (defName -> decodeDefInterface(defn))
}
}

val interfaceDataTypes = interfaces.view.map { case (k, _) => k -> DDataType.Interface }

Module(
moduleName,
interfaceDataTypes ++ defs,
templates,
exceptions,
interfaces,
decodeFeatureFlags(lfModule.getFlags),
)
}

// -----------------------------------------------------------------------
Expand Down Expand Up @@ -553,6 +572,9 @@ private[archive] class DecodeV1(minor: LV.Minor) {
}

private[this] def decodeTemplate(tpl: DottedName, lfTempl: PLF.DefTemplate): Template = {
val lfImplements = lfTempl.getImplementsList.asScala
if (versionIsOlderThan(LV.Features.interfaces))
assertEmpty(lfImplements, "DefTemplate.implements")
val paramName = handleInternedName(
lfTempl.getParamCase,
PLF.DefTemplate.ParamCase.PARAM_STR,
Expand All @@ -570,6 +592,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
.map(decodeChoice(tpl, _))
.map(ch => (ch.name, ch)),
observers = decodeExpr(lfTempl.getObservers, s"$tpl:observer"),
implements = lfImplements.map(decodeTypeConName),
key =
if (lfTempl.hasKey) Some(decodeTemplateKey(tpl, lfTempl.getKey, paramName))
else None,
Expand Down Expand Up @@ -621,6 +644,25 @@ private[archive] class DecodeV1(minor: LV.Minor) {
): DefException =
DefException(decodeExpr(lfException.getMessage, s"$exceptionName:message"))

private[this] def decodeDefInterface(
lfInterface: PLF.DefInterface
): DefInterface =
DefInterface(
lfInterface.getChoicesList.asScala.toList
.map(decodeInterfaceChoice)
.map(choice => (choice.name, choice))
)

private[this] def decodeInterfaceChoice(
lfChoice: PLF.InterfaceChoice
): InterfaceChoice =
InterfaceChoice(
name = getInternedName(lfChoice.getNameInternedString, "InterfaceChoice.name"),
consuming = lfChoice.getConsuming,
argType = decodeType(lfChoice.getArgType),
returnType = decodeType(lfChoice.getRetType),
)

private[lf] def decodeKind(lfKind: PLF.Kind): Kind =
lfKind.getSumCase match {
case PLF.Kind.SumCase.STAR => KStar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,9 @@ private[daml] class EncodeV1(minor: LV.Minor) {
setString(_, b.addConstructorsStr, b.addConstructorsInternedStr)
)
builder.setEnum(b)
case DataInterface =>
// TODO https://github.com/digital-asset/daml/issues/10810
sys.error("Interface not supported")
}
builder.build()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ private[engine] final class Preprocessor(
variants.foldRight(typesToProcess0)(_._2 :: _)
case Ast.DataEnum(_) =>
typesToProcess0
case Ast.DataInterface =>
// TODO https://github.com/digital-asset/daml/issues/10810
sys.error("Interface not supported")
}
go(
typesToProcess,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ object InterfaceReader {
variant(fullName, tyVars, dfn)
case dfn: Ast.DataEnum =>
enum(fullName, tyVars, dfn)
case Ast.DataInterface =>
// TODO https://github.com/digital-asset/daml/issues/10810
sys.error("Interface not supported")
}

locate(Symbol("name"), rootErrOf[ErrorLoc](result)) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,12 @@ class InterfaceReaderSpec extends AnyWordSpec with Matchers with Inside {

private def wrappInModule(dataName: DottedName, dfn: Ast.DDataType) =
Ast.Module(
moduleName,
Map(dataName -> dfn),
Map.empty,
Map.empty,
Ast.FeatureFlags.default,
name = moduleName,
definitions = Map(dataName -> dfn),
templates = Map.empty,
exceptions = Map.empty,
interfaces = Map.empty,
featureFlags = Ast.FeatureFlags.default,
)

private def dottedName(segments: Iterable[String]): DottedName =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ class InterpreterTest extends AnyWordSpec with Matchers with TableDrivenProperty
),
templates = Map.empty,
exceptions = Map.empty,
interfaces = List.empty,
featureFlags = FeatureFlags.default,
)
),
Expand All @@ -217,6 +218,7 @@ class InterpreterTest extends AnyWordSpec with Matchers with TableDrivenProperty
definitions = Map.empty,
templates = Map.empty,
exceptions = Map.empty,
interfaces = List.empty,
featureFlags = FeatureFlags.default,
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,10 @@ object Ast {
params: ImmArray[(TypeVarName, Kind)],
cons: DataCons,
) extends GenDefinition[Nothing]
object DDataType {
val Interface = DDataType(true, ImmArray.empty, DataInterface)
}

final case class GenDValue[E](
typ: Type,
noPartyLiterals: Boolean,
Expand Down Expand Up @@ -597,8 +601,9 @@ object Ast {
final case class DataEnum(constructors: ImmArray[EnumConName]) extends DataCons {
lazy val constructorRank: Map[EnumConName, Int] = constructors.iterator.zipWithIndex.toMap
}
case object DataInterface extends DataCons

case class GenTemplateKey[E](
final case class GenTemplateKey[E](
typ: Type,
body: E,
// function from key type to [Party]
Expand All @@ -619,6 +624,29 @@ object Ast {
type TemplateKeySignature = GenTemplateKey[Unit]
object TemplateKeySignature extends GenTemplateKeyCompanion[Unit]

final case class DefInterface(choices: Map[ChoiceName, InterfaceChoice])

object DefInterface {
def apply(
choices: Iterable[(ChoiceName, InterfaceChoice)]
): DefInterface = {
val choiceMap = toMapWithoutDuplicate(
choices,
(name: ChoiceName) =>
throw PackageError(s"collision on interface choice name ${name.toString}"),
)
DefInterface(choiceMap)
}
}

case class InterfaceChoice(
name: ChoiceName,
consuming: Boolean,
argType: Type,
returnType: Type,
// TODO interfaces Should observers or controllers be part of the interface?
)

case class GenTemplate[E] private[Ast] (
param: ExprVarName, // Binder for template argument.
precond: E, // Template creation precondition.
Expand All @@ -627,6 +655,7 @@ object Ast {
choices: Map[ChoiceName, GenTemplateChoice[E]], // Choices available in the template.
observers: E, // Observers of the contract.
key: Option[GenTemplateKey[E]],
implements: Set[TypeConName],
) extends NoCopy

sealed class GenTemplateCompanion[E] {
Expand All @@ -639,6 +668,7 @@ object Ast {
choices: Iterable[(ChoiceName, GenTemplateChoice[E])],
observers: E,
key: Option[GenTemplateKey[E]],
implements: Iterable[TypeConName],
): GenTemplate[E] = {

val choiceMap = toMapWithoutDuplicate(
Expand All @@ -647,6 +677,13 @@ object Ast {
throw PackageError(s"collision on choice name ${choiceName.toString}"),
)

val implementsSet = implements.foldLeft(Set.empty[TypeConName])((acc, implement) =>
if (acc.contains(implement))
throw PackageError(s"repeated implementation ${implements.toString}")
else
acc + implement
)

new GenTemplate[E](
param,
precond,
Expand All @@ -655,6 +692,7 @@ object Ast {
choiceMap,
observers,
key,
implementsSet,
)
}

Expand All @@ -667,6 +705,7 @@ object Ast {
Map[ChoiceName, GenTemplateChoice[E]],
E,
Option[GenTemplateKey[E]],
Set[TypeConName],
)
] = GenTemplate.unapply(arg)

Expand All @@ -679,6 +718,7 @@ object Ast {
Map[ChoiceName, GenTemplateChoice[E]],
E,
Option[GenTemplateKey[E]],
Set[TypeConName],
)
] = Some(
(
Expand All @@ -689,6 +729,7 @@ object Ast {
arg.choices,
arg.observers,
arg.key,
arg.implements,
)
)
}
Expand Down Expand Up @@ -801,6 +842,7 @@ object Ast {
definitions: Map[DottedName, GenDefinition[E]],
templates: Map[DottedName, GenTemplate[E]],
exceptions: Map[DottedName, GenDefException[E]],
interfaces: Map[DottedName, DefInterface],
featureFlags: FeatureFlags,
) extends NoCopy

Expand All @@ -823,6 +865,7 @@ object Ast {
definitions: Iterable[(DottedName, GenDefinition[E])],
templates: Iterable[(DottedName, GenTemplate[E])],
exceptions: Iterable[(DottedName, GenDefException[E])],
interfaces: Iterable[(DottedName, DefInterface)],
featureFlags: FeatureFlags,
): GenModule[E] = {

Expand All @@ -844,11 +887,17 @@ object Ast {
(name: DottedName) => throw PackageError(s"Collision on exception name ${name.toString}"),
)

val interfaceMap =
toMapWithoutDuplicate(
interfaces,
(name: DottedName) => throw PackageError(s"Collision on interface name ${name.toString}"),
)

templateMap.keysIterator.find(exceptionMap.keySet.contains).foreach { name =>
throw PackageError(s"Collision between exception and template name ${name.toString}")
}

GenModule(name, definitionMap, templateMap, exceptionMap, featureFlags)
GenModule(name, definitionMap, templateMap, exceptionMap, interfaceMap, featureFlags)
}

def unapply(arg: GenModule[E]): Some[
Expand All @@ -857,9 +906,12 @@ object Ast {
Map[DottedName, GenDefinition[E]],
Map[DottedName, GenTemplate[E]],
Map[DottedName, GenDefException[E]],
Map[DottedName, DefInterface],
FeatureFlags,
)
] = Some((arg.name, arg.definitions, arg.templates, arg.exceptions, arg.featureFlags))
] = Some(
(arg.name, arg.definitions, arg.templates, arg.exceptions, arg.interfaces, arg.featureFlags)
)
}

type Module = GenModule[Expr]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ object LanguageVersion {
val choiceObservers = v1_11
val bigNumeric = v1_13
val exceptions = v1_14
val interfaces = v1_dev

/** Unstable, experimental features. This should stay in 1.dev forever.
* Features implemented with this flag should be moved to a separate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ object Util {

private[this] def toSignature(template: Template): TemplateSignature =
template match {
case Template(param, _, _, _, choices, _, key) =>
case Template(param, _, _, _, choices, _, key, implements) =>
TemplateSignature(
param,
(),
Expand All @@ -212,12 +212,13 @@ object Util {
choices.transform((_, v) => toSignature(v)),
(),
key.map(toSignature),
implements,
)
}

private[this] def toSignature(module: Module): ModuleSignature =
module match {
case Module(name, definitions, templates, exceptions, featureFlags) =>
case Module(name, definitions, templates, exceptions, interfaces, featureFlags) =>
ModuleSignature(
name = name,
definitions = definitions.transform {
Expand All @@ -227,6 +228,7 @@ object Util {
},
templates = templates.transform((_, template) => toSignature(template)),
exceptions = exceptions.transform((_, _) => DefExceptionSignature),
interfaces = interfaces,
featureFlags = featureFlags,
)
}
Expand Down
Loading

0 comments on commit e42cd3a

Please sign in to comment.