Skip to content

Commit 196c1a4

Browse files
committed
Support completion from source
1 parent 7390f83 commit 196c1a4

File tree

8 files changed

+93
-16
lines changed

8 files changed

+93
-16
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import transform.TreeChecker
1818
import rewrite.Rewrites
1919
import java.io.{BufferedWriter, OutputStreamWriter}
2020
import printing.XprintMode
21+
import parsing.Parsers.Parser
2122
import typer.ImplicitRunInfo
2223

2324
import scala.annotation.tailrec
@@ -169,6 +170,20 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
169170
runPhases(runCtx)
170171
if (!ctx.reporter.hasErrors) Rewrites.writeBack()
171172
}
173+
174+
/** Enter top-level definitions of classes and objects contain in Scala source file `file`.
175+
* The newly added symbols replace any previously entered symbols.
176+
*/
177+
def enterRoots(file: AbstractFile)(implicit ctx: Context): Unit =
178+
if (!files.contains(file)) {
179+
val unit = new CompilationUnit(getSource(file.path))
180+
enterRoots(unit)(runContext.fresh.setCompilationUnit(unit))
181+
}
182+
183+
private def enterRoots(unit: CompilationUnit)(implicit ctx: Context): Unit = {
184+
unit.untpdTree = new Parser(unit.source).parse()
185+
ctx.typer.lateEnter(unit.untpdTree)
186+
}
172187

173188
private sealed trait PrintedTree
174189
private /*final*/ case class SomePrintedTree(phase: String, tree: String) extends PrintedTree

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ object Denotations {
929929
// printPeriods(current)
930930
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
931931
if (current.validFor.firstPhaseId >= targetId)
932-
insertInsteadOf(current)
932+
current.replaceWith(this)
933933
else {
934934
current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1)
935935
insertAfter(current)
@@ -950,7 +950,7 @@ object Denotations {
950950
val current1: SingleDenotation = f(current.asSymDenotation)
951951
if (current1 ne current) {
952952
current1.validFor = current.validFor
953-
current1.insertInsteadOf(current)
953+
current.replaceWith(current1)
954954
}
955955
hasNext = current1.nextInRun.validFor.code > current1.validFor.code
956956
current = current1.nextInRun
@@ -972,14 +972,14 @@ object Denotations {
972972
* The code to achieve this is subtle in that it works correctly
973973
* whether the replaced denotation is the only one in its cycle or not.
974974
*/
975-
private def insertInsteadOf(old: SingleDenotation): Unit = {
976-
var prev = old
977-
while (prev.nextInRun ne old) prev = prev.nextInRun
975+
private[dotc] def replaceWith(newd: SingleDenotation): Unit = {
976+
var prev = this
977+
while (prev.nextInRun ne this) prev = prev.nextInRun
978978
// order of next two assignments is important!
979-
prev.nextInRun = this
980-
this.nextInRun = old.nextInRun
981-
old.validFor = Nowhere
982-
old.nextInRun = this
979+
prev.nextInRun = newd
980+
newd.nextInRun = nextInRun
981+
validFor = Nowhere
982+
nextInRun = newd
983983
}
984984

985985
def staleSymbolError(implicit ctx: Context) =

compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/* NSC -- new Scala compiler
2-
* Copyright 2005-2012 LAMP/EPFL
3-
* @author Martin Odersky
4-
*/
5-
61
package dotty.tools
72
package dotc
83
package core
@@ -199,7 +194,7 @@ class SymbolLoaders {
199194
!root.unforcedDecls.lookup(classRep.name.toTypeName).exists
200195

201196
if (!root.isRoot) {
202-
val classReps = classPath.classes(packageName)
197+
val classReps = classPath.list(packageName).classesAndSources
203198

204199
for (classRep <- classReps)
205200
if (!maybeModuleClass(classRep) && isFlatName(classRep) == flat &&
@@ -343,5 +338,6 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {
343338
class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader {
344339
def description(implicit ctx: Context) = "source file " + srcfile.toString
345340
override def sourceFileOrNull = srcfile
346-
def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = unsupported("doComplete")
341+
def doComplete(root: SymDenotation)(implicit ctx: Context): Unit =
342+
ctx.run.enterRoots(srcfile)
347343
}

compiler/src/dotty/tools/dotc/typer/Namer.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ class Namer { typer: Typer =>
205205
*/
206206
val scope = newScope
207207

208+
/** We are entering symbols coming from a SourceLoader */
209+
private[this] var lateCompile = false
210+
208211
/** The symbol of the given expanded tree. */
209212
def symbolOfTree(tree: Tree)(implicit ctx: Context): Symbol = {
210213
val xtree = expanded(tree)
@@ -335,6 +338,15 @@ class Namer { typer: Typer =>
335338
*/
336339
def enterSymbol(sym: Symbol)(implicit ctx: Context) = {
337340
if (sym.exists) {
341+
if (lateCompile && sym.owner.is(Package)) {
342+
val preExisting = ctx.effectiveScope.lookup(sym.name)
343+
if (preExisting.exists) {
344+
typr.println(i"overwriting $preExisting to late loaded $sym")
345+
val old = preExisting.denot
346+
old.replaceWith(sym.denot)
347+
old.info = sym.info
348+
}
349+
}
338350
typr.println(s"entered: $sym in ${ctx.owner}")
339351
ctx.enter(sym)
340352
}
@@ -727,6 +739,16 @@ class Namer { typer: Typer =>
727739
localCtx
728740
}
729741

742+
/** Index and annotate symbols in `tree` while asserting the `lateCompile` flag.
743+
* This will cause any old top-level symbol with the same fully qualified
744+
* name as a newly created symbol to be replaced.
745+
*/
746+
def lateEnter(tree: Tree)(implicit ctx: Context) = {
747+
val saved = lateCompile
748+
lateCompile = true
749+
try indexAndAnnotate(tree :: Nil) finally lateCompile = saved
750+
}
751+
730752
/** The completer of a symbol defined by a member def or import (except ClassSymbols) */
731753
class Completer(val original: Tree)(implicit ctx: Context) extends LazyType {
732754

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class CompilationTests extends ParallelTesting {
5656
compileFile("../tests/pos-special/utf8encoded.scala", explicitUTF8) +
5757
compileFile("../tests/pos-special/utf16encoded.scala", explicitUTF16) +
5858
compileFile("../tests/pos-special/i3589-b.scala", defaultOptions.and("-Xfatal-warnings")) +
59+
compileFile("../tests/pos-special/completeFromSource/Test.scala", defaultOptions.and("-sourcepath", "../tests/pos-special")) +
60+
compileFile("../tests/pos-special/completeFromSource/Test2.scala", defaultOptions.and("-sourcepath", "../tests/pos-special")) +
5961
compileList(
6062
"compileMixed",
6163
List(
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package completeFromSource
2+
3+
class Test extends nested.A(22) {
4+
5+
val y: Int = this.x
6+
7+
val a = nested.A(33)
8+
9+
println(a.x)
10+
11+
}
12+
13+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package completeFromSource
2+
import nested._
3+
4+
class Test2 extends A(22) {
5+
6+
val y: Int = this.x
7+
8+
val a = A(33)
9+
10+
println(a.x)
11+
12+
}
13+
14+
15+
16+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package completeFromSource.nested
2+
3+
class A(y: Int) {
4+
5+
val x: Int = y
6+
7+
}
8+
9+
object A {
10+
11+
def apply(x: Int) = new A(22)
12+
13+
}

0 commit comments

Comments
 (0)