Skip to content

Commit

Permalink
Add new EXPLICITtpt to TASTy format (#17298)
Browse files Browse the repository at this point in the history
This is a new encoding of HOLE that differentiates between type and term
arguments of the hole.

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

We will pickle type trees in `arg_Tree` using the `EXPLICITtpt` tag.

We will only have hole captured types if there is a type defined in a
quote and used in a nested quote. Most of the time we do not have those
types and therefore no overhead in the encoding compared to before this
change.

Alternative to #17225
Fixes #17137
  • Loading branch information
nicolasstucki authored Aug 8, 2023
2 parents 5759bb8 + 46a8d13 commit 965818a
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 9 deletions.
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
18 changes: 10 additions & 8 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)

Expand Down
1 change: 1 addition & 0 deletions project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ object MiMaFilters {
// New API in 3.4.X
)
val TastyCore: Seq[ProblemFilter] = Seq(
ProblemFilters.exclude[DirectMissingMethodProblem]("dotty.tools.tasty.TastyFormat.EXPLICITtpt"),
)
val Interfaces: Seq[ProblemFilter] = Seq(
)
Expand Down
6 changes: 6 additions & 0 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -659,6 +663,7 @@ object TastyFormat {
| ANNOTATEDtpt
| BYNAMEtpt
| MATCHtpt
| EXPLICITtpt
| BIND => true
case _ => false
}
Expand Down Expand Up @@ -803,6 +808,7 @@ object TastyFormat {
case ANNOTATION => "ANNOTATION"
case PRIVATEqualified => "PRIVATEqualified"
case PROTECTEDqualified => "PROTECTEDqualified"
case EXPLICITtpt => "EXPLICITtpt"
case HOLE => "HOLE"
}

Expand Down
8 changes: 8 additions & 0 deletions tests/pos-macros/captured-type/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -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)
}
3 changes: 3 additions & 0 deletions tests/pos-macros/captured-type/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def test =
foo(1)
foo("abc")

0 comments on commit 965818a

Please sign in to comment.