From 148736c3df1fa6463b4b2658c01bcf452a52c224 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 7 Jan 2011 14:44:18 +0000 Subject: Made NamesDefault more robust to support idempo... Made NamesDefault more robust to support idempotent compilation. --- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 7 +++++++ .../scala/tools/nsc/typechecker/NamesDefaults.scala | 8 ++++++-- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 14 ++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 5aabe7a72e..4bebc0fddc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1036,6 +1036,13 @@ trait Namers { self: Analyzer => if (!isConstr) meth.owner.resetFlag(INTERFACE) // there's a concrete member now val default = parentNamer.enterSyntheticSym(defaultTree) + if (forInteractive && default.owner.isTerm) { + // enter into map from method symbols to default arguments. + // if compiling the same local block several times (which can happen in interactive mode) + // we might otherwise not find the default symbol, because the second time it the + // method symbol will be re-entered in the scope but the default parameter will not. + defaultParametersOfMethod(meth) += default + } } else if (baseHasDefault) { // the parameter does not have a default itself, but the corresponding parameter // in the base class does. diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 7982617fee..0c9bebd510 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -8,7 +8,8 @@ package typechecker import symtab.Flags._ -import scala.collection.mutable.ListBuffer +import scala.collection.mutable.{ListBuffer, WeakHashMap} +import scala.collection.immutable.Set /** * @author Lukas Rytz @@ -19,6 +20,10 @@ trait NamesDefaults { self: Analyzer => import global._ import definitions._ + val defaultParametersOfMethod = new WeakHashMap[Symbol, Set[Symbol]] { + override def default(key: Symbol) = Set() + } + case class NamedApplyInfo(qual: Option[Tree], targs: List[Tree], vargss: List[List[Tree]], blockTyper: Typer) val noApplyInfo = NamedApplyInfo(None, Nil, Nil, null) @@ -29,7 +34,6 @@ trait NamesDefaults { self: Analyzer => } def isNamed(arg: Tree) = nameOf(arg).isDefined - /** @param pos maps indicies from old to new */ def reorderArgs[T: ClassManifest](args: List[T], pos: Int => Int): List[T] = { val res = new Array[T](args.length) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7ef219bb23..2099278fe3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1797,14 +1797,20 @@ trait Typers extends Modes { */ def typedBlock(block: Block, mode: Int, pt: Type): Block = { val syntheticPrivates = new ListBuffer[Symbol] + def enterIfNotThere(sym: Symbol) { + var e = context.scope.lookupEntry(sym.name) + while ((e ne null) && (e.sym ne sym)) e = e.tail + if (e eq null) context.scope.enter(sym) + } try { namer.enterSyms(block.stats) for (stat <- block.stats) { if (forInteractive && stat.isDef) { - // this might be redundant now - var e = context.scope.lookupEntry(stat.symbol.name) - while ((e ne null) && (e.sym ne stat.symbol)) e = e.tail - if (e eq null) context.scope.enter(stat.symbol) + // this logic is needed in case typer was interrupted half way through a block and then comes + // back to do the block again. In that case the definitions that were already attributed as well as any + // default parameters of such methods need to be re-entered in the current scope. + enterIfNotThere(stat.symbol) + defaultParametersOfMethod(stat.symbol) foreach enterIfNotThere } enterLabelDef(stat) } -- cgit v1.2.3