Skip to content

Reposition trees in erasure using source from tree #9954

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

Closed
Closed
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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

steps:
- name: Set JDK 11 as default
run: echo "::add-path::/usr/lib/jvm/java-11-openjdk-amd64/bin"
run: echo "/usr/lib/jvm/java-11-openjdk-amd64/bin" >> $GITHUB_PATH

- name: Checkout cleanup script
uses: actions/checkout@v2
Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:

steps:
- name: Set JDK 11 as default
run: echo "::add-path::/usr/lib/jvm/java-11-openjdk-amd64/bin"
run: echo "/usr/lib/jvm/java-11-openjdk-amd64/bin" >> $GITHUB_PATH

- name: Checkout cleanup script
uses: actions/checkout@v2
Expand Down Expand Up @@ -191,7 +191,7 @@ jobs:

steps:
- name: Set JDK 8 as default
run: echo "::add-path::/usr/lib/jvm/java-1.8.0-openjdk-amd64/bin"
run: echo "/usr/lib/jvm/java-8-openjdk-amd64/bin" >> $GITHUB_PATH

- name: Checkout cleanup script
uses: actions/checkout@v2
Expand Down Expand Up @@ -378,7 +378,7 @@ jobs:
./project/scripts/sbt dist/packArchive
sha256sum dist/target/dotty-* > dist/target/sha256sum.txt
./project/scripts/sbtPublish ";project dotty-bootstrapped ;publishSigned ;sonatypeBundleRelease"
echo "::set-env name=RELEASE_TAG::${GITHUB_REF#*refs/tags/}"
echo "name=RELEASE_TAG::${GITHUB_REF#*refs/tags/}" >> $GITHUB_ENV

