Skip to content

Commit

Permalink
detect changed selectIn: error when same file, or suspend otherwise
Browse files Browse the repository at this point in the history
  • Loading branch information
bishabosha committed Oct 8, 2024
1 parent 020617f commit c45af2b
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 19 deletions.
8 changes: 7 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,14 @@ object Annotations {
assert(myTree != null)
myTree match {
case treeFn: (Context ?=> Tree) @unchecked =>
val retainedFn = treeFn // for some reason treeFn is null if exception is thrown
var result: Tree | Null = null
myTree = null
myTree = atPhaseBeforeTransforms(treeFn)
try
result = atPhaseBeforeTransforms(treeFn)
myTree = result
finally if result == null then
myTree = retainedFn // reset, if unit is suspended then it will re-enter this annotation
case _ =>
}
myTree.asInstanceOf[Tree]
Expand Down
30 changes: 14 additions & 16 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,13 @@ class TreeUnpickler(reader: TastyReader,
case ex: Exception => fail(ex)
}

class TreeReader(val reader: TastyReader) {
class TreeReader(val reader: TastyReader, inInlineBody: Boolean = false) {
import reader.*

def forkAt(start: Addr): TreeReader = new TreeReader(subReader(start, endAddr))
def fork: TreeReader = forkAt(currentAddr)
def forkAt(start: Addr, inInlineBody: Boolean = false): TreeReader =
new TreeReader(subReader(start, endAddr), inInlineBody)

def fork: TreeReader = forkAt(currentAddr, inInlineBody)

def skipParentTree(tag: Int): Unit = {
if tag == SPLITCLAUSE then ()
Expand Down Expand Up @@ -694,7 +696,7 @@ class TreeUnpickler(reader: TastyReader,
val ctx1 = localContext(sym)(using ctx0).addMode(Mode.ReadPositions)
inContext(sourceChangeContext(Addr(0))(using ctx1)) {
// avoids space leaks by not capturing the current context
forkAt(rhsStart).readTree()
forkAt(rhsStart, inInlineBody = true).readTree()
}
})
goto(start)
Expand Down Expand Up @@ -1580,21 +1582,14 @@ class TreeUnpickler(reader: TastyReader,
val d = ownerTpe.decl(name).atSignature(sig, target)
(if !d.exists then lookupInSuper else d).asSeenFrom(prefix)

val denot0 = inContext(ctx.addMode(Mode.ResolveFromTASTy)):
val denot = inContext(ctx.addMode(Mode.ResolveFromTASTy)):
searchDenot // able to resolve SourceInvisible members

val denot =
if
denot0.symbol.exists
&& denot0.symbol.is(SourceInvisible)
&& denot0.symbol.isDefinedInSource
then
searchDenot // fallback
else
denot0


makeSelect(qual, name, denot)
val sel = makeSelect(qual, name, denot)
if denot == NoDenotation && inInlineBody && sel.denot.symbol.exists && sel.symbol.isDefinedInCurrentRun then
throw new ChangedMethodDenot(sel.denot.symbol)
sel
case REPEATED =>
val elemtpt = readTpt()
SeqLiteral(until(end)(readTree()), elemtpt)
Expand Down Expand Up @@ -1901,6 +1896,9 @@ class TreeUnpickler(reader: TastyReader,

object TreeUnpickler {

/** Specifically thrown when a SELECTin was written to TASTy, i.e. is expected to resolve, and then doesn't. */
private[dotc] final class ChangedMethodDenot(val resolved: Symbol) extends Exception

/** Define the expected format of the tasty bytes
* - TopLevel: Tasty that contains a full class nested in its package
* - Term: Tasty that contains only a term tree
Expand Down
15 changes: 13 additions & 2 deletions compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import staging.StagingLevel
import collection.mutable
import reporting.{NotConstant, trace}
import util.Spans.Span
import dotty.tools.dotc.core.tasty.TreeUnpickler

/** Support for querying inlineable methods and for inlining calls to such methods */
object Inlines:
Expand Down Expand Up @@ -158,8 +159,18 @@ object Inlines:
else if enclosingInlineds.length < ctx.settings.XmaxInlines.value && !reachedInlinedTreesLimit then
val body =
try bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
catch case _: MissingInlineInfo =>
throw CyclicReference(ctx.owner)
catch
case _: MissingInlineInfo => throw CyclicReference(ctx.owner)
case err: TreeUnpickler.ChangedMethodDenot =>
// tested in sbt-test/tasty-compat/add-param-unroll2/a_v3/A.scala
if err.resolved.source == ctx.source then
report.error(em"""cannot inline ${tree.symbol}:
| The definition of ${err.resolved.showLocated}, defined in the current file, has changed incompatibly.
| Try inlining from a different file.""", tree.srcPos)
EmptyTree
else
// Tested in sbt-test/tasty-compat/add-param-unroll2/a_v3_2/C.scala
ctx.compilationUnit.suspend("suspending in case of possible generated methods")
new InlineCall(tree).expand(body)
else
ctx.base.stopInlining = true
Expand Down

0 comments on commit c45af2b

Please sign in to comment.