From fde88c76ceb1e575b89c813a039df1967c6f995c Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 19 Aug 2013 15:12:04 -0700 Subject: No longer crash on NoSymbol.owner. Historically calling NoSymbol.owner has crashed the compiler. With this commit, NoSymbol owns itself. This is consistent with the way ownership chains are handled elsewhere in the compiler (e.g. NoContext.owner is NoContext, NoSymbol.enclClass is NoSymbol, and so on) and frees every call site which handles symbols from having to perform precondition tests against NoSymbol. Since calling NoSymbol.owner sometimes (not always) indicates a bug which we'd like to catch sooner than later, I have introduced a couple more methods for selected call sites. def owner: Symbol // NoSymbol.owner is self, log if -Xdev def safeOwner: Symbol // NoSymbol.owner is self, ignore def assertOwner: Symbol // NoSymbol.owner is fatal The idea is that everyone can call sym.owner without undue anxiety or paranoid null-like tests. When compiling under -Xdev calls to `owner` are logged with a stack trace, so any call sites for which that is an expected occurrence should call safeOwner instead to communicate the intention and stay out of the log. Conversely, any call site where crashing on the owner call was a desirable behavior can opt into calling assertOwner. This commit also includes all the safeOwner calls necessary to give us a silent log when compiling scala. --- .../scala/reflect/macros/compiler/Validators.scala | 6 +++- src/compiler/scala/tools/nsc/Global.scala | 5 ++- src/compiler/scala/tools/nsc/ast/Trees.scala | 5 +-- .../scala/tools/nsc/backend/opt/Inliners.scala | 8 ++--- .../scala/tools/nsc/transform/AddInterfaces.scala | 26 -------------- .../scala/tools/nsc/transform/Erasure.scala | 3 +- .../scala/tools/nsc/transform/LambdaLift.scala | 2 +- src/compiler/scala/tools/nsc/transform/Mixin.scala | 5 +-- .../tools/nsc/transform/patmat/MatchAnalysis.scala | 8 ++--- .../tools/nsc/transform/patmat/MatchCodeGen.scala | 4 +-- .../nsc/transform/patmat/MatchTranslation.scala | 2 +- .../nsc/transform/patmat/MatchTreeMaking.scala | 3 +- .../scala/tools/nsc/typechecker/Contexts.scala | 13 +++---- .../scala/tools/nsc/typechecker/Duplicators.scala | 36 +++++++++---------- .../scala/tools/nsc/typechecker/Namers.scala | 4 +-- .../scala/tools/nsc/typechecker/RefChecks.scala | 4 +-- .../tools/nsc/typechecker/SuperAccessors.scala | 4 +-- .../tools/nsc/typechecker/TypeDiagnostics.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 4 +++ .../scala/reflect/internal/Definitions.scala | 5 +-- .../scala/reflect/internal/SymbolTable.scala | 7 +++- src/reflect/scala/reflect/internal/Symbols.scala | 41 ++++++++++++++-------- src/reflect/scala/reflect/internal/Trees.scala | 4 +-- src/reflect/scala/reflect/internal/Types.scala | 2 +- .../scala/reflect/internal/tpe/TypeMaps.scala | 4 +-- src/repl/scala/tools/nsc/interpreter/IMain.scala | 14 ++------ .../tools/nsc/interpreter/MemberHandlers.scala | 2 +- 27 files changed, 96 insertions(+), 127 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/macros/compiler/Validators.scala b/src/compiler/scala/reflect/macros/compiler/Validators.scala index fafd79d1d7..af17fd87c0 100644 --- a/src/compiler/scala/reflect/macros/compiler/Validators.scala +++ b/src/compiler/scala/reflect/macros/compiler/Validators.scala @@ -81,7 +81,11 @@ trait Validators { // Technically this can be just an alias to MethodType, but promoting it to a first-class entity // provides better encapsulation and convenient syntax for pattern matching. - private case class MacroImplSig(tparams: List[Symbol], paramss: List[List[Symbol]], ret: Type) + private case class MacroImplSig(tparams: List[Symbol], paramss: List[List[Symbol]], ret: Type) { + private def tparams_s = if (tparams.isEmpty) "" else tparams.map(_.defString).mkString("[", ", ", "]") + private def paramss_s = paramss map (ps => ps.map(s => s"${s.name}: ${s.tpe_*}").mkString("(", ", ", ")")) mkString "" + override def toString = "MacroImplSig(" + tparams_s + paramss_s + ret + ")" + } /** An actual macro implementation signature extracted from a macro implementation method. * diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index a6c69091c5..dcb41752f7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -258,6 +258,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) if (settings.debug) body } + + override protected def isDeveloper = settings.developer || super.isDeveloper + /** This is for WARNINGS which should reach the ears of scala developers * whenever they occur, but are not useful for normal users. They should * be precise, explanatory, and infrequent. Please don't use this as a @@ -265,7 +268,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) * to make them visually distinct. */ @inline final override def devWarning(msg: => String) { - if (settings.developer || settings.debug) + if (isDeveloper) warning("!!! " + msg) else log("!!! " + msg) // such warnings always at least logged diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 641ab9c279..381ffb1ed9 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -66,10 +66,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => */ def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): ClassDef = { // "if they have symbols they should be owned by `sym`" - assert( - mforall(vparamss)(p => (p.symbol eq NoSymbol) || (p.symbol.owner == sym)), - ((mmap(vparamss)(_.symbol), sym)) - ) + assert(mforall(vparamss)(_.symbol.owner == sym), (mmap(vparamss)(_.symbol), sym)) ClassDef(sym, gen.mkTemplate(sym.info.parents map TypeTree, diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 56191cc981..09095879bf 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -78,10 +78,10 @@ abstract class Inliners extends SubComponent { assert(clazz != NoSymbol, "Walked up past Object.superClass looking for " + sym + ", most likely this reveals the TFA at fault (receiver and callee don't match).") if (sym.owner == clazz || isBottomType(clazz)) sym - else sym.overridingSymbol(clazz) match { - case NoSymbol => if (sym.owner.isTrait) sym else lookup(clazz.superClass) - case imp => imp - } + else sym.overridingSymbol(clazz) orElse ( + if (sym.owner.isTrait) sym + else lookup(clazz.superClass) + ) } if (needsLookup) { val concreteMethod = lookup(clazz) diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 0dcf4d00b7..d9d08dde1e 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -367,29 +367,3 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure => } } } -/* - val ensureNoEscapes = new TypeTraverser { - def ensureNoEscape(sym: Symbol) { - if (sym.hasFlag(PRIVATE)) { - var o = currentOwner; - while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE)) - o = o.owner - if (o == sym.owner) sym.makeNotPrivate(base); - } - } - def traverse(t: Type): TypeTraverser = { - t match { - case TypeRef(qual, sym, args) => - ensureNoEscape(sym) - mapOver(t) - case ClassInfoType(parents, decls, clazz) => - parents foreach { p => traverse; () } - traverse(t.typeOfThis) - case _ => - mapOver(t) - } - this - } - } - -*/ diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index ee687e56b0..0a66ba8a32 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -525,8 +525,7 @@ abstract class Erasure extends AddInterfaces private def isDifferentErasedValueType(tpe: Type, other: Type) = isErasedValueType(tpe) && (tpe ne other) - private def isPrimitiveValueMember(sym: Symbol) = - sym != NoSymbol && isPrimitiveValueClass(sym.owner) + private def isPrimitiveValueMember(sym: Symbol) = isPrimitiveValueClass(sym.owner) @inline private def box(tree: Tree, target: => String): Tree = { val result = box1(tree) diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index ce495ca8ca..515fa66cfa 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -489,7 +489,7 @@ abstract class LambdaLift extends InfoTransform { treeCopy.Assign(tree, qual, rhs) case Ident(name) => val tree1 = - if (sym != NoSymbol && sym.isTerm && !sym.isLabel) + if (sym.isTerm && !sym.isLabel) if (sym.isMethod) atPos(tree.pos)(memberRef(sym)) else if (sym.isLocal && !isSameOwnerEnclosure(sym)) diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 1c44e86aca..3ec4d16bf5 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -734,10 +734,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { sym } - if (sym ne NoSymbol) - sym - else - createBitmap + sym orElse createBitmap } def maskForOffset(offset: Int, sym: Symbol, kind: ClassSymbol): Tree = { diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala index f089c8f5a5..dfd18d089e 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala @@ -222,7 +222,7 @@ trait MatchApproximation extends TreeAndTypeAnalysis with ScalaLogic with MatchT // so that we don't introduce new aliases for existing symbols, thus keeping the set of bound symbols minimal val (boundSubst, unboundSubst) = (subst.from zip subst.to) partition { case (f, t) => - t.isInstanceOf[Ident] && (t.symbol ne NoSymbol) && pointsToBound(f) + t.isInstanceOf[Ident] && t.symbol.exists && pointsToBound(f) } val (boundFrom, boundTo) = boundSubst.unzip val (unboundFrom, unboundTo) = unboundSubst.unzip @@ -624,9 +624,9 @@ trait MatchAnalysis extends MatchApproximation { private lazy val uniqueEqualTo = equalTo filterNot (subsumed => equalTo.exists(better => (better ne subsumed) && instanceOfTpImplies(better.tp, subsumed.tp))) private lazy val prunedEqualTo = uniqueEqualTo filterNot (subsumed => variable.staticTpCheckable <:< subsumed.tp) private lazy val ctor = (prunedEqualTo match { case List(TypeConst(tp)) => tp case _ => variable.staticTpCheckable }).typeSymbol.primaryConstructor - private lazy val ctorParams = if (ctor == NoSymbol || ctor.paramss.isEmpty) Nil else ctor.paramss.head - private lazy val cls = if (ctor == NoSymbol) NoSymbol else ctor.owner - private lazy val caseFieldAccs = if (cls == NoSymbol) Nil else cls.caseFieldAccessors + private lazy val ctorParams = if (ctor.paramss.isEmpty) Nil else ctor.paramss.head + private lazy val cls = ctor.safeOwner + private lazy val caseFieldAccs = cls.caseFieldAccessors def addField(symbol: Symbol, assign: VariableAssignment) { // SI-7669 Only register this field if if this class contains it. diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala index 1e4c56529c..6f597bef39 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala @@ -173,13 +173,13 @@ trait MatchCodeGen extends Interface { // catchAll.isEmpty iff no synthetic default case needed (the (last) user-defined case is a default) // if the last user-defined case is a default, it will never jump to the next case; it will go immediately to matchEnd val catchAllDef = matchFailGen map { matchFailGen => - val scrutRef = if(scrutSym ne NoSymbol) REF(scrutSym) else EmptyTree // for alternatives + val scrutRef = scrutSym.fold(EmptyTree: Tree)(REF) // for alternatives LabelDef(_currCase, Nil, matchEnd APPLY (matchFailGen(scrutRef))) } toList // at most 1 element // scrutSym == NoSymbol when generating an alternatives matcher - val scrutDef = if(scrutSym ne NoSymbol) List(VAL(scrutSym) === scrut) else Nil // for alternatives + val scrutDef = scrutSym.fold(List[Tree]())(sym => (VAL(sym) === scrut) :: Nil) // for alternatives // the generated block is taken apart in TailCalls under the following assumptions // the assumption is once we encounter a case, the remainder of the block will consist of cases diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala index fcee142932..9bc442467d 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala @@ -659,7 +659,7 @@ trait MatchTranslation { self: PatternMatching => object Bound { def unapply(t: Tree): Option[(Symbol, Tree)] = t match { - case t@Bind(n, p) if (t.symbol ne null) && (t.symbol ne NoSymbol) => // pos/t2429 does not satisfy these conditions + case t@Bind(n, p) if t.hasExistingSymbol => // pos/t2429 does not satisfy these conditions Some((t.symbol, p)) case _ => None } diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala index baccdcf544..b0a7749908 100644 --- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala +++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala @@ -587,9 +587,8 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging { t.symbol.owner = currentOwner case d : DefTree if (d.symbol != NoSymbol) && ((d.symbol.owner == NoSymbol) || (d.symbol.owner == origOwner)) => // don't indiscriminately change existing owners! (see e.g., pos/t3440, pos/t3534, pos/unapplyContexts2) debug.patmat("def: "+ ((d, d.symbol.ownerChain, currentOwner.ownerChain))) - if(d.symbol.moduleClass ne NoSymbol) - d.symbol.moduleClass.owner = currentOwner + d.symbol.moduleClass andAlso (_.owner = currentOwner) d.symbol.owner = currentOwner // case _ if (t.symbol != NoSymbol) && (t.symbol ne null) => debug.patmat("untouched "+ ((t, t.getClass, t.symbol.ownerChain, currentOwner.ownerChain))) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index f3a22a2cee..86a0d33737 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -269,7 +269,7 @@ trait Contexts { self: Analyzer => /** The next enclosing context (potentially `this`) that is owned by a class or method */ def enclClassOrMethod: Context = - if ((owner eq NoSymbol) || (owner.isClass) || (owner.isMethod)) this + if (!owner.exists || owner.isClass || owner.isMethod) this else outer.enclClassOrMethod /** The next enclosing context (potentially `this`) that has a `CaseDef` as a tree */ @@ -653,13 +653,8 @@ trait Contexts { self: Analyzer => lastAccessCheckDetails = "" // Console.println("isAccessible(%s, %s, %s)".format(sym, pre, superAccess)) - def accessWithinLinked(ab: Symbol) = { - val linked = ab.linkedClassOfClass - // don't have access if there is no linked class - // (before adding the `ne NoSymbol` check, this was a no-op when linked eq NoSymbol, - // since `accessWithin(NoSymbol) == true` whatever the symbol) - (linked ne NoSymbol) && accessWithin(linked) - } + // don't have access if there is no linked class (so exclude linkedClass=NoSymbol) + def accessWithinLinked(ab: Symbol) = ab.linkedClassOfClass.fold(false)(accessWithin) /* Are we inside definition of `ab`? */ def accessWithin(ab: Symbol) = { @@ -957,7 +952,7 @@ trait Contexts { self: Analyzer => // 2) sym.owner is inherited by the correct package object class // We try to establish 1) by inspecting the owners directly, and then we try // to rule out 2), and only if both those fail do we resort to looking in the info. - !sym.isPackage && (sym.owner ne NoSymbol) && ( + !sym.isPackage && sym.owner.exists && ( if (sym.owner.isPackageObjectClass) sym.owner.owner == pkgClass else diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index 0a2628b482..396f3407f3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -74,22 +74,19 @@ abstract class Duplicators extends Analyzer { override def mapOver(tpe: Type): Type = tpe match { case TypeRef(NoPrefix, sym, args) if sym.isTypeParameterOrSkolem => - var sym1 = context.scope.lookup(sym.name) - if (sym1 eq NoSymbol) { - // try harder (look in outer scopes) - // with virtpatmat, this can happen when the sym is referenced in the scope of a LabelDef but is defined in the scope of an outer DefDef (e.g., in AbstractPartialFunction's andThen) - BodyDuplicator.super.silent(_.typedType(Ident(sym.name))) match { - case SilentResultValue(t) => - sym1 = t.symbol - debuglog("fixed by trying harder: "+((sym, sym1, context))) - case _ => - } - } -// assert(sym1 ne NoSymbol, tpe) - if ((sym1 ne NoSymbol) && (sym1 ne sym)) { - debuglog("fixing " + sym + " -> " + sym1) + val sym1 = ( + context.scope lookup sym.name orElse { + // try harder (look in outer scopes) + // with virtpatmat, this can happen when the sym is referenced in the scope of a LabelDef but + // is defined in the scope of an outer DefDef (e.g., in AbstractPartialFunction's andThen) + BodyDuplicator.super.silent(_ typedType Ident(sym.name)).fold(NoSymbol: Symbol)(_.symbol) + } filter (_ ne sym) + ) + if (sym1.exists) { + debuglog(s"fixing $sym -> $sym1") typeRef(NoPrefix, sym1, mapOverArgs(args, sym1.typeParams)) - } else super.mapOver(tpe) + } + else super.mapOver(tpe) case TypeRef(pre, sym, args) => val newsym = updateSym(sym) @@ -157,7 +154,7 @@ abstract class Duplicators extends Analyzer { case vdef @ ValDef(mods, name, _, rhs) if mods.hasFlag(Flags.LAZY) => debuglog("ValDef " + name + " sym.info: " + vdef.symbol.info) invalidSyms(vdef.symbol) = vdef - val newowner = if (owner != NoSymbol) owner else context.owner + val newowner = owner orElse context.owner val newsym = vdef.symbol.cloneSymbol(newowner) newsym.setInfo(fixType(vdef.symbol.info)) vdef.symbol = newsym @@ -362,12 +359,11 @@ abstract class Duplicators extends Analyzer { case _ => debuglog("Duplicators default case: " + tree.summaryString) debuglog(" ---> " + tree) - if (tree.hasSymbolField && tree.symbol != NoSymbol && (tree.symbol.owner == AnyClass)) { + if (tree.hasSymbolField && tree.symbol.safeOwner == AnyClass) tree.symbol = NoSymbol // maybe we can find a more specific member in a subclass of Any (see AnyVal members, like ==) - } + val ntree = castType(tree, pt) - val res = super.typed(ntree, mode, pt) - res + super.typed(ntree, mode, pt) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index cac6bd2ef2..2bb2cc1ab4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -390,9 +390,7 @@ trait Namers extends MethodSynthesis { * has been defined in a separate file. */ private def validateCompanionDefs(tree: ImplDef) { - val sym = tree.symbol - if (sym eq NoSymbol) return - + val sym = tree.symbol orElse { return } val ctx = if (context.owner.isPackageObjectClass) context.outer else context val module = if (sym.isModule) sym else ctx.scope lookupModule tree.name val clazz = if (sym.isClass) sym else ctx.scope lookupClass tree.name diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 30b923e2a1..66dff792b6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -216,7 +216,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE) // Delaying calling memberType as long as possible - if (inherited ne NoSymbol) { + if (inherited.exists) { val jtpe = toJavaRepeatedParam(self memberType member) // this is a bit tortuous: we look for non-private members or bridges // if we find a bridge everything is OK. If we find another member, @@ -1521,7 +1521,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkCompileTimeOnly(sym, tree.pos) checkDelayedInitSelect(qual, sym, tree.pos) - if (sym eq NoSymbol) + if (!sym.exists) devWarning("Select node has NoSymbol! " + tree + " / " + tree.tpe) else if (sym.hasLocalFlag) varianceValidator.checkForEscape(sym, currentClass) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 6933b10a0a..12d6bb2e6a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -269,8 +269,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT && sym.enclClass != currentClass && !sym.owner.isPackageClass // SI-7091 no accessor needed package owned (ie, top level) symbols && !sym.owner.isTrait - && (sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass) - && (qual.symbol.info.member(sym.name) ne NoSymbol) + && sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass + && qual.symbol.info.member(sym.name).exists && !needsProtectedAccessor(sym, tree.pos) ) if (shouldEnsureAccessor) { diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index b4a37f9943..0c5f798c23 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -143,7 +143,7 @@ trait TypeDiagnostics { def defaultMessage = moduleMessage + preResultString + tree.tpe def applyMessage = defaultMessage + tree.symbol.locationString - if ((sym eq null) || (sym eq NoSymbol)) { + if (!tree.hasExistingSymbol) { if (isTyperInPattern) patternMessage else exprMessage } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d2ff47626d..f0c0942e95 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -63,6 +63,10 @@ trait Typers extends Adaptations with Tags with TypersTracking { } sealed abstract class SilentResult[+T] { + @inline final def fold[U](none: => U)(f: T => U): U = this match { + case SilentResultValue(value) => f(value) + case _ => none + } @inline final def map[U](f: T => U): SilentResult[U] = this match { case SilentResultValue(value) => SilentResultValue(f(value)) case x: SilentTypeError => x diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index 6b7aa2dddf..6715a5d1a6 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -227,10 +227,7 @@ trait Definitions extends api.StandardDefinitions { scope } /** Is this symbol a member of Object or Any? */ - def isUniversalMember(sym: Symbol) = ( - (sym ne NoSymbol) - && (ObjectClass isSubClass sym.owner) - ) + def isUniversalMember(sym: Symbol) = ObjectClass isSubClass sym.owner /** Is this symbol unimportable? Unimportable symbols include: * - constructors, because is not a real name diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala index c340670635..f0be0f7d05 100644 --- a/src/reflect/scala/reflect/internal/SymbolTable.scala +++ b/src/reflect/scala/reflect/internal/SymbolTable.scala @@ -60,6 +60,7 @@ abstract class SymbolTable extends macros.Universe def shouldLogAtThisPhase = false def isPastTyper = false + protected def isDeveloper: Boolean = settings.debug @deprecated("Give us a reason", "2.10.0") def abort(): Nothing = abort("unknown error") @@ -69,8 +70,12 @@ abstract class SymbolTable extends macros.Universe /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug) log(msg) - def devWarning(msg: => String): Unit = if (settings.debug) Console.err.println(msg) + def devWarning(msg: => String): Unit = if (isDeveloper) Console.err.println(msg) def throwableAsString(t: Throwable): String = "" + t + def throwableAsString(t: Throwable, maxFrames: Int): String = t.getStackTrace take maxFrames mkString "\n at " + + @inline final def devWarningDumpStack(msg: => String, maxFrames: Int): Unit = + devWarning(msg + "\n" + throwableAsString(new Throwable, maxFrames)) /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */ def debugStack(t: Throwable): Unit = devWarning(throwableAsString(t)) diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index e41038cafc..a8efa938c8 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -153,7 +153,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def asNameType(n: Name): NameType - private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api + // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api + // The null check is for NoSymbol, which can't pass a reference to itself to the constructor and also + // can't call owner_= due to an assertion it contains. + private[this] var _rawowner = if (initOwner eq null) this else initOwner private[this] var _rawflags: Long = _ def rawowner = _rawowner @@ -610,7 +613,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } final def isLazyAccessor = isLazy && lazyAccessor != NoSymbol - final def isOverridableMember = !(isClass || isEffectivelyFinal) && (this ne NoSymbol) && owner.isClass + final def isOverridableMember = !(isClass || isEffectivelyFinal) && safeOwner.isClass /** Does this symbol denote a wrapper created by the repl? */ final def isInterpreterWrapper = ( @@ -999,13 +1002,20 @@ trait Symbols extends api.Symbols { self: SymbolTable => // ------ owner attribute -------------------------------------------------------------- + /** In general when seeking the owner of a symbol, one should call `owner`. + * The other possibilities include: + * - call `safeOwner` if it is expected that the target may be NoSymbol + * - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol + * + * `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev. + * `assertOwner` aborts compilation immediately if called on NoSymbol. + */ def owner: Symbol = { if (Statistics.hotEnabled) Statistics.incCounter(ownerCount) rawowner } - - // Like owner, but NoSymbol.owner == NoSymbol instead of throwing an exception. - final def safeOwner: Symbol = if (this eq NoSymbol) NoSymbol else owner + final def safeOwner: Symbol = if (this eq NoSymbol) NoSymbol else owner + final def assertOwner: Symbol = if (this eq NoSymbol) abort("no-symbol does not have an owner") else owner // TODO - don't allow the owner to be changed without checking invariants, at least // when under some flag. Define per-phase invariants for owner/owned relationships, @@ -1781,10 +1791,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => result } - @inline final def map(f: Symbol => Symbol): Symbol = if (this eq NoSymbol) this else f(this) - - final def toOption: Option[Symbol] = if (exists) Some(this) else None - // ------ cloneing ------------------------------------------------------------------- /** A clone of this symbol. */ @@ -2179,8 +2185,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * the recursive knot. */ private def canMatchInheritedSymbols = ( - (this ne NoSymbol) - && owner.isClass + owner.isClass && !this.isClass && !this.isConstructor ) @@ -2352,6 +2357,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => @inline final def orElse(alt: => Symbol): Symbol = if (this ne NoSymbol) this else alt @inline final def andAlso(f: Symbol => Unit): Symbol = { if (this ne NoSymbol) f(this) ; this } + @inline final def fold[T](none: => T)(f: Symbol => T): T = if (this ne NoSymbol) f(this) else none + @inline final def map(f: Symbol => Symbol): Symbol = if (this eq NoSymbol) this else f(this) + + final def toOption: Option[Symbol] = if (exists) Some(this) else None + // ------ toString ------------------------------------------------------------------- @@ -3340,7 +3350,11 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def enclosingPackageClass: Symbol = this override def enclMethod: Symbol = this override def associatedFile = NoAbstractFile - override def ownerChain: List[Symbol] = List() + override def owner: Symbol = { + devWarningDumpStack("NoSymbol.owner", 15) + this + } + override def ownerChain: List[Symbol] = Nil override def ownersIterator: Iterator[Symbol] = Iterator.empty override def alternatives: List[Symbol] = List() override def reset(completer: Type): this.type = this @@ -3350,9 +3364,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def accessBoundary(base: Symbol): Symbol = enclosingRootClass def cloneSymbolImpl(owner: Symbol, newFlags: Long) = abort("NoSymbol.clone()") override def originalEnclosingMethod = this - - override def owner: Symbol = - abort("no-symbol does not have an owner") } protected def makeNoSymbol: NoSymbol = new NoSymbol diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 02bee5e369..a5a78cb3b8 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -185,8 +185,8 @@ trait Trees extends api.Trees { self: SymbolTable => def replace(from: Tree, to: Tree): Tree = new TreeReplacer(from, to, positionAware = false) transform this - def hasSymbolWhich(f: Symbol => Boolean) = - (symbol ne null) && (symbol ne NoSymbol) && f(symbol) + def hasExistingSymbol = (symbol ne null) && (symbol ne NoSymbol) + def hasSymbolWhich(f: Symbol => Boolean) = hasExistingSymbol && f(symbol) def isErroneous = (tpe ne null) && tpe.isErroneous def isTyped = (tpe ne null) && !tpe.isErroneous diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 71f46fedb7..cab2303dd0 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -3475,7 +3475,7 @@ trait Types def copyRefinedType(original: RefinedType, parents: List[Type], decls: Scope) = if ((parents eq original.parents) && (decls eq original.decls)) original else { - val owner = if (original.typeSymbol == NoSymbol) NoSymbol else original.typeSymbol.owner + val owner = original.typeSymbol.owner val result = refinedType(parents, owner) val syms1 = decls.toList for (sym <- syms1) diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala index bebc419c7c..6662ec522a 100644 --- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala +++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala @@ -524,7 +524,7 @@ private[internal] trait TypeMaps { private def correspondingTypeArgument(lhs: Type, rhs: Type): Type = { val TypeRef(_, lhsSym, lhsArgs) = lhs val TypeRef(_, rhsSym, rhsArgs) = rhs - require(lhsSym.safeOwner == rhsSym, s"$lhsSym is not a type parameter of $rhsSym") + require(lhsSym.owner == rhsSym, s"$lhsSym is not a type parameter of $rhsSym") // Find the type parameter position; we'll use the corresponding argument. // Why are we checking by name rather than by equality? Because for @@ -539,7 +539,7 @@ private[internal] trait TypeMaps { else { // It's easy to get here when working on hardcore type machinery (not to // mention when not doing so, see above) so let's provide a standout error. - def own_s(s: Symbol) = s.nameString + " in " + s.safeOwner.nameString + def own_s(s: Symbol) = s.nameString + " in " + s.owner.nameString def explain = sm"""| sought ${own_s(lhsSym)} | classSym ${own_s(rhsSym)} diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index ae318697ec..1723344306 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -297,19 +297,9 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set def flatPath(sym: Symbol): String = flatOp shift sym.javaClassName def translatePath(path: String) = { val sym = if (path endsWith "$") symbolOfTerm(path.init) else symbolOfIdent(path) - sym match { - case NoSymbol => None - case _ => Some(flatPath(sym)) - } - } - def translateEnclosingClass(n: String) = { - def enclosingClass(s: Symbol): Symbol = - if (s == NoSymbol || s.isClass) s else enclosingClass(s.owner) - enclosingClass(symbolOfTerm(n)) match { - case NoSymbol => None - case c => Some(flatPath(c)) - } + sym.toOption map flatPath } + def translateEnclosingClass(n: String) = symbolOfTerm(n).enclClass.toOption map flatPath private class TranslatingClassLoader(parent: ClassLoader) extends util.AbstractFileClassLoader(replOutput.dir, parent) { /** Overridden here to try translating a simple name to the generated diff --git a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala index 085a7c6065..c1faf30385 100644 --- a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -71,7 +71,7 @@ trait MemberHandlers { override def definesImplicit = member.mods.isImplicit override def definesTerm: Option[TermName] = Some(name.toTermName) filter (_ => name.isTermName) override def definesType: Option[TypeName] = Some(name.toTypeName) filter (_ => name.isTypeName) - override def definedSymbols = if (symbol eq NoSymbol) Nil else List(symbol) + override def definedSymbols = if (symbol.exists) symbol :: Nil else Nil } /** Class to handle one member among all the members included -- cgit v1.2.3