diff --git a/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/TypeOrderingSpec.scala b/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/TypeOrderingSpec.scala index 032d239837af..d0ef8b8ffe12 100644 --- a/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/TypeOrderingSpec.scala +++ b/daml-lf/archive/src/test/scala/com/digitalasset/daml/lf/archive/TypeOrderingSpec.scala @@ -29,6 +29,16 @@ class TypeOrderingSpec extends AnyWordSpec with Matchers { TypeOrdering.compare ) shouldBe primTypesInProtoOrder } + "order parametrized TypeReps" in { + TypeOrdering.compare( + Ast.TTypeRepGeneric(Ast.KStar), + Ast.TTypeRepGeneric(Ast.KStar), + ) shouldBe 0 + TypeOrdering.compare( + Ast.TTypeRepGeneric(Ast.KStar), + Ast.TTypeRepGeneric(Ast.KArrow(Ast.KStar, Ast.KStar)), + ) shouldBe -1 + } } } diff --git a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/Preprocessor.scala b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/Preprocessor.scala index 87afe5bd70a2..7e303a727a04 100644 --- a/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/Preprocessor.scala +++ b/daml-lf/engine/src/main/scala/com/digitalasset/daml/lf/engine/preprocessing/Preprocessor.scala @@ -88,7 +88,7 @@ private[engine] final class Preprocessor(compiledPackages: MutableCompiledPackag } case Ast.TTyCon(_) | Ast.TNat(_) | Ast.TBuiltin(_) | Ast.TVar(_) => go(typesToProcess, tmplToProcess0, tyConAlreadySeen0, tmplsAlreadySeen0) - case Ast.TSynApp(_, _) | Ast.TForall(_, _) | Ast.TStruct(_) => + case Ast.TSynApp(_, _) | Ast.TForall(_, _) | Ast.TStruct(_) | Ast.TTypeRepGeneric(_) => // We assume that getDependencies is always given serializable types ResultError( Error.Preprocessing diff --git a/daml-lf/interface/src/main/scala/com/digitalasset/daml/lf/iface/reader/InterfaceReader.scala b/daml-lf/interface/src/main/scala/com/digitalasset/daml/lf/iface/reader/InterfaceReader.scala index 72834dada9e8..550d78e8c860 100644 --- a/daml-lf/interface/src/main/scala/com/digitalasset/daml/lf/iface/reader/InterfaceReader.scala +++ b/daml-lf/interface/src/main/scala/com/digitalasset/daml/lf/iface/reader/InterfaceReader.scala @@ -243,7 +243,8 @@ object InterfaceReader { toIfaceType(ctx, arg, FrontStack.empty) flatMap (tArg => toIfaceType(ctx, tyfun, tArg +: args) ) - case Ast.TForall(_, _) | Ast.TStruct(_) | Ast.TNat(_) | Ast.TSynApp(_, _) => + case Ast.TForall(_, _) | Ast.TStruct(_) | Ast.TNat(_) | Ast.TSynApp(_, _) | + Ast.TTypeRepGeneric(_) => unserializableDataType(ctx, s"unserializable data type: ${a.pretty}") } diff --git a/daml-lf/interface/src/test/scala/com/digitalasset/daml/lf/iface/TypeSpec.scala b/daml-lf/interface/src/test/scala/com/digitalasset/daml/lf/iface/TypeSpec.scala index 2a1a80e3f311..56ebead26f97 100644 --- a/daml-lf/interface/src/test/scala/com/digitalasset/daml/lf/iface/TypeSpec.scala +++ b/daml-lf/interface/src/test/scala/com/digitalasset/daml/lf/iface/TypeSpec.scala @@ -88,6 +88,7 @@ class TypeSpec extends AnyWordSpec with Matchers { case _: Pkg.TStruct => sys.error("cannot use structs in interface type") case _: Pkg.TForall => sys.error("cannot use forall in interface type") case _: Pkg.TSynApp => sys.error("cannot use type synonym in interface type") + case _: Pkg.TTypeRepGeneric => sys.error("cannot use TypeRepGeneric in interface type") } go(pkgTyp00, BackStack.empty) diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala index 0d21e04322ec..b7b65a7e087f 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/Compiler.scala @@ -485,6 +485,10 @@ private[lf] final class Compiler( SBFromAny(ty)(compile(e)) case ETypeRep(typ) => SEValue(STypeRep(typ)) + case ETypeRepGeneric(_, typ) => + SEValue(STypeRep(typ)) + case ETypeRepGenericApp(_, _) => + SEBuiltin(SBTypeRepApp) case EToAnyException(ty, e) => SBToAny(ty)(compile(e)) case EFromAnyException(ty, e) => diff --git a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala index 3f2a14d53f5f..5b47f6402503 100644 --- a/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala +++ b/daml-lf/interpreter/src/main/scala/com/digitalasset/daml/lf/speedy/SBuiltin.scala @@ -162,6 +162,12 @@ private[speedy] sealed abstract class SBuiltin(val arity: Int) { case otherwise => unexpectedType(i, "Exception", otherwise) } + final protected def getSTypeRep(args: util.ArrayList[SValue], i: Int): Ast.Type = + args.get(i) match { + case STypeRep(x) => x + case otherwise => unexpectedType(i, "STNat", otherwise) + } + final protected def checkToken(args: util.ArrayList[SValue], i: Int): Unit = args.get(i) match { case SToken => () @@ -356,6 +362,14 @@ private[lf] object SBuiltin { } } + final case object SBTypeRepApp extends SBuiltinPure(2) { + override private[speedy] def executePure(args: util.ArrayList[SValue]): STypeRep = { + val t1 = getSTypeRep(args, 0) + val t2 = getSTypeRep(args, 1) + STypeRep(Ast.TApp(t1, t2)) + } + } + final case object SBShiftNumeric extends SBuiltinPure(3) { override private[speedy] def executePure(args: util.ArrayList[SValue]): SNumeric = { val inputScale = getSTNat(args, 0) diff --git a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala index 668cc96cc411..2fa4fd8313b7 100644 --- a/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala +++ b/daml-lf/interpreter/src/test/scala/com/digitalasset/daml/lf/speedy/SBuiltinTest.scala @@ -9,6 +9,7 @@ import java.util import com.daml.lf.data._ import com.daml.lf.interpretation.{Error => IE} import com.daml.lf.language.Ast._ +import com.daml.lf.language.Util._ import com.daml.lf.speedy.SError.{SError, SErrorCrash} import com.daml.lf.speedy.SExpr._ import com.daml.lf.speedy.SResult.{SResultError, SResultFinalValue, SResultNeedPackage} @@ -1565,6 +1566,22 @@ class SBuiltinTest extends AnyFreeSpec with Matchers with TableDrivenPropertyChe } } + "TypeRepGeneric/TypeRepGenericApp" - { + "should produce typerep for Unit" in { + eval(e"type_rep_generic @* @Unit") shouldBe Right(SValue.STypeRep(TUnit)) + } + "should produce typerep for Option" in { + eval(e"type_rep_generic @(* -> *) @Option") shouldBe Right( + SValue.STypeRep(TBuiltin(BTOptional)) + ) + } + "should produce typerep for Option Unit" in { + eval( + e"type_rep_generic_app @* @* (type_rep_generic @(* -> *) @Option) (type_rep_generic @* @Unit)" + ) shouldBe Right(SValue.STypeRep(TOptional(TUnit))) + } + } + } object SBuiltinTest { diff --git a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala index 9e4b1f6bd81a..c3a8103c24fd 100644 --- a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala +++ b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Ast.scala @@ -146,6 +146,9 @@ object Ast { /** Unique textual representation of template Id * */ final case class ETypeRep(typ: Type) extends Expr + final case class ETypeRepGeneric(kind: Kind, typ: Type) extends Expr + final case class ETypeRepGenericApp(argKind: Kind, resKind: Kind) extends Expr + /** Throw an exception */ final case class EThrow(returnType: Type, exceptionType: Type, exception: Expr) extends Expr @@ -240,6 +243,8 @@ object Ast { .map { case (n, t) => n + ": " + prettyType(t, precTForall) } .toSeq .mkString(", ") + ")" + case TTypeRepGeneric(kind) => + "TypeRep<" + kind.pretty + ">" } def prettyForAll(t: Type): String = t match { @@ -283,6 +288,8 @@ object Ast { /** Structs */ final case class TStruct(fields: Struct[Type]) extends Type + final case class TTypeRepGeneric(kind: Kind) extends Type + sealed abstract class BuiltinType extends Product with Serializable case object BTInt64 extends BuiltinType diff --git a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/KindOrdering.scala b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/KindOrdering.scala new file mode 100644 index 000000000000..ace0313525c2 --- /dev/null +++ b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/KindOrdering.scala @@ -0,0 +1,52 @@ +package com.daml.lf.language + +import Ast._ + +object KindOrdering extends Ordering[Ast.Kind] { + @inline + def compare(x: Kind, y: Kind): Int = { + var diff = 0 + var stackX = List(Iterator.single(x)) + var stackY = List(Iterator.single(y)) + + @inline + def push(xs: Iterator[Kind], ys: Iterator[Kind]): Unit = { + stackX = xs :: stackX + stackY = ys :: stackY + } + + @inline + def pop(): Unit = { + stackX = stackX.tail + stackY = stackY.tail + } + + @inline + def step(tuple: (Kind, Kind)): Unit = + tuple match { + case (KStar, KStar) => diff = 0 + case (KNat, KNat) => diff = 0 + case (KArrow(x1, x2), KArrow(y1, y2)) => + push(Iterator(x1, x2), Iterator(y1, y2)) + case (k1, k2) => + diff = kindRank(k1) compareTo kindRank(k2) + } + + while (diff == 0 && stackX.nonEmpty) { + diff = stackX.head.hasNext compare stackY.head.hasNext + if (diff == 0) + if (stackX.head.hasNext) + step((stackX.head.next(), stackY.head.next())) + else + pop() + } + + diff + } + + private[this] def kindRank(kind: Ast.Kind): Int = kind match { + case KStar => 0 + case KNat => 1 + case KArrow(_, _) => 2 + } +} diff --git a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala index b659863c87b0..93646e2746a9 100644 --- a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala +++ b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/LanguageVersion.scala @@ -53,6 +53,7 @@ object LanguageVersion { val choiceObservers = v1_11 val bigNumeric = v1_13 val exceptions = v1_14 + val typeRepGeneric = v1_dev /** Unstable, experimental features. This should stay in 1.dev forever. * Features implemented with this flag should be moved to a separate diff --git a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/TypeOrdering.scala b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/TypeOrdering.scala index c97af5076c45..e2041c0e8f91 100644 --- a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/TypeOrdering.scala +++ b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/TypeOrdering.scala @@ -50,6 +50,8 @@ object TypeOrdering extends Ordering[Type] { push(xs.values, ys.values) case (Ast.TApp(x1, x2), Ast.TApp(y1, y2)) => push(Iterator(x1, x2), Iterator(y1, y2)) + case (Ast.TTypeRepGeneric(k1), Ast.TTypeRepGeneric(k2)) => + diff = KindOrdering.compare(k1, k2) case (t1, t2) => diff = typeRank(t1) compareTo typeRank(t2) } @@ -100,6 +102,8 @@ object TypeOrdering extends Ordering[Type] { case Ast.TNat(_) => 2 case Ast.TStruct(_) => 3 case Ast.TApp(_, _) => 4 + // TODO fixme + case Ast.TTypeRepGeneric(_) => 5 case Ast.TVar(_) | Ast.TForall(_, _) | Ast.TSynApp(_, _) => InternalError.illegalArgumentException( NameOf.qualifiedNameOfCurrentFunc, diff --git a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Util.scala b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Util.scala index 7a96f3165650..28ba0f347384 100644 --- a/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Util.scala +++ b/daml-lf/language/src/main/scala/com/digitalasset/daml/lf/language/Util.scala @@ -48,8 +48,8 @@ object Util { TApp(TApp(TBuiltin(BTArrow), targ), tres) } - class ParametricType1(bType: BuiltinType) { - val cons = TBuiltin(bType) + class ParametricType1(val cons: Type) { + def this(bType: BuiltinType) = this(TBuiltin(bType)) def apply(typ: Type): Type = TApp(cons, typ) def unapply(typ: TApp): Option[Type] = typ match { @@ -77,6 +77,7 @@ object Util { val TParty = TBuiltin(BTParty) val TAny = TBuiltin(BTAny) val TTypeRep = TBuiltin(BTTypeRep) + def TTypeRepGen(kind: Kind) = new ParametricType1(TTypeRepGeneric(kind)) val TBigNumeric = TBuiltin(BTBigNumeric) val TRoundingMode = TBuiltin(BTRoundingMode) diff --git a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/AstRewriter.scala b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/AstRewriter.scala index 79206192c7bd..2c71d82a0999 100644 --- a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/AstRewriter.scala +++ b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/AstRewriter.scala @@ -49,6 +49,8 @@ private[daml] class AstRewriter( TForall(binder, apply(body)) case TStruct(fields) => TStruct(fields.mapValues(apply)) + case TTypeRepGeneric(kind) => + TTypeRepGeneric(kind) } def apply(nameWithType: (Name, Type)): (Name, Type) = nameWithType match { @@ -60,9 +62,11 @@ private[daml] class AstRewriter( exprRule(x) else x match { - case EVar(_) | EBuiltin(_) | EPrimCon(_) | EPrimLit(_) | ETypeRep(_) | - EExperimental(_, _) => + case EVar(_) | EBuiltin(_) | EPrimCon(_) | EPrimLit(_) | EExperimental(_, _) | + ETypeRepGenericApp(_, _) => x + case ETypeRep(ty) => ETypeRep(apply(ty)) + case ETypeRepGeneric(kind, ty) => ETypeRepGeneric(kind, apply(ty)) case EVal(ref) => EVal(apply(ref)) case ELocation(loc, expr) => diff --git a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/ExprParser.scala b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/ExprParser.scala index bf8e62c27995..c96792f51d37 100644 --- a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/ExprParser.scala +++ b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/ExprParser.scala @@ -40,7 +40,9 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) { eFromAny | eToAnyException | eFromAnyException | - eToTextTypeConName | + eTypeRep | + eTypeRepGeneric | + eTypeRepGenericApp | eThrow | (id ^? builtinFunctions) ^^ EBuiltin | caseOf | @@ -217,9 +219,19 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) { EThrow(retType, excepType, exception) } - private lazy val eToTextTypeConName: Parser[Expr] = + private lazy val eTypeRep: Parser[Expr] = `type_rep` ~>! argTyp ^^ ETypeRep + private lazy val eTypeRepGeneric: Parser[Expr] = + `type_rep_generic` ~>! argKind ~ argTyp ^^ { case kind ~ typ => + ETypeRepGeneric(kind, typ) + } + + private lazy val eTypeRepGenericApp: Parser[Expr] = + `type_rep_generic_app` ~>! argKind ~ argKind ^^ { case k1 ~ k2 => + ETypeRepGenericApp(k1, k2) + } + private lazy val pattern: Parser[CasePat] = primCon ^^ CPPrimCon | (`nil` ^^^ CPNil) | diff --git a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Lexer.scala b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Lexer.scala index cb7f5832ba15..926a4e7a9261 100644 --- a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Lexer.scala +++ b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Lexer.scala @@ -38,6 +38,8 @@ private[parser] object Lexer extends RegexParsers { "to_any" -> `to_any`, "from_any" -> `from_any`, "type_rep" -> `type_rep`, + "type_rep_generic" -> `type_rep_generic`, + "type_rep_generic_app" -> `type_rep_generic_app`, "loc" -> `loc`, "to_any_exception" -> `to_any_exception`, "from_any_exception" -> `from_any_exception`, diff --git a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Token.scala b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Token.scala index 96d6ca0e0990..36c10ab47503 100644 --- a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Token.scala +++ b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/Token.scala @@ -46,6 +46,8 @@ private[parser] object Token { case object `to_any` extends Token case object `from_any` extends Token case object `type_rep` extends Token + case object `type_rep_generic` extends Token + case object `type_rep_generic_app` extends Token case object `loc` extends Token case object `to_any_exception` extends Token case object `from_any_exception` extends Token diff --git a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/TypeParser.scala b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/TypeParser.scala index 7cd881e0e5b7..98cffa97a0b4 100644 --- a/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/TypeParser.scala +++ b/daml-lf/parser/src/main/scala/com/digitalasset/daml/lf/testing/parser/TypeParser.scala @@ -65,12 +65,18 @@ private[parser] class TypeParser[P](parameters: ParserParameters[P]) { private lazy val tTypeSynApp: Parser[Type] = `|` ~> fullIdentifier ~ rep(typ0) <~ `|` ^^ { case id ~ tys => TSynApp(id, ImmArray(tys)) } + private lazy val tTypeRepGeneric: Parser[Type] = + Id("TypeRepGeneric") ~>! (`[` ~> KindParser.kind <~ `]`) ^^ { k => + TTypeRepGeneric(k) + } + lazy val typ0: Parser[Type] = `(` ~> typ <~ `)` | tNat | tForall | tStruct | tTypeSynApp | + tTypeRepGeneric | (id ^? builtinTypes) ^^ TBuiltin | fullIdentifier ^^ TTyCon.apply | id ^^ TVar.apply @@ -80,5 +86,6 @@ private[parser] class TypeParser[P](parameters: ParserParameters[P]) { lazy val typ: Parser[Type] = rep1sep(typ1, `->`) ^^ (_.reduceRight(TFun)) private[parser] lazy val argTyp: Parser[Type] = `@` ~> typ0 + private[parser] lazy val argKind: Parser[Kind] = `@` ~> KindParser.kind0 } diff --git a/daml-lf/parser/src/test/scala/com/digitalasset/daml/lf/testing/parser/ParsersSpec.scala b/daml-lf/parser/src/test/scala/com/digitalasset/daml/lf/testing/parser/ParsersSpec.scala index b4000fccf0b1..b6bfb95e1cf0 100644 --- a/daml-lf/parser/src/test/scala/com/digitalasset/daml/lf/testing/parser/ParsersSpec.scala +++ b/daml-lf/parser/src/test/scala/com/digitalasset/daml/lf/testing/parser/ParsersSpec.scala @@ -108,6 +108,7 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher "forall (a: *). Mod:T a" -> TForall((α.name, KStar), TApp(T, α)), "" -> TStruct(Struct.assertFromSeq(List(n"f1" -> α, n"f2" -> TBuiltin(BTBool), n"f3" -> T))), + "TypeRepGeneric[* -> *]" -> TTypeRepGeneric(KArrow(KStar, KStar)), ) forEvery(testCases)((stringToParse, expectedType) => @@ -331,6 +332,12 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher EFromAnyException(E, e"anyException"), "throw @Unit @Mod:E exception" -> EThrow(TUnit, E, e"exception"), + "type_rep_generic @(* -> *) @Option" -> ETypeRepGeneric( + KArrow(KStar, KStar), + TBuiltin(BTOptional), + ), + "type_rep_generic @* @Unit" -> ETypeRepGeneric(KStar, TUnit), + "type_rep_generic_app @* @(* -> *)" -> ETypeRepGenericApp(KStar, KArrow(KStar, KStar)), ) forEvery(testCases)((stringToParse, expectedExp) => @@ -729,6 +736,8 @@ class ParsersSpec extends AnyWordSpec with ScalaCheckPropertyChecks with Matcher "to_any", "from_any", "type_rep", + "type_rep_generic", + "type_rep_generic_app", "loc", "to_any_exception", "from_any_exception", diff --git a/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala b/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala index 45f008b0d08c..ee78ae23cbbc 100644 --- a/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala +++ b/daml-lf/repl/src/main/scala/com/digitalasset/daml/lf/repl/testing/Main.scala @@ -376,6 +376,7 @@ object Repl { .map { case (n, t) => n + ": " + prettyType(t, precTForall) } .toSeq .mkString(", ") + ")" + case TTypeRepGeneric(_) => "typerepgeneric" } def prettyForAll(t: Type): String = t match { diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/AlphaEquiv.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/AlphaEquiv.scala index 22a16c39bad7..3d5461618481 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/AlphaEquiv.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/AlphaEquiv.scala @@ -32,6 +32,8 @@ private[validation] object AlphaEquiv { case (TStruct(fs1), TStruct(fs2)) => (fs1.names sameElements fs2.names) && (fs1.values zip fs2.values).forall((alphaEquiv _).tupled) + case (TTypeRepGeneric(k1), TTypeRepGeneric(k2)) => + k1 == k2 case _ => false } } diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Serializability.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Serializability.scala index 2fcfe581d1a4..29a07e527278 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Serializability.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Serializability.scala @@ -90,6 +90,7 @@ private[validation] object Serializability { case BTBigNumeric => unserializable(URBigNumeric) } + case TTypeRepGeneric(_) => unserializable(URTypeRepGeneric) case TForall(_, _) => unserializable(URForall) case TStruct(_) => diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/TypeSubst.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/TypeSubst.scala index b347f2b9c01b..0dca73e1271a 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/TypeSubst.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/TypeSubst.scala @@ -30,6 +30,7 @@ private[validation] object TypeSubst { TForall(v0 -> k, go(fv0 + v0, subst0 - v0, t)) case TStruct(ts) => TStruct(ts.mapValues(go(fv0, subst0, _))) + case TTypeRepGeneric(kind) => TTypeRepGeneric(kind) } private def freshTypeVarName(fv: Set[TypeVarName]): TypeVarName = diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala index cf3260b3049e..587cf87eaa62 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/Typing.scala @@ -16,6 +16,10 @@ import scala.annotation.tailrec private[validation] object Typing { + private val alpha = TVar(Name.assertFromString("$alpha$")) + private val beta = TVar(Name.assertFromString("$beta$")) + private val gamma = TVar(Name.assertFromString("$gamma$")) + import Util.handleLookup /* Typing */ @@ -46,9 +50,6 @@ private[validation] object Typing { } protected[validation] lazy val typeOfBuiltinFunction = { - val alpha = TVar(Name.assertFromString("$alpha$")) - val beta = TVar(Name.assertFromString("$beta$")) - val gamma = TVar(Name.assertFromString("$gamma$")) def tBinop(typ: Type): Type = typ ->: typ ->: typ val tNumBinop = TForall(alpha.name -> KNat, tBinop(TNumeric(alpha))) val tMultiNumBinop = @@ -481,6 +482,8 @@ private[validation] object Typing { case TStruct(fields) => checkRecordType(fields.toImmArray) KStar + case TTypeRepGeneric(kind) => + KArrow(kind, KStar) } private def expandTypeSynonyms(typ0: Type): Type = typ0 match { @@ -501,6 +504,7 @@ private[validation] object Typing { TForall((v, k), introTypeVar(v, k).expandTypeSynonyms(b)) case TStruct(recordType) => TStruct(recordType.mapValues(expandTypeSynonyms(_))) + case TTypeRepGeneric(_) => typ0 } private def expandSynApp(syn: TypeSynName, tArgs: ImmArray[Type]): Type = { @@ -1033,6 +1037,19 @@ private[validation] object Typing { case ETypeRep(typ) => checkAnyType(typ) TTypeRep + case ETypeRepGeneric(kind, typ) => + checkType(typ, kind) + TTypeRepGen(kind)(typ) + case ETypeRepGenericApp(argKind, resKind) => + TForall( + alpha.name -> KArrow(argKind, resKind), + TForall( + beta.name -> argKind, + TTypeRepGen(KArrow(argKind, resKind))(alpha) ->: TTypeRepGen(argKind)( + beta + ) ->: TTypeRepGen(resKind)(TApp(alpha, beta)), + ), + ) case EThrow(returnTyp, excepTyp, body) => checkType(returnTyp, KStar) checkExceptionType(excepTyp) diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/ValidationError.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/ValidationError.scala index 2b60614702f2..271a5c667672 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/ValidationError.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/ValidationError.scala @@ -142,6 +142,9 @@ case object URAny extends UnserializabilityReason { case object URTypeRep extends UnserializabilityReason { def pretty: String = "TypeRep" } +case object URTypeRepGeneric extends UnserializabilityReason { + def pretty: String = "TypeRepGeneric" +} case object URRoundingMode extends UnserializabilityReason { def pretty: String = "RoundingMode" } diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/ExprIterable.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/ExprIterable.scala index 1eee8ad87310..87f5a1f4b717 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/ExprIterable.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/ExprIterable.scala @@ -64,6 +64,8 @@ private[validation] object ExprIterable { Iterator(value) case EFromAnyException(typ @ _, value) => Iterator(value) + case ETypeRepGeneric(kind @ _, ty @ _) => Iterator.empty + case ETypeRepGenericApp(_, _) => Iterator.empty } } diff --git a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/TypeIterable.scala b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/TypeIterable.scala index 3067cfbb3ec5..9b4c6f44199f 100644 --- a/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/TypeIterable.scala +++ b/daml-lf/validation/src/main/scala/com/digitalasset/daml/lf/validation/iterable/TypeIterable.scala @@ -25,6 +25,7 @@ private[validation] object TypeIterable { Iterator(body) case TStruct(fields) => fields.values + case TTypeRepGeneric(_) => Iterator.empty } private[validation] def iterator(expr0: Expr): Iterator[Type] = { @@ -55,6 +56,8 @@ private[validation] object TypeIterable { Iterator(typ) ++ iterator(expr) case ETypeRep(tyCon) => Iterator(tyCon) + case ETypeRepGeneric(kind @ _, ty) => Iterator(ty) + case ETypeRepGenericApp(_, _) => Iterator.empty case ENil(typ) => Iterator(typ) case ECons(typ, front, tail) => diff --git a/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala b/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala index 8df666c0ee61..5aa23f19b41c 100644 --- a/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala +++ b/daml-lf/validation/src/test/scala/com/digitalasset/daml/lf/validation/TypingSpec.scala @@ -87,6 +87,8 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher t"forall (a:*) (b:*) . a -> b -> a" -> k"*", t"< f1 : Int64, f2 : Bool >" -> k"*", t"Arrow Int64" -> k"* -> *", + t"TypeRepGeneric[*]" -> k"* -> *", + t"TypeRepGeneric[* -> *]" -> k"(* -> *) -> *", ) forEvery(testCases) { (typ: Type, expectedKind: Kind) => @@ -247,6 +249,12 @@ class TypingSpec extends AnyWordSpec with TableDrivenPropertyChecks with Matcher // UpdTryCatch E"Λ (σ : ⋆). λ (e₁ : Update σ) (e₂: AnyException → Option (Update σ)) → (( try @σ e₁ catch x → e₂ x ))" -> T"∀ (σ : ⋆). Update σ → (AnyException → Option (Update σ)) → Update σ", + // ExpTypeRepGeneric + E"type_rep_generic @(⋆ → ⋆) @Option" -> T"TypeRepGeneric[⋆ → ⋆] Option", + E"type_rep_generic @⋆ @Unit" -> T"TypeRepGeneric[⋆] Unit", + // ExpTypeRepGenericApp + E"type_rep_generic_app @⋆ @⋆" -> T"∀ ($$alpha$$ : ⋆ → ⋆) ($$beta$$ : ⋆). TypeRepGeneric[⋆ → ⋆] $$alpha$$ → TypeRepGeneric[⋆] $$beta$$ → TypeRepGeneric[⋆] ($$alpha$$ $$beta$$)", + E"type_rep_generic_app @(⋆ → ⋆) @(⋆ → ⋆)" -> T"∀ ($$alpha$$ : (⋆ → ⋆) → ⋆ → ⋆) ($$beta$$ : ⋆ → ⋆). TypeRepGeneric[(⋆ → ⋆) → ⋆ → ⋆] $$alpha$$ → TypeRepGeneric[⋆ → ⋆] $$beta$$ → TypeRepGeneric[⋆ → ⋆] ($$alpha$$ $$beta$$)", // EExperimental E"$$ ANSWER (Unit -> Int64)" -> T"Unit -> Int64", diff --git a/daml-script/export/src/main/scala/com/daml/script/export/Encode.scala b/daml-script/export/src/main/scala/com/daml/script/export/Encode.scala index 9f1e93052e3a..c1703a06a90f 100644 --- a/daml-script/export/src/main/scala/com/daml/script/export/Encode.scala +++ b/daml-script/export/src/main/scala/com/daml/script/export/Encode.scala @@ -309,6 +309,9 @@ private[export] object Encode { case Ast.TStruct(_) => // We only need to encode types in type-class instances. Structs don't occur in that position. throw new NotImplementedError("Encoding of struct types is not implemented") + case Ast.TTypeRepGeneric(_) => + // We only need to encode types in type-class instances. TypeRepGeneric don't occur in that position. + throw new NotImplementedError("Encoding of TypeRepGeenric is not implemented") } }