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:
Moisés Ackerman 2022-06-23 19:13:38 +02:00 committed by GitHub
parent d74af21e90
commit 0d1ef10472
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 424 additions and 16 deletions

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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 };

View File

@ -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.

View File

@ -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)),
)
}

View File

@ -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(

View File

@ -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)) },
)
}
}

View File

@ -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")

View File

@ -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")

View File

@ -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,

View File

@ -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] =

View File

@ -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] =