Skip to content

Commit

Permalink
Add Inlined.inlinedFromOuterScope and refactor typedInlined
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Jul 19, 2023
1 parent da16f43 commit 4f90e13
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 40 deletions.
13 changes: 8 additions & 5 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,9 @@ object Trees {
*/
case class Inlined[+T <: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T])(implicit @constructorOnly src: SourceFile)
extends Tree[T] {

def inlinedFromOuterScope: Boolean = call.isEmpty

type ThisTree[+T <: Untyped] = Inlined[T]
override def isTerm = expansion.isTerm
override def isType = expansion.isType
Expand Down Expand Up @@ -1479,7 +1482,7 @@ object Trees {
* innermost enclosing call for which the inlined version is currently
* processed.
*/
protected def inlineContext(call: tpd.Tree)(using Context): Context = ctx
protected def inlineContext(tree: Inlined)(using Context): Context = ctx

/** The context to use when mapping or accumulating over a tree */
def localCtx(tree: Tree)(using Context): Context
Expand Down Expand Up @@ -1549,8 +1552,8 @@ object Trees {
cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer))
case SeqLiteral(elems, elemtpt) =>
cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt))
case Inlined(call, bindings, expansion) =>
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(call)))
case tree @ Inlined(call, bindings, expansion) =>
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(tree)))
case TypeTree() =>
tree
case SingletonTypeTree(ref) =>
Expand Down Expand Up @@ -1693,8 +1696,8 @@ object Trees {
this(this(this(x, block), handler), finalizer)
case SeqLiteral(elems, elemtpt) =>
this(this(x, elems), elemtpt)
case Inlined(call, bindings, expansion) =>
this(this(x, bindings), expansion)(using inlineContext(call))
case tree @ Inlined(call, bindings, expansion) =>
this(this(x, bindings), expansion)(using inlineContext(tree))
case TypeTree() =>
x
case SingletonTypeTree(ref) =>
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 @@ -1392,17 +1392,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
* EmptyTree calls (for parameters) cancel the next-enclosing call in the list instead of being added to it.
* We assume parameters are never nested inside parameters.
*/
override def inlineContext(call: Tree)(using Context): Context = {
override def inlineContext(tree: Inlined)(using Context): Context = {
// We assume enclosingInlineds is already normalized, and only process the new call with the head.
val oldIC = enclosingInlineds

val newIC =
if call.isEmpty then
if tree.inlinedFromOuterScope then
oldIC match
case t1 :: ts2 => ts2
case _ => oldIC
else
call :: oldIC
tree.call :: oldIC

val ctx1 = ctx.fresh.setProperty(InlinedCalls, newIC)
if oldIC.isEmpty then ctx1.setProperty(InlinedTrees, new Counter) else ctx1
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 @@ -528,12 +528,12 @@ class TreePickler(pickler: TastyPickler) {
case SeqLiteral(elems, elemtpt) =>
writeByte(REPEATED)
withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
case Inlined(call, bindings, expansion) =>
case tree @ Inlined(call, bindings, expansion) =>
writeByte(INLINED)
bindings.foreach(preRegister)
withLength {
pickleTree(expansion)
if (!call.isEmpty) pickleTree(call)
if (!tree.inlinedFromOuterScope) pickleTree(call)
bindings.foreach { b =>
assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef])
pickleTree(b)
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,8 @@ class InlineReducer(inliner: Inliner)(using Context):
}
case Alternative(pats) =>
pats.exists(reducePattern(caseBindingMap, scrut, _))
case Inlined(EmptyTree, Nil, ipat) =>
reducePattern(caseBindingMap, scrut, ipat)
case tree: Inlined if tree.inlinedFromOuterScope =>
reducePattern(caseBindingMap, scrut, tree.expansion)
case _ => false
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ object Inliner:
new InlinerMap(typeMap, treeMap, oldOwners, newOwners, substFrom, substTo)

override def transformInlined(tree: Inlined)(using Context) =
if tree.call.isEmpty then
if tree.inlinedFromOuterScope then
tree.expansion match
case expansion: TypeTree => expansion
case _ => tree
Expand Down Expand Up @@ -549,7 +549,7 @@ class Inliner(val call: tpd.Tree)(using Context):

val inlineTyper = new InlineTyper(ctx.reporter.errorCount)

val inlineCtx = inlineContext(call).fresh.setTyper(inlineTyper).setNewScope
val inlineCtx = inlineContext(Inlined(call, Nil, ref(defn.Predef_undefined))).fresh.setTyper(inlineTyper).setNewScope

def inlinedFromOutside(tree: Tree)(span: Span): Tree =
Inlined(EmptyTree, Nil, tree)(using ctx.withSource(inlinedMethod.topLevelClass.source)).withSpan(span)
Expand Down Expand Up @@ -1049,7 +1049,7 @@ class Inliner(val call: tpd.Tree)(using Context):
}
val inlinedNormalizer = new TreeMap {
override def transform(tree: tpd.Tree)(using Context): tpd.Tree = tree match {
case Inlined(EmptyTree, Nil, expr) if enclosingInlineds.isEmpty => transform(expr)
case tree @ Inlined(_, Nil, expr) if tree.inlinedFromOuterScope && enclosingInlineds.isEmpty => transform(expr)
case _ => super.transform(tree)
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ object Inlines:
override def transform(t: Tree)(using Context) =
if call.span.exists then
t match
case Inlined(t, Nil, expr) if t.isEmpty => expr
case t @ Inlined(_, Nil, expr) if t.inlinedFromOuterScope => expr
case _ if t.isEmpty => t
case _ => super.transform(t.withSpan(call.span))
else t
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case tree @ Inlined(call, bindings, body) =>
val bodyText = if bindings.isEmpty then toText(body) else blockText(bindings :+ body)
if homogenizedView || !ctx.settings.XprintInline.value then bodyText
else if call.isEmpty then stringText("{{") ~ stringText("/* inlined from outside */") ~ bodyText ~ stringText("}}")
else if tree.inlinedFromOuterScope then stringText("{{") ~ stringText("/* inlined from outside */") ~ bodyText ~ stringText("}}")
else keywordText("{{") ~ keywordText("/* inlined from ") ~ toText(call) ~ keywordText(" */") ~ bodyText ~ keywordText("}}")
case tpt: untpd.DerivedTypeTree =>
"<derived typetree watching " ~ tpt.watched.showSummary() ~ ">"
Expand Down
12 changes: 6 additions & 6 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ object PickledQuotes {

/** Unpickle the tree contained in the TastyExpr */
def unpickleTerm(pickled: String | List[String], typeHole: TypeHole, termHole: ExprHole)(using Context): Tree = {
val unpickled = withMode(Mode.ReadPositions)(unpickle(pickled, isType = false))
val Inlined(call, Nil, expansion) = unpickled: @unchecked
val inlineCtx = inlineContext(call)
val expansion1 = spliceTypes(expansion, typeHole)(using inlineCtx)
val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx)
cpy.Inlined(unpickled)(call, Nil, expansion2)
withMode(Mode.ReadPositions)(unpickle(pickled, isType = false)) match
case tree @ Inlined(call, Nil, expansion) =>
val inlineCtx = inlineContext(tree)
val expansion1 = spliceTypes(expansion, typeHole)(using inlineCtx)
val expansion2 = spliceTerms(expansion1, typeHole, termHole)(using inlineCtx)
cpy.Inlined(tree)(call, Nil, expansion2)
}


Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/sbt/ExtractDependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ private class ExtractDependenciesCollector extends tpd.TreeTraverser { thisTreeT
}

tree match {
case Inlined(call, _, _) if !call.isEmpty =>
case tree: Inlined if !tree.inlinedFromOuterScope =>
// The inlined call is normally ignored by TreeTraverser but we need to
// record it as a dependency
traverse(call)
traverse(tree.call)
case vd: ValDef if vd.symbol.is(ModuleVal) =>
// Don't visit module val
case t: Template if t.symbol.owner.is(ModuleClass) =>
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/MegaPhase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ class MegaPhase(val miniPhases: Array[MiniPhase]) extends Phase {
case tree: Inlined =>
inContext(prepInlined(tree, start)(using outerCtx)) {
val bindings = transformSpecificTrees(tree.bindings, start)
val expansion = transformTree(tree.expansion, start)(using inlineContext(tree.call))
val expansion = transformTree(tree.expansion, start)(using inlineContext(tree))
goInlined(cpy.Inlined(tree)(tree.call, bindings, expansion), start)
}
case tree: Quote =>
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,12 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
case _ =>
super.transform(tree1)
}
case Inlined(call, bindings, expansion) if !call.isEmpty =>
case tree @ Inlined(call, bindings, expansion) if !tree.inlinedFromOuterScope =>
val pos = call.sourcePos
CrossVersionChecks.checkExperimentalRef(call.symbol, pos)
withMode(Mode.InlinedCall)(transform(call))
val callTrace = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call)))
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree)))
case templ: Template =>
withNoCheckNews(templ.parents.flatMap(newPart)) {
forwardParamAccessors(templ)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Recheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ abstract class Recheck extends Phase, SymTransformer:
recheckBlock(tree.stats, tree.expr, pt)

def recheckInlined(tree: Inlined, pt: Type)(using Context): Type =
recheckBlock(tree.bindings, tree.expansion, pt)(using inlineContext(tree.call))
recheckBlock(tree.bindings, tree.expansion, pt)(using inlineContext(tree))

def recheckIf(tree: If, pt: Type)(using Context): Type =
recheck(tree.cond, defn.BooleanType)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/Splicer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ object Splicer {
case expr: Ident if expr.symbol.isAllOf(InlineByNameProxy) =>
// inline proxy for by-name parameter
expr.symbol.defTree.asInstanceOf[DefDef].rhs
case Inlined(EmptyTree, _, body1) => body1
case tree: Inlined if tree.inlinedFromOuterScope => tree.expansion
case _ => body
}
new ExprImpl(Inlined(EmptyTree, Nil, QuoteUtils.changeOwnerOfTree(body1, ctx.owner)).withSpan(body1.span), SpliceScope.getCurrent)
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ class YCheckPositions extends Phase {
// Recursivlely check children while keeping track of current source
reporting.trace(i"check pos ${tree.getClass} ${tree.source} ${sources.head} $tree") {
tree match {
case Inlined(EmptyTree, bindings, expansion) =>
case tree @ Inlined(_, bindings, expansion) if tree.inlinedFromOuterScope =>
assert(bindings.isEmpty)
val old = sources
sources = old.tail
traverse(expansion)(using inlineContext(EmptyTree).withSource(sources.head))
traverse(expansion)(using inlineContext(tree).withSource(sources.head))
sources = old
case Inlined(call, bindings, expansion) =>
case tree @ Inlined(call, bindings, expansion) =>
// bindings.foreach(traverse(_)) // TODO check inline proxies (see tests/tun/lst)
sources = call.symbol.topLevelClass.source :: sources
if (!isMacro(call)) // FIXME macro implementations can drop Inlined nodes. We should reinsert them after macro expansion based on the positions of the trees
traverse(expansion)(using inlineContext(call).withSource(sources.head))
traverse(expansion)(using inlineContext(tree).withSource(sources.head))
sources = sources.tail
case _ => traverseChildren(tree)
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/ReTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ class ReTyper(nestingLevel: Int = 0) extends Typer(nestingLevel) with ReChecking
override def typedUnApply(tree: untpd.Apply, selType: Type)(using Context): Tree =
typedApply(tree, selType)

override def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree = {
val (bindings1, exprCtx) = typedBlockStats(tree.bindings)
val expansion1 = typed(tree.expansion, pt)(using inlineContext(promote(tree))(using exprCtx))
untpd.cpy.Inlined(tree)(tree.call, bindings1.asInstanceOf[List[MemberDef]], expansion1)
.withType(avoidingType(expansion1, bindings1))
}

override def typedQuote(tree: untpd.Quote, pt: Type)(using Context): Tree =
assertTyped(tree)
val body1 = typed(tree.body, promote(tree).bodyType)(using quoteContext)
Expand Down
8 changes: 2 additions & 6 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2092,12 +2092,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
}
}

def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree = {
val (bindings1, exprCtx) = typedBlockStats(tree.bindings)
val expansion1 = typed(tree.expansion, pt)(using inlineContext(tree.call)(using exprCtx))
assignType(cpy.Inlined(tree)(tree.call, bindings1.asInstanceOf[List[MemberDef]], expansion1),
bindings1, expansion1)
}
def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree =
throw new UnsupportedOperationException("cannot type check a Inlined node")

def completeTypeTree(tree: untpd.TypeTree, pt: Type, original: untpd.Tree)(using Context): TypeTree =
tree.withSpan(original.span).withAttachmentsFrom(original)
Expand Down

0 comments on commit 4f90e13

Please sign in to comment.