From e3a9890adae25fa46ee4e5a069114467c12172a3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 11 Apr 2024 17:30:21 +0200 Subject: [PATCH 1/3] Add quote ASTs to TASTy Add AST nodes for Quote, Splice, QuotePattern, and QuoteSplice to TASTy. --- compiler/src/dotty/tools/dotc/ast/tpd.scala | 6 +++ .../tools/dotc/core/tasty/TreePickler.scala | 38 ++++++++++--------- .../tools/dotc/core/tasty/TreeUnpickler.scala | 25 ++++++++++-- .../dotty/tools/dotc/typer/TypeAssigner.scala | 6 +++ tasty/src/dotty/tools/tasty/TastyFormat.scala | 15 ++++++-- tests/{pos => pos-macros}/i13532/Bar.scala | 0 tests/{pos => pos-macros}/i13532/Foo.scala | 0 .../i13532/TestMacro.scala | 0 tests/{pos => pos-macros}/i16331/Macro.scala | 0 tests/{pos => pos-macros}/i16331/Main.scala | 0 tests/{pos => pos-macros}/i19604/ZSet.scala | 0 tests/{pos => pos-macros}/i19604/core.scala | 0 tests/{pos => pos-macros}/i19604/macro.scala | 0 .../{pos => pos-macros}/i19604/prelude.scala | 0 tests/run-staging/quote-nested-1.check | 2 +- tests/run-staging/quote-nested-2.check | 2 +- tests/run-staging/quote-nested-5.check | 2 +- 17 files changed, 68 insertions(+), 28 deletions(-) rename tests/{pos => pos-macros}/i13532/Bar.scala (100%) rename tests/{pos => pos-macros}/i13532/Foo.scala (100%) rename tests/{pos => pos-macros}/i13532/TestMacro.scala (100%) rename tests/{pos => pos-macros}/i16331/Macro.scala (100%) rename tests/{pos => pos-macros}/i16331/Main.scala (100%) rename tests/{pos => pos-macros}/i19604/ZSet.scala (100%) rename tests/{pos => pos-macros}/i19604/core.scala (100%) rename tests/{pos => pos-macros}/i19604/macro.scala (100%) rename tests/{pos => pos-macros}/i19604/prelude.scala (100%) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 71b85d97a187..8746277d1b26 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -178,6 +178,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Splice(expr: Tree, tpe: Type)(using Context): Splice = untpd.Splice(expr).withType(tpe) + def Splice(expr: Tree)(using Context): Splice = + ta.assignType(untpd.Splice(expr), expr) + + def SplicePattern(pat: Tree, args: List[Tree], tpe: Type)(using Context): SplicePattern = + untpd.SplicePattern(pat, args).withType(tpe) + def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpe: Type)(using Context): Hole = untpd.Hole(isTerm, idx, args, content).withType(tpe) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 0a8669292a74..f5625e694822 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -701,28 +701,30 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { pickleTree(alias) } case tree @ Quote(body, Nil) => - // TODO: Add QUOTE tag to TASTy assert(body.isTerm, """Quote with type should not be pickled. |Quote with type should only exists after staging phase at staging level 0.""".stripMargin) - pickleTree( - // scala.quoted.runtime.Expr.quoted[]() - ref(defn.QuotedRuntime_exprQuote) - .appliedToType(tree.bodyType) - .appliedTo(body) - .withSpan(tree.span) - ) + writeByte(QUOTE) + pickleTree(body) case Splice(expr) => - pickleTree( // TODO: Add SPLICE tag to TASTy - // scala.quoted.runtime.Expr.splice[]() - ref(defn.QuotedRuntime_exprSplice) - .appliedToType(tree.tpe) - .appliedTo(expr) - .withSpan(tree.span) - ) - case tree: QuotePattern => - // TODO: Add QUOTEPATTERN tag to TASTy - pickleTree(QuotePatterns.encode(tree)) + writeByte(SPLICE) + pickleTree(expr) + case QuotePattern(bindings, body, quotes) => + writeByte(QUOTEPATTERN) + withLength { + if body.isType then writeByte(EXPLICITtpt) + pickleTree(body) + pickleTree(quotes) + pickleType(tree.tpe) + bindings.foreach(pickleTree) + } + case SplicePattern(pat, args) => + writeByte(SPLICEPATTERN) + withLength { + pickleTree(pat) + pickleType(tree.tpe) + args.foreach(pickleTree) + } case Hole(_, idx, args, _) => writeByte(HOLE) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 073edb536151..5d4fcbfc5abe 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1314,6 +1314,10 @@ class TreeUnpickler(reader: TastyReader, NamedArg(readName(), readTree()) case EXPLICITtpt => readTpt() + case QUOTE => + Quote(readTree(), Nil) + case SPLICE => + Splice(readTree()) case _ => readPathTree() } @@ -1379,9 +1383,9 @@ class TreeUnpickler(reader: TastyReader, val fn = readTree() val args = until(end)(readTree()) if fn.symbol.isConstructor then constructorApply(fn, args) - else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args) - else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args) - else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args) + else if fn.symbol == defn.QuotedRuntime_exprQuote then quotedExpr(fn, args) // decode pre 3.5.0 encoding + else if fn.symbol == defn.QuotedRuntime_exprSplice then splicedExpr(fn, args) // decode pre 3.5.0 encoding + else if fn.symbol == defn.QuotedRuntime_exprNestedSplice then nestedSpliceExpr(fn, args) // decode pre 3.5.0 encoding else tpd.Apply(fn, args) case TYPEAPPLY => tpd.TypeApply(readTree(), until(end)(readTpt())) @@ -1503,7 +1507,7 @@ class TreeUnpickler(reader: TastyReader, val unapply = UnApply(fn, implicitArgs, argPats, patType) if fn.symbol == defn.QuoteMatching_ExprMatch_unapply || fn.symbol == defn.QuoteMatching_TypeMatch_unapply - then QuotePatterns.decode(unapply) + then QuotePatterns.decode(unapply) // decode pre 3.5.0 encoding else unapply case REFINEDtpt => val refineCls = symAtAddr.getOrElse(start, @@ -1551,6 +1555,19 @@ class TreeUnpickler(reader: TastyReader, val hi = if currentAddr == end then lo else readTpt() val alias = if currentAddr == end then EmptyTree else readTpt() createNullableTypeBoundsTree(lo, hi, alias) + case QUOTEPATTERN => + val bodyReader = fork + skipTree() + val quotes = readTree() + val patType = readType() + val bindings = readStats(ctx.owner, end) + val body = bodyReader.readTree() // need bindings in scope, so needs to be read before + QuotePattern(bindings, body, quotes, patType) + case SPLICEPATTERN => + val pat = readTree() + val patType = readType() + val args = until(end)(readTree()) + SplicePattern(pat, args, patType) case HOLE => readHole(end, isTerm = true) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index c7476f5d9777..64722d51708c 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -531,6 +531,12 @@ trait TypeAssigner { def assignType(tree: untpd.UnApply, proto: Type)(using Context): UnApply = tree.withType(proto) + def assignType(tree: untpd.Splice, expr: Tree)(using Context): Splice = + val tpe = expr.tpe // Quotes ?=> Expr[T] + .baseType(defn.FunctionSymbol(1, isContextual = true)).argTypes.last // Expr[T] + .baseType(defn.QuotedExprClass).argTypes.head // T + tree.withType(tpe) + def assignType(tree: untpd.QuotePattern, proto: Type)(using Context): QuotePattern = tree.withType(proto) diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 6cd63d0d8f01..606f61a3baf8 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -110,10 +110,14 @@ Standard-Section: "ASTs" TopLevelStat* WHILE Length cond_Term body_Term -- while cond do body REPEATED Length elem_Type elem_Term* -- Varargs argument of type `elem` SELECTouter Length levels_Nat qual_Term underlying_Type -- Follow `levels` outer links, starting from `qual`, with given `underlying` type + QUOTE body_Term -- Quoted expression `'{ body }` + SPLICE expr_Term -- Spliced expression `${ expr }` + SPLICEPATTEN Length pat_Term tpe_Type args_Term* -- Pattern splice `${pat}` or `$pat(args*)` in a quoted pattern of type `tpe` -- patterns: BIND Length boundName_NameRef patType_Type pat_Term -- name @ pat, wherev `patType` is the type of the bound symbol ALTERNATIVE Length alt_Term* -- alt1 | ... | altn as a pattern UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term* -- Unapply node `fun(_: pat_Type)(implicitArgs)` flowing into patterns `pat`. + QUOTEPATTERN Length body_Term quotes_Term pat_Type bindings_Term* -- Quote pattern node `'{ bindings*; body }(using quotes)` -- type trees: IDENTtpt NameRef Type -- Used for all type idents SELECTtpt NameRef qual_Term -- qual.name @@ -543,7 +547,8 @@ object TastyFormat { final val BOUNDED = 102 final val EXPLICITtpt = 103 final val ELIDED = 104 - + final val QUOTE = 105 + final val SPLICE = 106 // Tree Cat. 4: tag Nat AST final val firstNatASTTreeTag = IDENT @@ -610,8 +615,8 @@ object TastyFormat { final val TYPEREFin = 175 final val SELECTin = 176 final val EXPORT = 177 - // final val ??? = 178 - // final val ??? = 179 + final val QUOTEPATTERN = 178 + final val SPLICEPATTERN = 179 final val METHODtype = 180 final val APPLYsigpoly = 181 @@ -858,6 +863,10 @@ object TastyFormat { case PROTECTEDqualified => "PROTECTEDqualified" case EXPLICITtpt => "EXPLICITtpt" case ELIDED => "ELIDED" + case QUOTE => "QUOTE" + case SPLICE => "SPLICE" + case QUOTEPATTERN => "QUOTEPATTERN" + case SPLICEPATTERN => "SPLICEPATTERN" case HOLE => "HOLE" } diff --git a/tests/pos/i13532/Bar.scala b/tests/pos-macros/i13532/Bar.scala similarity index 100% rename from tests/pos/i13532/Bar.scala rename to tests/pos-macros/i13532/Bar.scala diff --git a/tests/pos/i13532/Foo.scala b/tests/pos-macros/i13532/Foo.scala similarity index 100% rename from tests/pos/i13532/Foo.scala rename to tests/pos-macros/i13532/Foo.scala diff --git a/tests/pos/i13532/TestMacro.scala b/tests/pos-macros/i13532/TestMacro.scala similarity index 100% rename from tests/pos/i13532/TestMacro.scala rename to tests/pos-macros/i13532/TestMacro.scala diff --git a/tests/pos/i16331/Macro.scala b/tests/pos-macros/i16331/Macro.scala similarity index 100% rename from tests/pos/i16331/Macro.scala rename to tests/pos-macros/i16331/Macro.scala diff --git a/tests/pos/i16331/Main.scala b/tests/pos-macros/i16331/Main.scala similarity index 100% rename from tests/pos/i16331/Main.scala rename to tests/pos-macros/i16331/Main.scala diff --git a/tests/pos/i19604/ZSet.scala b/tests/pos-macros/i19604/ZSet.scala similarity index 100% rename from tests/pos/i19604/ZSet.scala rename to tests/pos-macros/i19604/ZSet.scala diff --git a/tests/pos/i19604/core.scala b/tests/pos-macros/i19604/core.scala similarity index 100% rename from tests/pos/i19604/core.scala rename to tests/pos-macros/i19604/core.scala diff --git a/tests/pos/i19604/macro.scala b/tests/pos-macros/i19604/macro.scala similarity index 100% rename from tests/pos/i19604/macro.scala rename to tests/pos-macros/i19604/macro.scala diff --git a/tests/pos/i19604/prelude.scala b/tests/pos-macros/i19604/prelude.scala similarity index 100% rename from tests/pos/i19604/prelude.scala rename to tests/pos-macros/i19604/prelude.scala diff --git a/tests/run-staging/quote-nested-1.check b/tests/run-staging/quote-nested-1.check index 455e123a642c..84b8a0f533fb 100644 --- a/tests/run-staging/quote-nested-1.check +++ b/tests/run-staging/quote-nested-1.check @@ -1 +1 @@ -((q: scala.quoted.Quotes) ?=> scala.quoted.runtime.Expr.quote[scala.Int](3).apply(using q)) +((q: scala.quoted.Quotes) ?=> scala.quoted.runtime.Expr.quote[3](3).apply(using q)) diff --git a/tests/run-staging/quote-nested-2.check b/tests/run-staging/quote-nested-2.check index 48ecf87577ab..39d1a05fad8e 100644 --- a/tests/run-staging/quote-nested-2.check +++ b/tests/run-staging/quote-nested-2.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { - val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) + val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[4](4).apply(using q) ((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q) }) diff --git a/tests/run-staging/quote-nested-5.check b/tests/run-staging/quote-nested-5.check index 47d39cc92611..6561c9cbbb2e 100644 --- a/tests/run-staging/quote-nested-5.check +++ b/tests/run-staging/quote-nested-5.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { - val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) + val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[4](4).apply(using q) ((q2: scala.quoted.Quotes) ?=> ((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q2)) }.apply(using q)) From 31fe8977f71c9b94e4ca5c04c73eeb8f8f5f4de2 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 19 Apr 2024 11:57:29 +0200 Subject: [PATCH 2/3] Pickle type of quote and splices These types where encoded explicitly before in the type parameter of the `runtime.Expr.{expr,splice,nestedSplice}` methods. We still need them. --- .../dotty/tools/dotc/core/tasty/TreePickler.scala | 10 ++++++++-- .../dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 8 ++++---- tasty/src/dotty/tools/tasty/TastyFormat.scala | 12 ++++++------ tests/run-staging/quote-nested-1.check | 2 +- tests/run-staging/quote-nested-2.check | 2 +- tests/run-staging/quote-nested-5.check | 2 +- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index f5625e694822..55d25eeb3654 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -705,10 +705,16 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { """Quote with type should not be pickled. |Quote with type should only exists after staging phase at staging level 0.""".stripMargin) writeByte(QUOTE) - pickleTree(body) + withLength { + pickleTree(body) + pickleType(tree.bodyType) + } case Splice(expr) => writeByte(SPLICE) - pickleTree(expr) + withLength { + pickleTree(expr) + pickleType(tree.tpe) + } case QuotePattern(bindings, body, quotes) => writeByte(QUOTEPATTERN) withLength { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 5d4fcbfc5abe..ee3c98632b95 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1314,10 +1314,6 @@ class TreeUnpickler(reader: TastyReader, NamedArg(readName(), readTree()) case EXPLICITtpt => readTpt() - case QUOTE => - Quote(readTree(), Nil) - case SPLICE => - Splice(readTree()) case _ => readPathTree() } @@ -1555,6 +1551,10 @@ class TreeUnpickler(reader: TastyReader, val hi = if currentAddr == end then lo else readTpt() val alias = if currentAddr == end then EmptyTree else readTpt() createNullableTypeBoundsTree(lo, hi, alias) + case QUOTE => + Quote(readTree(), Nil).withBodyType(readType()) + case SPLICE => + Splice(readTree()).withType(readType()) case QUOTEPATTERN => val bodyReader = fork skipTree() diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 606f61a3baf8..413702ea0d71 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -110,8 +110,8 @@ Standard-Section: "ASTs" TopLevelStat* WHILE Length cond_Term body_Term -- while cond do body REPEATED Length elem_Type elem_Term* -- Varargs argument of type `elem` SELECTouter Length levels_Nat qual_Term underlying_Type -- Follow `levels` outer links, starting from `qual`, with given `underlying` type - QUOTE body_Term -- Quoted expression `'{ body }` - SPLICE expr_Term -- Spliced expression `${ expr }` + QUOTE Length body_Term bodyTpe_Type -- Quoted expression `'{ body }` of a body typed as `bodyTpe` + SPLICE Length expr_Term tpe_Type -- Spliced expression `${ expr }` typed as `tpe` SPLICEPATTEN Length pat_Term tpe_Type args_Term* -- Pattern splice `${pat}` or `$pat(args*)` in a quoted pattern of type `tpe` -- patterns: BIND Length boundName_NameRef patType_Type pat_Term -- name @ pat, wherev `patType` is the type of the bound symbol @@ -547,8 +547,6 @@ object TastyFormat { final val BOUNDED = 102 final val EXPLICITtpt = 103 final val ELIDED = 104 - final val QUOTE = 105 - final val SPLICE = 106 // Tree Cat. 4: tag Nat AST final val firstNatASTTreeTag = IDENT @@ -615,10 +613,12 @@ object TastyFormat { final val TYPEREFin = 175 final val SELECTin = 176 final val EXPORT = 177 - final val QUOTEPATTERN = 178 - final val SPLICEPATTERN = 179 + final val QUOTE = 178 + final val SPLICE = 179 final val METHODtype = 180 final val APPLYsigpoly = 181 + final val QUOTEPATTERN = 182 + final val SPLICEPATTERN = 183 final val MATCHtype = 190 final val MATCHtpt = 191 diff --git a/tests/run-staging/quote-nested-1.check b/tests/run-staging/quote-nested-1.check index 84b8a0f533fb..455e123a642c 100644 --- a/tests/run-staging/quote-nested-1.check +++ b/tests/run-staging/quote-nested-1.check @@ -1 +1 @@ -((q: scala.quoted.Quotes) ?=> scala.quoted.runtime.Expr.quote[3](3).apply(using q)) +((q: scala.quoted.Quotes) ?=> scala.quoted.runtime.Expr.quote[scala.Int](3).apply(using q)) diff --git a/tests/run-staging/quote-nested-2.check b/tests/run-staging/quote-nested-2.check index 39d1a05fad8e..48ecf87577ab 100644 --- a/tests/run-staging/quote-nested-2.check +++ b/tests/run-staging/quote-nested-2.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { - val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[4](4).apply(using q) + val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) ((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q) }) diff --git a/tests/run-staging/quote-nested-5.check b/tests/run-staging/quote-nested-5.check index 6561c9cbbb2e..47d39cc92611 100644 --- a/tests/run-staging/quote-nested-5.check +++ b/tests/run-staging/quote-nested-5.check @@ -1,4 +1,4 @@ ((q: scala.quoted.Quotes) ?=> { - val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[4](4).apply(using q) + val a: scala.quoted.Expr[scala.Int] = scala.quoted.runtime.Expr.quote[scala.Int](4).apply(using q) ((q2: scala.quoted.Quotes) ?=> ((contextual$2: scala.quoted.Quotes) ?=> a).apply(using q2)) }.apply(using q)) From 743cc0b0f79a5886267ef6da2d5b101b6e98c54e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 22 Apr 2024 09:39:38 +0200 Subject: [PATCH 3/3] Add type argument encoding to SPLICEPATTERN Future proof for #18271. --- compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala | 4 ++++ compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala | 3 ++- tasty/src/dotty/tools/tasty/TastyFormat.scala | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 55d25eeb3654..f8a0f725ea52 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -725,10 +725,14 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) { bindings.foreach(pickleTree) } case SplicePattern(pat, args) => + val targs = Nil // SplicePattern `targs` will be added with #18271 writeByte(SPLICEPATTERN) withLength { pickleTree(pat) pickleType(tree.tpe) + for targ <- targs do + writeByte(EXPLICITtpt) + pickleTree(targ) args.foreach(pickleTree) } case Hole(_, idx, args, _) => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index ee3c98632b95..64ea2d497295 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1566,7 +1566,8 @@ class TreeUnpickler(reader: TastyReader, case SPLICEPATTERN => val pat = readTree() val patType = readType() - val args = until(end)(readTree()) + val (targs, args) = until(end)(readTree()).span(_.isType) + assert(targs.isEmpty, "unexpected type arguments in SPLICEPATTERN") // `targs` will be needed for #18271. Until this fearure is added they should be empty. SplicePattern(pat, args, patType) case HOLE => readHole(end, isTerm = true) diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 413702ea0d71..164243d3b469 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -112,7 +112,7 @@ Standard-Section: "ASTs" TopLevelStat* SELECTouter Length levels_Nat qual_Term underlying_Type -- Follow `levels` outer links, starting from `qual`, with given `underlying` type QUOTE Length body_Term bodyTpe_Type -- Quoted expression `'{ body }` of a body typed as `bodyTpe` SPLICE Length expr_Term tpe_Type -- Spliced expression `${ expr }` typed as `tpe` - SPLICEPATTEN Length pat_Term tpe_Type args_Term* -- Pattern splice `${pat}` or `$pat(args*)` in a quoted pattern of type `tpe` + SPLICEPATTEN Length pat_Term tpe_Type targs_Type* args_Term* -- Pattern splice `${pat}` or `$pat[targs*](args*)` in a quoted pattern of type `tpe`. -- patterns: BIND Length boundName_NameRef patType_Type pat_Term -- name @ pat, wherev `patType` is the type of the bound symbol ALTERNATIVE Length alt_Term* -- alt1 | ... | altn as a pattern