Skip to content

Commit 0b78a01

Browse files
committed
Made presentation type checker idempotent and r...
Made presentation type checker idempotent and removed code in Global that was needed to work around non-idempotency.
1 parent 09052a6 commit 0b78a01

File tree

3 files changed

+45
-31
lines changed

3 files changed

+45
-31
lines changed

src/compiler/scala/tools/nsc/interactive/Global.scala

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ self =>
114114
while(true)
115115
try {
116116
try {
117-
pollForWork()
117+
pollForWork(old.pos)
118118
} catch {
119119
case ex : Throwable =>
120120
if (context.unit != null) integrateNew()
@@ -176,7 +176,7 @@ self =>
176176
* Then, poll for exceptions and execute them.
177177
* Then, poll for work reload/typedTreeAt/doFirst commands during background checking.
178178
*/
179-
def pollForWork() {
179+
def pollForWork(pos: Position) {
180180
scheduler.pollInterrupt() match {
181181
case Some(ir) =>
182182
try {
@@ -185,7 +185,7 @@ self =>
185185
} finally {
186186
activeLocks -= 1
187187
}
188-
pollForWork()
188+
pollForWork(pos)
189189
case _ =>
190190
}
191191

@@ -219,7 +219,7 @@ self =>
219219
logreplay("workitem", scheduler.nextWorkItem()) match {
220220
case Some(action) =>
221221
try {
222-
debugLog("picked up work item: "+action)
222+
debugLog("picked up work item at "+pos+": "+action)
223223
action()
224224
debugLog("done with work item: "+action)
225225
} finally {
@@ -282,7 +282,7 @@ self =>
282282
try {
283283
while (true) {
284284
logreplay("wait for more work", { scheduler.waitForMoreWork(); true })
285-
pollForWork()
285+
pollForWork(NoPosition)
286286
debugLog("got more work")
287287
while (outOfDate) {
288288
try {
@@ -359,7 +359,7 @@ self =>
359359
*/
360360
def typeCheck(unit: RichCompilationUnit) {
361361
debugLog("type checking: "+unit)
362-
if (currentlyChecked == Some(unit) || unit.status > JustParsed) reset(unit)
362+
//if (currentlyChecked == Some(unit) || unit.status > JustParsed) reset(unit) // not deeded for idempotent type checker phase
363363
if (unit.status == NotLoaded) parse(unit)
364364
currentlyChecked = Some(unit)
365365
currentTyperRun.typeCheck(unit)
@@ -412,9 +412,11 @@ self =>
412412
} catch {
413413
case CancelException =>
414414
;
415+
/* Commented out. Typing should always cancel requests
415416
case ex @ FreshRunReq =>
416417
scheduler.postWorkItem(() => respondGradually(response)(op))
417418
throw ex
419+
*/
418420
case ex =>
419421
response raise ex
420422
throw ex
@@ -459,7 +461,7 @@ self =>
459461
unit.targetPos = pos
460462
try {
461463
debugLog("starting targeted type check")
462-
newTyperRun()
464+
//newTyperRun() // not deeded for idempotent type checker phase
463465
typeCheck(unit)
464466
println("tree not found at "+pos)
465467
EmptyTree
@@ -477,7 +479,7 @@ self =>
477479
val unit = unitOf(source)
478480
if (forceReload) reset(unit)
479481
if (unit.status <= JustParsed) {
480-
newTyperRun()
482+
//newTyperRun() // not deeded for idempotent type checker phase
481483
typeCheck(unit)
482484
}
483485
unit.body
@@ -678,10 +680,10 @@ self =>
678680
class TyperRun extends Run {
679681
// units is always empty
680682

681-
/** canRedefine is used to detect double declarations in multiple source files.
683+
/** canRedefine is used to detect double declarations of classes and objects
684+
* in multiple source files.
682685
* Since the IDE rechecks units several times in the same run, these tests
683686
* are disabled by always returning true here.
684-
* (I think we don't need that anymore)
685687
*/
686688
override def canRedefine(sym: Symbol) = true
687689

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ trait Namers { self: Analyzer =>
173173
if (!(sym.isSourceMethod && sym.owner.isClass && !sym.owner.isPackageClass)) {
174174
var prev = scope.lookupEntry(sym.name)
175175
if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) {
176-
doubleDefError(sym.pos, prev.sym)
177-
sym setInfo ErrorType
178-
scope unlink prev.sym // let them co-exist...
179-
scope enter sym
176+
doubleDefError(sym.pos, prev.sym)
177+
sym setInfo ErrorType
178+
scope unlink prev.sym // let them co-exist...
179+
scope enter sym
180180
} else scope enter sym
181181
} else scope enter sym
182182
}
@@ -338,13 +338,32 @@ trait Namers { self: Analyzer =>
338338
} else setInfo(sym)(ltype)
339339
}
340340

341+
def enterIfNotThere(sym: Symbol) {
342+
val scope = context.scope
343+
var e = scope.lookupEntry(sym.name)
344+
while ((e ne null) && (e.owner eq scope) && (e.sym ne sym)) e = e.tail
345+
if (!((e ne null) && (e.owner eq scope))) context.scope.enter(sym)
346+
}
347+
341348
def enterSym(tree: Tree): Context = {
342349
def finishWith(tparams: List[TypeDef]) { enterSymFinishWith(tree, tparams) }
343350
def finish = finishWith(Nil)
344351
def sym = tree.symbol
345-
if (sym != NoSymbol)
352+
if (sym != NoSymbol) {
353+
if (forInteractive && sym != null && sym.owner.isTerm) {
354+
// this logic is needed in case typer was interrupted half way through and then comes
355+
// back to do the tree again. In that case the definitions that were already
356+
// attributed as well as any default parameters of such methods need to be
357+
// re-entered in the current scope.
358+
enterIfNotThere(sym)
359+
if (sym.isLazy) {
360+
val acc = sym.lazyAccessor
361+
if (acc != NoSymbol) enterIfNotThere(acc)
362+
}
363+
defaultParametersOfMethod(sym) foreach enterIfNotThere
364+
}
346365
return this.context
347-
366+
}
348367
try {
349368
val owner = context.owner
350369
tree match {

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,23 +1798,9 @@ trait Typers extends Modes {
17981798
*/
17991799
def typedBlock(block: Block, mode: Int, pt: Type): Block = {
18001800
val syntheticPrivates = new ListBuffer[Symbol]
1801-
def enterIfNotThere(sym: Symbol) {
1802-
var e = context.scope.lookupEntry(sym.name)
1803-
while ((e ne null) && (e.sym ne sym)) e = e.tail
1804-
if (e eq null) context.scope.enter(sym)
1805-
}
18061801
try {
18071802
namer.enterSyms(block.stats)
1808-
for (stat <- block.stats) {
1809-
if (forInteractive && stat.isDef) {
1810-
// this logic is needed in case typer was interrupted half way through a block and then comes
1811-
// back to do the block again. In that case the definitions that were already attributed as well as any
1812-
// default parameters of such methods need to be re-entered in the current scope.
1813-
enterIfNotThere(stat.symbol)
1814-
defaultParametersOfMethod(stat.symbol) foreach enterIfNotThere
1815-
}
1816-
enterLabelDef(stat)
1817-
}
1803+
for (stat <- block.stats) enterLabelDef(stat)
18181804

18191805
if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
18201806
// This is very tricky stuff, because we are navigating
@@ -1888,6 +1874,13 @@ trait Typers extends Modes {
18881874
error(x.pos, "_* may only come last")
18891875

18901876
val pat1: Tree = typedPattern(cdef.pat, pattpe)
1877+
1878+
if (forInteractive) {
1879+
for (bind @ Bind(name, _) <- cdef.pat)
1880+
if (name.toTermName != nme.WILDCARD && bind.symbol != null && bind.symbol != NoSymbol)
1881+
namer.enterIfNotThere(bind.symbol)
1882+
}
1883+
18911884
val guard1: Tree = if (cdef.guard == EmptyTree) EmptyTree
18921885
else typed(cdef.guard, BooleanClass.tpe)
18931886
var body1: Tree = typed(cdef.body, pt)

0 commit comments

Comments
 (0)