- name: Create GitHub Release
id: create_gh_release
Expand Down
1 change: 0 additions & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class Compiler {
/** Phases dealing with the frontend up to trees ready for TASTY pickling */
protected def frontendPhases: List[List[Phase]] =
List(new FrontEnd) :: // Compiler frontend: scanner, parser, namer, typer
List(new YCheckPositions) :: // YCheck positions
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files
List(new PostTyper) :: // Additional checks and cleanups after type checking
Expand Down
10 changes: 4 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1242,11 +1242,9 @@ object Trees {
protected def skipTransform(tree: Tree)(using Context): Boolean = false

/** For untyped trees, this is just the identity.
* For typed trees, a context derived form `ctx` that records `call` as the
* innermost enclosing call for which the inlined version is currently
* processed.
* For typed trees, this record the position of an enclosing inlined positions
*/
protected def inlineContext(call: Tree)(using Context): Context = ctx
protected def inlineContext(pos: SrcPos)(using Context): Context = ctx

abstract class TreeMap(val cpy: TreeCopier = inst.cpy) { self =>
def transform(tree: Tree)(using Context): Tree = {
Expand Down Expand Up @@ -1304,7 +1302,7 @@ object Trees {
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)))
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion)(using inlineContext(tree)))
case TypeTree() =>
tree
case SingletonTypeTree(ref) =>
Expand Down Expand Up @@ -1442,7 +1440,7 @@ object Trees {
case SeqLiteral(elems, elemtpt) =>
this(this(x, elems), elemtpt)
case Inlined(call, bindings, expansion) =>
this(this(x, bindings), expansion)(using inlineContext(call))
this(this(x, bindings), expansion)(using inlineContext(tree))
case TypeTree() =>
x
case SingletonTypeTree(ref) =>
Expand Down
22 changes: 6 additions & 16 deletions compiler/src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import typer.ProtoTypes
import transform.SymUtils._
import transform.TypeUtils._
import core._
import util.Spans._, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._
import util.Spans._, util.SrcPos, Types._, Contexts._, Constants._, Names._, Flags._, NameOps._
import Symbols._, StdNames._, Annotations._, Trees._, Symbols._
import Decorators._, DenotTransformers._
import collection.{immutable, mutable}
Expand Down Expand Up @@ -1232,37 +1232,27 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

/** A key to be used in a context property that tracks enclosing inlined calls */
private val InlinedCalls = Property.Key[List[Tree]]()
private val InlinedCalls = Property.Key[List[SrcPos]]()

/** A key to be used in a context property that tracks the number of inlined trees */
private val InlinedTrees = Property.Key[Counter]()
final class Counter {
var count: Int = 0
}

/** Record an enclosing inlined call.
* 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 = {
/** Record an enclosing inlined positions. */
override def inlineContext(pos: SrcPos)(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
oldIC match
case t1 :: ts2 => ts2
case _ => oldIC
else
call :: oldIC
val newIC = pos :: oldIC

val ctx1 = ctx.fresh.setProperty(InlinedCalls, newIC)
if oldIC.isEmpty then ctx1.setProperty(InlinedTrees, new Counter) else ctx1
}

/** All enclosing calls that are currently inlined, from innermost to outermost.
*/
def enclosingInlineds(using Context): List[Tree] =
def enclosingInlineds(using Context): List[SrcPos] =
ctx.property(InlinedCalls).getOrElse(Nil)

/** Record inlined trees */
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/quoted/MacroExpansion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object MacroExpansion {
def position(using Context): Option[SourcePosition] =
ctx.property(MacroExpansionPosition)

def context(inlinedFrom: tpd.Tree)(using Context): Context =
ctx.fresh.setProperty(MacroExpansionPosition, SourcePosition(inlinedFrom.source, inlinedFrom.span)).setTypeAssigner(new Typer).withSource(inlinedFrom.source)
def context(inlinedFrom: SourcePosition)(using Context): Context =
ctx.fresh.setProperty(MacroExpansionPosition, inlinedFrom).setTypeAssigner(new Typer).withSource(inlinedFrom.source)
}

11 changes: 5 additions & 6 deletions compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ object PickledQuotes {
def pickleQuote(tree: Tree)(using Context): PickledQuote =
if (ctx.reporter.hasErrors) Nil
else {
assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
// FIXME handle new optimization opportunities. Previousliy we got some `Inlined(EmptyTree, Nil, Hole(...))` that did not get optimized
// assert(!tree.isInstanceOf[Hole]) // Should not be pickled as it represents `'{$x}` which should be optimized to `x`
val pickled = pickle(tree)
TastyString.pickle(pickled)
}
Expand All @@ -56,11 +57,9 @@ object PickledQuotes {
val tastyBytes = TastyString.unpickle(tasty)
val unpickled = withMode(Mode.ReadPositions)(
unpickle(tastyBytes, splices, isType = false))
val Inlined(call, Nil, expnasion) = unpickled
val inlineCtx = inlineContext(call)
val expansion1 = spliceTypes(expnasion, splices)(using inlineCtx)
val expansion2 = spliceTerms(expansion1, splices)(using inlineCtx)
cpy.Inlined(unpickled)(call, Nil, expansion2)
val expansion1 = spliceTypes(unpickled, splices)
val expansion2 = spliceTerms(expansion1, splices)
cpy.Inlined(unpickled)(EmptyTree, Nil, expansion2)
}

/** Unpickle the tree contained in the TastyType */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ object QuoteContextImpl {
new QuoteContextImpl(ctx)

def showTree(tree: tpd.Tree)(using Context): String = {
val qctx = QuoteContextImpl()(using MacroExpansion.context(tree))
val qctx = QuoteContextImpl()(using MacroExpansion.context(tree.sourcePos))
val syntaxHighlight =
if (ctx.settings.color.value == "always") SyntaxHighlight.ANSI
else SyntaxHighlight.plain
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ object report:
if (ctx.settings.Ydebug.value) warning(msg, pos)

private def addInlineds(pos: SrcPos)(using Context): SourcePosition =
def recur(pos: SourcePosition, inlineds: List[Trees.Tree[?]]): SourcePosition = inlineds match
case inlined :: inlineds1 => pos.withOuter(recur(inlined.sourcePos, inlineds1))
def recur(pos: SourcePosition, inlineds: List[SrcPos]): SourcePosition = inlineds match
case inlined :: inlineds1 => pos.sourcePos.withOuter(recur(inlined.sourcePos, inlineds1))
case Nil => pos
recur(pos.sourcePos, tpd.enclosingInlineds)

Expand Down
30 changes: 24 additions & 6 deletions compiler/src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ object Erasure {
if (tree.typeOpt.isRef(defn.UnitClass))
tree.withType(tree.typeOpt)
else if (tree.const.tag == Constants.ClazzTag)
clsOf(tree.const.typeValue)
clsOf(tree.const.typeValue).withSpan(tree.span)
else
super.typedLiteral(tree)

Expand Down Expand Up @@ -739,6 +739,23 @@ object Erasure {
checkValue(checkNotErased(recur(qual1)), pt)
}

// TODO track in a cleaner way
private var enclosingSrcPos: util.SrcPos = util.NoSourcePosition

override def typed(tree: untpd.Tree, pt: Type, locked: TypeVars)(using Context): Tree =
val old = enclosingSrcPos
enclosingSrcPos = tree
val tree1 =
try super.typed(tree, pt, locked)
finally enclosingSrcPos = old

if tree1.source.exists && ctx.source != tree1.source && ctx.source == ctx.owner.topLevelClass.source
then
// TODO reposition while erasing instead of retraversing
Inliner.reposition(tree1, enclosingSrcPos.span)
else tree1


override def typedThis(tree: untpd.This)(using Context): Tree =
if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree)
else {
Expand Down Expand Up @@ -830,17 +847,18 @@ object Erasure {
override def typedTry(tree: untpd.Try, pt: Type)(using Context): Try =
super.typedTry(tree, adaptProto(tree, pt))

override def typedBlock(tree: untpd.Block, pt: Type)(using Context): Tree =
super.typedBlock(tree, pt) match
// Drop empty block after it has been repositioned (see Inliner.reposition)
case Block(Nil, expr) => expr
case block => block

private def adaptProto(tree: untpd.Tree, pt: Type)(using Context) =
if (pt.isValueType) pt else
if (tree.typeOpt.derivesFrom(ctx.definitions.UnitClass))
tree.typeOpt
else valueErasure(tree.typeOpt)

override def typedInlined(tree: untpd.Inlined, pt: Type)(using Context): Tree =
super.typedInlined(tree, pt) match {
case tree: Inlined => Inliner.dropInlined(tree)
}

override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
if (sym.isEffectivelyErased) erasedDef(sym)
else
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/FirstTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase =>
case _ => tree
}

override def transformInlined(tree: Inlined)(using Context): Tree =
cpy.Block(tree)(tree.bindings, tree.expansion)

// invariants: all modules have companion objects
// all types are TypeTrees
// all this types are explicit
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 @@ -394,7 +394,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: Return =>
Expand Down
4 changes: 1 addition & 3 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
super.transform(tree1)
}
case Inlined(call, bindings, expansion) if !call.isEmpty =>
val pos = call.sourcePos
val callTrace = Inliner.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call)))
cpy.Inlined(tree)(EmptyTree, transformSub(bindings), transform(expansion)(using inlineContext(tree)))
case templ: Template =>
withNoCheckNews(templ.parents.flatMap(newPart)) {
forwardParamAccessors(templ)
Expand Down
10 changes: 2 additions & 8 deletions compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,8 @@ class ReifyQuotes extends MacroTransform {
}
else {
val (body1, splices) = nested(isQuote = true).splitQuote(body)(using quoteContext)
if (level == 0) {
val body2 =
if (body1.isType) body1
else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1)
pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span)
}
else
body
if level == 0 then pickledQuote(body1, splices, body.tpe, isType).withSpan(quote.span)
else body
}
}

Expand Down
62 changes: 0 additions & 62 deletions compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala

This file was deleted.

Loading