mirror of
https://github.com/digital-asset/daml.git
synced 2024-11-04 00:36:58 +03:00
Revert "remove support of retroactie interface instance in api-type-s… (#18856)
* Revert "remove support of retroactie interface instance in api-type-signature (#18382)"
This commit is contained in:
parent
179183441a
commit
d786b53522
@ -12,7 +12,17 @@ import scalaz.syntax.semigroup._
|
||||
import scalaz.syntax.traverse._
|
||||
import scalaz.syntax.std.map._
|
||||
import scalaz.syntax.std.option._
|
||||
import scalaz.{Applicative, Bifunctor, Bitraverse, Bifoldable, Foldable, Functor, Monoid, Traverse}
|
||||
import scalaz.{
|
||||
Applicative,
|
||||
Bifunctor,
|
||||
Bitraverse,
|
||||
Bifoldable,
|
||||
Foldable,
|
||||
Functor,
|
||||
Monoid,
|
||||
Semigroup,
|
||||
Traverse,
|
||||
}
|
||||
import scalaz.Tags.FirstVal
|
||||
import java.{util => j}
|
||||
|
||||
@ -203,6 +213,29 @@ final case class DefTemplate[+Ty](
|
||||
}
|
||||
|
||||
def getKey: j.Optional[_ <: Ty] = key.toJava
|
||||
|
||||
private[typesig] def extendWithInterface[OTy >: Ty](
|
||||
ifaceName: Ref.TypeConName,
|
||||
ifc: DefInterface[OTy],
|
||||
): DefTemplate[OTy] = {
|
||||
import TemplateChoices.{Resolved, Unresolved}
|
||||
copy(
|
||||
implementedInterfaces = implementedInterfaces :+ ifaceName,
|
||||
tChoices = tChoices match {
|
||||
case unr @ Unresolved(_, sources) =>
|
||||
unr.copy(unresolvedChoiceSources = sources incl ifaceName)
|
||||
// If unresolved, we need only add ifc as a future interface to resolve;
|
||||
// otherwise, we must self-resolve and add to preexisting resolutions
|
||||
case r @ Resolved(rc) =>
|
||||
type K[C] = Semigroup[Resolved.Choices[C]]
|
||||
r.copy(resolvedChoices =
|
||||
FirstVal
|
||||
.unsubst[K, TemplateChoice[OTy]](Semigroup.apply)
|
||||
.append(rc, ifc choicesAsResolved ifaceName)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object DefTemplate {
|
||||
@ -282,16 +315,14 @@ sealed abstract class TemplateChoices[+Ty] extends Product with Serializable {
|
||||
): Either[ResolveError[Resolved[O]], Resolved[O]] = this match {
|
||||
case Unresolved(direct, unresolved) =>
|
||||
val getAstInterface = astInterfaces.lift
|
||||
type ResolutionResult[C] =
|
||||
(Set[Ref.TypeConName], Map[Ref.ChoiceName, NonEmpty[Map[Option[Ref.TypeConName], C]]])
|
||||
type ResolutionResult[C] = (Set[Ref.TypeConName], Resolved.Choices[C])
|
||||
val (missing, resolved): ResolutionResult[TemplateChoice[O]] =
|
||||
FirstVal.unsubst[ResolutionResult, TemplateChoice[O]](
|
||||
unresolved.forgetNE
|
||||
.foldMap { tcn =>
|
||||
getAstInterface(tcn).cata(
|
||||
{ astIf =>
|
||||
val tcnResolved =
|
||||
astIf.choices.transform((_, tc) => NonEmpty(Map, some(tcn) -> tc))
|
||||
val tcnResolved = astIf choicesAsResolved tcn
|
||||
FirstVal.subst[ResolutionResult, TemplateChoice[O]](
|
||||
Set.empty[Ref.TypeConName],
|
||||
tcnResolved,
|
||||
@ -350,6 +381,11 @@ object TemplateChoices {
|
||||
object Resolved {
|
||||
private[daml] def fromDirect[Ty](directChoices: Map[Ref.ChoiceName, TemplateChoice[Ty]]) =
|
||||
Resolved(directAsResolved(directChoices))
|
||||
|
||||
// choice type abstracted over the TemplateChoice, for specifying
|
||||
// aggregation of choices (typically with tags, foldMap, semigroup)
|
||||
private[typesig] type Choices[C] =
|
||||
Map[Ref.ChoiceName, NonEmpty[Map[Option[Ref.TypeConName], C]]]
|
||||
}
|
||||
|
||||
implicit val `TemplateChoices traverse`: Traverse[TemplateChoices] = new Traverse[TemplateChoices]
|
||||
@ -388,13 +424,38 @@ object TemplateChoice {
|
||||
}
|
||||
|
||||
/** @param choices Choices of this interface, indexed by name
|
||||
* @param retroImplements IDs of templates that implement this interface, upon
|
||||
* introduction of this interface into the environment
|
||||
*/
|
||||
final case class DefInterface[+Ty](
|
||||
choices: Map[Ref.ChoiceName, TemplateChoice[Ty]],
|
||||
viewType: Option[Ref.TypeConName],
|
||||
// retroImplements are used only by LF 1.x
|
||||
retroImplements: Set[Ref.TypeConName] = Set.empty,
|
||||
) {
|
||||
def getChoices: j.Map[Ref.ChoiceName, _ <: TemplateChoice[Ty]] =
|
||||
choices.asJava
|
||||
|
||||
// Restructure `choices` in the resolved-choices data structure format,
|
||||
// for aggregation with [[TemplateChoices.Resolved]].
|
||||
private[typesig] def choicesAsResolved[Name](
|
||||
selfName: Name
|
||||
): Map[Ref.ChoiceName, NonEmpty[Map[Option[Name], TemplateChoice[Ty]]]] =
|
||||
choices transform ((_, tc) => NonEmpty(Map, some(selfName) -> tc))
|
||||
|
||||
private[typesig] def resolveRetroImplements[S, OTy >: Ty](selfName: Ref.TypeConName, s: S)(
|
||||
setTemplate: SetterAt[Ref.TypeConName, S, DefTemplate[OTy]]
|
||||
): (S, DefInterface[OTy]) = {
|
||||
def addMySelf(dt: DefTemplate[OTy]) =
|
||||
dt.extendWithInterface(selfName, this)
|
||||
|
||||
retroImplements
|
||||
.foldLeft((s, retroImplements)) { (sr, tplName) =>
|
||||
val (s, remaining) = sr
|
||||
setTemplate(s, tplName).cata(setter => (setter(addMySelf), remaining - tplName), sr)
|
||||
}
|
||||
.map(remaining => copy(retroImplements = remaining))
|
||||
}
|
||||
}
|
||||
|
||||
object DefInterface extends FWTLike[DefInterface] {
|
||||
|
@ -8,6 +8,8 @@ import com.daml.lf.archive.Dar
|
||||
import data.Ref, Ref.{Identifier, PackageId}
|
||||
|
||||
import scala.collection.immutable.Map
|
||||
import scalaz.std.tuple._
|
||||
import scalaz.syntax.functor._
|
||||
import scalaz.syntax.std.map._
|
||||
import scalaz.Semigroup
|
||||
|
||||
@ -45,6 +47,21 @@ final case class EnvironmentSignature(
|
||||
}
|
||||
})
|
||||
|
||||
def resolveRetroImplements: EnvironmentSignature = {
|
||||
import PackageSignature.findTemplate
|
||||
val (newTypeDecls, newInterfaces) = interfaces.foldLeft((typeDecls, interfaces)) {
|
||||
case ((typeDecls, interfaces), (ifTc, defIf)) =>
|
||||
defIf
|
||||
.resolveRetroImplements(ifTc, typeDecls) { case (typeDecls, tplName) =>
|
||||
findTemplate(typeDecls, tplName) map { itt => f =>
|
||||
typeDecls.updated(tplName, itt.copy(template = f(itt.template)))
|
||||
}
|
||||
}
|
||||
.map(defIf => interfaces.updated(ifTc, defIf))
|
||||
}
|
||||
copy(typeDecls = newTypeDecls, interfaces = newInterfaces)
|
||||
}
|
||||
|
||||
def resolveInterfaceViewType(tcn: Ref.TypeConName): Option[DefInterface.ViewTypeFWT] =
|
||||
typeDecls get tcn flatMap (_.asInterfaceViewType)
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ import reader.Errors
|
||||
import com.daml.daml_lf_dev.DamlLf
|
||||
import com.daml.lf.archive.ArchivePayload
|
||||
import scalaz.std.either._
|
||||
import scalaz.std.tuple._
|
||||
import scalaz.syntax.bifunctor._
|
||||
import scalaz.syntax.std.boolean._
|
||||
|
||||
import scala.collection.immutable.Map
|
||||
import scala.collection.immutable.{Map, SeqOps}
|
||||
import scala.jdk.CollectionConverters._
|
||||
|
||||
// Duplicate of the one in com.daml.lf.language to separate Ast and Iface
|
||||
@ -98,6 +100,41 @@ final case class PackageSignature(
|
||||
findInterface: PartialFunction[Ref.TypeConName, DefInterface.FWT]
|
||||
): PackageSignature = resolveChoices(findInterface, failIfUnresolvedChoicesLeft = false)
|
||||
|
||||
/** Update internal templates, as well as external templates via `setTemplates`,
|
||||
* with retroactive interface implementations. Note retroactive interfaces are
|
||||
* available only on LF 1.x
|
||||
*
|
||||
* @param setTemplate Used to look up templates that can't be found in this
|
||||
* interface
|
||||
*/
|
||||
private def resolveRetroImplements[S](
|
||||
s: S
|
||||
)(setTemplate: SetterAt[Ref.TypeConName, S, DefTemplate.FWT]): (S, PackageSignature) = {
|
||||
type SandTpls = (S, Map[QualifiedName, TypeDecl.Template])
|
||||
def setTpl(
|
||||
sm: SandTpls,
|
||||
tcn: Ref.TypeConName,
|
||||
): Option[(DefTemplate.FWT => DefTemplate.FWT) => SandTpls] = {
|
||||
import PackageSignature.findTemplate
|
||||
val (s, tplsM) = sm
|
||||
if (tcn.packageId == packageId)
|
||||
findTemplate(tplsM orElse typeDecls, tcn.qualifiedName).map {
|
||||
case itt @ TypeDecl.Template(_, dt) =>
|
||||
f => (s, tplsM.updated(tcn.qualifiedName, itt.copy(template = f(dt))))
|
||||
}
|
||||
else setTemplate(s, tcn) map (_ andThen ((_, tplsM)))
|
||||
}
|
||||
|
||||
val ((sEnd, newTpls), newIfcs) = interfaces.foldLeft(
|
||||
((s, Map.empty): SandTpls, Map.empty[QualifiedName, DefInterface.FWT])
|
||||
) { case ((s, astIfs), (ifcName, astIf)) =>
|
||||
astIf
|
||||
.resolveRetroImplements(Ref.TypeConName(packageId, ifcName), s)(setTpl)
|
||||
.rightMap(newIf => astIfs.updated(ifcName, newIf))
|
||||
}
|
||||
(sEnd, copy(typeDecls = typeDecls ++ newTpls, interfaces = newIfcs))
|
||||
}
|
||||
|
||||
private def resolveInterfaceViewType(n: Ref.QualifiedName): Option[Record.FWT] =
|
||||
typeDecls get n flatMap (_.asInterfaceViewType)
|
||||
}
|
||||
@ -156,6 +193,55 @@ object PackageSignature {
|
||||
): Option[TypeDecl.Template] =
|
||||
m.lift(k) collect { case itt: TypeDecl.Template => itt }
|
||||
|
||||
// Given a lookup function for package state setters, produce a lookup function
|
||||
// for setters on specific templates in that set of packages.
|
||||
private[this] def setPackageTemplates[S](
|
||||
findPackage: GetterSetterAt[PackageId, S, PackageSignature]
|
||||
): SetterAt[Ref.TypeConName, S, DefTemplate.FWT] = {
|
||||
def go(s: S, tcn: Ref.TypeConName): Option[(DefTemplate.FWT => DefTemplate.FWT) => S] = for {
|
||||
foundPkg <- findPackage(s, tcn.packageId)
|
||||
(ifc, sIfc) = foundPkg
|
||||
itt <- findTemplate(ifc.typeDecls, tcn.qualifiedName)
|
||||
} yield f =>
|
||||
sIfc(
|
||||
ifc.copy(typeDecls =
|
||||
ifc.typeDecls.updated(tcn.qualifiedName, itt.copy(template = f(itt.template)))
|
||||
)
|
||||
)
|
||||
go
|
||||
}
|
||||
|
||||
/** Extend the set of interfaces represented by `s` and `findPackage` with
|
||||
* `newSignatures`. Produce the resulting `S` and a replacement copy of
|
||||
* `newSignatures` with templates and interfaces therein resolved.
|
||||
*
|
||||
* Does not search members of `s` for fresh interfaces.
|
||||
*/
|
||||
def resolveRetroImplements[S, CC[B] <: Seq[B] with SeqOps[B, CC, CC[B]]](
|
||||
s: S,
|
||||
newSignatures: CC[PackageSignature],
|
||||
)(
|
||||
findPackage: GetterSetterAt[PackageId, S, PackageSignature]
|
||||
): (S, CC[PackageSignature]) = {
|
||||
type St = (S, CC[PackageSignature])
|
||||
val findTpl = setPackageTemplates[St] { case ((s, newSignatures), pkgId) =>
|
||||
findPackage(s, pkgId).map(_.rightMap(_ andThen ((_, newSignatures)))).orElse {
|
||||
val ix = newSignatures indexWhere (_.packageId == pkgId)
|
||||
(ix >= 0) option ((newSignatures(ix), newSig => (s, newSignatures.updated(ix, newSig))))
|
||||
}
|
||||
}
|
||||
|
||||
(0 until newSignatures.size).foldLeft((s, newSignatures)) {
|
||||
case (st @ (_, newSignatures), ifcK) =>
|
||||
val ((s2, newSignatures2), newAtIfcK) =
|
||||
newSignatures(ifcK).resolveRetroImplements(st)(findTpl)
|
||||
// the tricky part here: newSignatures2 is guaranteed not to have altered
|
||||
// the value at ifcK, and to have made all "self" changes in newAtIfcK.
|
||||
// So there is no conflict, we can discard the value in the seq
|
||||
(s2, newSignatures2.updated(ifcK, newAtIfcK))
|
||||
}
|
||||
}
|
||||
|
||||
/** An argument for [[PackageSignature#resolveChoices]] given a package database,
|
||||
* such as json-api's `LedgerReader.PackageStore`.
|
||||
*/
|
||||
|
@ -201,6 +201,14 @@ class SignatureReaderSpec extends AnyWordSpec with Matchers with Inside {
|
||||
}
|
||||
lazy val itpES = EnvironmentSignature.fromPackageSignatures(itp).resolveChoices
|
||||
|
||||
lazy val itpWithoutRetroImplements = itp.copy(
|
||||
main = itp.main.copy(
|
||||
interfaces = itp.main.interfaces - qn("RetroInterface:RetroIf")
|
||||
)
|
||||
)
|
||||
lazy val itpESWithoutRetroImplements =
|
||||
EnvironmentSignature.fromPackageSignatures(itpWithoutRetroImplements).resolveChoices
|
||||
|
||||
"load without errors" in {
|
||||
itp shouldBe itp
|
||||
}
|
||||
@ -321,6 +329,13 @@ class SignatureReaderSpec extends AnyWordSpec with Matchers with Inside {
|
||||
Bar -> Set(None),
|
||||
)
|
||||
}
|
||||
|
||||
"resolve retro implements harmlessly when there are none" in {
|
||||
PackageSignature.resolveRetroImplements((), itpWithoutRetroImplements.all)((_, _) =>
|
||||
None
|
||||
) should ===((), itpWithoutRetroImplements.all)
|
||||
itpESWithoutRetroImplements.resolveRetroImplements should ===(itpESWithoutRetroImplements)
|
||||
}
|
||||
}
|
||||
|
||||
private def wrappInModule(dataName: DottedName, dfn: Ast.DDataType) =
|
||||
|
Loading…
Reference in New Issue
Block a user