diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 93d15eca265d..a04f05cb820c 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -694,7 +694,12 @@ class TreePickler(pickler: TastyPickler) { withLength { writeNat(idx) pickleType(tree.tpe, richTypes = true) - args.foreach(pickleTree) + args.foreach { arg => + arg.tpe match + case _: TermRef if arg.isType => writeByte(EXPLICITtpt) + case _ => + pickleTree(arg) + } } } catch { diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 804a1f8244f3..0645ebecd1d0 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -1243,6 +1243,8 @@ class TreeUnpickler(reader: TastyReader, ByNameTypeTree(if withPureFuns then arg else arg.adaptByNameArgUnderPureFuns) case NAMEDARG => NamedArg(readName(), readTree()) + case EXPLICITtpt => + readTpt() case _ => readPathTree() } @@ -1468,10 +1470,7 @@ class TreeUnpickler(reader: TastyReader, val alias = if currentAddr == end then EmptyTree else readTpt() createNullableTypeBoundsTree(lo, hi, alias) case HOLE => - val idx = readNat() - val tpe = readType() - val args = until(end)(readTree()) - Hole(true, idx, args, EmptyTree, tpe) + readHole(end, isTerm = true) case _ => readPathTree() } @@ -1502,10 +1501,7 @@ class TreeUnpickler(reader: TastyReader, case HOLE => readByte() val end = readEnd() - val idx = readNat() - val tpe = readType() - val args = until(end)(readTree()) - Hole(false, idx, args, EmptyTree, tpe) + readHole(end, isTerm = false) case _ => if (isTypeTreeTag(nextByte)) readTree() else { @@ -1538,6 +1534,12 @@ class TreeUnpickler(reader: TastyReader, setSpan(start, CaseDef(pat, guard, rhs)) } + def readHole(end: Addr, isTerm: Boolean)(using Context): Tree = + val idx = readNat() + val tpe = readType() + val args = until(end)(readTree()) + Hole(isTerm, idx, args, EmptyTree, tpe) + def readLater[T <: AnyRef](end: Addr, op: TreeReader => Context ?=> T)(using Context): Trees.Lazy[T] = readLaterWithOwner(end, op)(ctx.owner) diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index b40e53cb4f39..c93dbd2c2f00 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -5,6 +5,7 @@ object MiMaFilters { val Library: Seq[ProblemFilter] = Seq( ) val TastyCore: Seq[ProblemFilter] = Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("dotty.tools.tasty.TastyFormat.EXPLICITtpt"), ) val Interfaces: Seq[ProblemFilter] = Seq( ) diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index 226fc14acb39..d91295f06af5 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -122,6 +122,8 @@ Standard-Section: "ASTs" TopLevelStat* MATCHtpt Length bound_Term? sel_Term CaseDef* -- sel match { CaseDef } where `bound` is optional upper bound of all rhs BYNAMEtpt underlying_Term -- => underlying SHAREDterm term_ASTRef -- Link to previously serialized term + -- pickled quote trees: -- These trees can only appear in pickled quotes. They will never be in a TASTy file. + EXPLICITtpt tpt_Term -- Tag for a type tree that in a context where it is not explicitly known that this tree is a type. HOLE Length idx_Nat tpe_Type arg_Tree* -- Splice hole with index `idx`, the type of the hole `tpe`, type and term arguments of the hole `arg`s @@ -511,6 +513,8 @@ object TastyFormat { final val RECtype = 100 final val SINGLETONtpt = 101 final val BOUNDED = 102 + final val EXPLICITtpt = 103 + // Cat. 4: tag Nat AST @@ -659,6 +663,7 @@ object TastyFormat { | ANNOTATEDtpt | BYNAMEtpt | MATCHtpt + | EXPLICITtpt | BIND => true case _ => false } @@ -803,6 +808,7 @@ object TastyFormat { case ANNOTATION => "ANNOTATION" case PRIVATEqualified => "PRIVATEqualified" case PROTECTEDqualified => "PROTECTEDqualified" + case EXPLICITtpt => "EXPLICITtpt" case HOLE => "HOLE" } diff --git a/tests/pos-macros/captured-type/Macro_1.scala b/tests/pos-macros/captured-type/Macro_1.scala new file mode 100644 index 000000000000..3f094487ee4f --- /dev/null +++ b/tests/pos-macros/captured-type/Macro_1.scala @@ -0,0 +1,8 @@ +import scala.quoted.* + +inline def foo[U](u: U): U = ${ fooImpl[U]('u) } + +def fooImpl[U: Type](u: Expr[U])(using Quotes): Expr[U] = '{ + def f[T](x: T): T = ${ identity('{ x: T }) } + f[U]($u) +} diff --git a/tests/pos-macros/captured-type/Test_2.scala b/tests/pos-macros/captured-type/Test_2.scala new file mode 100644 index 000000000000..ed1baab565e0 --- /dev/null +++ b/tests/pos-macros/captured-type/Test_2.scala @@ -0,0 +1,3 @@ +def test = + foo(1) + foo("abc")