mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
Retroactive Implements - Scala side (#14130)
* Add CoImplements to daml-lf AST * Add AstSpec case for duplicate co-implements in interface * Add placeholders for CoImplements in daml-lf validation * Handle CoImplements in daml-lf iterators * Handle CoImplements in daml-lf scala decoder * Test DefInterface components in DecodeV1Spec * Handle CoImplements in daml-lf (testing) parser * Handle CoImplements in daml-lf (testing) encoder changelog_begin changelog_end
This commit is contained in:
parent
d74af21e90
commit
0d1ef10472
@ -658,7 +658,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
|
||||
): DefException =
|
||||
DefException(decodeExpr(lfException.getMessage, s"$exceptionName:message"))
|
||||
|
||||
private[this] def decodeDefInterface(
|
||||
private[lf] def decodeDefInterface(
|
||||
id: DottedName,
|
||||
lfInterface: PLF.DefInterface,
|
||||
): DefInterface =
|
||||
@ -668,6 +668,7 @@ private[archive] class DecodeV1(minor: LV.Minor) {
|
||||
choices = lfInterface.getChoicesList.asScala.view.map(decodeChoice(id, _)),
|
||||
methods = lfInterface.getMethodsList.asScala.view.map(decodeInterfaceMethod),
|
||||
precond = decodeExpr(lfInterface.getPrecond, s"$id:ensure"),
|
||||
coImplements = lfInterface.getCoImplementsList.asScala.view.map(decodeInterfaceCoImplements),
|
||||
)
|
||||
|
||||
private[this] def decodeInterfaceMethod(
|
||||
@ -678,6 +679,23 @@ private[archive] class DecodeV1(minor: LV.Minor) {
|
||||
returnType = decodeType(lfMethod.getType),
|
||||
)
|
||||
|
||||
private[this] def decodeInterfaceCoImplements(
|
||||
lfCoImpl: PLF.DefInterface.CoImplements
|
||||
): InterfaceCoImplements =
|
||||
InterfaceCoImplements.build(
|
||||
templateId = decodeTypeConName(lfCoImpl.getTemplate),
|
||||
methods = lfCoImpl.getMethodsList.asScala.view.map(decodeInterfaceCoImplementsMethod),
|
||||
)
|
||||
|
||||
private[this] def decodeInterfaceCoImplementsMethod(
|
||||
lfMethod: PLF.DefInterface.CoImplementsMethod
|
||||
): InterfaceCoImplementsMethod =
|
||||
InterfaceCoImplementsMethod(
|
||||
methodName =
|
||||
getInternedName(lfMethod.getMethodInternedName, "InterfaceCoImplementsMethod.name"),
|
||||
value = decodeExpr(lfMethod.getValue, "InterfaceCoImplementsMethod.value"),
|
||||
)
|
||||
|
||||
private[lf] def decodeKind(lfKind: PLF.Kind): Kind =
|
||||
lfKind.getSumCase match {
|
||||
case PLF.Kind.SumCase.STAR => KStar
|
||||
|
@ -25,6 +25,7 @@ import com.daml.lf.language.Ast.{
|
||||
EUnsafeFromRequiredInterface,
|
||||
FeatureFlags,
|
||||
GenDefInterface,
|
||||
InterfaceMethod,
|
||||
GenModule,
|
||||
GenTemplate,
|
||||
GenTemplateImplements,
|
||||
@ -52,9 +53,19 @@ class DecodeV1Spec
|
||||
.newBuilder()
|
||||
.setPrim(DamlLf1.Type.Prim.newBuilder().setPrim(DamlLf1.PrimType.UNIT))
|
||||
.build()
|
||||
val boolTyp: DamlLf1.Type = DamlLf1.Type
|
||||
.newBuilder()
|
||||
.setPrim(DamlLf1.Type.Prim.newBuilder().setPrim(DamlLf1.PrimType.BOOL))
|
||||
.build()
|
||||
val textTyp: DamlLf1.Type = DamlLf1.Type
|
||||
.newBuilder()
|
||||
.setPrim(DamlLf1.Type.Prim.newBuilder().setPrim(DamlLf1.PrimType.TEXT))
|
||||
.build()
|
||||
|
||||
val typeTable = ImmArraySeq(TUnit)
|
||||
val typeTable = ImmArraySeq(TUnit, TBool, TText)
|
||||
val unitTypInterned = DamlLf1.Type.newBuilder().setInterned(0).build()
|
||||
val boolTypInterned = DamlLf1.Type.newBuilder().setInterned(1).build()
|
||||
val textTypInterned = DamlLf1.Type.newBuilder().setInterned(2).build()
|
||||
|
||||
val unitExpr: DamlLf1.Expr = DamlLf1.Expr
|
||||
.newBuilder()
|
||||
@ -1050,6 +1061,7 @@ class DecodeV1Spec
|
||||
Map(),
|
||||
Map(),
|
||||
EPrimCon(PCUnit),
|
||||
Map(),
|
||||
)
|
||||
),
|
||||
FeatureFlags(),
|
||||
@ -1072,6 +1084,137 @@ class DecodeV1Spec
|
||||
}
|
||||
}
|
||||
|
||||
s"Decode interface definitions correctly iff version >= ${LV.Features.interfaces}" in {
|
||||
|
||||
val unit = DamlLf1.Unit.newBuilder()
|
||||
val pkgRef = DamlLf1.PackageRef.newBuilder().setSelf(unit)
|
||||
val modRef =
|
||||
DamlLf1.ModuleRef.newBuilder().setPackageRef(pkgRef).setModuleNameInternedDname(0)
|
||||
|
||||
val emptyDefInterface = DamlLf1.DefInterface
|
||||
.newBuilder()
|
||||
.setTyconInternedDname(1)
|
||||
.setParamInternedStr(0)
|
||||
.setPrecond(unitExpr)
|
||||
.build()
|
||||
|
||||
val emptyDefInterfaceScala =
|
||||
GenDefInterface(
|
||||
Set.empty,
|
||||
Ref.IdString.Name.assertFromString("this"),
|
||||
Map(),
|
||||
Map(),
|
||||
EPrimCon(PCUnit),
|
||||
Map(),
|
||||
)
|
||||
|
||||
val requiresDefInterface = {
|
||||
val typeConNameJ =
|
||||
DamlLf1.TypeConName.newBuilder().setModule(modRef).setNameInternedDname(3)
|
||||
val typeConNameK =
|
||||
DamlLf1.TypeConName.newBuilder().setModule(modRef).setNameInternedDname(4)
|
||||
|
||||
DamlLf1.DefInterface
|
||||
.newBuilder()
|
||||
.setTyconInternedDname(1)
|
||||
.setParamInternedStr(0)
|
||||
.setPrecond(unitExpr)
|
||||
.addRequires(typeConNameJ)
|
||||
.addRequires(typeConNameK)
|
||||
.build()
|
||||
}
|
||||
|
||||
val requiresDefInterfaceScala =
|
||||
GenDefInterface(
|
||||
Set(
|
||||
Ref.TypeConName.assertFromString("noPkgId:Mod:J"),
|
||||
Ref.TypeConName.assertFromString("noPkgId:Mod:K"),
|
||||
),
|
||||
Ref.IdString.Name.assertFromString("this"),
|
||||
Map(),
|
||||
Map(),
|
||||
EPrimCon(PCUnit),
|
||||
Map(),
|
||||
)
|
||||
|
||||
val methodsDefInterface = {
|
||||
val interfaceMethod1 =
|
||||
DamlLf1.InterfaceMethod.newBuilder().setMethodInternedName(1).setType(textTypInterned)
|
||||
val interfaceMethod2 =
|
||||
DamlLf1.InterfaceMethod.newBuilder().setMethodInternedName(2).setType(boolTypInterned)
|
||||
|
||||
DamlLf1.DefInterface
|
||||
.newBuilder()
|
||||
.setTyconInternedDname(1)
|
||||
.setParamInternedStr(0)
|
||||
.setPrecond(unitExpr)
|
||||
.addMethods(interfaceMethod1)
|
||||
.addMethods(interfaceMethod2)
|
||||
.build()
|
||||
}
|
||||
|
||||
val methodsDefInterfaceScala = {
|
||||
val methodName1 = Ref.MethodName.assertFromString("method1")
|
||||
val methodName2 = Ref.MethodName.assertFromString("method2")
|
||||
|
||||
GenDefInterface(
|
||||
Set.empty,
|
||||
Ref.IdString.Name.assertFromString("this"),
|
||||
Map(),
|
||||
Map(
|
||||
methodName1 -> InterfaceMethod(methodName1, TText),
|
||||
methodName2 -> InterfaceMethod(methodName2, TBool),
|
||||
),
|
||||
EPrimCon(PCUnit),
|
||||
Map(),
|
||||
)
|
||||
}
|
||||
|
||||
val coImplementsDefInterface = DamlLf1.DefInterface
|
||||
.newBuilder()
|
||||
.setTyconInternedDname(1)
|
||||
.setParamInternedStr(0)
|
||||
.setPrecond(unitExpr)
|
||||
.build()
|
||||
|
||||
val coImplementsDefInterfaceScala =
|
||||
GenDefInterface(
|
||||
Set.empty,
|
||||
Ref.IdString.Name.assertFromString("this"),
|
||||
Map(),
|
||||
Map(),
|
||||
EPrimCon(PCUnit),
|
||||
Map(),
|
||||
)
|
||||
|
||||
val interfaceDefTestCases = {
|
||||
Table(
|
||||
"input" -> "expected output",
|
||||
emptyDefInterface -> emptyDefInterfaceScala,
|
||||
requiresDefInterface -> requiresDefInterfaceScala,
|
||||
methodsDefInterface -> methodsDefInterfaceScala,
|
||||
coImplementsDefInterface -> coImplementsDefInterfaceScala,
|
||||
)
|
||||
}
|
||||
|
||||
val interfaceName = Ref.DottedName.assertFromString("I")
|
||||
|
||||
val interfaceDefStringTable = ImmArraySeq("this", "method1", "method2")
|
||||
|
||||
val interfaceDefDottedNameTable =
|
||||
ImmArraySeq("Mod", "T", "I", "J", "K").map(Ref.DottedName.assertFromString)
|
||||
|
||||
val interfaceDefDecoder =
|
||||
(version: LV) =>
|
||||
moduleDecoder(version, interfaceDefStringTable, interfaceDefDottedNameTable, typeTable)
|
||||
|
||||
forEveryVersionSuchThat(_ >= LV.Features.interfaces) { version =>
|
||||
forEvery(interfaceDefTestCases) { (proto, scala) =>
|
||||
interfaceDefDecoder(version).decodeDefInterface(interfaceName, proto) shouldBe scala
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val interfacePrimitivesDottedNameTable =
|
||||
ImmArraySeq("Mod", "T", "I", "J").map(Ref.DottedName.assertFromString)
|
||||
|
||||
|
@ -802,6 +802,7 @@ private[daml] class EncodeV1(minor: LV.Minor) {
|
||||
builder.accumulateLeft(interface.methods.sortByKey)(_ addMethods _)
|
||||
builder.accumulateLeft(interface.requires)(_ addRequires _)
|
||||
builder.setPrecond(interface.precond)
|
||||
builder.accumulateLeft(interface.coImplements.sortByKey)(_ addCoImplements _)
|
||||
builder.build()
|
||||
}
|
||||
|
||||
@ -815,6 +816,26 @@ private[daml] class EncodeV1(minor: LV.Minor) {
|
||||
b.build()
|
||||
}
|
||||
|
||||
private implicit def encodeInterfaceCoImplements(
|
||||
templateWithCoImplements: (TypeConName, InterfaceCoImplements)
|
||||
): PLF.DefInterface.CoImplements = {
|
||||
val (template, coImplements) = templateWithCoImplements
|
||||
val b = PLF.DefInterface.CoImplements.newBuilder()
|
||||
b.setTemplate(template)
|
||||
b.accumulateLeft(coImplements.methods.sortByKey)(_ addMethods _)
|
||||
b.build()
|
||||
}
|
||||
|
||||
private implicit def encodeInterfaceCoImplementsMethod(
|
||||
nameWithMethod: (MethodName, InterfaceCoImplementsMethod)
|
||||
): PLF.DefInterface.CoImplementsMethod = {
|
||||
val (name, method) = nameWithMethod
|
||||
val b = PLF.DefInterface.CoImplementsMethod.newBuilder()
|
||||
b.setMethodInternedName(stringsTable.insert(name))
|
||||
b.setValue(method.value)
|
||||
b.build()
|
||||
}
|
||||
|
||||
private implicit def encodeSynonymDef(nameWithDef: (DottedName, DTypeSyn)): PLF.DefTypeSyn = {
|
||||
val (dottedName, typeSyn) = nameWithDef
|
||||
val builder = PLF.DefTypeSyn.newBuilder()
|
||||
|
@ -15,6 +15,9 @@ module InterfaceMod {
|
||||
, controllers Cons @Party [call_method @InterfaceMod:Boxy getParty this] (Nil @Party)
|
||||
, observers Nil @Party
|
||||
to upure @Int64 i;
|
||||
coimplements Other:Package {
|
||||
method getParty = Other:Package {party} this;
|
||||
};
|
||||
};
|
||||
|
||||
record @serializable Box = { party: Party, name: Text };
|
||||
|
@ -702,6 +702,9 @@ object Ast {
|
||||
choices: Map[ChoiceName, GenTemplateChoice[E]],
|
||||
methods: Map[MethodName, InterfaceMethod],
|
||||
precond: E, // Interface creation precondition.
|
||||
coImplements: Map[TypeConName, GenInterfaceCoImplements[
|
||||
E
|
||||
]],
|
||||
)
|
||||
|
||||
final class GenDefInterfaceCompanion[E] {
|
||||
@ -712,6 +715,7 @@ object Ast {
|
||||
choices: Iterable[GenTemplateChoice[E]],
|
||||
methods: Iterable[InterfaceMethod],
|
||||
precond: E,
|
||||
coImplements: Iterable[GenInterfaceCoImplements[E]],
|
||||
): GenDefInterface[E] = {
|
||||
val requiresSet = toSetWithoutDuplicate(
|
||||
requires,
|
||||
@ -725,7 +729,12 @@ object Ast {
|
||||
methods.view.map(c => c.name -> c),
|
||||
(name: MethodName) => PackageError(s"collision on interface method name $name"),
|
||||
)
|
||||
GenDefInterface(requiresSet, param, choiceMap, methodMap, precond)
|
||||
val coImplementsMap = toMapWithoutDuplicate(
|
||||
coImplements.view.map(c => c.templateId -> c),
|
||||
(templateId: TypeConName) =>
|
||||
PackageError(s"repeated interface co-implementation ${templateId.toString}"),
|
||||
)
|
||||
GenDefInterface(requiresSet, param, choiceMap, methodMap, precond, coImplementsMap)
|
||||
}
|
||||
|
||||
def apply(
|
||||
@ -734,8 +743,9 @@ object Ast {
|
||||
choices: Map[ChoiceName, GenTemplateChoice[E]],
|
||||
methods: Map[MethodName, InterfaceMethod],
|
||||
precond: E,
|
||||
coImplements: Map[TypeConName, GenInterfaceCoImplements[E]],
|
||||
): GenDefInterface[E] =
|
||||
GenDefInterface(requires, param, choices, methods, precond)
|
||||
GenDefInterface(requires, param, choices, methods, precond, coImplements)
|
||||
|
||||
def unapply(arg: GenDefInterface[E]): Some[
|
||||
(
|
||||
@ -744,9 +754,10 @@ object Ast {
|
||||
Map[ChoiceName, GenTemplateChoice[E]],
|
||||
Map[MethodName, InterfaceMethod],
|
||||
E,
|
||||
Map[TypeConName, GenInterfaceCoImplements[E]],
|
||||
)
|
||||
] =
|
||||
Some((arg.requires, arg.param, arg.choices, arg.methods, arg.precond))
|
||||
Some((arg.requires, arg.param, arg.choices, arg.methods, arg.precond, arg.coImplements))
|
||||
}
|
||||
|
||||
type DefInterface = GenDefInterface[Expr]
|
||||
@ -760,6 +771,64 @@ object Ast {
|
||||
returnType: Type,
|
||||
)
|
||||
|
||||
final case class GenInterfaceCoImplements[E](
|
||||
templateId: TypeConName,
|
||||
methods: Map[MethodName, GenInterfaceCoImplementsMethod[E]],
|
||||
)
|
||||
|
||||
final class GenInterfaceCoImplementsCompanion[E] private[Ast] {
|
||||
@throws[PackageError]
|
||||
def build(
|
||||
templateId: TypeConName,
|
||||
methods: Iterable[GenInterfaceCoImplementsMethod[E]],
|
||||
): GenInterfaceCoImplements[E] =
|
||||
new GenInterfaceCoImplements[E](
|
||||
templateId = templateId,
|
||||
methods = toMapWithoutDuplicate(
|
||||
methods.map(m => m.name -> m),
|
||||
(name: MethodName) => PackageError(s"repeated method co-implementation $name"),
|
||||
),
|
||||
)
|
||||
|
||||
def apply(
|
||||
templateId: TypeConName,
|
||||
methods: Map[MethodName, GenInterfaceCoImplementsMethod[E]],
|
||||
): GenInterfaceCoImplements[E] =
|
||||
GenInterfaceCoImplements[E](templateId, methods)
|
||||
|
||||
def unapply(
|
||||
arg: GenInterfaceCoImplements[E]
|
||||
): Some[(TypeConName, Map[MethodName, GenInterfaceCoImplementsMethod[E]])] =
|
||||
Some((arg.templateId, arg.methods))
|
||||
}
|
||||
|
||||
type InterfaceCoImplements = GenInterfaceCoImplements[Expr]
|
||||
val InterfaceCoImplements = new GenInterfaceCoImplementsCompanion[Expr]
|
||||
|
||||
type InterfaceCoImplementsSignature = GenInterfaceCoImplements[Unit]
|
||||
val InterfaceCoImplementsSignature = new GenInterfaceCoImplementsCompanion[Unit]
|
||||
|
||||
final case class GenInterfaceCoImplementsMethod[E](
|
||||
name: MethodName,
|
||||
value: E,
|
||||
)
|
||||
|
||||
final class GenInterfaceCoImplementsMethodCompanion[E] {
|
||||
def apply(methodName: MethodName, value: E): GenInterfaceCoImplementsMethod[E] =
|
||||
GenInterfaceCoImplementsMethod[E](methodName, value)
|
||||
|
||||
def unapply(
|
||||
arg: GenInterfaceCoImplementsMethod[E]
|
||||
): Some[(MethodName, E)] =
|
||||
Some((arg.name, arg.value))
|
||||
}
|
||||
|
||||
type InterfaceCoImplementsMethod = GenInterfaceCoImplementsMethod[Expr]
|
||||
val InterfaceCoImplementsMethod = new GenInterfaceCoImplementsMethodCompanion[Expr]
|
||||
|
||||
type InterfaceCoImplementsMethodSignature = GenInterfaceCoImplementsMethod[Unit]
|
||||
val InterfaceCoImplementsMethodSignature = new GenInterfaceCoImplementsMethodCompanion[Unit]
|
||||
|
||||
final case class GenTemplate[E](
|
||||
param: ExprVarName, // Binder for template argument.
|
||||
precond: E, // Template creation precondition.
|
||||
|
@ -244,15 +244,35 @@ object Util {
|
||||
)
|
||||
}
|
||||
|
||||
private[this] def toSignature(
|
||||
coImplementsMethod: InterfaceCoImplementsMethod
|
||||
): InterfaceCoImplementsMethodSignature =
|
||||
coImplementsMethod match {
|
||||
case InterfaceCoImplementsMethod(name, _) =>
|
||||
InterfaceCoImplementsMethodSignature(name, ())
|
||||
}
|
||||
|
||||
private[this] def toSignature(
|
||||
coImplements: InterfaceCoImplements
|
||||
): InterfaceCoImplementsSignature =
|
||||
coImplements match {
|
||||
case InterfaceCoImplements(name, methods) =>
|
||||
InterfaceCoImplementsSignature(
|
||||
name,
|
||||
methods.transform((_, v) => toSignature(v)),
|
||||
)
|
||||
}
|
||||
|
||||
private def toSignature(interface: DefInterface): DefInterfaceSignature =
|
||||
interface match {
|
||||
case DefInterface(requires, param, choices, methods, _) =>
|
||||
case DefInterface(requires, param, choices, methods, _, coImplements) =>
|
||||
DefInterfaceSignature(
|
||||
requires,
|
||||
param,
|
||||
choices.transform((_, choice) => toSignature(choice)),
|
||||
methods,
|
||||
(),
|
||||
coImplements.transform((_, v) => toSignature(v)),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
choices = Map.empty,
|
||||
methods = Map.empty,
|
||||
requires = Set.empty,
|
||||
coImplements = Map.empty,
|
||||
)
|
||||
|
||||
def exception = DefException(
|
||||
@ -381,6 +382,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
),
|
||||
methods = List(ifaceMethod1, ifaceMethod2),
|
||||
precond = ETrue,
|
||||
coImplements = List.empty,
|
||||
)
|
||||
}
|
||||
|
||||
@ -396,6 +398,7 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
),
|
||||
methods = List.empty,
|
||||
precond = ETrue,
|
||||
coImplements = List.empty,
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -408,6 +411,29 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
choices = List.empty,
|
||||
methods = List(ifaceMethod1, ifaceMethod1),
|
||||
precond = ETrue,
|
||||
coImplements = List.empty,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"catch duplicate co-implementation" in {
|
||||
DefInterface.build(
|
||||
requires = List.empty,
|
||||
param = Name.assertFromString("x"),
|
||||
choices = List.empty,
|
||||
methods = List(ifaceMethod1, ifaceMethod2),
|
||||
precond = ETrue,
|
||||
coImplements = List(ifaceCoImpl1, ifaceCoImpl2),
|
||||
)
|
||||
|
||||
a[PackageError] shouldBe thrownBy(
|
||||
DefInterface.build(
|
||||
requires = List.empty,
|
||||
param = Name.assertFromString("x"),
|
||||
choices = List.empty,
|
||||
methods = List(ifaceMethod1, ifaceMethod2),
|
||||
precond = ETrue,
|
||||
coImplements = List(ifaceCoImpl1, ifaceCoImpl1),
|
||||
)
|
||||
)
|
||||
}
|
||||
@ -426,6 +452,14 @@ class AstSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matchers {
|
||||
interfaceId = TypeConName.assertFromString("pkgId:Mod:I2"),
|
||||
methods = Map.empty,
|
||||
)
|
||||
private val ifaceCoImpl1 = InterfaceCoImplements(
|
||||
templateId = TypeConName.assertFromString("pkgId:Mod:T1"),
|
||||
methods = Map.empty,
|
||||
)
|
||||
private val ifaceCoImpl2 = InterfaceCoImplements(
|
||||
templateId = TypeConName.assertFromString("pkgId:Mod:T2"),
|
||||
methods = Map.empty,
|
||||
)
|
||||
private val ifaceMethod1 = InterfaceMethod(name = Name.assertFromString("x"), returnType = TUnit)
|
||||
private val ifaceMethod2 = InterfaceMethod(name = Name.assertFromString("y"), returnType = TUnit)
|
||||
private def choiceBuilder(name: ChoiceName, typ: Type, expr: Expr) = TemplateChoice(
|
||||
|
@ -274,7 +274,7 @@ private[daml] class AstRewriter(
|
||||
},
|
||||
apply(observers),
|
||||
key.map(apply),
|
||||
implements.map({ case (t, x) => (apply(t), apply(x)) }),
|
||||
implements.map { case (t, x) => (apply(t), apply(x)) },
|
||||
)
|
||||
}
|
||||
|
||||
@ -342,15 +342,39 @@ private[daml] class AstRewriter(
|
||||
InterfaceMethod(name, apply(returnType))
|
||||
}
|
||||
|
||||
def apply(x: InterfaceCoImplements): InterfaceCoImplements =
|
||||
x match {
|
||||
case InterfaceCoImplements(
|
||||
templateId,
|
||||
methods,
|
||||
) =>
|
||||
InterfaceCoImplements(
|
||||
apply(templateId),
|
||||
methods.transform((_, x) => apply(x)),
|
||||
)
|
||||
}
|
||||
def apply(x: InterfaceCoImplementsMethod): InterfaceCoImplementsMethod =
|
||||
x match {
|
||||
case InterfaceCoImplementsMethod(
|
||||
name,
|
||||
value,
|
||||
) =>
|
||||
InterfaceCoImplementsMethod(
|
||||
name,
|
||||
apply(value),
|
||||
)
|
||||
}
|
||||
|
||||
def apply(x: DefInterface): DefInterface =
|
||||
x match {
|
||||
case DefInterface(requires, param, choices, methods, precond) =>
|
||||
case DefInterface(requires, param, choices, methods, precond, coImplements) =>
|
||||
DefInterface(
|
||||
requires.map(apply(_)),
|
||||
param,
|
||||
choices.transform((_, v) => apply(v)),
|
||||
methods.transform((_, v) => apply(v)),
|
||||
apply(precond),
|
||||
coImplements.map { case (t, x) => (apply(t), apply(x)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -201,16 +201,18 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
|
||||
rep(interfaceRequires <~ `;`) ~
|
||||
(Id("precondition") ~> expr <~ `;`) ~
|
||||
rep(interfaceMethod <~ `;`) ~
|
||||
rep(templateChoice <~ `;`) <~
|
||||
rep(templateChoice <~ `;`) ~
|
||||
rep(coImplements <~ `;`) <~
|
||||
`}` ^^ {
|
||||
case x ~ _ ~ tycon ~ _ ~ _ ~ _ ~
|
||||
requires ~
|
||||
precond ~
|
||||
methods ~
|
||||
choices =>
|
||||
choices ~
|
||||
coImplements =>
|
||||
IfaceDef(
|
||||
tycon,
|
||||
DefInterface.build(Set.from(requires), x, choices, methods, precond),
|
||||
DefInterface.build(Set.from(requires), x, choices, methods, precond, coImplements),
|
||||
)
|
||||
}
|
||||
private val interfaceRequires: Parser[Ref.TypeConName] =
|
||||
@ -221,6 +223,17 @@ private[parser] class ModParser[P](parameters: ParserParameters[P]) {
|
||||
InterfaceMethod(name, typ)
|
||||
}
|
||||
|
||||
private lazy val coImplementsMethod: Parser[InterfaceCoImplementsMethod] =
|
||||
Id("method") ~>! id ~ `=` ~ expr ^^ { case (name ~ _ ~ value) =>
|
||||
InterfaceCoImplementsMethod(name, value)
|
||||
}
|
||||
|
||||
private lazy val coImplements: Parser[InterfaceCoImplements] =
|
||||
Id("coimplements") ~>! fullIdentifier ~ (`{` ~> rep(coImplementsMethod <~ `;`) <~ `}`) ^^ {
|
||||
case tplId ~ methods =>
|
||||
InterfaceCoImplements.build(tplId, methods)
|
||||
}
|
||||
|
||||
private val serializableTag = Ref.Name.assertFromString("serializable")
|
||||
private val isTestTag = Ref.Name.assertFromString("isTest")
|
||||
private val nonConsumingTag = Ref.Name.assertFromString("nonConsuming")
|
||||
|
@ -795,10 +795,15 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
|
||||
, controllers Cons @Party [call_method @Mod:Person asParty this] (Nil @Party)
|
||||
, observers Nil @Party
|
||||
to upure @Int64 i;
|
||||
coimplements Mod1:Company {
|
||||
method asParty = Mod1:Company {party} this;
|
||||
method getName = Mod1:Company {legalName} this;
|
||||
};
|
||||
} ;
|
||||
}
|
||||
|
||||
"""
|
||||
val TTyCon(company) = t"Mod1:Company"
|
||||
|
||||
val interface =
|
||||
DefInterface(
|
||||
@ -831,6 +836,22 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher
|
||||
update = e"upure @Int64 i",
|
||||
),
|
||||
),
|
||||
coImplements = Map(
|
||||
company ->
|
||||
InterfaceCoImplements(
|
||||
company,
|
||||
Map(
|
||||
n"asParty" -> InterfaceCoImplementsMethod(
|
||||
n"asParty",
|
||||
e"Mod1:Company {party} this",
|
||||
),
|
||||
n"getName" -> InterfaceCoImplementsMethod(
|
||||
n"getName",
|
||||
e"Mod1:Company {legalName} this",
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
val person = DottedName.assertFromString("Person")
|
||||
|
@ -14,6 +14,8 @@ import com.daml.scalautil.Statement.discard
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
import annotation.nowarn
|
||||
|
||||
private[validation] object Typing {
|
||||
|
||||
import Util.handleLookup
|
||||
@ -458,7 +460,7 @@ private[validation] object Typing {
|
||||
|
||||
private[Typing] def checkDefIface(ifaceName: TypeConName, iface: DefInterface): Unit =
|
||||
iface match {
|
||||
case DefInterface(requires, param, choices, methods, precond) =>
|
||||
case DefInterface(requires, param, choices, methods, precond, coImplements) =>
|
||||
val env = introExprVar(param, TTyCon(ifaceName))
|
||||
if (requires(ifaceName))
|
||||
throw ECircularInterfaceRequires(ctx, ifaceName)
|
||||
@ -470,6 +472,7 @@ private[validation] object Typing {
|
||||
env.checkExpr(precond, TBool)
|
||||
methods.values.foreach(checkIfaceMethod)
|
||||
choices.values.foreach(env.checkChoice(ifaceName, _))
|
||||
env.checkIfaceCoImplementations(ifaceName, coImplements)
|
||||
}
|
||||
|
||||
private def checkIfaceMethod(method: InterfaceMethod): Unit = {
|
||||
@ -486,7 +489,7 @@ private[validation] object Typing {
|
||||
): Unit = {
|
||||
|
||||
impls.foreach { case (iface, impl) =>
|
||||
val DefInterfaceSignature(requires, _, _, methods, _) =
|
||||
val DefInterfaceSignature(requires, _, _, methods, _, _) =
|
||||
handleLookup(ctx, interface.lookupInterface(impl.interfaceId))
|
||||
|
||||
requires
|
||||
@ -508,6 +511,14 @@ private[validation] object Typing {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (MA): https://github.com/digital-asset/daml/issues/14047
|
||||
@nowarn("cat=unused&msg=parameter value ifaceTcon in method")
|
||||
@nowarn("cat=unused&msg=parameter value coImpls in method")
|
||||
private def checkIfaceCoImplementations(
|
||||
ifaceTcon: TypeConName,
|
||||
coImpls: Map[TypeConName, InterfaceCoImplements],
|
||||
): Unit = {}
|
||||
|
||||
private[Typing] def checkDefException(
|
||||
excepName: TypeConName,
|
||||
defException: DefException,
|
||||
|
@ -220,8 +220,25 @@ private[validation] object ExprIterable {
|
||||
choices,
|
||||
methods @ _,
|
||||
precond,
|
||||
coImplements,
|
||||
) =>
|
||||
Iterator(precond) ++ choices.values.iterator.flatMap(iterator(_))
|
||||
Iterator(precond) ++ choices.values.iterator.flatMap(iterator(_)) ++
|
||||
coImplements.values.iterator.flatMap(iterator(_))
|
||||
}
|
||||
|
||||
private[iterable] def iterator(x: InterfaceCoImplements): Iterator[Expr] =
|
||||
x match {
|
||||
case InterfaceCoImplements(
|
||||
template @ _,
|
||||
methods,
|
||||
) =>
|
||||
methods.values.iterator.flatMap(iterator(_))
|
||||
}
|
||||
|
||||
private[iterable] def iterator(x: InterfaceCoImplementsMethod): Iterator[Expr] =
|
||||
x match {
|
||||
case InterfaceCoImplementsMethod(name @ _, value) =>
|
||||
Iterator(value)
|
||||
}
|
||||
|
||||
def apply(expr: Expr): Iterable[Expr] =
|
||||
|
@ -255,13 +255,27 @@ private[validation] object TypeIterable {
|
||||
iterator(value)
|
||||
}
|
||||
|
||||
private[validation] def iterator(coImpl: InterfaceCoImplements): Iterator[Type] =
|
||||
coImpl match {
|
||||
case InterfaceCoImplements(template, methods) =>
|
||||
Iterator(TTyCon(template)) ++
|
||||
methods.values.flatMap(iterator)
|
||||
}
|
||||
|
||||
private[validation] def iterator(method: InterfaceCoImplementsMethod): Iterator[Type] =
|
||||
method match {
|
||||
case InterfaceCoImplementsMethod(name @ _, value) =>
|
||||
iterator(value)
|
||||
}
|
||||
|
||||
private[validation] def iterator(interface: DefInterface): Iterator[Type] =
|
||||
interface match {
|
||||
case DefInterface(requires, _, choices, methods, precond) =>
|
||||
case DefInterface(requires, _, choices, methods, precond, coImplements) =>
|
||||
requires.iterator.map(TTyCon) ++
|
||||
iterator(precond) ++
|
||||
choices.values.iterator.flatMap(iterator) ++
|
||||
methods.values.iterator.flatMap(iterator)
|
||||
methods.values.iterator.flatMap(iterator) ++
|
||||
coImplements.values.flatMap(iterator)
|
||||
}
|
||||
|
||||
private[validation] def iterator(imethod: InterfaceMethod): Iterator[Type] =
|
||||
|
Loading…
Reference in New Issue
Block a user