Skip to content

Commit

Permalink
interface methods: Scala AST
Browse files Browse the repository at this point in the history
Part of #11006
This PR takes care of the Scala AST and decoder.
It leaves the encoder, type checker, and speedy for later.

changelog_begin
changelog_end
  • Loading branch information
sofiafaro-da committed Sep 29, 2021
1 parent 5112599 commit 737a7f2
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -591,17 +591,26 @@ 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(decodeTemplateImplements),
implements = lfImplements.map(decodeTemplateImplements).map(impl => (impl.interface, impl)),
key =
if (lfTempl.hasKey) Some(decodeTemplateKey(tpl, lfTempl.getKey, paramName))
else None,
)
}

// TODO https://github.com/digital-asset/daml/issues/11006
// Decode the rest and store it in the AST
private[this] def decodeTemplateImplements(impl: PLF.DefTemplate.Implements): TypeConName =
decodeTypeConName(impl.getInterface)
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))
)

private[this] def decodeTemplateImplementsMethod(lfMethod: PLF.DefTemplate.ImplementsMethod): TemplateImplementsMethod =
TemplateImplementsMethod(
name = getInternedName(lfMethod.getMethodInternedName, "TemplateImplementsMethod.name"),
value = decodeExpr(lfMethod.getValue, "TemplateImplementsMethod.value")
)

