diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index ba86e3e70de2..bf1d6e05e98f 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -33,6 +33,7 @@ class Run(comp: Compiler)(implicit ctx: Context) { compileSources(sources) } catch { case NonFatal(ex) => + ex.printStackTrace() ctx.println(i"exception occurred while compiling $units%, %") throw ex } @@ -50,7 +51,6 @@ class Run(comp: Compiler)(implicit ctx: Context) { } protected def compileUnits() = Stats.monitorHeartBeat { - ctx.checkSingleThreaded() val phases = ctx.squashPhases(ctx.phasePlan, ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) ctx.usePhases(phases) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 522240b0f09a..464e43ddd270 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -16,7 +16,7 @@ import Flags.ParamAccessor import util.Positions._ import ast.Trees._ import ast.untpd -import util.{FreshNameCreator, SimpleMap, SourceFile, NoSource} +import util.{FreshNameCreator, SimpleMap, SourceFile, NoSource, CheckedSingleThreaded} import typer._ import Implicits.ContextualImplicits import config.Settings._ @@ -615,16 +615,6 @@ object Contexts { superIdOfClass.clear() lastSuperId = -1 } - - // Test that access is single threaded - - /** The thread on which `checkSingleThreaded was invoked last */ - @sharable private var thread: Thread = null - - /** Check that we are on the same thread as before */ - def checkSingleThreaded() = - if (thread == null) thread = Thread.currentThread() - else assert(thread == Thread.currentThread(), "illegal multithreaded access to ContextBase") } object Context { diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 666908fabd0e..e82885b99d97 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -205,8 +205,32 @@ object Denotations { denot.symbol } + def slowSearch(name: Name)(implicit ctx: Context): Symbol = + info.decls.find(_.name == name).getOrElse(NoSymbol) + def requiredMethod(name: PreName)(implicit ctx: Context): TermSymbol = - info.member(name.toTermName).requiredSymbol(_ is Method).asTerm + if (info.exists) { + val meth = info.member(name.toTermName) + if (meth.exists) meth.requiredSymbol(_ is Method).asTerm + else { // Heisenbughunt + println(s"*** missing method: ${name.toString} in $this") + info.decls.checkConsistent() + println(i"decls = ${info.decls}") + if (slowSearch(name.toTermName).exists) { + System.err.println(i"**** slow search found: ${slowSearch(name.toTermName)}") + System.err.println("scope entries found:") + var e = info.decls.lastEntry + while (e != null) { + println(e.name) + e = e.prev + } + System.err.println("no more entries found") + } + throw new TypeError(s"Missing method: $this . $name") + } + } + else throw new TypeError(s"M issing module: $this") + def requiredMethodRef(name: PreName)(implicit ctx: Context): TermRef = requiredMethod(name).termRef diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index 3daa8117e291..76be2fde3a0e 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -153,7 +153,7 @@ object Scopes { * SynchronizedScope as mixin. */ class MutableScope protected[Scopes](initElems: ScopeEntry, initSize: Int, val nestingLevel: Int = 0) - extends Scope { + extends Scope with util.CheckedSingleThreaded { protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { this(base.lastEntry, base.size, base.nestingLevel + 1) @@ -208,8 +208,10 @@ object Scopes { } /** create and enter a scope entry */ - protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = + protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = { + checkSingleThreaded() newScopeEntry(sym.name, sym) + } private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = { val idx = e.name.hashCode & (hashTable.length - 1) @@ -310,6 +312,7 @@ object Scopes { /** Lookup a symbol entry matching given name. */ override final def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = { + checkSingleThreaded() var e: ScopeEntry = null if (hashTable ne null) { e = hashTable(name.hashCode & (hashTable.length - 1)) @@ -339,6 +342,7 @@ object Scopes { * Does _not_ include the elements of inherited scopes. */ override final def toList: List[Symbol] = { + checkSingleThreaded() if (elemsCache eq null) { elemsCache = Nil var e = lastEntry diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 5d079640fb9a..79400574ac27 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -70,7 +70,7 @@ object SymDenotations { final val name: Name, initFlags: FlagSet, initInfo: Type, - initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) { + initPrivateWithin: Symbol = NoSymbol) extends SingleDenotation(symbol) with util.CheckedSingleThreaded { //assert(symbol.id != 4940, name) @@ -148,10 +148,12 @@ object SymDenotations { * The info is an instance of TypeType iff this is a type denotation * Uncompleted denotations set myInfo to a LazyType. */ - final def info(implicit ctx: Context): Type = myInfo match { + final def info(implicit ctx: Context): Type = { + if (exists) checkSingleThreaded() + myInfo match { case myInfo: LazyType => completeFrom(myInfo); info case _ => myInfo - } + }} /** The type info, or, if symbol is not yet completed, the completer */ final def infoOrCompleter = myInfo @@ -1534,6 +1536,7 @@ object SymDenotations { } override final def findMember(name: Name, pre: Type, excluded: FlagSet)(implicit ctx: Context): Denotation = { + if (exists) checkSingleThreaded() val raw = if (excluded is Private) nonPrivateMembersNamed(name) else membersNamed(name) raw.filterExcluded(excluded).asSeenFrom(pre).toDenot(pre) } diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index e33f9651ecd7..7827751d6c08 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -364,7 +364,8 @@ object Symbols { * @param coord The coordinates of the symbol (a position or an index) * @param id A unique identifier of the symbol (unique per ContextBase) */ - class Symbol private[Symbols] (val coord: Coord, val id: Int) extends DotClass with printing.Showable { + class Symbol private[Symbols] (val coord: Coord, val id: Int) + extends DotClass with printing.Showable with util.CheckedSingleThreaded { type ThisName <: Name @@ -381,6 +382,8 @@ object Symbols { final def denot(implicit ctx: Context): SymDenotation = { var denot = lastDenot if (!(denot.validFor contains ctx.period)) { + if (denot.exists) + checkSingleThreaded() denot = denot.current.asInstanceOf[SymDenotation] lastDenot = denot } diff --git a/src/dotty/tools/dotc/typer/FrontEnd.scala b/src/dotty/tools/dotc/typer/FrontEnd.scala index eee8744a5dd4..d91919328642 100644 --- a/src/dotty/tools/dotc/typer/FrontEnd.scala +++ b/src/dotty/tools/dotc/typer/FrontEnd.scala @@ -23,6 +23,7 @@ class FrontEnd extends Phase { try body catch { case NonFatal(ex) => + ex.printStackTrace() ctx.println(s"exception occurred while $doing ${ctx.compilationUnit}") throw ex } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 10bca44bfb27..4e6547c5751b 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1151,7 +1151,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit try adapt(typedUnadapted(tree, pt), pt, tree) catch { case ex: CyclicReference => errorTree(tree, cyclicErrorMsg(ex)) - case ex: TypeError => errorTree(tree, ex.getMessage) + case ex: TypeError => + ex.printStackTrace() // debug + errorTree(tree, ex.getMessage) } } diff --git a/src/dotty/tools/dotc/util/CheckedSingleThreaded.scala b/src/dotty/tools/dotc/util/CheckedSingleThreaded.scala new file mode 100644 index 000000000000..06791d72c9a9 --- /dev/null +++ b/src/dotty/tools/dotc/util/CheckedSingleThreaded.scala @@ -0,0 +1,14 @@ +package dotty.tools +package dotc.util + +trait CheckedSingleThreaded { + + /** The thread on which `checkSingleThreaded was invoked last */ + @sharable @volatile private var thread: Thread = null + + /** Check that we are on the same thread as before */ + def checkSingleThreaded() = + if (thread == null) thread = Thread.currentThread() + else assert(thread == Thread.currentThread(), s"illegal multithreaded access to $this") + +} \ No newline at end of file