Skip to content

Remove tpt from Hole #17455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,19 @@ object Trees {
s"TypeTree${if (hasType) s"[$typeOpt]" else ""}"
}

/** Tree that replaces a level 1 splices in pickled (level 0) quotes.
* It is only used when picking quotes (will never be in a TASTy file).
*
* @param isTerm If this hole is a term, otherwise it is a type hole.
* @param idx The index of the hole in it's enclosing level 0 quote.
* @param args The arguments of the splice to compute its content
* @param content Lambda that computes the content of the hole. This tree is empty when in a quote pickle.
*/
case class Hole[+T <: Untyped](override val isTerm: Boolean, idx: Int, args: List[Tree[T]], content: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] {
type ThisTree[+T <: Untyped] <: Hole[T]
override def isType: Boolean = !isTerm
}

/** A type tree whose type is inferred. These trees appear in two contexts
* - as an argument of a TypeApply. In that case its type is always a TypeVar
* - as a (result-)type of an inferred ValDef or DefDef.
Expand Down Expand Up @@ -1035,20 +1048,6 @@ object Trees {
def genericEmptyValDef[T <: Untyped]: ValDef[T] = theEmptyValDef.asInstanceOf[ValDef[T]]
def genericEmptyTree[T <: Untyped]: Thicket[T] = theEmptyTree.asInstanceOf[Thicket[T]]

/** Tree that replaces a level 1 splices in pickled (level 0) quotes.
* It is only used when picking quotes (will never be in a TASTy file).
*
* @param isTerm If this hole is a term, otherwise it is a type hole.
* @param idx The index of the hole in it's enclosing level 0 quote.
* @param args The arguments of the splice to compute its content
* @param content Lambda that computes the content of the hole. This tree is empty when in a quote pickle.
* @param tpt Type of the hole
*/
case class Hole[+T <: Untyped](override val isTerm: Boolean, idx: Int, args: List[Tree[T]], content: Tree[T], tpt: Tree[T])(implicit @constructorOnly src: SourceFile) extends Tree[T] {
type ThisTree[+T <: Untyped] <: Hole[T]
override def isType: Boolean = !isTerm
}