private[archive] def decodeChoice(
tpl: DottedName,
Expand Down Expand Up @@ -654,7 +663,10 @@ private[archive] class DecodeV1(minor: LV.Minor) {
DefInterface(
lfInterface.getChoicesList.asScala.toList
.map(decodeInterfaceChoice)
.map(choice => (choice.name, choice))
.map(choice => (choice.name, choice)),
lfInterface.getMethodsList.asScala.toList
.map(decodeInterfaceMethod)
.map(method => (method.name, method)),
)

private[this] def decodeInterfaceChoice(
Expand All @@ -667,6 +679,14 @@ private[archive] class DecodeV1(minor: LV.Minor) {
returnType = decodeType(lfChoice.getRetType),
)

private[this] def decodeInterfaceMethod(
lfMethod: PLF.InterfaceMethod
): InterfaceMethod =
InterfaceMethod(
name = getInternedName(lfMethod.getMethodInternedName, "InterfaceMethod.name"),
returnType = decodeType(lfMethod.getType)
)

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 @@ -246,6 +246,10 @@ object Ref {
type ChoiceName = Name
val ChoiceName = Name

/* Method name in an interface */
type MethodName = Name
val MethodName = Name

type ModuleName = DottedName
val ModuleName = DottedName

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,8 @@ private[daml] class EncodeV1(minor: LV.Minor) {
val builder = PLF.DefInterface.newBuilder()
builder.setTyconInternedDname(dottedNameTable.insert(dottedName))
builder.accumulateLeft(interface.choices.sortByKey)(_ addChoices _)
// TODO https://github.com/digital-asset/daml/issues/11006
// encode interface methods as well
builder.build()
}

Expand Down Expand Up @@ -814,16 +816,17 @@ private[daml] class EncodeV1(minor: LV.Minor) {
b.accumulateLeft(template.choices.sortByKey)(_ addChoices _)
b.setObservers(template.observers)
template.key.foreach(b.setKey(_))
b.accumulateLeft(template.implements)(_ addImplements encodeTemplateImplements(_))
b.accumulateLeft(template.implements.values)(_ addImplements encodeTemplateImplements(_))
b.build()
}

// TODO https://github.com/digital-asset/daml/issues/11006
// encode rest of TemplateImplements
private implicit def encodeTemplateImplements(
name: Ref.TypeConName
impl: TemplateImplements
): PLF.DefTemplate.Implements = {
val b = PLF.DefTemplate.Implements.newBuilder()
b.setInterface(name)
b.setInterface(impl.interface)
b.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,11 @@ private[lf] final class Compiler(
addDef(compileKey(identifier, tmpl))
addDef(compileSignatories(identifier, tmpl))
addDef(compileObservers(identifier, tmpl))
tmpl.implements.foreach(x => addDef(compileImplements(identifier, x)))
tmpl.implements.values.foreach { impl =>
addDef(compileImplements(identifier, impl.interface))
// TODO https://github.com/digital-asset/daml/issues/11006
// compile methods also
}

tmpl.choices.values.foreach(x => addDef(compileChoice(identifier, tmpl, x)))

Expand Down Expand Up @@ -503,6 +507,9 @@ private[lf] final class Compiler(
compile(e) // interfaces have the same representation as underlying template
case EFromInterface(iface @ _, tpl, e) =>
SBFromInterface(tpl)(compile(e))
case ECallInterface(_, _, _) =>
// TODO https://github.com/digital-asset/daml/issues/11006
throw CompilationError("ECallInterface not implemented")
case EExperimental(name, _) =>
SBExperimental(name)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ object Ast {
/** Convert interface back to template payload if possible */
final case class EFromInterface(iface: TypeConName, tpl: TypeConName, value: Expr) extends Expr

/** Invoke an interface method */
final case class ECallInterface(iface: TypeConName, method: MethodName, value: Expr) extends Expr

//
// Kinds
//
Expand Down Expand Up @@ -637,18 +640,27 @@ object Ast {
type TemplateKeySignature = GenTemplateKey[Unit]
object TemplateKeySignature extends GenTemplateKeyCompanion[Unit]

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

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

Expand All @@ -660,6 +672,11 @@ object Ast {
// TODO interfaces Should observers or controllers be part of the interface?
)

case class InterfaceMethod(
name: MethodName,
returnType: Type,
)

case class GenTemplate[E] private[Ast] (
param: ExprVarName, // Binder for template argument.
precond: E, // Template creation precondition.
Expand All @@ -668,7 +685,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],
implements: Map[TypeConName, GenTemplateImplements[E]],
) extends NoCopy

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

val choiceMap = toMapWithoutDuplicate(
Expand All @@ -690,11 +707,10 @@ 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
val implementsMap = toMapWithoutDuplicate(
implements,
(ifaceName: TypeConName) =>
throw PackageError(s"repeated interface implementation ${ifaceName.toString}")
)

new GenTemplate[E](
Expand All @@ -705,7 +721,7 @@ object Ast {
choiceMap,
observers,
key,
implementsSet,
implementsMap,
)
}

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

Expand All @@ -731,7 +747,7 @@ object Ast {
Map[ChoiceName, GenTemplateChoice[E]],
E,
Option[GenTemplateKey[E]],
Set[TypeConName],
Map[TypeConName, GenTemplateImplements[E]],
)
] = Some(
(
Expand Down Expand Up @@ -809,6 +825,66 @@ object Ast {
type TemplateChoiceSignature = GenTemplateChoice[Unit]
object TemplateChoiceSignature extends GenTemplateChoiceCompanion[Unit]

case class GenTemplateImplements[E] private[Ast] (
interface: TypeConName,
methods: Map[MethodName, GenTemplateImplementsMethod[E]],
)

sealed class GenTemplateImplementsCompanion[E] {
def apply(
interface: TypeConName,
methods: Iterable[(MethodName, GenTemplateImplementsMethod[E])],
): GenTemplateImplements[E] = {
val methodMap = toMapWithoutDuplicate(
methods,
(methodName: MethodName) =>
throw PackageError(s"repeated method implementation ${methodName.toString}")
)
new GenTemplateImplements[E](interface, methodMap)
}

def apply(
interface: TypeConName,
methods: Map[MethodName, GenTemplateImplementsMethod[E]],
): GenTemplateImplements[E] =
GenTemplateImplements[E](interface, methods)

def unapply(
arg: GenTemplateImplements[E]
): Some[(TypeConName, Map[MethodName, GenTemplateImplementsMethod[E]])] =
Some((arg.interface, arg.methods))
}

type TemplateImplements = GenTemplateImplements[Expr]
object TemplateImplements extends GenTemplateImplementsCompanion[Expr]

type TemplateImplementsSignature = GenTemplateImplements[Unit]
object TemplateImplementsSignature extends GenTemplateImplementsCompanion[Unit]

case class GenTemplateImplementsMethod[E] private[Ast] (
name: MethodName,
value: E
)

sealed class GenTemplateImplementsMethodCompanion[E] {
def apply(
name: MethodName,
value: E,
): GenTemplateImplementsMethod[E] =
GenTemplateImplementsMethod[E](name, value)

def unapply(
arg: GenTemplateImplementsMethod[E]
): Some[(MethodName, E)] =
Some((arg.name, arg.value))
}

type TemplateImplementsMethod = GenTemplateImplementsMethod[Expr]
object TemplateImplementsMethod extends GenTemplateImplementsMethodCompanion[Expr]

type TemplateImplementsMethodSignature = GenTemplateImplementsMethod[Unit]
object TemplateImplementsMethodSignature extends GenTemplateImplementsMethodCompanion[Unit]

final case class GenDefException[E](message: E)

sealed class GenDefExceptionCompanion[E] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,12 @@ object Reference {
override def pretty: String = s"choice $choiceName in template $tyCon"
}

final case class Method(tyCon: TypeConName, methodName: MethodName) extends Reference {
override def pretty: String = s"method $methodName in interface $tyCon"
}

final case class Exception(tyCon: TypeConName) extends Reference {
override def pretty: String = s"exception: $tyCon"
override def pretty: String = s"exception $tyCon"
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -208,19 +208,34 @@ private[lf] class PackageInterface(signatures: PartialFunction[PackageId, Packag
lookupChoice(tmpName, chName, Reference.Choice(tmpName, chName))

private[this] def lookupInterfaceChoice(
tmpName: TypeConName,
ifaceName: TypeConName,
chName: ChoiceName,
context: => Reference,
): Either[LookupError, InterfaceChoice] =
lookupInterface(tmpName, context).flatMap(
_.choices.get(chName).toRight(LookupError(Reference.Choice(tmpName, chName), context))
lookupInterface(ifaceName, context).flatMap(
_.choices.get(chName).toRight(LookupError(Reference.Choice(ifaceName, chName), context))
)

def lookupInterfaceChoice(
tmpName: TypeConName,
ifaceName: TypeConName,
chName: ChoiceName,
): Either[LookupError, InterfaceChoice] =
lookupInterfaceChoice(tmpName, chName, Reference.Choice(tmpName, chName))
lookupInterfaceChoice(ifaceName, chName, Reference.Choice(ifaceName, chName))

private[this] def lookupInterfaceMethod(
ifaceName: TypeConName,
methodName: MethodName,
context: => Reference,
): Either[LookupError, InterfaceMethod] =
lookupInterface(ifaceName, context).flatMap(
_.methods.get(methodName).toRight(LookupError(Reference.Method(ifaceName, methodName), context))
)

def lookupInterfaceMethod(
ifaceName: TypeConName,
methodName: MethodName
): Either[LookupError, InterfaceMethod] =
lookupInterfaceMethod(ifaceName, methodName, Reference.Method(ifaceName, methodName))

private[this] def lookupTemplateKey(
name: TypeConName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,18 @@ object Util {
TemplateKeySignature(typ, (), ())
}

private[this] def toSignature(implementsMethod: TemplateImplementsMethod): TemplateImplementsMethodSignature =
implementsMethod match {
case TemplateImplementsMethod(name, _) =>
TemplateImplementsMethodSignature(name, ())
}

private[this] def toSignature(implements: TemplateImplements): TemplateImplementsSignature =
implements match {
case TemplateImplements(name, methods) =>
TemplateImplementsSignature(name, methods.transform((_, v) => toSignature(v)))
}

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

Expand Down
Loading

0 comments on commit 737a7f2

Please sign in to comment.