diff options
Diffstat (limited to 'src')
23 files changed, 364 insertions, 342 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index f53f99a279..6a0f4407fc 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -14,6 +14,65 @@ package ast abstract class TreeInfo extends scala.reflect.internal.TreeInfo { val global: Global import global._ + import definitions._ + + // arg1.op(arg2) returns (arg1, op.symbol, arg2) + object BinaryOp { + def unapply(t: Tree): Option[(Tree, Symbol, Tree)] = t match { + case Apply(sel @ Select(arg1, _), arg2 :: Nil) => Some((arg1, sel.symbol, arg2)) + case _ => None + } + } + // recv.op[T1, ...] returns (recv, op.symbol, type argument types) + object TypeApplyOp { + def unapply(t: Tree): Option[(Tree, Symbol, List[Type])] = t match { + case TypeApply(sel @ Select(recv, _), targs) => Some((recv, sel.symbol, targs map (_.tpe))) + case _ => None + } + } + + // x.asInstanceOf[T] returns (x, typeOf[T]) + object AsInstanceOf { + def unapply(t: Tree): Option[(Tree, Type)] = t match { + case Apply(TypeApplyOp(recv, Object_asInstanceOf, tpe :: Nil), Nil) => Some((recv, tpe)) + case _ => None + } + } + + // Extractors for value classes. + object ValueClass { + def isValueClass(tpe: Type) = enteringErasure(tpe.typeSymbol.isDerivedValueClass) + def valueUnbox(tpe: Type) = enteringErasure(tpe.typeSymbol.derivedValueClassUnbox) + + // B.unbox. Returns B. + object Unbox { + def unapply(t: Tree): Option[Tree] = t match { + case Apply(sel @ Select(ref, _), Nil) if valueUnbox(ref.tpe) == sel.symbol => Some(ref) + case _ => None + } + } + // new B(v). Returns B and v. + object Box { + def unapply(t: Tree): Option[(Tree, Type)] = t match { + case Apply(sel @ Select(New(tpt), nme.CONSTRUCTOR), v :: Nil) => Some((v, tpt.tpe.finalResultType)) + case _ => None + } + } + // (new B(v)).unbox. returns v. + object BoxAndUnbox { + def unapply(t: Tree): Option[Tree] = t match { + case Unbox(Box(v, tpe)) if isValueClass(tpe) => Some(v) + case _ => None + } + } + // new B(v1) op new B(v2) where op is == or !=. Returns v1, op, v2. + object BoxAndCompare { + def unapply(t: Tree): Option[(Tree, Symbol, Tree)] = t match { + case BinaryOp(Box(v1, tpe1), op @ (Object_== | Object_!=), Box(v2, tpe2)) if isValueClass(tpe1) && tpe1 =:= tpe2 => Some((v1, op, v2)) + case _ => None + } + } + } /** Is tree legal as a member definition of an interface? */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 3025e4c440..1554be6ebb 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -133,24 +133,16 @@ trait Scanners extends ScannersCommon { /** Should doc comments be built? */ def buildDocs: Boolean = forScaladoc - /** buffer for the documentation comment + /** holder for the documentation comment */ - var docBuffer: StringBuilder = null - var docPos: Position = null + var docComment: DocComment = null - /** Return current docBuffer and set docBuffer to null */ def flushDoc: DocComment = { - val ret = if (docBuffer != null) DocComment(docBuffer.toString, docPos) else null - docBuffer = null + val ret = docComment + docComment = null ret } - /** add the given character to the documentation buffer - */ - protected def putDocChar(c: Char) { - if (docBuffer ne null) docBuffer.append(c) - } - protected def foundComment(value: String, start: Int, end: Int) = () protected def foundDocComment(value: String, start: Int, end: Int) = () @@ -227,11 +219,11 @@ trait Scanners extends ScannersCommon { while (!sepRegions.isEmpty && sepRegions.head != RBRACE) sepRegions = sepRegions.tail if (!sepRegions.isEmpty) sepRegions = sepRegions.tail - docBuffer = null + docComment = null case RBRACKET | RPAREN => if (!sepRegions.isEmpty && sepRegions.head == lastToken) sepRegions = sepRegions.tail - docBuffer = null + docComment = null case ARROW => if (!sepRegions.isEmpty && sepRegions.head == lastToken) sepRegions = sepRegions.tail @@ -537,7 +529,7 @@ trait Scanners extends ScannersCommon { nextChar() } while ((ch != CR) && (ch != LF) && (ch != SU)) } else { - docBuffer = null + docComment = null var openComments = 1 appendToComment() nextChar() @@ -545,24 +537,23 @@ trait Scanners extends ScannersCommon { var buildingDocComment = false if (ch == '*' && buildDocs) { buildingDocComment = true - docBuffer = new StringBuilder("/**") } while (openComments > 0) { do { do { if (ch == '/') { - nextChar(); putDocChar(ch); appendToComment() + nextChar(); appendToComment() if (ch == '*') { - nextChar(); putDocChar(ch); appendToComment() + nextChar(); appendToComment() openComments += 1 } } if (ch != '*' && ch != SU) { - nextChar(); putDocChar(ch); appendToComment() + nextChar(); appendToComment() } } while (ch != '*' && ch != SU) while (ch == '*') { - nextChar(); putDocChar(ch); appendToComment() + nextChar(); appendToComment() } } while (ch != '/' && ch != SU) if (ch == '/') nextChar() @@ -1297,7 +1288,8 @@ trait Scanners extends ScannersCommon { } override def foundDocComment(value: String, start: Int, end: Int) { - docPos = new RangePosition(unit.source, start, start, end) + val docPos = new RangePosition(unit.source, start, start, end) + docComment = new DocComment(value, docPos) unit.comment(docPos, value) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 5497719f89..add932441d 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -567,7 +567,7 @@ abstract class TreeBuilder { if (contextBounds.isEmpty) vparamss else { val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM) - def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshTermName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree) + def makeEvidenceParam(tpt: Tree) = ValDef(mods | IMPLICIT | SYNTHETIC, freshTermName(nme.EVIDENCE_PARAM_PREFIX), tpt, EmptyTree) val evidenceParams = contextBounds map makeEvidenceParam val vparamssLast = if(vparamss.nonEmpty) vparamss.last else Nil diff --git a/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala index 216157e19a..8d80333195 100755 --- a/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala +++ b/src/compiler/scala/tools/nsc/doc/base/MemberLookupBase.scala @@ -10,15 +10,15 @@ import comment._ trait MemberLookupBase { val global: Global - val settings: doc.Settings - import global._ + def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] def chooseLink(links: List[LinkTo]): LinkTo def toString(link: LinkTo): String + def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] + def warnNoLink: Boolean import global._ - import definitions.{ NothingClass, AnyClass, AnyValClass, AnyRefClass, ListClass } import rootMirror.{RootPackage, EmptyPackage} private def isRoot(s: Symbol) = s.isRootSymbol || s.isEmptyPackage || s.isEmptyPackageClass @@ -83,7 +83,7 @@ trait MemberLookupBase { } links match { case Nil => - if (!settings.docNoLinkWarnings.value) + if (warnNoLink) reporter.warning(pos, "Could not find any member to link for \"" + query + "\".") // (4) if we still haven't found anything, create a tooltip Tooltip(query) @@ -95,7 +95,7 @@ trait MemberLookupBase { if (link == chosen) " [chosen]" else "" toString(link) + chosenInfo + "\n" } - if (!settings.docNoLinkWarnings.value) { + if (warnNoLink) { val allLinks = links.map(linkToString).mkString reporter.warning(pos, s"""The link target \"$query\" is ambiguous. Several members fit the target: @@ -199,29 +199,6 @@ trait MemberLookupBase { members.reverse } - - def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] = { - val sym1 = - if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass - else if (sym.isPackage) - /* Get package object which has associatedFile ne null */ - sym.info.member(newTermName("package")) - else sym - sym1.associatedFile.underlyingSource flatMap { src => - val path = src.path - settings.extUrlMapping get path map { url => - LinkToExternal(name, url + "#" + name) - } - } orElse { - // Deprecated option. - settings.extUrlPackageMapping find { - case (pkg, _) => name startsWith pkg - } map { - case (_, url) => LinkToExternal(name, url + "#" + name) - } - } - } - def externalSignature(sym: Symbol) = { sym.info // force it, otherwise we see lazy types (sym.nameString + sym.signatureString).replaceAll("\\s", "") diff --git a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala index c7a767f992..23259a4ae8 100644 --- a/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala +++ b/src/compiler/scala/tools/nsc/doc/model/MemberLookup.scala @@ -9,6 +9,7 @@ trait MemberLookup extends base.MemberLookupBase { thisFactory: ModelFactory => import global._ + import definitions.{ NothingClass, AnyClass, AnyValClass, AnyRefClass, ListClass } override def internalLink(sym: Symbol, site: Symbol): Option[LinkTo] = findTemplateMaybe(sym) match { @@ -35,4 +36,28 @@ trait MemberLookup extends base.MemberLookupBase { mbr.sym.signatureString + " in " + inTpl.sym.toString case _ => link.toString } + + override def findExternalLink(sym: Symbol, name: String): Option[LinkToExternal] = { + val sym1 = + if (sym == AnyClass || sym == AnyRefClass || sym == AnyValClass || sym == NothingClass) ListClass + else if (sym.isPackage) + /* Get package object which has associatedFile ne null */ + sym.info.member(newTermName("package")) + else sym + Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src => + val path = src.path + settings.extUrlMapping get path map { url => + LinkToExternal(name, url + "#" + name) + } + } orElse { + // Deprecated option. + settings.extUrlPackageMapping find { + case (pkg, _) => name startsWith pkg + } map { + case (_, url) => LinkToExternal(name, url + "#" + name) + } + } + } + + override def warnNoLink = !settings.docNoLinkWarnings.value } diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 9bb2d552be..b0318f40c4 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -69,7 +69,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") if (verboseIDE) println("[%s][%s]".format(projectName, msg)) override def forInteractive = true - override def forScaladoc = settings.isScaladoc /** A map of all loaded files to the rich compilation units that correspond to them. */ diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala index 034a844e2e..5cda0e53fb 100644 --- a/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala +++ b/src/compiler/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala @@ -7,7 +7,7 @@ import reporters.{Reporter => CompilerReporter} /** Trait encapsulating the creation of a presentation compiler's instance.*/ private[tests] trait PresentationCompilerInstance extends TestSettings { protected val settings = new Settings - protected val docSettings = new doc.Settings(_ => ()) + protected val withDocComments = false protected val compilerReporter: CompilerReporter = new InteractiveReporter { override def compiler = PresentationCompilerInstance.this.compiler @@ -15,7 +15,9 @@ private[tests] trait PresentationCompilerInstance extends TestSettings { protected lazy val compiler: Global = { prepareSettings(settings) - new Global(settings, compilerReporter) + new Global(settings, compilerReporter) { + override def forScaladoc = withDocComments + } } /** diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index f380b9d04f..8287c1f631 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -21,6 +21,7 @@ abstract class Erasure extends AddInterfaces import global._ import definitions._ import CODE._ + import treeInfo._ val phaseName: String = "erasure" @@ -357,41 +358,10 @@ abstract class Erasure extends AddInterfaces override def newTyper(context: Context) = new Eraser(context) - private def safeToRemoveUnbox(cls: Symbol): Boolean = - (cls == definitions.NullClass) || isBoxedValueClass(cls) - - /** An extractor object for unboxed expressions (maybe subsumed by posterasure?) */ - object Unboxed { - def unapply(tree: Tree): Option[Tree] = tree match { - case Apply(fn, List(arg)) if isUnbox(fn.symbol) && safeToRemoveUnbox(arg.tpe.typeSymbol) => - Some(arg) - case Apply( - TypeApply( - cast @ Select( - Apply( - sel @ Select(arg, acc), - List()), - asinstanceof), - List(tpt)), - List()) - if cast.symbol == Object_asInstanceOf && - tpt.tpe.typeSymbol.isDerivedValueClass && - sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox => - Some(arg) - case _ => - None - } - } - - /** An extractor object for boxed expressions (maybe subsumed by posterasure?) */ - object Boxed { - def unapply(tree: Tree): Option[Tree] = tree match { - case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) => - Some(arg) - case LabelDef(name, params, Boxed(rhs)) => - Some(treeCopy.LabelDef(tree, name, params, rhs) setType rhs.tpe) - case _ => - None + private def isSafelyRemovableUnbox(fn: Tree, arg: Tree): Boolean = { + isUnbox(fn.symbol) && { + val cls = arg.tpe.typeSymbol + (cls == definitions.NullClass) || isBoxedValueClass(cls) } } @@ -578,12 +548,7 @@ abstract class Erasure extends AddInterfaces val tree1 = tree.tpe match { case ErasedValueType(tref) => val clazz = tref.sym - tree match { - case Unboxed(arg) if arg.tpe.typeSymbol == clazz => - log("shortcircuiting unbox -> box "+arg); arg - case _ => - New(clazz, cast(tree, underlyingOfValueClass(clazz))) - } + New(clazz, cast(tree, underlyingOfValueClass(clazz))) case _ => tree.tpe.typeSymbol match { case UnitClass => @@ -599,7 +564,7 @@ abstract class Erasure extends AddInterfaces * This is important for specialization: calls to the super constructor should not box/unbox specialized * fields (see TupleX). (ID) */ - case Apply(boxFun, List(arg)) if isUnbox(tree.symbol) && safeToRemoveUnbox(arg.tpe.typeSymbol) => + case Apply(boxFun, List(arg)) if isSafelyRemovableUnbox(tree, arg) => log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}") arg case _ => @@ -634,24 +599,18 @@ abstract class Erasure extends AddInterfaces case _ => val tree1 = pt match { case ErasedValueType(tref) => - tree match { - case Boxed(arg) if arg.tpe.isInstanceOf[ErasedValueType] => - log("shortcircuiting box -> unbox "+arg) - arg - case _ => - val clazz = tref.sym - log("not boxed: "+tree) - lazy val underlying = underlyingOfValueClass(clazz) - val tree0 = - if (tree.tpe.typeSymbol == NullClass && - isPrimitiveValueClass(underlying.typeSymbol)) { - // convert `null` directly to underlying type, as going - // via the unboxed type would yield a NPE (see SI-5866) - unbox1(tree, underlying) - } else - Apply(Select(adaptToType(tree, clazz.tpe), clazz.derivedValueClassUnbox), List()) - cast(tree0, pt) - } + val clazz = tref.sym + log("not boxed: "+tree) + lazy val underlying = underlyingOfValueClass(clazz) + val tree0 = + if (tree.tpe.typeSymbol == NullClass && + isPrimitiveValueClass(underlying.typeSymbol)) { + // convert `null` directly to underlying type, as going + // via the unboxed type would yield a NPE (see SI-5866) + unbox1(tree, underlying) + } else + Apply(Select(adaptToType(tree, clazz.tpe), clazz.derivedValueClassUnbox), List()) + cast(tree0, pt) case _ => pt.typeSymbol match { case UnitClass => diff --git a/src/compiler/scala/tools/nsc/transform/PostErasure.scala b/src/compiler/scala/tools/nsc/transform/PostErasure.scala index a8dc47046b..2a86d711f1 100644 --- a/src/compiler/scala/tools/nsc/transform/PostErasure.scala +++ b/src/compiler/scala/tools/nsc/transform/PostErasure.scala @@ -9,10 +9,10 @@ package transform * performs peephole optimizations. */ trait PostErasure extends InfoTransform with TypingTransformers { - val global: Global + import global._ - import definitions._ + import treeInfo._ val phaseName: String = "posterasure" @@ -21,51 +21,33 @@ trait PostErasure extends InfoTransform with TypingTransformers { object elimErasedValueType extends TypeMap { def apply(tp: Type) = tp match { - case ConstantType(Constant(tp: Type)) => - ConstantType(Constant(apply(tp))) - case ErasedValueType(tref) => - enteringPhase(currentRun.erasurePhase)(erasure.erasedValueClassArg(tref)) - case _ => mapOver(tp) + case ConstantType(Constant(tp: Type)) => ConstantType(Constant(apply(tp))) + case ErasedValueType(tref) => enteringErasure(erasure.erasedValueClassArg(tref)) + case _ => mapOver(tp) } } def transformInfo(sym: Symbol, tp: Type) = elimErasedValueType(tp) class PostErasureTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { + override def transform(tree: Tree) = { + def finish(res: Tree) = logResult(s"Posterasure reduction\n Old: $tree\n New")(res) + + /** We use the name of the operation being performed and not the symbol + * itself because the symbol hails from the boxed class, and this transformation + * exists to operate directly on the values. So we are for instance looking + * up == on an lhs of type Int, whereas the symbol which has been passed in + * is from java.lang.Integer. + */ + def binop(lhs: Tree, op: Symbol, rhs: Tree) = + finish(localTyper typed (Apply(Select(lhs, op.name) setPos tree.pos, rhs :: Nil) setPos tree.pos)) - override def transform(tree: Tree) = super.transform(tree) setType elimErasedValueType(tree.tpe) match { - case // new C(arg).underlying ==> arg - Apply(sel @ Select( - Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)), - acc), List()) - if enteringPhase(currentRun.erasurePhase) { - tpt.tpe.typeSymbol.isDerivedValueClass && - sel.symbol == tpt.tpe.typeSymbol.derivedValueClassUnbox - } => - if (settings.debug.value) log("Removing "+tree+" -> "+arg) - arg - case // new C(arg1) == new C(arg2) ==> arg1 == arg2 - Apply(sel @ Select( - Apply(Select(New(tpt1), nme.CONSTRUCTOR), List(arg1)), - cmp), - List(Apply(Select(New(tpt2), nme.CONSTRUCTOR), List(arg2)))) - if enteringPhase(currentRun.erasurePhase) { - tpt1.tpe.typeSymbol.isDerivedValueClass && - (sel.symbol == Object_== || sel.symbol == Object_!=) && - tpt2.tpe.typeSymbol == tpt1.tpe.typeSymbol - } => - val result = Apply(Select(arg1, cmp) setPos sel.pos, List(arg2)) setPos tree.pos - log("shortcircuiting equality "+tree+" -> "+result) - localTyper.typed(result) - - case // arg.asInstanceOf[T] ==> arg if arg.tpe == T - Apply(TypeApply(cast @ Select(arg, asinstanceof), List(tpt)), List()) - if cast.symbol == Object_asInstanceOf && arg.tpe =:= tpt.tpe => // !!! <:< ? - if (settings.debug.value) log("Shortening "+tree+" -> "+arg) - arg - case tree1 => - tree1 + case AsInstanceOf(v, tpe) if v.tpe <:< tpe => finish(v) // x.asInstanceOf[X] ==> x + case ValueClass.BoxAndUnbox(v) => finish(v) // (new B(v)).unbox ==> v + case ValueClass.BoxAndCompare(v1, op, v2) => binop(v1, op, v2) // new B(v1) == new B(v2) ==> v1 == v2 + case tree => tree } + } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 711085e6c9..b070bd1b49 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -573,8 +573,7 @@ trait Contexts { self: Analyzer => ( superAccess || pre.isInstanceOf[ThisType] || phase.erasedTypes - || isProtectedAccessOK(sym) - || (sym.allOverriddenSymbols exists isProtectedAccessOK) + || (sym.overrideChain exists isProtectedAccessOK) // that last condition makes protected access via self types work. ) ) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index fb8d6b934f..8829a9a92e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -331,7 +331,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { def param(tree: Tree): Symbol = ( cache.getOrElseUpdate(tree.symbol, { val sym = tree.symbol - makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe), sym getFlag SYNTHETIC) + makeParam(sym.name, sym.pos, implType(sym.isType, sym.tpe), sym.flags) }) ) } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 60a73036f8..dd16e9de30 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -726,8 +726,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans else if (clazz.isTrait && !(clazz isSubClass AnyValClass)) { // For non-AnyVal classes, prevent abstract methods in interfaces that override // final members in Object; see #4431 - for (decl <- clazz.info.decls.iterator) { - val overridden = decl.overriddenSymbol(ObjectClass) + for (decl <- clazz.info.decls) { + // Have to use matchingSymbol, not a method involving overridden symbols, + // because the scala type system understands that an abstract method here does not + // override a concrete method in Object. The jvm, however, does not. + val overridden = decl.matchingSymbol(ObjectClass, ObjectClass.tpe) if (overridden.isFinal) unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") } @@ -1499,8 +1502,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans // on Unit, in which case we had better let it slide. val isOk = ( sym.isGetter - || sym.allOverriddenSymbols.exists(over => !(over.tpe.resultType =:= sym.tpe.resultType)) || (sym.name containsName nme.DEFAULT_GETTER_STRING) + || sym.allOverriddenSymbols.exists(over => !(over.tpe.resultType =:= sym.tpe.resultType)) ) if (!isOk) unit.warning(sym.pos, s"side-effecting nullary methods are discouraged: suggest defining as `def ${sym.name.decode}()` instead") diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 0992cd7955..f2129992e5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -67,7 +67,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT case t => t } acc setInfoAndEnter (tpe cloneInfo acc) - storeAccessorDefinition(clazz, DefDef(acc, EmptyTree)) + // Diagnostic for SI-7091 + if (!accDefs.contains(clazz)) + reporter.error(sel.pos, s"Internal error: unable to store accessor definition in ${clazz}. clazz.isPackage=${clazz.isPackage}. Accessor required for ${sel} (${showRaw(sel)})") + else storeAccessorDefinition(clazz, DefDef(acc, EmptyTree)) acc } @@ -288,6 +291,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT currentClass.isTrait && sym.isProtected && 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) diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index cfe962d65f..81ea5630d0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -101,14 +101,9 @@ trait TypeDiagnostics { "\n(Note that variables need to be initialized to be defined)" else "" - /** Only prints the parameter names if they're not synthetic, - * since "x$1: Int" does not offer any more information than "Int". - */ private def methodTypeErrorString(tp: Type) = tp match { case mt @ MethodType(params, resultType) => - def forString = - if (params exists (_.isSynthetic)) params map (_.tpe) - else params map (_.defString) + def forString = params map (_.defString) forString.mkString("(", ",", ")") + resultType case x => x.toString diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c1fcff0c4e..561ca7f382 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4070,15 +4070,11 @@ trait Typers extends Adaptations with Tags { def resultingTypeTree(tpe: Type) = { // we need symbol-ful originals for reification // hence we go the extra mile to hand-craft tis guy - val original = - if (arg1.isType) - arg1 match { - case tt @ TypeTree() => Annotated(ann, tt.original) - // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)" - case _ => Annotated(ann, arg1) - } - else - tree + val original = arg1 match { + case tt @ TypeTree() => Annotated(ann, tt.original) + // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)" + case _ => Annotated(ann, arg1) + } original setType ann.tpe TypeTree(tpe) setOriginal original setPos tree.pos.focus } diff --git a/src/library/scala/collection/mutable/ArrayBuffer.scala b/src/library/scala/collection/mutable/ArrayBuffer.scala index 0877bfbb69..f1cfd2d69a 100644 --- a/src/library/scala/collection/mutable/ArrayBuffer.scala +++ b/src/library/scala/collection/mutable/ArrayBuffer.scala @@ -107,7 +107,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) * the identity of the buffer. It takes time linear in * the buffer size. * - * @param elem the element to append. + * @param elem the element to prepend. * @return the updated buffer. */ def +=:(elem: A): this.type = { diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 36f3be341f..0670da137c 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -299,8 +299,8 @@ trait Future[+T] extends Awaitable[T] { * val f = future { 5 } * val g = f filter { _ % 2 == 1 } * val h = f filter { _ % 2 == 0 } - * await(g, 0) // evaluates to 5 - * await(h, 0) // throw a NoSuchElementException + * Await.result(g, Duration.Zero) // evaluates to 5 + * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} */ def filter(pred: T => Boolean)(implicit executor: ExecutionContext): Future[T] = { @@ -348,8 +348,8 @@ trait Future[+T] extends Awaitable[T] { * val h = f collect { * case x if x > 0 => x * 2 * } - * await(g, 0) // evaluates to 5 - * await(h, 0) // throw a NoSuchElementException + * Await.result(g, Duration.Zero) // evaluates to 5 + * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} */ def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = { @@ -454,7 +454,7 @@ trait Future[+T] extends Awaitable[T] { * val f = future { sys.error("failed") } * val g = future { 5 } * val h = f fallbackTo g - * await(h, 0) // evaluates to 5 + * Await.result(h, Duration.Zero) // evaluates to 5 * }}} */ def fallbackTo[U >: T](that: Future[U]): Future[U] = { @@ -634,7 +634,7 @@ object Future { * * Example: * {{{ - * val result = Await.result(Futures.reduce(futures)(_ + _), 5 seconds) + * val result = Await.result(Future.reduce(futures)(_ + _), 5 seconds) * }}} */ def reduce[T, R >: T](futures: TraversableOnce[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 8f86fd5aa7..feb538033b 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -247,7 +247,7 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo */ def gcd (that: BigInt): BigInt = new BigInt(this.bigInteger.gcd(that.bigInteger)) - /** Returns a BigInt whose value is (this mod m). + /** Returns a BigInt whose value is (this mod that). * This method differs from `%` in that it always returns a non-negative BigInt. */ def mod (that: BigInt): BigInt = new BigInt(this.bigInteger.mod(that.bigInteger)) diff --git a/src/reflect/scala/reflect/api/ImplicitTags.scala b/src/reflect/scala/reflect/api/ImplicitTags.scala new file mode 100644 index 0000000000..3f377d6cff --- /dev/null +++ b/src/reflect/scala/reflect/api/ImplicitTags.scala @@ -0,0 +1,108 @@ +package scala.reflect +package api + +trait ImplicitTags { + self: Types => + + /** A tag that preserves the identity of the `Type` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val TypeTagg: ClassTag[Type] + + /** A tag that preserves the identity of the `SingletonType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val SingletonTypeTag: ClassTag[SingletonType] + + /** A tag that preserves the identity of the `ThisType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val ThisTypeTag: ClassTag[ThisType] + + /** A tag that preserves the identity of the `SingleType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val SingleTypeTag: ClassTag[SingleType] + + /** A tag that preserves the identity of the `SuperType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val SuperTypeTag: ClassTag[SuperType] + + /** A tag that preserves the identity of the `ConstantType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val ConstantTypeTag: ClassTag[ConstantType] + + /** A tag that preserves the identity of the `TypeRef` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val TypeRefTag: ClassTag[TypeRef] + + /** A tag that preserves the identity of the `CompoundType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val CompoundTypeTag: ClassTag[CompoundType] + + /** A tag that preserves the identity of the `RefinedType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val RefinedTypeTag: ClassTag[RefinedType] + + /** A tag that preserves the identity of the `ClassInfoType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val ClassInfoTypeTag: ClassTag[ClassInfoType] + + /** A tag that preserves the identity of the `MethodType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val MethodTypeTag: ClassTag[MethodType] + + /** A tag that preserves the identity of the `NullaryMethodType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType] + + /** A tag that preserves the identity of the `PolyType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val PolyTypeTag: ClassTag[PolyType] + + /** A tag that preserves the identity of the `ExistentialType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val ExistentialTypeTag: ClassTag[ExistentialType] + + /** A tag that preserves the identity of the `AnnotatedType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val AnnotatedTypeTag: ClassTag[AnnotatedType] + + /** A tag that preserves the identity of the `TypeBounds` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val TypeBoundsTag: ClassTag[TypeBounds] + + /** A tag that preserves the identity of the `BoundedWildcardType` abstract type from erasure. + * Can be used for pattern matching, instance tests, serialization and likes. + * @group Tags + */ + implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType] +} diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala index 143438b8f5..e8e9e9c048 100644 --- a/src/reflect/scala/reflect/api/Types.scala +++ b/src/reflect/scala/reflect/api/Types.scala @@ -50,7 +50,8 @@ package api * * @contentDiagram hideNodes "*Api" */ -trait Types { self: Universe => +trait Types extends ImplicitTags { + self: Universe => /** The type of Scala types, and also Scala type signatures. * (No difference is internally made between the two). @@ -59,12 +60,6 @@ trait Types { self: Universe => */ type Type >: Null <: TypeApi - /** A tag that preserves the identity of the `Type` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val TypeTagg: ClassTag[Type] - /** This constant is used as a special value that indicates that no meaningful type exists. * @group Types */ @@ -256,12 +251,6 @@ trait Types { self: Universe => */ type SingletonType >: Null <: Type - /** A tag that preserves the identity of the `SingletonType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val SingletonTypeTag: ClassTag[SingletonType] - /** A singleton type that describes types of the form on the left with the * corresponding `ThisType` representation to the right: * {{{ @@ -272,12 +261,6 @@ trait Types { self: Universe => */ type ThisType >: Null <: AnyRef with SingletonType with ThisTypeApi - /** A tag that preserves the identity of the `ThisType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val ThisTypeTag: ClassTag[ThisType] - /** The constructor/extractor for `ThisType` instances. * @group Extractors */ @@ -316,12 +299,6 @@ trait Types { self: Universe => */ type SingleType >: Null <: AnyRef with SingletonType with SingleTypeApi - /** A tag that preserves the identity of the `SingleType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val SingleTypeTag: ClassTag[SingleType] - /** The constructor/extractor for `SingleType` instances. * @group Extractors */ @@ -361,12 +338,6 @@ trait Types { self: Universe => */ type SuperType >: Null <: AnyRef with SingletonType with SuperTypeApi - /** A tag that preserves the identity of the `SuperType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val SuperTypeTag: ClassTag[SuperType] - /** The constructor/extractor for `SuperType` instances. * @group Extractors */ @@ -406,12 +377,6 @@ trait Types { self: Universe => */ type ConstantType >: Null <: AnyRef with SingletonType with ConstantTypeApi - /** A tag that preserves the identity of the `ConstantType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val ConstantTypeTag: ClassTag[ConstantType] - /** The constructor/extractor for `ConstantType` instances. * @group Extractors */ @@ -450,12 +415,6 @@ trait Types { self: Universe => */ type TypeRef >: Null <: AnyRef with Type with TypeRefApi - /** A tag that preserves the identity of the `TypeRef` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val TypeRefTag: ClassTag[TypeRef] - /** The constructor/extractor for `TypeRef` instances. * @group Extractors */ @@ -497,12 +456,6 @@ trait Types { self: Universe => */ type CompoundType >: Null <: AnyRef with Type - /** A tag that preserves the identity of the `CompoundType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val CompoundTypeTag: ClassTag[CompoundType] - /** The `RefinedType` type defines types of any of the forms on the left, * with their RefinedType representations to the right. * {{{ @@ -515,12 +468,6 @@ trait Types { self: Universe => */ type RefinedType >: Null <: AnyRef with CompoundType with RefinedTypeApi - /** A tag that preserves the identity of the `RefinedType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val RefinedTypeTag: ClassTag[RefinedType] - /** The constructor/extractor for `RefinedType` instances. * @group Extractors */ @@ -567,12 +514,6 @@ trait Types { self: Universe => */ type ClassInfoType >: Null <: AnyRef with CompoundType with ClassInfoTypeApi - /** A tag that preserves the identity of the `ClassInfoType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val ClassInfoTypeTag: ClassTag[ClassInfoType] - /** The constructor/extractor for `ClassInfoType` instances. * @group Extractors */ @@ -610,12 +551,6 @@ trait Types { self: Universe => */ type MethodType >: Null <: AnyRef with Type with MethodTypeApi - /** A tag that preserves the identity of the `MethodType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val MethodTypeTag: ClassTag[MethodType] - /** The constructor/extractor for `MethodType` instances. * @group Extractors */ @@ -660,12 +595,6 @@ trait Types { self: Universe => */ type NullaryMethodType >: Null <: AnyRef with Type with NullaryMethodTypeApi - /** A tag that preserves the identity of the `NullaryMethodType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val NullaryMethodTypeTag: ClassTag[NullaryMethodType] - /** The constructor/extractor for `NullaryMethodType` instances. * @group Extractors */ @@ -696,12 +625,6 @@ trait Types { self: Universe => */ type PolyType >: Null <: AnyRef with Type with PolyTypeApi - /** A tag that preserves the identity of the `PolyType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val PolyTypeTag: ClassTag[PolyType] - /** The constructor/extractor for `PolyType` instances. * @group Extractors */ @@ -736,12 +659,6 @@ trait Types { self: Universe => */ type ExistentialType >: Null <: AnyRef with Type with ExistentialTypeApi - /** A tag that preserves the identity of the `ExistentialType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val ExistentialTypeTag: ClassTag[ExistentialType] - /** The constructor/extractor for `ExistentialType` instances. * @group Extractors */ @@ -777,12 +694,6 @@ trait Types { self: Universe => */ type AnnotatedType >: Null <: AnyRef with Type with AnnotatedTypeApi - /** A tag that preserves the identity of the `AnnotatedType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val AnnotatedTypeTag: ClassTag[AnnotatedType] - /** The constructor/extractor for `AnnotatedType` instances. * @group Extractors */ @@ -828,12 +739,6 @@ trait Types { self: Universe => */ type TypeBounds >: Null <: AnyRef with Type with TypeBoundsApi - /** A tag that preserves the identity of the `TypeBounds` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val TypeBoundsTag: ClassTag[TypeBounds] - /** The constructor/extractor for `TypeBounds` instances. * @group Extractors */ @@ -885,12 +790,6 @@ trait Types { self: Universe => */ type BoundedWildcardType >: Null <: AnyRef with Type with BoundedWildcardTypeApi - /** A tag that preserves the identity of the `BoundedWildcardType` abstract type from erasure. - * Can be used for pattern matching, instance tests, serialization and likes. - * @group Tags - */ - implicit val BoundedWildcardTypeTag: ClassTag[BoundedWildcardType] - /** The constructor/extractor for `BoundedWildcardType` instances. * @group Extractors */ diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala index 45c5279574..06f6c46fc3 100644 --- a/src/reflect/scala/reflect/internal/Flags.scala +++ b/src/reflect/scala/reflect/internal/Flags.scala @@ -287,7 +287,7 @@ class Flags extends ModifierFlags { * from Modifiers. Others which may be applied at creation time are: * SYNTHETIC. */ - final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE + final val ValueParameterFlags = BYNAMEPARAM | IMPLICIT | DEFAULTPARAM | STABLE | SYNTHETIC final val BeanPropertyFlags = DEFERRED | OVERRIDE | STATIC final val VarianceFlags = COVARIANT | CONTRAVARIANT diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 4f6dab3e7c..fbf14e8156 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -853,12 +853,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Is this a term symbol only defined in a refinement (so that it needs * to be accessed by reflection)? */ - def isOnlyRefinementMember: Boolean = + def isOnlyRefinementMember: Boolean = ( isTerm && // type members are not affected owner.isRefinementClass && // owner must be a refinement class (owner.info decl name) == this && // symbol must be explicitly declared in the refinement (not synthesized from glb) - allOverriddenSymbols.isEmpty && // symbol must not override a symbol in a base class + !isOverridingSymbol && // symbol must not override a symbol in a base class !isConstant // symbol must not be a constant. Question: Can we exclude @inline methods as well? + ) final def isStructuralRefinementMember = owner.isStructuralRefinement && isPossibleInRefinement && isPublic final def isPossibleInRefinement = !isConstructor && !isOverridingSymbol @@ -960,14 +961,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => def ownerChain: List[Symbol] = this :: owner.ownerChain def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain - // All the symbols overridden by this symbol and this symbol at the head, - // or Nil if this is NoSymbol. - def overrideChain = ( - if (this eq NoSymbol) Nil - else if (!owner.isClass) this :: Nil - else this :: allOverriddenSymbols - ) - // Non-classes skip self and return rest of owner chain; overridden in ClassSymbol. def enclClassChain: List[Symbol] = owner.enclClassChain @@ -2070,81 +2063,111 @@ trait Symbols extends api.Symbols { self: SymbolTable => * @param ofclazz The class containing the symbol's definition * @param site The base type from which member types are computed */ - final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = { - //OPT cut down on #closures by special casing non-overloaded case - // was: ofclazz.info.nonPrivateDecl(name) filter (sym => - // !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) - val result = ofclazz.info.nonPrivateDecl(name) - def qualifies(sym: Symbol) = !sym.isTerm || (site.memberType(this) matches site.memberType(sym)) - if ((result eq NoSymbol) || !result.isOverloaded && qualifies(result)) result - else result filter qualifies - } + final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = + matchingSymbolInternal(site, ofclazz.info nonPrivateDecl name) /** The non-private member of `site` whose type and name match the type of this symbol. */ final def matchingSymbol(site: Type, admit: Long = 0L): Symbol = - site.nonPrivateMemberAdmitting(name, admit).filter(sym => - !sym.isTerm || (site.memberType(this) matches site.memberType(sym))) + matchingSymbolInternal(site, site.nonPrivateMemberAdmitting(name, admit)) - /** The symbol, in class `ofclazz`, that is overridden by this symbol. + private def matchingSymbolInternal(site: Type, candidate: Symbol): Symbol = { + def qualifies(sym: Symbol) = !sym.isTerm || ((site memberType this) matches (site memberType sym)) + //OPT cut down on #closures by special casing non-overloaded case + if (candidate.isOverloaded) candidate filter qualifies + else if (qualifies(candidate)) candidate + else NoSymbol + } + + /** The symbol, in class `baseClass`, that is overridden by this symbol. * - * @param ofclazz is a base class of this symbol's owner. + * @param baseClass is a base class of this symbol's owner. */ - final def overriddenSymbol(ofclazz: Symbol): Symbol = - if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, owner.thisType) + final def overriddenSymbol(baseClass: Symbol): Symbol = ( + // concrete always overrides abstract, so don't let an abstract definition + // claim to be overriding an inherited concrete one. + matchingInheritedSymbolIn(baseClass) filter (res => res.isDeferred || !this.isDeferred) + ) + + private def matchingInheritedSymbolIn(baseClass: Symbol): Symbol = + if (canMatchInheritedSymbols) matchingSymbol(baseClass, owner.thisType) else NoSymbol /** The symbol overriding this symbol in given subclass `ofclazz`. * * @param ofclazz is a subclass of this symbol's owner */ - final def overridingSymbol(ofclazz: Symbol): Symbol = - if (isClassConstructor) NoSymbol else matchingSymbol(ofclazz, ofclazz.thisType) + final def overridingSymbol(ofclazz: Symbol): Symbol = ( + if (canMatchInheritedSymbols) + matchingSymbol(ofclazz, ofclazz.thisType) + else + NoSymbol + ) - /** Returns all symbols overriden by this symbol. */ - final def allOverriddenSymbols: List[Symbol] = ( - if ((this eq NoSymbol) || !owner.isClass) Nil - else { - def loop(xs: List[Symbol]): List[Symbol] = xs match { - case Nil => Nil - case x :: xs => - overriddenSymbol(x) match { - case NoSymbol => loop(xs) - case sym => sym :: loop(xs) - } - } - loop(owner.ancestors) - } + /** If false, this symbol cannot possibly participate in an override, + * either as overrider or overridee. For internal use; you should consult + * with isOverridingSymbol. This is used by isOverridingSymbol to escape + * the recursive knot. + */ + private def canMatchInheritedSymbols = ( + (this ne NoSymbol) + && owner.isClass + && !this.isClass + && !this.isConstructor + ) + + // All the symbols overridden by this symbol and this symbol at the head, + // or Nil if this is NoSymbol. + def overrideChain = ( + if (this eq NoSymbol) Nil + else if (isOverridingSymbol) this :: allOverriddenSymbols + else this :: Nil ) + /** Returns all symbols overridden by this symbol. */ + final def allOverriddenSymbols: List[Symbol] = { + def loop(xs: List[Symbol]): List[Symbol] = xs match { + case Nil => Nil + case x :: xs => + overriddenSymbol(x) match { + case NoSymbol => loop(xs) + case sym => sym :: loop(xs) + } + } + if (isOverridingSymbol) loop(owner.ancestors) else Nil + } + /** Equivalent to allOverriddenSymbols.nonEmpty, but more efficient. */ - // !!! When if ever will this answer differ from .isOverride? - // How/where is the OVERRIDE flag managed, as compared to how checks - // based on type membership will evaluate? - def isOverridingSymbol = owner.isClass && ( - owner.ancestors exists (cls => matchingSymbol(cls, owner.thisType) != NoSymbol) + lazy val isOverridingSymbol = ( + canMatchInheritedSymbols + && owner.ancestors.exists(base => overriddenSymbol(base) != NoSymbol) ) + /** Equivalent to allOverriddenSymbols.head (or NoSymbol if no overrides) but more efficient. */ def nextOverriddenSymbol: Symbol = { - if ((this ne NoSymbol) && owner.isClass) owner.ancestors foreach { base => - val sym = overriddenSymbol(base) - if (sym != NoSymbol) - return sym + @tailrec def loop(bases: List[Symbol]): Symbol = bases match { + case Nil => NoSymbol + case base :: rest => + val sym = overriddenSymbol(base) + if (sym == NoSymbol) loop(rest) else sym } - NoSymbol + if (isOverridingSymbol) loop(owner.ancestors) else NoSymbol } /** Returns all symbols overridden by this symbol, plus all matching symbols * defined in parents of the selftype. */ - final def extendedOverriddenSymbols: List[Symbol] = - if (!owner.isClass) Nil - else owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol) + final def extendedOverriddenSymbols: List[Symbol] = ( + if (canMatchInheritedSymbols) + owner.thisSym.ancestors map overriddenSymbol filter (_ != NoSymbol) + else + Nil + ) /** The symbol accessed by a super in the definition of this symbol when * seen from class `base`. This symbol is always concrete. * pre: `this.owner` is in the base class sequence of `base`. */ final def superSymbol(base: Symbol): Symbol = { - var bcs = base.info.baseClasses.dropWhile(owner != _).tail + var bcs = base.info.baseClasses dropWhile (owner != _) drop 1 var sym: Symbol = NoSymbol while (!bcs.isEmpty && sym == NoSymbol) { if (!bcs.head.isImplClass) diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala index b078b7d4f9..0fa798058d 100644 --- a/src/reflect/scala/reflect/internal/util/Statistics.scala +++ b/src/reflect/scala/reflect/internal/util/Statistics.scala @@ -109,7 +109,7 @@ quant) * Quantities with non-empty prefix are printed in the statistics info. */ trait Quantity { - if (prefix.nonEmpty) { + if (enabled && prefix.nonEmpty) { val key = s"${if (underlying != this) underlying.prefix else ""}/$prefix" qs(key) = this } |