def flatten[T <: Untyped](trees: List[Tree[T]]): List[Tree[T]] = {
def recur(buf: ListBuffer[Tree[T]] | Null, remaining: List[Tree[T]]): ListBuffer[Tree[T]] | Null =
remaining match {
Expand Down Expand Up @@ -1406,9 +1405,9 @@ object Trees {
case tree: Thicket if (trees eq tree.trees) => tree
case _ => finalize(tree, untpd.Thicket(trees)(sourceFile(tree)))
}
def Hole(tree: Tree)(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole = tree match {
def Hole(tree: Tree)(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree)(using Context): Hole = tree match {
case tree: Hole if isTerm == tree.isTerm && idx == tree.idx && args.eq(tree.args) && content.eq(tree.content) && content.eq(tree.content) => tree
case _ => finalize(tree, untpd.Hole(isTerm, idx, args, content, tpt)(sourceFile(tree)))
case _ => finalize(tree, untpd.Hole(isTerm, idx, args, content)(sourceFile(tree)))
}

// Copier methods with default arguments; these demand that the original tree
Expand All @@ -1431,8 +1430,8 @@ object Trees {
TypeDef(tree: Tree)(name, rhs)
def Template(tree: Template)(using Context)(constr: DefDef = tree.constr, parents: List[Tree] = tree.parents, derived: List[untpd.Tree] = tree.derived, self: ValDef = tree.self, body: LazyTreeList = tree.unforcedBody): Template =
Template(tree: Tree)(constr, parents, derived, self, body)
def Hole(tree: Hole)(isTerm: Boolean = tree.isTerm, idx: Int = tree.idx, args: List[Tree] = tree.args, content: Tree = tree.content, tpt: Tree = tree.tpt)(using Context): Hole =
Hole(tree: Tree)(isTerm, idx, args, content, tpt)
def Hole(tree: Hole)(isTerm: Boolean = tree.isTerm, idx: Int = tree.idx, args: List[Tree] = tree.args, content: Tree = tree.content)(using Context): Hole =
Hole(tree: Tree)(isTerm, idx, args, content)

}

Expand Down Expand Up @@ -1567,8 +1566,8 @@ object Trees {
cpy.Quote(tree)(transform(body)(using quoteContext), transform(tags))
case tree @ Splice(expr) =>
cpy.Splice(tree)(transform(expr)(using spliceContext))
case tree @ Hole(isTerm, idx, args, content, tpt) =>
cpy.Hole(tree)(isTerm, idx, transform(args), transform(content), transform(tpt))
case tree @ Hole(isTerm, idx, args, content) =>
cpy.Hole(tree)(isTerm, idx, transform(args), transform(content))
case _ =>
transformMoreCases(tree)
}
Expand Down Expand Up @@ -1712,8 +1711,8 @@ object Trees {
this(this(x, body)(using quoteContext), tags)
case Splice(expr) =>
this(x, expr)(using spliceContext)
case Hole(_, _, args, content, tpt) =>
this(this(this(x, args), content), tpt)
case Hole(_, _, args, content) =>
this(this(x, args), content)
case _ =>
foldMoreCases(x, tree)
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Splice(expr: Tree, tpe: Type)(using Context): Splice =
untpd.Splice(expr).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)

def TypeTree(tp: Type, inferred: Boolean = false)(using Context): TypeTree =
(if inferred then untpd.InferredTypeTree() else untpd.TypeTree()).withType(tp)

Expand Down Expand Up @@ -397,9 +400,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Throw(expr: Tree)(using Context): Tree =
ref(defn.throwMethod).appliedTo(expr)

def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(using Context): Hole =
ta.assignType(untpd.Hole(isTerm, idx, args, content, tpt), tpt)

// ------ Making references ------------------------------------------------------

def prefixIsElidable(tp: NamedType)(using Context): Boolean = {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def Export(expr: Tree, selectors: List[ImportSelector])(implicit src: SourceFile): Export = new Export(expr, selectors)
def PackageDef(pid: RefTree, stats: List[Tree])(implicit src: SourceFile): PackageDef = new PackageDef(pid, stats)
def Annotated(arg: Tree, annot: Tree)(implicit src: SourceFile): Annotated = new Annotated(arg, annot)
def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree, tpt: Tree)(implicit src: SourceFile): Hole = new Hole(isTerm, idx, args, content, tpt)
def Hole(isTerm: Boolean, idx: Int, args: List[Tree], content: Tree)(implicit src: SourceFile): Hole = new Hole(isTerm, idx, args, content)

// ------ Additional creation methods for untyped only -----------------

Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,11 @@ class TreePickler(pickler: TastyPickler) {
.appliedTo(expr)
.withSpan(tree.span)
)
case Hole(_, idx, args, _, tpt) =>
case Hole(_, idx, args, _) =>
writeByte(HOLE)
withLength {
writeNat(idx)
pickleType(tpt.tpe, richTypes = true)
pickleType(tree.tpe, richTypes = true)
args.foreach(pickleTree)
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,7 @@ class TreeUnpickler(reader: TastyReader,
val idx = readNat()
val tpe = readType()
val args = until(end)(readTree())
Hole(true, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
Hole(true, idx, args, EmptyTree, tpe)
case _ =>
readPathTree()
}
Expand Down Expand Up @@ -1491,7 +1491,7 @@ class TreeUnpickler(reader: TastyReader,
val idx = readNat()
val tpe = readType()
val args = until(end)(readTree())
Hole(false, idx, args, EmptyTree, TypeTree(tpe)).withType(tpe)
Hole(false, idx, args, EmptyTree, tpe)
case _ =>
if (isTypeTreeTag(nextByte)) readTree()
else {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -735,12 +735,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case Splice(expr) =>
val spliceTypeText = (keywordStr("[") ~ toTextGlobal(tree.typeOpt) ~ keywordStr("]")).provided(printDebug && tree.typeOpt.exists)
keywordStr("$") ~ spliceTypeText ~ keywordStr("{") ~ toTextGlobal(expr) ~ keywordStr("}")
case Hole(isTerm, idx, args, content, tpt) =>
case Hole(isTerm, idx, args, content) =>
val (prefix, postfix) = if isTerm then ("{{{", "}}}") else ("[[[", "]]]")
val argsText = toTextGlobal(args, ", ")
val contentText = toTextGlobal(content)
val tptText = toTextGlobal(tpt)
prefix ~~ idx.toString ~~ "|" ~~ tptText ~~ "|" ~~ argsText ~~ "|" ~~ contentText ~~ postfix
val tpeText = toTextGlobal(tree.typeOpt)
prefix ~~ idx.toString ~~ "|" ~~ tpeText ~~ "|" ~~ argsText ~~ "|" ~~ contentText ~~ postfix
case CapturesAndResult(refs, parent) =>
changePrec(GlobalPrec)("^{" ~ Text(refs.map(toText), ", ") ~ "}" ~ toText(parent))
case _ =>
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ object PickledQuotes {
private def spliceTerms(tree: Tree, typeHole: TypeHole, termHole: ExprHole)(using Context): Tree = {
def evaluateHoles = new TreeMap {
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
case Hole(isTerm, idx, args, _, _) =>
case Hole(isTerm, idx, args, _) =>
inContext(SpliceScope.contextWithNewSpliceScope(tree.sourcePos)) {
if isTerm then
val quotedExpr = termHole match
Expand Down Expand Up @@ -165,15 +165,15 @@ object PickledQuotes {
val tree = typeHole match
case TypeHole.V1(evalHole) =>
tdef.rhs match
case TypeBoundsTree(_, Hole(_, idx, args, _, _), _) =>
case TypeBoundsTree(_, Hole(_, idx, args, _), _) =>
// To keep for backwards compatibility. In some older version holes where created in the bounds.
val quotedType = evalHole.nn.apply(idx, reifyTypeHoleArgs(args))
PickledQuotes.quotedTypeToTree(quotedType)
case TypeBoundsTree(_, tpt, _) =>
// To keep for backwards compatibility. In some older version we missed the creation of some holes.
tpt
case TypeHole.V2(types) =>
val Hole(_, idx, _, _, _) = tdef.rhs: @unchecked
val Hole(_, idx, _, _) = tdef.rhs: @unchecked
PickledQuotes.quotedTypeToTree(types.nn.apply(idx))
(tdef.symbol, tree.tpe)
}.toMap
Expand Down
7 changes: 4 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ast.TreeTypeMap
import SymUtils._
import NameKinds._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.ast.untpd
import dotty.tools.dotc.config.ScalaRelease.*

import scala.collection.mutable
Expand Down Expand Up @@ -108,12 +109,12 @@ class PickleQuotes extends MacroTransform {
private val contents = List.newBuilder[Tree]
override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
tree match
case tree @ Hole(isTerm, _, _, content, _) =>
case tree @ Hole(isTerm, _, _, content) =>
assert(isTerm)
assert(!content.isEmpty)
contents += content
val holeType = getTermHoleType(tree.tpe)
val hole = cpy.Hole(tree)(content = EmptyTree, TypeTree(holeType))
val hole = untpd.cpy.Hole(tree)(content = EmptyTree).withType(holeType)
cpy.Inlined(tree)(EmptyTree, Nil, hole)
case tree: DefTree =>
val newAnnotations = tree.symbol.annotations.mapconserve { annot =>
Expand Down Expand Up @@ -197,7 +198,7 @@ class PickleQuotes extends MacroTransform {

private def mkTagSymbolAndAssignType(typeArg: Tree, idx: Int)(using Context): TypeDef = {
val holeType = getTypeHoleType(typeArg.tpe.select(tpnme.Underlying))
val hole = cpy.Hole(typeArg)(isTerm = false, idx, Nil, EmptyTree, TypeTree(holeType))
val hole = untpd.cpy.Hole(typeArg)(isTerm = false, idx, Nil, EmptyTree).withType(holeType)
val local = newSymbol(
owner = ctx.owner,
name = UniqueName.fresh(hole.tpe.dealias.typeSymbol.name.toTypeName),
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Splicing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class Splicing extends MacroTransform:
val ddef = DefDef(meth, List(bindings), newTree.tpe, newTree.changeOwner(ctx.owner, meth))
val fnType = defn.FunctionType(bindings.size, isContextual = false).appliedTo(bindingsTypes :+ newTree.tpe)
val closure = Block(ddef :: Nil, Closure(Nil, ref(meth), TypeTree(fnType)))
tpd.Hole(true, holeIdx, refs, closure, TypeTree(tpe))
tpd.Hole(true, holeIdx, refs, closure, tpe)

override def transform(tree: tpd.Tree)(using Context): tpd.Tree =
tree match
Expand Down
13 changes: 8 additions & 5 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -688,16 +688,19 @@ object TreeChecker {
super.typedSplice(tree, pt)

override def typedHole(tree: untpd.Hole, pt: Type)(using Context): Tree = {
val tree1 @ Hole(isTerm, _, args, content, tpt) = super.typedHole(tree, pt): @unchecked
val tree1 @ Hole(isTerm, idx, args, content) = super.typedHole(tree, pt): @unchecked

assert(idx >= 0, i"hole should not have negative index: $tree")
assert(isTerm || tree.args.isEmpty, i"type hole should not have arguments: $tree")

// Check that we only add the captured type `T` instead of a more complex type like `List[T]`.
// If we have `F[T]` with captured `F` and `T`, we should list `F` and `T` separately in the args.
for arg <- args do
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef], "Expected TypeRef in Hole type args but got: " + arg.tpe)

// Check result type of the hole
if isTerm then assert(tpt.typeOpt <:< pt)
else assert(tpt.typeOpt =:= pt)
if isTerm then assert(tree1.typeOpt <:< pt)
else assert(tree1.typeOpt =:= pt)

// Check that the types of the args conform to the types of the contents of the hole
val argQuotedTypes = args.map { arg =>
Expand All @@ -712,8 +715,8 @@ object TreeChecker {
else defn.QuotedTypeClass.typeRef.appliedTo(arg.typeOpt.widenTermRefExpr)
}
val expectedResultType =
if isTerm then defn.QuotedExprClass.typeRef.appliedTo(tpt.typeOpt)
else defn.QuotedTypeClass.typeRef.appliedTo(tpt.typeOpt)
if isTerm then defn.QuotedExprClass.typeRef.appliedTo(tree1.typeOpt)
else defn.QuotedTypeClass.typeRef.appliedTo(tree1.typeOpt)
val contextualResult =
defn.FunctionOf(List(defn.QuotesClass.typeRef), expectedResultType, isContextual = true)
val expectedContentType =
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/typer/QuotesAndSplices.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ trait QuotesAndSplices {
}

def typedHole(tree: untpd.Hole, pt: Type)(using Context): Tree =
val tpt = typedType(tree.tpt)
assignType(tree, tpt)
throw new UnsupportedOperationException("cannot type check a Hole node")

/** Types a splice applied to some arguments `$f(arg1, ..., argn)` in a quote pattern.
*
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ReTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking
val expr1 = typed(tree.expr, quoteType)(using spliceContext)
untpd.cpy.Splice(tree)(expr1).withType(tree.typeOpt)

override def typedHole(tree: untpd.Hole, pt: Type)(using Context): Tree =
promote(tree)

override def localDummy(cls: ClassSymbol, impl: untpd.Template)(using Context): Symbol = impl.symbol

override def retrieveSym(tree: untpd.Tree)(using Context): Symbol = tree.symbol
Expand Down