diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
index 36a72abe911a..0fbae89aec28 100644
--- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
+++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -201,7 +201,8 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
val plainC = pcb.cnode
if (claszSymbol.isClass) // @DarkDimius is this test needed here?
- for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) {
+ for (pickler <- ctx.compilationUnit.picklers.get(claszSymbol.asClass)) {
+ val binary = pickler.assembleParts()
val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, binary)
val store = if (mirrorC ne null) mirrorC else plainC
store.visitAttribute(dataAttr)
diff --git a/compiler/src/dotty/tools/dotc/CompilationUnit.scala b/compiler/src/dotty/tools/dotc/CompilationUnit.scala
index da8b3923be1e..16a59250bb7f 100644
--- a/compiler/src/dotty/tools/dotc/CompilationUnit.scala
+++ b/compiler/src/dotty/tools/dotc/CompilationUnit.scala
@@ -17,6 +17,12 @@ class CompilationUnit(val source: SourceFile) {
def isJava = source.file.name.endsWith(".java")
- /** Pickled TASTY binaries, indexed by class. */
- var pickled: Map[ClassSymbol, Array[Byte]] = Map()
+ /**
+ * Picklers used to create TASTY sections, indexed by toplevel class to which they belong.
+ * Sections: Header, ASTs and Positions are populated by `pickler` phase.
+ * Subsequent phases can add new sections.
+ */
+ var picklers: Map[ClassSymbol, TastyPickler] = Map()
+
+ var unpicklers: Map[ClassSymbol, TastyUnpickler] = Map()
}
diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala
index ea77e0e50192..299448a398ae 100644
--- a/compiler/src/dotty/tools/dotc/Compiler.scala
+++ b/compiler/src/dotty/tools/dotc/Compiler.scala
@@ -13,6 +13,7 @@ import Phases.Phase
import transform._
import util.FreshNameCreator
import transform.TreeTransforms.{TreeTransform, TreeTransformer}
+import transform.linker._
import core.DenotTransformers.DenotTransformer
import core.Denotations.SingleDenotation
@@ -47,6 +48,8 @@ class Compiler {
List(new PostTyper), // Additional checks and cleanups after type checking
List(new sbt.ExtractAPI), // Sends a representation of the API of classes to sbt via callbacks
List(new Pickler), // Generate TASTY info
+ List(new CollectSummaries), // Collects method summaries for the call graph construction
+ List(new BuildCallGraph), // Builds the call graph
List(new FirstTransform, // Some transformations to put trees into a canonical form
new CheckReentrant, // Internal use only: Check that compiled program has no data races involving global vars
new ElimJavaPackages), // Eliminate syntactic references to Java packages
@@ -69,6 +72,8 @@ class Compiler {
new ShortcutImplicits, // Allow implicit functions without creating closures
new CrossCastAnd, // Normalize selections involving intersection types.
new Splitter), // Expand selections involving union types into conditionals
+ List(new OuterSpecializer),
+ List(new OuterSpecializeParents),
List(new VCInlineMethods, // Inlines calls to value class methods
new IsInstanceOfEvaluator, // Issues warnings when unreachable statements are present in match/if expressions
new SeqLiterals, // Express vararg arguments as arrays
@@ -82,7 +87,7 @@ class Compiler {
new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method
new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
- List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types
+ List(new ElimErasedValueType, // Expand erased value types to their underlying implementation types
new VCElideAllocations, // Peep-hole optimization to eliminate unnecessary value class allocations
new Mixin, // Expand trait fields and trait initializers
new LazyVals, // Expand lazy vals
@@ -94,6 +99,8 @@ class Compiler {
// Note: constructors changes decls in transformTemplate, no InfoTransformers should be added after it
new FunctionalInterfaces, // Rewrites closures to implement @specialized types of Functions.
new GetClass, // Rewrites getClass calls on primitive types.
+ new CallGraphChecks,
+ new DeadCodeElimination, // Replaces dead code by a `throw new DeadCodeEliminated`
new Simplify), // Perform local optimizations, simplified versions of what linker does.
List(new LambdaLift, // Lifts out nested functions to class scope, storing free variables in environments
// Note: in this mini-phase block scopes are incorrect. No phases that rely on scopes should be here
diff --git a/compiler/src/dotty/tools/dotc/FromTasty.scala b/compiler/src/dotty/tools/dotc/FromTasty.scala
index 6f74a5d46ea2..3f22c08a1720 100644
--- a/compiler/src/dotty/tools/dotc/FromTasty.scala
+++ b/compiler/src/dotty/tools/dotc/FromTasty.scala
@@ -15,7 +15,7 @@ import util._
import reporting.Reporter
import Decorators._
import dotty.tools.dotc.transform.Pickler
-import tasty.DottyUnpickler
+import tasty.{DottyUnpickler, TastyBuffer}
import ast.tpd._
import NameKinds.QualifiedName
@@ -101,4 +101,13 @@ object FromTasty extends Driver {
}
}
}
+
+ def compilationUnit(clsd: ClassDenotation, unpickler: DottyUnpickler)(implicit ctx: Context): CompilationUnit = {
+ val List(unpickled) = unpickler.body(ctx.addMode(Mode.ReadPositions))
+ val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
+ unit1.tpdTree = unpickled
+ unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler)
+ force.traverse(unit1.tpdTree)
+ unit1
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
index ed05140dcfeb..16764b739668 100644
--- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
+++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
@@ -43,6 +43,12 @@ class ScalaSettings extends Settings.SettingGroup {
val rewrite = OptionSetting[Rewrites]("-rewrite", "When used in conjunction with -language:Scala2 rewrites sources to migrate to new syntax")
val silentWarnings = BooleanSetting("-nowarn", "Silence all warnings.")
+ val linkDCE = BooleanSetting("-link-dce", "Enable dead code elimination.")
+ val linkDCEAggressive = BooleanSetting("-link-aggressive-dce", "Enable aggressive dead code elimination.")
+ val linkVis = BooleanSetting("-link-vis", "Output the visual representation of the call graph.")
+ val linkJavaConservative = BooleanSetting("-link-java-conservative", "Compute call graph for java methods.")
+ val linkSpecialize = BooleanSetting("-link-specialize", "Enable link time specialization.")
+
/** -X "Advanced" settings
*/
val Xhelp = BooleanSetting("-X", "Print a synopsis of advanced options.")
@@ -105,6 +111,9 @@ class ScalaSettings extends Settings.SettingGroup {
val YnoDoubleBindings = BooleanSetting("-Yno-double-bindings", "Assert no namedtype is bound twice (should be enabled only if program is error-free).")
val YshowVarBounds = BooleanSetting("-Yshow-var-bounds", "Print type variables with their bounds")
val YnoInline = BooleanSetting("-Yno-inline", "Suppress inlining.")
+ val YlinkDCEChecks = BooleanSetting("-Ylink-dce-checks", "Check number of reachable classes and methods.")
+ val YlinkSpecialize = IntSetting("-YlinkSpecialize","Specialize methods with maximum this amount of polymorphic types.", 0, 0 to 10)
+
/** Linker specific flags */
val optimise = BooleanSetting("-optimise", "Generates faster bytecode by applying optimisations to the program") withAbbreviation "-optimize"
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index ebfbf5926851..6689103e4b9b 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -355,6 +355,8 @@ class Definitions {
def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol
def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray")
def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray")
+ def DottyArraysMethods(implicit ctx: Context) = List(newArrayMethod, newGenericArrayMethod)
+
lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
def NilModule(implicit ctx: Context) = NilModuleRef.symbol
@@ -388,7 +390,7 @@ class Definitions {
def ArrayConstructor(implicit ctx: Context) = ArrayConstructorR.symbol
lazy val ArrayModuleType = ctx.requiredModuleRef("scala.Array")
def ArrayModule(implicit ctx: Context) = ArrayModuleType.symbol.moduleClass.asClass
-
+ def ArrayMethods(implicit ctx: Context) = List(Array_apply, Array_update, Array_length, Array_clone, ArrayConstructor)
lazy val UnitType: TypeRef = valueTypeRef("scala.Unit", BoxedUnitType, java.lang.Void.TYPE, UnitEnc)
def UnitClass(implicit ctx: Context) = UnitType.symbol.asClass
@@ -458,6 +460,12 @@ class Definitions {
def BoxedUnit_UNIT(implicit ctx: Context) = BoxedUnitClass.linkedClass.requiredValue("UNIT")
+
+ def isPrimitiveClass(sym: Symbol): Boolean = {
+ sym == defn.IntClass || sym == defn.LongClass || sym == defn.ShortClass || sym == defn.CharClass || sym == defn.ByteClass ||
+ sym == defn.BooleanClass || sym == defn.FloatClass || sym == defn.DoubleClass || sym == defn.UnitClass
+ }
+
lazy val BoxedBooleanType: TypeRef = ctx.requiredClassRef("java.lang.Boolean")
def BoxedBooleanClass(implicit ctx: Context) = BoxedBooleanType.symbol.asClass
lazy val BoxedByteType: TypeRef = ctx.requiredClassRef("java.lang.Byte")
@@ -600,6 +608,8 @@ class Definitions {
def ContravariantBetweenAnnot(implicit ctx: Context) = ContravariantBetweenAnnotType.symbol.asClass
lazy val DeprecatedAnnotType = ctx.requiredClassRef("scala.deprecated")
def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass
+ lazy val EntryPointAnnotType = ctx.requiredClassRef("scala.EntryPoint")
+ def EntryPointAnnot(implicit ctx: Context) = EntryPointAnnotType.symbol.asClass
lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound")
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")
diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala
index 543b15fb1460..313536c1cec2 100644
--- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala
+++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala
@@ -284,6 +284,8 @@ object NameKinds {
val SkolemName = new UniqueNameKind("?")
val LiftedTreeName = new UniqueNameKind("liftedTree")
val SuperArgName = new UniqueNameKind("$superArg$")
+ val SpecializedName = new UniqueNameKind("$spec")
+ val DefaultExceptionName = new UniqueNameKind(nme.DEFAULT_EXCEPTION_NAME.toString)
/** A kind of unique extension methods; Unlike other unique names, these can be
* unmangled.
diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala
index bf33471cc98f..6c3a46a1b33f 100644
--- a/compiler/src/dotty/tools/dotc/core/Phases.scala
+++ b/compiler/src/dotty/tools/dotc/core/Phases.scala
@@ -13,6 +13,7 @@ import config.Printers.config
import scala.collection.mutable.{ListBuffer, ArrayBuffer}
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform}
import dotty.tools.dotc.transform._
+import dotty.tools.dotc.transform.linker._
import Periods._
import typer.{FrontEnd, RefChecks}
import ast.tpd
@@ -243,6 +244,7 @@ object Phases {
private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter])
private val gettersCache = new PhaseCache(classOf[Getters])
private val genBCodeCache = new PhaseCache(classOf[GenBCode])
+ private val summariesCache = new PhaseCache(classOf[CollectSummaries])
def typerPhase = typerCache.phase
def picklerPhase = picklerCache.phase
@@ -257,6 +259,7 @@ object Phases {
def explicitOuterPhase = explicitOuterCache.phase
def gettersPhase = gettersCache.phase
def genBCodePhase = genBCodeCache.phase
+ def summariesPhase = summariesCache.phase
def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
}
diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala
index a0ab31b70105..0d1a6d76f10c 100644
--- a/compiler/src/dotty/tools/dotc/core/StdNames.scala
+++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala
@@ -433,9 +433,9 @@ object StdNames {
val info: N = "info"
val inlinedEquals: N = "inlinedEquals"
val isArray: N = "isArray"
+ val isDefined: N = "isDefined"
val isDefinedAt: N = "isDefinedAt"
val isDefinedAtImpl: N = "$isDefinedAt"
- val isDefined: N = "isDefined"
val isEmpty: N = "isEmpty"
val isInstanceOf_ : N = "isInstanceOf"
val java: N = "java"
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index 154f6ad90c41..a9e70ebabdd4 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -18,6 +18,8 @@ import util.Stats
import java.util.WeakHashMap
import config.Config
import config.Printers.{completions, incremental, noPrinter}
+import classfile.ClassfileParser
+import dotty.tools.dotc.core.tasty.DottyUnpickler
trait SymDenotations { this: Context =>
import SymDenotations._
@@ -1236,6 +1238,8 @@ object SymDenotations {
initRunId: RunId)
extends SymDenotation(symbol, ownerIfExists, name, initFlags, initInfo, initPrivateWithin) {
+ private[dotc] var dottyUnpickler: Option[DottyUnpickler] = None
+
import util.LRUCache
// ----- caches -------------------------------------------------------
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index ac3245c37db3..87fd5bd265c4 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -1935,6 +1935,18 @@ object Types {
class TermRefWithFixedSym(prefix: Type, name: TermName, val fixedSym: TermSymbol) extends TermRef(prefix, name) with WithFixedSym
class TypeRefWithFixedSym(prefix: Type, name: TypeName, val fixedSym: TypeSymbol) extends TypeRef(prefix, name) with WithFixedSym
+ /* used by linker */
+ final class TypeRefWithFixedSymAndInfo(prefix: Type, name: TypeName, fixedSym: TypeSymbol, val underl: Type) extends TypeRefWithFixedSym(prefix, name, fixedSym) {
+ override def derivedSelect(prefix: Type)(implicit ctx: Context): Type = {
+ assert(prefix eq this.prefix, "loss in precision")
+ this
+ }
+
+ override def info(implicit ctx: Context): Type = underl
+
+ override def equals(that: Any): Boolean = that.isInstanceOf[TypeRefWithFixedSymAndInfo] && super.equals(that) && this.underl == that.asInstanceOf[TypeRefWithFixedSymAndInfo].underl
+ }
+
/** Assert current phase does not have erasure semantics */
private def assertUnerased()(implicit ctx: Context) =
if (Config.checkUnerased) assert(!ctx.phase.erasedTypes)
@@ -2045,6 +2057,10 @@ object Types {
*/
def withFixedSym(prefix: Type, name: TypeName, sym: TypeSymbol)(implicit ctx: Context): TypeRef =
unique(new TypeRefWithFixedSym(prefix, name, sym))
+
+ def withFixedSymAndInfo(prefix: Type, name: TypeName, sym: TypeSymbol, info: Type)(implicit ctx: Context): TypeRef = {
+ unique(new TypeRefWithFixedSymAndInfo(prefix, name, sym, info))
+ }
/** Create a type ref referring to given symbol with given name.
* This is very similar to TypeRef(Type, Symbol),
@@ -3440,22 +3456,28 @@ object Types {
// ----- Annotated and Import types -----------------------------------------------
/** An annotated type tpe @ annot */
- case class AnnotatedType(tpe: Type, annot: Annotation)
- extends UncachedProxyType with ValueType {
+ abstract case class AnnotatedType(tpe: Type, annot: Annotation)
+ extends CachedProxyType with ValueType {
// todo: cache them? but this makes only sense if annotations and trees are also cached.
override def underlying(implicit ctx: Context): Type = tpe
- def derivedAnnotatedType(tpe: Type, annot: Annotation) =
+ def derivedAnnotatedType(tpe: Type, annot: Annotation)(implicit ctx: Context) =
if ((tpe eq this.tpe) && (annot eq this.annot)) this
else AnnotatedType(tpe, annot)
override def stripTypeVar(implicit ctx: Context): Type =
derivedAnnotatedType(tpe.stripTypeVar, annot)
override def stripAnnots(implicit ctx: Context): Type = tpe.stripAnnots
+
+ override def computeHash: Int = doHash(annot, tpe)
}
+ class CachedAnnotatedType(tpe: Type, annot: Annotation) extends AnnotatedType(tpe, annot)
+
object AnnotatedType {
- def make(underlying: Type, annots: List[Annotation]) =
- (underlying /: annots)(AnnotatedType(_, _))
+ def apply(tpe: Type, annot: Annotation)(implicit ctx: Context) =
+ unique(new CachedAnnotatedType(tpe, annot))
+ def make(underlying: Type, annots: List[Annotation])(implicit ctx: Context) =
+ (underlying /: annots)(apply(_, _))
}
// Special type objects and classes -----------------------------------------------------
diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
index ba58393a4c39..7ea8532d15d3 100644
--- a/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
+++ b/compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
@@ -6,6 +6,7 @@ package classfile
import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._
import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotations._, util.Positions._
import NameKinds.{ModuleClassName, DefaultGetterName}
+import tasty.DottyUnpickler
import ast.tpd._
import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException }
import java.lang.Integer.toHexString
@@ -145,6 +146,13 @@ class ClassfileParser(
setClassInfo(moduleRoot, staticInfo)
}
+ result match {
+ case result @ Some(_: DottyUnpickler) =>
+ classRoot.dottyUnpickler = result.asInstanceOf[Option[DottyUnpickler]]
+ moduleRoot.dottyUnpickler = result.asInstanceOf[Option[DottyUnpickler]]
+ case _ =>
+ }
+
// eager load java enum definitions for exhaustivity check of pattern match
if (isEnum) {
instanceScope.toList.map(_.ensureCompleted())
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
index 8178019aa033..5ef15fd9c8ff 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
@@ -11,6 +11,9 @@ import util.{SourceFile, NoSource}
import Annotations.Annotation
import core.Mode
import classfile.ClassfileParser
+import dotty.tools.dotc.transform.linker.summaries.MethodSummary
+import dotty.tools.dotc.transform.linker.summaries.TastySummaries
+import scala.collection.mutable
object DottyUnpickler {
@@ -27,6 +30,13 @@ object DottyUnpickler {
def unpickle(reader: TastyReader, nameAtRef: NameTable) =
new PositionUnpickler(reader)
}
+
+ class SummariesTreeSectionUnpickler(symAtAddr: mutable.HashMap[Addr, Symbol], sectionName: String)
+ extends TreeSectionUnpickler(posUnpickler = None) {
+ override def unpickle(reader: TastyReader, tastyName: NameTable): SummariesTreeUnpickler = {
+ new SummariesTreeUnpickler(symAtAddr, reader, tastyName, sectionName)
+ }
+ }
}
/** A class for unpickling Tasty trees and symbols.
@@ -57,4 +67,20 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
myBody
} else computeBody()
}
+
+ def summaries(implicit ctx: Context): List[MethodSummary] = {
+ val sectionName = TastySummaries.sectionName
+ val tastySection = unpickler.unpickle(new SummariesTreeSectionUnpickler(treeUnpickler.symAtAddr, sectionName)).get
+ tastySection.asInstanceOf[SummariesTreeUnpickler].getStartReader(ctx) match {
+ case Some(treeReader) =>
+ val unp = new TastyUnpickler.SectionUnpickler[List[MethodSummary]](sectionName) {
+ def unpickle(reader: TastyReader, tastyName: NameTable): List[MethodSummary] =
+ new TastySummaries.SummaryReader(treeReader, reader)(ctx).read()
+ }
+ unpickler.unpickle(unp).getOrElse(Nil)
+
+ case None => Nil
+ }
+
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/SummariesTreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/SummariesTreeUnpickler.scala
new file mode 100644
index 000000000000..64e865c08cb3
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/tasty/SummariesTreeUnpickler.scala
@@ -0,0 +1,34 @@
+package dotty.tools.dotc.core.tasty
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Mode
+import dotty.tools.dotc.core.Names.TermName
+import dotty.tools.dotc.core.tasty.TastyBuffer.{Addr, NameRef}
+
+import scala.collection.mutable
+
+class SummariesTreeUnpickler(override val symAtAddr: mutable.HashMap[Addr, Symbol], reader: TastyReader, tastyName: NameRef => TermName, sectionName: String)
+ extends TreeUnpickler(reader, tastyName, posUnpicklerOpt = None) {
+
+ roots = Set.empty
+
+ def getStartReader(implicit ctx: Context): Option[TreeReader] = {
+ val st = new TreeReader(reader)
+ st.skipToplevel()(ctx.addMode(Mode.AllowDependentFunctions))
+
+ while (true) {
+ while (reader.nextByte != TastyFormat.VALDEF && !reader.isAtEnd) st.skipTree()
+ if (reader.isAtEnd) return None // no section here
+ val tag = reader.readByte()
+ val end = reader.readEnd()
+ val name = st.readName()
+ if (name.toString == sectionName) return Some(st.forkAt(end))
+ st.skipTree() // skip type
+ st.skipTree() // skip rhs
+ }
+
+ None
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index 338a395ab685..7cfce4bc9bc8 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -153,6 +153,11 @@ class TreePickler(pickler: TastyPickler) {
writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
pickleSymRef(sym)
}
+ else if (tpe.isTerm) {
+ writeByte(TERMREF) // should be changed to a new entry that keeps track of prefix, symbol & owner
+ pickleName(tpe.name)
+ pickleType(tpe.prefix)
+ }
else {
assert(tpe.symbol.isClass)
assert(tpe.symbol.is(Flags.Scala2x), tpe.symbol.showLocated)
diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index d1f800c9926f..82b4dca0ac41 100644
--- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -29,7 +29,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
import tpd._
/** A map from addresses of definition entries to the symbols they define */
- private val symAtAddr = new mutable.HashMap[Addr, Symbol]
+ private[tasty] val symAtAddr = new mutable.HashMap[Addr, Symbol]
/** A temporary map from addresses of definition entries to the trees they define.
* Used to remember trees of symbols that are created by a completion. Emptied
@@ -46,7 +46,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
/** The root symbol denotation which are defined by the Tasty file associated with this
* TreeUnpickler. Set by `enterTopLevel`.
*/
- private var roots: Set[SymDenotation] = null
+ private[tasty] var roots: Set[SymDenotation] = null
/** The root symbols that are defined in this Tasty file. This
* is a subset of `roots.map(_.symbol)`.
@@ -66,13 +66,13 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
this.roots = roots
var rdr = new TreeReader(reader).fork
ownerTree = new OwnerTree(NoAddr, 0, rdr.fork, reader.endAddr)
- rdr.indexStats(reader.endAddr)
+ rdr.indexTopLevel
}
/** The unpickled trees */
def unpickle()(implicit ctx: Context): List[Tree] = {
assert(roots != null, "unpickle without previous enterTopLevel")
- new TreeReader(reader).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions))
+ new TreeReader(reader).forkAt(Addr(0)).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions))
}
class Completer(owner: Symbol, reader: TastyReader) extends LazyType {
@@ -433,7 +433,7 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
def adjustIfModule(completer: LazyType) =
if (flags is Module) ctx.adjustModuleCompleter(completer, name) else completer
val sym =
- roots.find(root => (root.owner eq ctx.owner) && root.name == name) match {
+ roots.find(root => root.exists && (root.owner eq ctx.owner) && root.name == name) match {
case Some(rootd) =>
pickling.println(i"overwriting ${rootd.symbol} # ${rootd.hashCode}")
rootd.info = adjustIfModule(
@@ -531,6 +531,17 @@ class TreeUnpickler(reader: TastyReader, nameAtRef: NameRef => TermName, posUnpi
(flags, annots.toList, privateWithin)
}
+ /** Create symbols for the definitions in the top level statements.
+ */
+ def indexTopLevel(implicit ctx: Context): Unit = {
+ nextByte match {
+ case PACKAGE =>
+ processPackage { (pid, end) => implicit ctx => indexStats(end) }
+ case _ =>
+ skipTree()
+ }
+ }
+
/** Create symbols for the definitions in the statement sequence between
* current address and `end`.
* @return the largest subset of {NoInits, PureInterface} that a
diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
index dfd2fda15a02..211a3e7619fb 100644
--- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -266,6 +266,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
else "{...}.this" // TODO move underlying type to an addendum, e.g. ... z3 ... where z3: ...
case tp: SkolemType =>
if (homogenizedView) toText(tp.info) else toText(tp.repr)
+ case tp: SingletonType =>
+ toText(tp.underlying)
}
}
diff --git a/compiler/src/dotty/tools/dotc/transform/OuterSpecializer.scala b/compiler/src/dotty/tools/dotc/transform/OuterSpecializer.scala
new file mode 100644
index 000000000000..66f6bf9f3c10
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/OuterSpecializer.scala
@@ -0,0 +1,816 @@
+package dotty.tools.dotc.transform
+
+import java.util
+
+import dotty.tools.dotc.ast.Trees._
+import dotty.tools.dotc.ast.{TreeTypeMap, tpd}
+import dotty.tools.dotc.core.Contexts.{Context, ContextBase}
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.DenotTransformers.InfoTransformer
+import dotty.tools.dotc.core.Denotations.SingleDenotation
+import dotty.tools.dotc.core.NameKinds._
+import dotty.tools.dotc.core.Names.{Name, TypeName}
+import dotty.tools.dotc.core.SymDenotations.SymDenotation
+import dotty.tools.dotc.core._
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core.Flags.FlagSet
+import dotty.tools.dotc.core.StdNames._
+import dotty.tools.dotc.core.Symbols.{ClassSymbol, Symbol}
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo, TreeTransform}
+import dotty.tools.dotc.transform.linker.callgraph.{CallGraph, OuterTargs, SubstituteByParentMap}
+
+import scala.collection.mutable
+
+object OuterSpecializer {
+ def isPhaseRequired(implicit ctx: Context): Boolean =
+ ctx.settings.linkSpecialize.value
+}
+
+// TODO: Check secondary constructors.
+// TODO: check private fields
+class OuterSpecializer extends MiniPhaseTransform with InfoTransformer {
+ import OuterSpecializer._
+ import tpd._
+
+ override def phaseName = "specializeClass"
+
+ type Specialization = Array[Type]
+
+ /**
+ * Methods requested for specialization
+ * Generic Symbol => List[ (position in list of args, specialized type requested) ]
+ */
+ private val specializationRequests: mutable.HashMap[Symbol, List[OuterTargs]] = mutable.HashMap.empty
+
+ /**
+ * A map that links symbols to their specialized variants.
+ * Each symbol maps to another map, from the list of specialization types to the specialized symbol.
+ * Generic symbol =>
+ * Map{ List of [ Tuple(position in list of args, specialized Type) ] for each variant => Specialized Symbol }
+ */
+ val newSymbolMap: mutable.HashMap[Symbol, mutable.HashMap[OuterTargs, Symbol]] = mutable.HashMap.empty
+
+ /**
+ * A map that links symbols to their speciazation requests.
+ * Each symbol maps to another map, from the list of specialization types to the specialized symbol.
+ * Generic symbol =>
+ * Map{ List of [ Tuple(position in list of args, specialized Type) ] for each variant => Specialized Symbol }
+ */
+ val outerBySym: mutable.HashMap[Symbol, OuterTargs] = mutable.HashMap.empty
+
+ val addBridges: mutable.HashMap[ClassSymbol, List[(Symbol, Symbol)]] = mutable.HashMap.empty
+
+ /** maps bridges back to original symbol */
+ val canonical: mutable.HashMap[Symbol, Symbol] = mutable.HashMap.empty
+
+ val originBySpecialized: mutable.HashMap[Symbol, Symbol] = mutable.HashMap.empty
+
+ /**
+ * A list of symbols gone through the specialisation pipeline
+ * Is used to make calls to transformInfo idempotent
+ */
+ private val processed: util.IdentityHashMap[Symbol, Type] = new util.IdentityHashMap()
+
+
+ def isSpecializable(sym: Symbol, numOfTypes: Int)(implicit ctx: Context): Boolean =
+ numOfTypes > 0 &&
+ sym.name != nme.asInstanceOf_ &&
+ !newSymbolMap.contains(sym) &&
+ !(sym is Flags.JavaDefined) &&
+ !sym.isPrimaryConstructor
+
+ /** Get list of types to specialize for */
+ def getSpecTypes(method: Symbol, poly: PolyType)(implicit ctx: Context): List[OuterTargs] = {
+
+ val requested = specializationRequests.getOrElse(method, List.empty)
+ if (requested.nonEmpty) {
+ requested
+ }
+ else {
+ Nil
+ }
+ }
+
+ override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform =
+ if (isPhaseRequired) this else TreeTransforms.NoTransform
+
+ /** was decl requested to be specialized */
+ def requestedSpecialization(decl: Symbol)(implicit ctx: Context): Boolean = {
+ ctx.settings.YlinkSpecialize.value != 0 || specializationRequests.contains(decl) || {
+ originBySpecialized.getOrElse(decl, null) match {
+ case null => false
+ case origin if !origin.isClass => requestedSpecialization(origin) // a specialized version of specialized method todo: Am i right?
+ case _ => false
+ }
+ }
+ }
+
+ def isSimilar(arguments: OuterTargs, other: OuterTargs)(implicit ctx: Context) = {
+ other.mp.forall { other =>
+ arguments.mp.get(other._1) match {
+ case None => false
+ case Some(mapping) =>
+ mapping.forall { thisMapping =>
+ other._2.get(thisMapping._1) match {
+ case None => false
+ case Some(otherTp) =>
+ otherTp.dropAlias =:= thisMapping._2.dropAlias
+ }
+ }
+ }
+ }
+ }
+
+ def subsumes(arguments: OuterTargs, other: OuterTargs)(implicit ctx: Context) = {
+ other.mp.forall { other =>
+ arguments.mp.get(other._1) match {
+ case None => false
+ case Some(mapping) =>
+ mapping.forall { thisMapping =>
+ other._2.get(thisMapping._1) match {
+ case None => false
+ case Some(otherTp) =>
+ otherTp.dropAlias <:< thisMapping._2.dropAlias
+ }
+ }
+ }
+ }
+ }
+
+ def specializationRequest(callGraph: CallGraph)(implicit ctx: Context): Unit = {
+ callGraph.reachableMethods.foreach { mc =>
+ val methodSym = mc.call.termSymbol
+ val outerTargs = methodSym.info.widen match {
+ case PolyType(names, _) =>
+ (names.map(_.paramName) zip mc.targs).foldLeft(mc.outerTargs)((x, nameType) => x.add(methodSym, nameType._1, nameType._2))
+ case _ =>
+ mc.outerTargs
+ }
+ if (outerTargs.mp.nonEmpty && !methodSym.isPrimaryConstructor)
+ registerSpecializationRequest(methodSym)(outerTargs)
+ }
+ callGraph.reachableTypes.foreach { tpc =>
+ if (!tpc.tp.typeSymbol.is(Flags.JavaDefined)) {
+ val parentOverrides = tpc.tp.typeMembers(ctx).foldLeft(OuterTargs.empty)((outerTargs, denot) =>
+ if (!denot.exists || (denot.symbol.owner eq defn.ScalaShadowingPackageClass)) outerTargs // TODO get outer targs from shadowed classes
+ else {
+ denot.symbol.allOverriddenSymbols.foldLeft(outerTargs)((outerTargs, sym) =>
+ outerTargs.add(sym.owner, denot.symbol.name, denot.info))
+ }
+ )
+
+ val spec = tpc.outerTargs ++ parentOverrides ++ OuterTargs.parentRefinements(tpc.tp)
+
+ if (spec.nonEmpty) {
+ registerSpecializationRequest(tpc.tp.typeSymbol)(spec)
+
+ def loop(remaining: List[Symbol]): Unit = {
+ if (remaining.isEmpty) return;
+ val target = remaining.head
+
+ val nspec = new OuterTargs(spec.mp.filter { x => target.derivesFrom(x._1) })
+ if (nspec.nonEmpty)
+ registerSpecializationRequest(target)(nspec)
+ loop(remaining.tail)
+ }
+
+ val parents = tpc.tp.baseClasses
+ loop(parents)
+ }
+ }
+ }
+ }
+
+ def registerSpecializationRequest(methodOrClass: Symbol)(arguments: OuterTargs)(implicit ctx: Context): Unit = {
+ if (((methodOrClass.isClass && (!methodOrClass.is(Flags.Module) || !methodOrClass.isStatic)) ||
+ methodOrClass.is(Flags.Method))
+ && (methodOrClass.sourceFile ne null)) {
+ if (ctx.phaseId > this.treeTransformPhase.id)
+ assert(ctx.phaseId <= this.treeTransformPhase.id)
+ val prev = specializationRequests.getOrElse(methodOrClass, List.empty)
+ def isSimilar(arguments: OuterTargs, other: OuterTargs) = {
+ other.mp.forall { other =>
+ arguments.mp.get(other._1) match {
+ case None => false
+ case Some(mapping) =>
+ mapping.forall { thisMapping =>
+ other._2.get(thisMapping._1) match {
+ case None => false
+ case Some(otherTp) =>
+ otherTp =:= thisMapping._2
+ }
+ }
+ }
+ }
+ }
+
+ if (prev.exists(isSimilar(arguments, _)))
+ return;
+
+ specializationRequests.put(methodOrClass, arguments :: prev)
+ }
+ else {
+ ctx.log(s"ignoring specialization reguest for ${methodOrClass.showFullName} for ${arguments}")
+ }
+ }
+
+ override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
+ if (!isPhaseRequired) return ref
+
+ val n = super.transform(ref)
+ if (n.symbol.isClass && requestedSpecialization(n.symbol)) {
+ val sd = n.asInstanceOf[SymDenotation]
+ val newParent = n.symbol.asClass.baseClasses.find(x => x.isClass && !(x is Flags.Trait) && !requestedSpecialization(x))
+ val info = n.info.asInstanceOf[ClassInfo]
+ // todo: fix parents
+ sd.copySymDenotation(initFlags = sd.flags | Flags.Trait, info = info)
+ } else n
+ }
+
+ /* Provided a class that owns a method to be specialized, adds specializations to the body of the class, without forcing new symbols
+ * provided a method to be specialized, specializes it and enters it into its owner
+ * */
+ override def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = {
+ if (!isPhaseRequired) return tp
+
+ def enterNewSyms(newDecls: List[Symbol], classInfo: ClassInfo, tp: Type) = {
+ if (!classInfo.typeSymbol.is(Flags.Package)) {
+ val decls = classInfo.decls.cloneScope
+ newDecls.foreach(x => decls.enter(x))
+ classInfo.derivedClassInfo(decls = decls)
+ } else {
+ newDecls.foreach(_.entered)
+ classInfo // used to return tp here. why?
+ }
+ }
+
+ def duplicateClass(originalClass: ClassInfo, specialization: OuterTargs): ClassSymbol = {
+ val claz = originalClass.typeSymbol.asClass
+
+ val newParents = originalClass.classParents.head :: claz.typeRef :: originalClass.classParents.tail
+ val map = new SubstituteByParentMap(specialization)
+ val newDecls = originalClass.decls.cloneScope.openForMutations // this is a hack. I'm mutating this scope later
+ def newType(nwClaz: ClassSymbol): Type =
+ ClassInfo(originalClass.prefix, nwClaz, newParents, newDecls, map.apply(originalClass.selfType))
+
+ def fixModule(nm: TypeName): TypeName = {
+ import NameOps._
+ if (claz.flags is Flags.Module) nm.moduleClassName
+ else nm
+ }
+ val sepcName: TypeName = SpecializedName.fresh(claz.name.toTermName).toTypeName
+ val newClaz = ctx.newClassSymbol(claz.owner, fixModule(sepcName), claz.flags | Flags.Synthetic, newType)
+
+ originalClass.decls.foreach { originalDecl =>
+
+ lazy val otherTr = originalDecl.typeRef
+ lazy val mappedTr = map(otherTr)
+ originalDecl match {
+ case other: Symbol if other.isType && !other.isClass && (otherTr ne mappedTr) =>
+ other.info match {
+ case tp: TypeBounds =>
+ // val newParam = ctx.newSymbol(newClaz, other.name, other.flags, TypeAlias(otherTr), other.privateWithin, other.coord)
+ val newBoulds =
+ if (mappedTr.typeSymbol eq defn.AnyClass) tp
+ else TypeAlias(mappedTr)
+ val nw = ctx.newSymbol(newClaz, other.name, other.flags, newBoulds, other.privateWithin, other.coord)
+ newDecls.replace(other, nw)
+ }
+
+ case other =>
+ val tpe = if (other.isClassConstructor) other.info match {
+ case oinfo: PolyType =>
+ val newConstructorBounds = originalClass.typeParams.map(x => specialization.mp(claz)(x.paramName))
+ val fullConstructorBounds = (oinfo.paramInfos zip newConstructorBounds).map { case (old, nw) => TypeBounds(old.lo | nw.dropAlias, old.hi & nw.dropAlias) }
+ def newResultType(m: MethodType): LambdaType = {
+ m.resultType match {
+ case r: MethodType => m.derivedLambdaType(m.paramNames, m.paramInfos, newResultType(r))
+ case r: RefinedType =>
+ m.derivedLambdaType(m.paramNames, m.paramInfos, r.translateParameterized(claz, newClaz))
+ case r => ???
+ }
+ }
+ val resultType = newResultType(oinfo.resultType.asInstanceOf[MethodType])
+ oinfo.derivedLambdaType(oinfo.paramNames, fullConstructorBounds, resultType)
+ case _ => map(other.info)
+ } else map(other.info)
+ def fixMethodic(tp: Type, flags: FlagSet) = {
+ if (flags is Flags.Method)
+ if (tp.isInstanceOf[MethodicType]) tp
+ else ExprType(tp)
+ else tp
+ }
+ val nw = ctx.newSymbol(newClaz, other.name, other.flags, fixMethodic(tpe, other.flags), other.privateWithin, other.coord)
+ originBySpecialized.put(nw, other)
+
+ val currentBridge = addBridges.getOrElse(claz, Nil).filter(x => x._2 == other && x._1.signature == nw.signature)
+
+ if (!other.isClassConstructor && (nw.signature.matchDegree(other.signature) != Signature.FullMatch) && currentBridge.isEmpty) {
+ // bridge is needed
+
+ {
+ val bridgeInSuper = ctx.newSymbol(claz, nw.name, nw.flags.&~(Flags.Accessor | Flags.ParamAccessor) | Flags.Bridge, nw.info).enteredAfter(this)
+ val lst = addBridges.getOrElse(claz, Nil)
+ canonical.put(bridgeInSuper, other)
+ addBridges.put(claz, (bridgeInSuper, other) :: lst)
+ // add spec?
+ }
+
+ {
+ val bridgeInSub =
+ ctx.newSymbol(newClaz, nw.name, nw.flags.&~(Flags.Accessor | Flags.ParamAccessor) | Flags.Bridge, other.info)
+ val lst = addBridges.getOrElse(newClaz, Nil)
+
+ // add spec?
+
+ newDecls.enter(bridgeInSub)
+ canonical.put(bridgeInSub, nw)
+ addBridges.put(newClaz, (bridgeInSub, nw) :: lst)
+ }
+
+
+ }
+
+ if (other.isTerm && !(other.is(Flags.Method))) {
+ // field
+ val newFlags = (other.symbol.flags &~ (Flags.Mutable)) | Flags.Deferred | Flags.Method | Flags.Stable
+ other.asSymDenotation.copySymDenotation(initFlags = newFlags, info = fixMethodic(other.info, newFlags)).installAfter(this)
+ }
+
+ /* if (other.isTerm && other.is(Flags.ParamAccessor)) {
+ val newFlags = (other.symbol.flags &~ (Flags.ParamAccessor | Flags.Accessor | Flags.Private)) | Flags.Deferred | Flags.Method| Flags.Stable
+ other.asSymDenotation.copySymDenotation(initFlags = newFlags, info = fixMethodic(other.info, newFlags)).installAfter(this)
+ } */
+
+ newDecls.replace(other, nw)
+ }
+ }
+
+ val umap: mutable.HashMap[OuterTargs, Symbol] = newSymbolMap.getOrElse(claz, mutable.HashMap.empty)
+ umap.put(specialization, newClaz)
+ newSymbolMap.put(claz, umap)
+ originBySpecialized.put(newClaz, claz)
+
+
+ val specializedByOrigin = newDecls.filter(x => x.isTerm && originBySpecialized.contains(x)).
+ map(x => (originBySpecialized(x), x)).toMap
+
+ // update specialized mappings for subclass
+ newDecls.foreach(newSym => {
+ if (newSym.isTerm && !newSym.isPrimaryConstructor && !newSym.is(Flags.Bridge)) {
+ val oldSym = originBySpecialized(newSym)
+ val oldSpeciazlizations = newSymbolMap.get(oldSym)
+ oldSpeciazlizations match {
+ case None =>
+ case Some(oldspecs) if oldspecs.nonEmpty=>
+ val newspec = oldspecs.map{case (oldargs, oldspecsym) =>
+ val updatedOldArgs = oldargs.mp(oldSym)
+ (new OuterTargs((oldargs.mp - oldSym) + (newSym -> updatedOldArgs)) ++ specialization,
+ specializedByOrigin(oldspecsym))
+ }
+ newSymbolMap.put(newSym, newspec)
+ }
+ }
+ })
+
+ newClaz
+ }
+
+ def specializeSymbol(sym: Symbol): Type = {
+ processed.put(sym, NoType)
+ ctx.debuglog(s"started specializing type of $sym")
+ val ret = sym.info match {
+ case classInfo: ClassInfo =>
+
+ val newDecls = classInfo.decls
+ .filter(x => x.isDefinedInCurrentRun && x.isCompleted) // We do not want to force symbols. Unforced symbol are not used in the source
+ .filterNot(_.isConstructor)
+ .filter(requestedSpecialization)
+ .flatMap(decl => {
+ decl.info.widen match {
+ case poly: PolyType if isSpecializable(decl.symbol, poly.paramNames.length) =>
+ generateMethodSpecializations(getSpecTypes(decl, poly))(poly, decl)
+ case claz: ClassInfo if requestedSpecialization(decl) =>
+ def addGenericSpec(x: List[OuterTargs]): List[OuterTargs] =
+ if (x.isEmpty) x
+ else {
+ val tparams = decl.typeParams
+ val generic = x.find(_.mp.values.flatten.forall(x => TypeErasure.erasure(x._2) == defn.ObjectType))
+ if (generic.isEmpty) {
+ val tparamsMapping: Map[Name, Type] = tparams.map(x => (x.name, TypeAlias(defn.AnyType))).toMap
+ new OuterTargs(Map(decl -> tparamsMapping)) :: x
+ } else x
+ }
+ val clazInfo = specializeSymbol(decl.asClass).asInstanceOf[ClassInfo]
+ /*addGenericSpec*/ (specializationRequests(decl)).map(x => duplicateClass(clazInfo, x))
+ case _ => Nil
+ }
+ })
+
+ val ntp =
+ if (newDecls.nonEmpty) enterNewSyms(newDecls.toList, classInfo, tp)
+ else classInfo
+ ntp
+ case poly: PolyType if isSpecializable(sym, poly.paramNames.length) => // specialize method
+ if (sym.owner.info.isInstanceOf[ClassInfo]) {
+ transformInfo(sym.owner.info, sym.owner) //why does it ever need to recurse into owner?
+ tp
+ }
+ else if (requestedSpecialization(sym) &&
+ isSpecializable(sym, poly.paramNames.length)) {
+ generateMethodSpecializations(getSpecTypes(sym, poly))(poly, sym) // todo: this value is discarded. a bug?
+ tp
+ }
+ else tp
+ case _ => tp
+ }
+ processed.put(sym, ret)
+ ctx.debuglog(s"finished specializing $sym")
+ ret
+ }
+
+ def generateMethodSpecializations(specTypes: List[OuterTargs])
+ (poly: PolyType, decl: Symbol)
+ (implicit ctx: Context): List[Symbol] = {
+ specTypes.map(x => generateSpecializedSymbol(x, poly, decl))
+ }
+
+ def generateSpecializedSymbol(instantiations: OuterTargs, poly: PolyType, decl: Symbol)
+ (implicit ctx: Context): Symbol = {
+ val resType = new SubstituteByParentMap(instantiations).apply(poly.resType)
+
+ val bounds = if (instantiations.mp.contains(decl)) (poly.paramInfos zip poly.paramNames).map { case (bound, name) =>
+ instantiations.mp.getOrElse(decl, Map.empty).get(name) match {
+ case Some(instantiation) => TypeBounds(bound.lo | instantiation, bound.hi & instantiation)
+ case None => bound
+ }
+ } else poly.paramInfos
+ val newSym = ctx.newSymbol(
+ decl.owner,
+ SpecializedName.fresh(decl.name.asTermName)
+ /*NameOps.NameDecorator(decl.name)
+ .specializedFor(Nil, Nil, instantiations.toList, poly.paramNames)
+ .asInstanceOf[TermName]*/ ,
+ decl.flags | Flags.Synthetic,
+ poly.newLikeThis(poly.paramNames, bounds, resType)
+ )
+
+ val map: mutable.HashMap[OuterTargs, Symbol] = newSymbolMap.getOrElse(decl, mutable.HashMap.empty)
+ map.put(instantiations, newSym)
+ newSymbolMap.put(decl, map)
+ outerBySym.put(newSym, instantiations)
+
+ newSym
+ }
+
+ if (processed.containsKey(sym)) {
+ val v = processed.get(sym)
+ if (v eq NoType)
+ ctx.error("circular error")
+ v
+ }
+
+ if (!processed.containsKey(sym) &&
+ (sym ne defn.ScalaPredefModule.moduleClass) &&
+ !(sym is(Flags.JavaDefined, Flags.Package)) &&
+ !(sym is Flags.Scala2x) &&
+ !sym.isAnonymousClass /*why? becasue nobody can call from outside? they can still be called from inside the class*/ ) {
+ specializeSymbol(sym)
+ } else tp
+ }
+
+ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ tree.tpe.widen match {
+
+ case poly: PolyType
+ if !(tree.symbol.isPrimaryConstructor
+ || (tree.symbol is Flags.Label)
+ ) =>
+
+ def specialize(decl: Symbol): List[Tree] = {
+ if (newSymbolMap.contains(decl)) {
+ val specInfo = newSymbolMap(decl)
+ val newSyms = specInfo.values.toList
+
+
+ newSyms.map { newSym =>
+ val newSymType = newSym.info.widenDealias
+ ctx.log(s"specializing ${tree.symbol.fullName} for ${newSymType.show}")
+ val typemap: (Type, List[Symbol], List[Type]) => (List[Symbol], List[Type]) => Type => Type =
+ (oldPoly, oldTparams, newTparams) => (oldArgs, newArgs) =>
+ new SubstituteByParentMap(outerBySym(newSym)) {
+ override def apply(tp: Type): Type = {
+ val t = super.apply(tp)
+ .substDealias(oldTparams, newTparams)
+ val t2 = oldPoly match {
+ case oldPoly: PolyType => t.substParams(oldPoly, newTparams)
+ case _ => t
+ }
+ t2.subst(oldArgs, newArgs)
+ }
+ }
+ duplicateMethod(newSym, tree)(typeMap = typemap)()
+ }
+ } else Nil
+ }
+ val specializedTrees = specialize(tree.symbol)
+ Thicket(tree :: specializedTrees)
+ case _ => tree
+ }
+ }
+
+ def duplicateMethod(newSym: Symbol, oldTree: DefDef)
+ (typeMap: (Type, List[Symbol], List[Type]) => (List[Symbol], List[Type]) => Type => Type)
+ (substFrom: List[Symbol] = Nil, substTo: List[Symbol] = Nil)
+ (implicit ctx: Context): DefDef = {
+ val oldSym = oldTree.symbol
+ originBySpecialized.put(newSym, oldSym)
+ val origTParams = oldTree.tparams.map(_.symbol)
+ val origVParams = oldTree.vparamss.flatten.map(_.symbol)
+
+ def rhsFn(tparams: List[Type])(vparamss: List[List[Tree]]) = {
+ def treemap(tree: Tree): Tree = tree match {
+ case Return(t, from) if from.symbol == oldSym => Return(t, ref(newSym))
+ case t: This if t.symbol eq oldSym.enclosingClass => This(newSym.enclosingClass.asClass)
+ case t => t
+ }
+
+ val abstractPolyType = oldSym.info.widenDealias
+ val vparamTpes = vparamss.flatten.map(_.tpe)
+
+ val typesReplaced = new TreeTypeMap(
+ treeMap = treemap,
+ typeMap = typeMap(abstractPolyType, origTParams, tparams)(origVParams, vparamTpes),
+ oldOwners = oldSym :: substFrom,
+ newOwners = newSym :: substTo
+ ).transform(oldTree.rhs)
+
+ typesReplaced
+ }
+ polyDefDef(newSym.asTerm, rhsFn)
+ }
+
+ private def newBridges(claz: ClassSymbol)(implicit ctx: Context) = {
+ val bridgeSymbols = addBridges.getOrElse(claz, Nil)
+ bridgeSymbols.map { case (nw, old) =>
+ def rhsFn(tparams: List[Type])(vparamss: List[List[Tree]]) = {
+ val prefix = This(claz).select(old).appliedToTypes(tparams)
+ val argTypess = prefix.tpe.widen.paramInfoss
+ val argss = (vparamss zip argTypess).map { case (vparams, argTypes) =>
+ (vparams zip argTypes).map { case (vparam, argType) => vparam.ensureConforms(argType) }
+ }
+ prefix.appliedToArgss(argss).ensureConforms(nw.info.finalResultType)
+ }
+ polyDefDef(nw.asTerm, rhsFn)
+ }
+
+ }
+
+
+ override def transformTypeDef(tree: tpd.TypeDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val oldSym = tree.symbol
+ if (oldSym.isClass) newSymbolMap.get(tree.symbol) match {
+ case Some(x) =>
+ val newClasses: List[Tree] = x.iterator.map { case (outersTargs, newClassSym) =>
+ def typemap(oldPoly: Type, oldTparams: List[Symbol], newTparams: List[Type])(oldArgs: List[Symbol], newArgs: List[Type]): SubstituteByParentMap = {
+ new SubstituteByParentMap(outersTargs) {
+ override def apply(tp: Type): Type = {
+ val t = super.apply(tp)
+ .substDealias(oldTparams, newTparams)
+ val t2 = oldPoly match {
+ case oldPoly: PolyType => t.substParams(oldPoly, newTparams)
+ case _ => t
+ }
+ t2.subst(oldArgs, newArgs)
+ }
+ }
+ }
+ //duplicateMethod(newSym, tree)(typeMap = typemap)()
+ val treeRhs = tree.rhs.asInstanceOf[Template]
+ val newSubst = newClassSym.info.fields.map(_.symbol).toList // ++ newSym.info.accessors
+ val oldSubst = oldSym.info.fields.map(_.symbol).toList // ++ oldSym.info.accessors
+ def treeMap(t: Tree): Tree = t match {
+ case t: This if t.symbol eq oldSym => tpd.This(newClassSym.asClass)
+ case _ => t
+ }
+ val bodytreeTypeMap = new TreeTypeMap(typeMap = typemap(null, Nil, Nil)(Nil, Nil), substFrom = oldSubst, substTo = newSubst, treeMap = treeMap
+ /*oldOwners = oldSubst, newOwners = newSubst*/)
+ val constr = duplicateMethod(newClassSym.primaryConstructor, treeRhs.constr)(typemap)(oldSubst, newSubst)
+
+ val body = treeRhs.body.map {
+ case t: DefDef =>
+ val variants = newClassSym.info.decl(t.symbol.name).suchThat(p => !(p is Flags.Bridge))
+ val popa = variants.alternatives.map(_.symbol.info.overrides(t.symbol.info))
+ val newMeth: Symbol = // todo: handle overloading
+ /*if(!t.symbol.is(Flags.Private)) t.symbol.matchingMember(newSym.info) // does not work. Signatures do not match anymore
+ else */
+ t.symbol.asSymDenotation.matchingDecl(newClassSym, newClassSym.thisType).filter(p => !(p is Flags.Bridge)).orElse(
+ variants.symbol
+ )
+ //x.matchingDecl(original.symbol.owner.asClass, x.owner.thisType).exists)
+
+ duplicateMethod(newMeth, t)(typemap)(oldSubst, newSubst)
+ case t: TypeDef if !t.isClassDef =>
+ val newMember = newClassSym.info.decl(t.symbol.name).asSymDenotation.symbol.asType
+ tpd.TypeDef(newMember)
+ case t: ValDef =>
+ val newMember = newClassSym.info.decl(t.symbol.name).asSymDenotation.symbol.asTerm
+ tpd.ValDef(newMember, bodytreeTypeMap.apply(t.rhs))
+ case t => // just body. TTM this shit
+ bodytreeTypeMap.apply(t)
+ } ++ newBridges(newClassSym.asClass)
+ val superArgs = treeRhs.parents.head match {
+ case Apply(fn, args) => args
+ case _ => Nil
+ }
+
+ tpd.ClassDef(newClassSym.asClass, constr, body, superArgs)
+ }.toList
+
+ val genericBridges = newBridges(oldSym.asClass)
+
+ val newTrait =
+ if (genericBridges.nonEmpty) {
+ val currentRhs = tree.rhs.asInstanceOf[Template]
+ cpy.TypeDef(tree)(rhs = cpy.Template(currentRhs)(body = currentRhs.body ++ genericBridges))
+ } else tree
+
+ val ret = Thicket(newTrait :: newClasses)
+ ret
+ case None =>
+ tree
+ } else tree
+ }
+
+ def rewireTree(tree: Tree)(implicit ctx: Context): Tree = {
+ assert(tree.isInstanceOf[TypeApply])
+ val TypeApply(fun, args) = tree
+
+ val canonicalSymbol = canonical.getOrElse(fun.symbol, fun.symbol)
+
+ if (canonicalSymbol.isPrimaryConstructor && newSymbolMap.contains(canonicalSymbol.owner)) {
+ val availableSpecializations = newSymbolMap(fun.symbol.owner)
+ val poly = canonicalSymbol.info.widen.asInstanceOf[PolyType]
+ val argsNames = canonicalSymbol.owner.asClass.classInfo.typeParams.map(_.paramName) zip args
+ val availableClasses = availableSpecializations.filter {
+ case (instantiations, symbol) => {
+ val mappings = instantiations.mp(canonicalSymbol.owner)
+ argsNames.forall { case (name, arg) => arg.tpe <:< mappings(name).dropAlias }
+ }
+ }
+
+ val bestVersions = availableClasses.iterator.filter { case (instantiations1, symbol1) =>
+ !availableClasses.exists { case (instantiations2, symbol2) =>
+ (symbol2 ne symbol1) && subsumes(instantiations1, instantiations2)
+ }
+ }.toList
+
+ val ideal = availableSpecializations.find {
+ case (instantiations, symbol) => {
+ val mappings = instantiations.mp(canonicalSymbol.owner)
+ argsNames.forall { case (name, arg) => arg.tpe =:= mappings(name).dropAlias }
+ }
+ }
+
+ def rewrite(newClassSym: Symbol) = {
+ ctx.debuglog(s"new ${canonicalSymbol.owner} rewired to ${newClassSym}")
+ tpd.New(newClassSym.typeRef)
+ .select(newClassSym.primaryConstructor) // todo handle secondary cosntr
+ .appliedToTypeTrees(args)
+ }
+
+ if (ideal.nonEmpty) {
+ rewrite(ideal.get._2)
+ } else if (bestVersions.length > 1) {
+ ctx.error(s"Several specialized variants fit for ${canonicalSymbol.name} of ${canonicalSymbol.owner}." +
+ s" Defaulting to no specialization. This is not supported yet. Variants: \n ${bestVersions.map { x => (x._2.name, x._2.info.widenDealias.show) }.mkString("\n")}")
+ tree
+ } else if (bestVersions.nonEmpty) {
+ val newClassSym = bestVersions.head._2
+ ctx.debuglog(s"new ${canonicalSymbol.owner} rewired to ${newClassSym}")
+ tpd.New(newClassSym.typeRef)
+ .select(newClassSym.primaryConstructor) // todo handle secondary cosntr
+ .appliedToTypeTrees(args)
+ } else EmptyTree
+ } else if (newSymbolMap.contains(canonicalSymbol)) {
+ // not a constructor
+ val poly = fun.symbol.info.widen.asInstanceOf[PolyType]
+ val argsNames = poly.paramNames zip args
+ val availableSpecializations = newSymbolMap(canonicalSymbol)
+ val betterDefs = availableSpecializations.filter {
+ case (instantiations, symbol) => {
+ val mappings = instantiations.mp(canonicalSymbol)
+ argsNames.forall { case (name, arg) => arg.tpe <:< mappings(name) }
+ }
+ }.toList
+
+ if (betterDefs.length > 1) {
+ ctx.debuglog(s"Several specialized variants fit for ${fun.symbol.name} of ${fun.symbol.owner}.")
+ }
+
+ if (betterDefs.nonEmpty) {
+ val newFunSym = betterDefs.head._2
+ ctx.debuglog(s"method ${fun.symbol.name} of ${fun.symbol.owner} rewired to specialized variant")
+ val prefix = fun match {
+ case Select(pre, name) =>
+ pre
+ case t@Ident(_) if t.tpe.isInstanceOf[TermRef] =>
+ val tp = t.tpe.asInstanceOf[TermRef]
+ if (tp.prefix ne NoPrefix)
+ ref(tp.prefix.termSymbol)
+ else EmptyTree
+ case _ => EmptyTree
+ }
+ if (prefix ne EmptyTree) prefix.select(newFunSym).appliedToTypeTrees(args)
+ else ref(newFunSym).appliedToTypeTrees(args)
+ } else tree
+ } else tree
+
+ }
+
+ def transormGenApply(tree: GenericApply[Type])(implicit ctx: Context): Tree = {
+ tree match {
+ case t: tpd.TypeApply =>
+ val TypeApply(fun, _) = tree
+ if (fun.tpe.widenDealias.isParameterless) rewireTree(tree)
+ else tree
+ case t: tpd.Apply =>
+ val Apply(fun, args) = tree
+ fun match {
+ case fun: TypeApply =>
+ val typeArgs = fun.args
+ val newFun = rewireTree(fun)
+ if (fun ne newFun)
+ if (newFun ne EmptyTree)
+ Apply(newFun, args)
+ else {
+ Typed(ref(defn.Sys_errorR).appliedTo(Literal(Constant("should never be reached"))), TypeTree(tree.tpe))
+ }
+ else tree
+ case fun: Apply =>
+ Apply(transormGenApply(fun), args)
+ case _ => tree
+ }
+ }
+ }
+}
+
+object OuterSpecializeParents {
+ def isPhaseRequired(implicit ctx: Context): Boolean =
+ OuterSpecializer.isPhaseRequired
+}
+
+class OuterSpecializeParents extends MiniPhaseTransform with InfoTransformer {
+ import OuterSpecializer._
+
+ var specPhase: OuterSpecializer = null
+
+ override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform =
+ if (isPhaseRequired) this else TreeTransforms.NoTransform
+
+ override def init(base: ContextBase, id: Int): Unit = {
+ specPhase = base.phaseOfClass(classOf[OuterSpecializer]).asInstanceOf[OuterSpecializer]
+ super.init(base, id)
+ }
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = {
+ if (!isPhaseRequired) return tp
+
+ if (sym.isClass && specPhase.originBySpecialized.contains(sym)) {
+ val origSym = specPhase.originBySpecialized(sym)
+ val specialization: OuterTargs = specPhase.newSymbolMap(origSym).find(_._2 == sym).get._1
+
+ tp match {
+ case classInfo: ClassInfo =>
+ val classParent :: original :: others = classInfo.classParents
+
+ def betterParent (parent: TypeRef): TypeRef = {
+ specPhase.newSymbolMap.get(parent.typeSymbol) match {
+ case None => parent
+ case Some(variants) =>
+ /* same as in CollectSummaries.sendSpecializationRequests */
+ def filterApplies(spec: OuterTargs, parent: Symbol) = {
+ new OuterTargs(spec.mp.filter{x => parent.derivesFrom(x._1)})
+ }
+
+ variants.find { case (outerTargs, newSym) =>
+ specPhase.isSimilar(filterApplies(specialization, parent.typeSymbol), filterApplies(outerTargs, parent.typeSymbol))
+ }.map(_._2.typeRef).getOrElse(parent)
+ }
+ }
+ val mappedParents: List[TypeRef] = betterParent(classParent) :: original :: others.map(betterParent)
+ classInfo.derivedClassInfo(classParents = mappedParents)
+ case _ =>
+ ???
+ }
+ } else tp
+ }
+
+ val phaseName: String = "specializeClassParents"
+
+ override def transformApply(tree: tpd.Apply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = specPhase.transormGenApply(tree)
+
+ override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = specPhase.transormGenApply(tree)
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala
index 76b1658d1558..d50e609cacf9 100644
--- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala
@@ -26,9 +26,7 @@ class Pickler extends Phase {
s.close
}
- // Maps that keep a record if -Ytest-pickler is set.
private val beforePickling = new mutable.HashMap[ClassSymbol, String]
- private val picklers = new mutable.HashMap[ClassSymbol, TastyPickler]
/** Drop any elements of this list that are linked module classes of other elements in the list */
private def dropCompanionModuleClasses(clss: List[ClassSymbol])(implicit ctx: Context): List[ClassSymbol] = {
@@ -43,25 +41,17 @@ class Pickler extends Phase {
for { cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
tree <- sliceTopLevel(unit.tpdTree, cls) } {
+ if (ctx.settings.YtestPickler.value) beforePickling(cls) = tree.show
val pickler = new TastyPickler()
- if (ctx.settings.YtestPickler.value) {
- beforePickling(cls) = tree.show
- picklers(cls) = pickler
- }
+ unit.picklers += (cls -> pickler)
val treePkl = pickler.treePkl
treePkl.pickle(tree :: Nil)
- treePkl.compactify()
pickler.addrOfTree = treePkl.buf.addrOfTree
- pickler.addrOfSym = treePkl.addrOfSym
if (tree.pos.exists)
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil)
- // other pickle sections go here.
- val pickled = pickler.assembleParts()
- unit.pickled += (cls -> pickled)
-
def rawBytes = // not needed right now, but useful to print raw format.
- pickled.iterator.grouped(10).toList.zipWithIndex.map {
+ pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
case (row, i) => s"${i}0: ${row.mkString(" ")}"
}
// println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
@@ -75,7 +65,7 @@ class Pickler extends Phase {
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val result = super.runOn(units)
if (ctx.settings.YtestPickler.value)
- testUnpickler(
+ testUnpickler(units)(
ctx.fresh
.setPeriod(Period(ctx.runId + 1, FirstPhaseId))
.setReporter(new ThrowingReporter(ctx.reporter))
@@ -84,11 +74,11 @@ class Pickler extends Phase {
result
}
- private def testUnpickler(implicit ctx: Context): Unit = {
+ private def testUnpickler(units: List[CompilationUnit])(implicit ctx: Context): Unit = {
pickling.println(i"testing unpickler at run ${ctx.runId}")
ctx.initialize()
val unpicklers =
- for ((cls, pickler) <- picklers) yield {
+ for (unit <- units; (cls, pickler) <- unit.picklers) yield {
val unpickler = new DottyUnpickler(pickler.assembleParts())
unpickler.enter(roots = Set())
cls -> unpickler
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index b05de26a7b04..f803109241c2 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -32,6 +32,7 @@ import config.Printers
import java.lang.AssertionError
import dotty.tools.dotc.core.Names
+import linker.DeadCodeElimination
import scala.util.control.NonFatal
@@ -376,7 +377,9 @@ class TreeChecker extends Phase with SymTransformer {
!x.isCompanionMethod &&
!x.isValueClassConvertMethod
- val symbolsNotDefined = cls.classInfo.decls.toList.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol
+ val dce = ctx.phaseOfClass(classOf[DeadCodeElimination]).asInstanceOf[DeadCodeElimination]
+
+ val symbolsNotDefined = cls.classInfo.decls.toList.toSet.filter(x => isNonMagicalMethod(x) && !dce.wasAggressivelyDCEd(x)) -- impl.body.map(_.symbol) - constr.symbol
assert(symbolsNotDefined.isEmpty,
i" $cls tree does not define methods: ${symbolsNotDefined.toList}%, %\n" +
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/BuildCallGraph.scala b/compiler/src/dotty/tools/dotc/transform/linker/BuildCallGraph.scala
new file mode 100644
index 000000000000..a231b4f109a0
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/BuildCallGraph.scala
@@ -0,0 +1,129 @@
+package dotty.tools.dotc.transform.linker
+
+import dotty.tools.backend.jvm.CollectEntryPoints
+import dotty.tools.dotc.{CompilationUnit, FromTasty}
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.Flags._
+import dotty.tools.dotc.core.Phases.Phase
+import dotty.tools.dotc.core.StdNames.nme
+import dotty.tools.dotc.core.SymDenotations.ClassDenotation
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.tasty.DottyUnpickler
+import dotty.tools.dotc.transform.OuterSpecializer
+import dotty.tools.dotc.transform.linker.callgraph._
+
+object BuildCallGraph {
+ def withJavaCallGraph(implicit ctx: Context): Boolean =
+ ctx.settings.linkJavaConservative.value
+
+ def withOutEdges(implicit ctx: Context): Boolean =
+ ctx.settings.linkVis.value
+
+ def isPhaseRequired(implicit ctx: Context): Boolean = {
+ DeadCodeElimination.isPhaseRequired || CallGraphChecks.isPhaseRequired ||
+ OuterSpecializer.isPhaseRequired || ctx.settings.linkVis.value
+ }
+
+ def listPhase(implicit ctx: Context): List[Phase] = {
+ if (isPhaseRequired) List(new BuildCallGraph)
+ else Nil
+ }
+}
+
+class BuildCallGraph extends Phase {
+ import BuildCallGraph._
+
+ private var callGraph: CallGraph = _
+
+ def phaseName: String = "callGraph"
+
+ def getCallGraph: CallGraph = callGraph
+
+ /**
+ * @param mode see modes above
+ * @param specLimit how many specializations symbol can have max
+ * @return (reachableMethods, reachableTypes, casts, outerMethod)
+ */
+ private def buildCallGraph(mode: Int, specLimit: Int)(implicit ctx: Context): CallGraph = {
+ val startTime = java.lang.System.currentTimeMillis()
+
+ val collectedSummaries = ctx.summariesPhase.asInstanceOf[CollectSummaries].methodSummaries
+
+ val callGraphBuilder = new CallGraphBuilder(collectedSummaries, mode, specLimit, withJavaCallGraph, withOutEdges)
+
+ lazy val scalaApp = ctx.requiredClass("scala.App".toTypeName)
+ lazy val scalaUtilPropertiesTrait = ctx.requiredClass("scala.util.PropertiesTrait".toTypeName)
+ def isEntryPoint(s: Symbol): Boolean = {
+ def filteredMain = (s.owner eq scalaApp) || (s.owner eq scalaUtilPropertiesTrait)
+ ((s.name eq nme.main) /* for speed */ && s.is(Method) && CollectEntryPoints.isJavaMainMethod(s) && !filteredMain) || // Java main method
+ (s.is(Method) && s.hasAnnotation(defn.EntryPointAnnot)) // Explicit entry point
+ }
+
+ var entryPointId = 0
+ for (x <- collectedSummaries.valuesIterator) {
+ if (isEntryPoint(x.methodDef)) {
+ entryPointId += 1
+ callGraphBuilder.pushEntryPoint(x.methodDef, entryPointId)
+ x.methodDef.owner.ownersIterator.foreach { owner =>
+ if (owner.is(Module) && !owner.isEmptyPackage) {
+ val sourceModule = owner.sourceModule
+ val moduleEntryPoint =
+ if (sourceModule.owner.exists && !sourceModule.owner.isEmptyPackage) sourceModule
+ else if (owner.primaryConstructor.exists) owner.primaryConstructor // workaround for modules in the empty package
+ else NoSymbol
+ if (moduleEntryPoint.exists)
+ callGraphBuilder.pushEntryPoint(moduleEntryPoint, entryPointId)
+ }
+ }
+ }
+ }
+
+ callGraphBuilder.build()
+
+ val endTime = java.lang.System.currentTimeMillis()
+ ctx.log("++++++++++ finished in " + (endTime - startTime)/1000.0 +" seconds. ++++++++++ ")
+
+ callGraphBuilder.result()
+ }
+
+ override def run(implicit ctx: Context): Unit = ()
+
+ override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
+ if (!BuildCallGraph.isPhaseRequired) units
+ else {
+ val mode = CallGraphBuilder.AnalyseArgs
+ val specLimit = 15
+
+ ctx.log(s"\n\t\t\tType & Arg flow analysis")
+
+ val callGraph = buildCallGraph(mode, specLimit)
+ this.callGraph = callGraph
+
+ if (OuterSpecializer.isPhaseRequired) {
+ val outerSpecializer = ctx.phaseOfClass(classOf[OuterSpecializer]).asInstanceOf[OuterSpecializer]
+ outerSpecializer.specializationRequest(callGraph)
+ }
+
+ callGraph.getInfo().log()
+
+ if (ctx.settings.linkVis.value) {
+ val visFile = new java.io.File(ctx.settings.d.value + "/call-graph.html")
+ GraphVisualization.outputGraphVisToFile(callGraph, visFile)
+ ctx.log("Created call graph visualization: " + visFile.getAbsoluteFile)
+ }
+
+ def loadCompilationUnits(clsd: ClassDenotation): List[CompilationUnit] = clsd.dottyUnpickler match {
+ case Some(unpickler: DottyUnpickler) =>
+ ctx.log("Loading compilation unit for: " + clsd)
+ List(FromTasty.compilationUnit(clsd, unpickler))
+ case _ => Nil
+ }
+
+ val topLevelClasses0 = callGraph.reachableClassesSet.map(x => x.topLevelClass.denot.asClass)
+ val topLevelClasses1 = topLevelClasses0.filter(x => !x.is(JavaDefined) && (x.symbol ne defn.ObjectClass))
+ val newUnits = topLevelClasses1.flatMap(loadCompilationUnits)
+ units ::: newUnits.toList
+ }
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/CallGraphChecks.scala b/compiler/src/dotty/tools/dotc/transform/linker/CallGraphChecks.scala
new file mode 100644
index 000000000000..2d0affbd1969
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/CallGraphChecks.scala
@@ -0,0 +1,87 @@
+package dotty.tools.dotc
+package transform
+package linker
+
+import scala.language.postfixOps
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.ast.Trees
+import dotty.tools.dotc.core.Constants._
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.transform.TreeTransforms._
+import dotty.tools.dotc.transform.linker.callgraph.CallGraph
+
+object CallGraphChecks {
+ def isPhaseRequired(implicit ctx: Context): Boolean = ctx.settings.YlinkDCEChecks.value
+}
+
+class CallGraphChecks extends MiniPhaseTransform {
+ import tpd._
+
+ def phaseName: String = "dce"
+
+ private var doYChecks: Boolean = _
+ private var callGraph: CallGraph = _
+ private var assertReachableAnnotation: ClassSymbol = _
+ private var assertNotReachableAnnotation: ClassSymbol = _
+ private var callGraphBoundsAnnotation: ClassSymbol = _
+
+ override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
+ if (DeadCodeElimination.isPhaseRequired) {
+ val buildCallGraphPhase = ctx.phaseOfClass(classOf[BuildCallGraph]).asInstanceOf[BuildCallGraph]
+ callGraph = buildCallGraphPhase.getCallGraph
+ assertReachableAnnotation = ctx.requiredClassRef("scala.annotation.internal.link.AssertReachable").symbol.asClass
+ assertNotReachableAnnotation = ctx.requiredClassRef("scala.annotation.internal.link.AssertNotReachable").symbol.asClass
+ callGraphBoundsAnnotation = ctx.requiredClassRef("scala.annotation.internal.link.CallGraphBounds").symbol.asClass
+ doYChecks = true
+ } else {
+ doYChecks = false
+ }
+ this
+ }
+
+ override def transformUnit(tree: tpd.Tree)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ callGraph = null
+ assertReachableAnnotation = null
+ assertNotReachableAnnotation = null
+ callGraphBoundsAnnotation = null
+ tree
+ }
+
+ override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ if (doYChecks) {
+ val sym = tree.symbol
+ val isReachableThroughCallGraph = callGraph.isReachableMethod(sym)
+
+ if (isReachableThroughCallGraph && sym.hasAnnotation(assertNotReachableAnnotation))
+ ctx.error("@internal.link.AssertNotReachable annotation was used on a reachable member", tree.pos)
+ else if (!isReachableThroughCallGraph && sym.hasAnnotation(assertReachableAnnotation))
+ ctx.error("@internal.link.AssertReachable annotation was used on a non reachable member", tree.pos)
+
+ val info = callGraph.getInfo
+ sym.getAnnotation(callGraphBoundsAnnotation).foreach { ann =>
+ def check(indexInAnnotation: Int, name: String, actual: Int): Unit = {
+ ann.argument(indexInAnnotation) match {
+ case Some(lit @ Trees.Literal(Constant(bound: Int))) =>
+ if (bound <= 0)
+ ctx.error(s"Invalid bound $name: bound must be positive ", lit.pos)
+ else if (actual > bound)
+ ctx.error(s"Too many $name: expected at most $bound but was $actual", lit.pos)
+ // else if (actual < bound / 1.2)
+ // ctx.error(s"Bound is not tight for $name: bound is $bound and actually have $actual", lit.pos)
+ case Some(arg) => ctx.error("Argument must be a literal integer", arg.pos)
+ case _ => assert(false)
+ }
+ }
+
+ check(0, "reachable classes", info.reachableClasses.size)
+ check(1, "classes with reachable methods", info.classesWithReachableMethods.size)
+ check(2, "reachable methods", info.reachableDefs.size)
+ }
+ }
+
+ tree
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/CollectSummaries.scala b/compiler/src/dotty/tools/dotc/transform/linker/CollectSummaries.scala
new file mode 100644
index 000000000000..ba8eb1b1211b
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/CollectSummaries.scala
@@ -0,0 +1,432 @@
+package dotty.tools.dotc.transform.linker
+
+import dotty.tools.dotc.FromTasty.TASTYCompilationUnit
+import dotty.tools.dotc.ast.Trees._
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core._
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Flags._
+import dotty.tools.dotc.core.Names._
+import dotty.tools.dotc.core.StdNames.nme
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.SymDenotations.ClassDenotation
+import dotty.tools.dotc.core.tasty._
+import dotty.tools.dotc.core.tasty.DottyUnpickler
+import dotty.tools.dotc.transform.SymUtils._
+import dotty.tools.dotc.transform.TreeGen
+import dotty.tools.dotc.transform.TreeTransforms._
+import dotty.tools.dotc.transform.linker.summaries._
+import dotty.tools.dotc.transform.linker.types.{ClosureType, PreciseType}
+import dotty.tools.dotc.typer.Applications
+import dotty.tools.dotc.typer.Applications._
+
+import scala.annotation.tailrec
+import scala.collection.mutable
+
+class CollectSummaries extends MiniPhase { thisTransform =>
+ import tpd._
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "summaries"
+
+ val treeTransform: Collect = new Collect
+
+ override def run(implicit ctx: Context): Unit = {
+ if (CollectSummaries.isPhaseRequired)
+ super.run
+ }
+
+ def methodSummaries: Map[Symbol, MethodSummary] = treeTransform.getMethodSummaries
+
+ class Collect extends TreeTransform {
+ def phase: CollectSummaries = thisTransform
+
+ private var methodSummaries: Map[Symbol, MethodSummary] = Map.empty
+ private var methodSummaryStack: mutable.Stack[MethodSummaryBuilder] = mutable.Stack()
+ private var curMethodSummary: MethodSummaryBuilder = _
+
+ def getMethodSummaries: Map[Symbol, MethodSummary] = methodSummaries
+
+ override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
+ if (ctx.compilationUnit.isInstanceOf[TASTYCompilationUnit])
+ NoTransform // will retrieve them lazily
+ else this
+ }
+
+ override def prepareForDefDef(tree: tpd.DefDef)(implicit ctx: Context): TreeTransform = {
+ val sym = tree.symbol
+ if (!sym.is(Label) && !sym.isPrimaryConstructor) {
+ methodSummaryStack.push(curMethodSummary)
+ val args = tree.vparamss.flatten.map(_.symbol) // outer param for constructors
+ val argumentStoredToHeap = (0 to args.length).map(_ => true).toList
+ curMethodSummary = new MethodSummaryBuilder(sym, argumentStoredToHeap)
+ }
+ this
+ }
+
+ override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if (!tree.symbol.is(Label) && !tree.symbol.isPrimaryConstructor) {
+ assert(curMethodSummary.methodDef eq tree.symbol)
+ assert(!methodSummaries.contains(curMethodSummary.methodDef))
+ methodSummaries = methodSummaries.updated(curMethodSummary.methodDef, curMethodSummary.result())
+ curMethodSummary = methodSummaryStack.pop()
+ }
+ tree
+ }
+
+ override def prepareForValDef(tree: tpd.ValDef)(implicit ctx: Context): TreeTransform = {
+ val sym = tree.symbol
+ if (sym.exists && ((sym.is(Lazy) && (sym.owner.is(Package) || sym.owner.isClass)) || //lazy vals and modules
+ sym.owner.name.startsWith(StdNames.str.LOCALDUMMY_PREFIX) || // blocks inside constructor
+ sym.owner.isClass)) { // fields
+ // owner is a template
+ methodSummaryStack.push(curMethodSummary)
+ curMethodSummary = new MethodSummaryBuilder(sym, List(true))
+ }
+ this
+ }
+
+ override def transformValDef(tree: tpd.ValDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val sym = tree.symbol
+ if (sym.exists) {
+ val ownerIsClass = sym.owner.isClass
+ val isLazyValOrModule = sym.is(Lazy) && (ownerIsClass || sym.owner.is(Package))
+ val isBockInsideConstructor = sym.owner.name.startsWith(StdNames.str.LOCALDUMMY_PREFIX)
+ if (isLazyValOrModule || isBockInsideConstructor || ownerIsClass) {
+ assert(curMethodSummary.methodDef eq tree.symbol)
+ assert(!methodSummaries.contains(curMethodSummary.methodDef))
+ methodSummaries = methodSummaries.updated(curMethodSummary.methodDef, curMethodSummary.result())
+ curMethodSummary = methodSummaryStack.pop()
+ }
+ if (!isLazyValOrModule && (isBockInsideConstructor || ownerIsClass))
+ registerCall(tree)
+ }
+ tree
+ }
+
+ override def prepareForTemplate(tree: tpd.Template)(implicit ctx: Context): TreeTransform = {
+ val sym = tree.symbol
+ assert(!sym.is(Label))
+ methodSummaryStack.push(curMethodSummary)
+ curMethodSummary = new MethodSummaryBuilder(sym.owner.primaryConstructor, List(true))
+ this
+ }
+
+ override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val sym = tree.symbol
+ assert(!sym.is(Label))
+ assert(curMethodSummary.methodDef eq tree.symbol.owner.primaryConstructor)
+ assert(!methodSummaries.contains(curMethodSummary.methodDef))
+ methodSummaries = methodSummaries.updated(curMethodSummary.methodDef, curMethodSummary.result())
+ curMethodSummary = methodSummaryStack.pop()
+ tree
+ }
+
+ /*
+ override def transformTypeDef(tree: tpd.TypeDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val sym = tree.symbol
+ if (sym.isClass) {
+ val isEntryPoint = dotty.tools.backend.jvm.CollectEntryPoints.isJavaEntryPoint(sym)
+ /*summaries = ClassSummary(sym.asClass,
+ methodSummaries
+ ) :: summaries
+ methodSummaries = Nil*/
+ }
+ tree
+ }
+ */
+
+ def registerModule(sym: Symbol)(implicit ctx: Context): Unit = {
+ if ((curMethodSummary ne null) && sym.is(ModuleVal)) {
+ curMethodSummary.addAccessedModules(sym)
+ registerModule(sym.owner)
+ }
+ val res = sym.info.finalResultType.termSymbol
+ if ((curMethodSummary ne null) && res.is(ModuleVal)) {
+ curMethodSummary.addAccessedModules(res)
+ registerModule(res.owner)
+ }
+
+ }
+
+ def registerCall(tree: Tree)(implicit ctx: Context): Unit = {
+
+ def symbolOf(t: Tree) = {
+ val s = t.symbol.orElse(t.tpe.classSymbol).orElse(TypeErasure.erasure(t.tpe).classSymbol)
+ assert(s.exists)
+ s
+ }
+
+ @tailrec def receiverArgumentsAndSymbol(t: Tree, accArgs: List[List[Tree]] = Nil, accT: List[Tree] = Nil):
+ (Tree, Tree, List[List[Tree]], List[Tree], TermRef) = t match {
+ case Block(stats, expr) => receiverArgumentsAndSymbol(expr, accArgs, accT)
+ case TypeApply(fun, targs) if fun.symbol eq t.symbol => receiverArgumentsAndSymbol(fun, accArgs, targs)
+ case Apply(fn, args) if fn.symbol == t.symbol => receiverArgumentsAndSymbol(fn, args :: accArgs, accT)
+ case Select(qual, _) =>
+ (qual, t, accArgs, accT, t.tpe.asInstanceOf[TermRef])
+ case x: This => (x, x, accArgs, accT, x.tpe.asInstanceOf[TermRef])
+ case x => (x, x, accArgs, accT, x.tpe.asInstanceOf[TermRef])
+ }
+ val widenedTp = tree.tpe.widen
+ if (!widenedTp.isInstanceOf[MethodicType] || (tree.symbol.exists && !tree.symbol.info.isInstanceOf[MethodicType])) {
+ val (receiver, _ /*call*/ , arguments, typeArguments, method) = receiverArgumentsAndSymbol(tree)
+
+ val storedReceiver = receiver.tpe
+
+ assert(storedReceiver.exists)
+
+ def wrapArrayTermRef(wrapArrayMethodName: TermName) =
+ TermRef(defn.ScalaPredefModuleRef, defn.ScalaPredefModule.requiredMethod(wrapArrayMethodName))
+
+ @tailrec def skipBlocks(s: Tree): Tree = s match {
+ case s: Block => skipBlocks(s.expr)
+ case _ => s
+ }
+
+ @tailrec def argType(x: Tree): Type = skipBlocks(x) match {
+ case exp: Closure =>
+ val SAMType(e) = exp.tpe
+ new ClosureType(exp, x.tpe, e.symbol)
+ case Select(New(tp), _) => new PreciseType(tp.tpe)
+ case Apply(Select(New(tp), _), args) => new PreciseType(tp.tpe)
+ case Apply(TypeApply(Select(New(tp), _), targs), args) => new PreciseType(tp.tpe)
+ case Typed(expr: SeqLiteral, tpt) if x.tpe.isRepeatedParam =>
+ val tp = expr.elemtpt.tpe
+ wrapArrayTermRef(TreeGen.wrapArrayMethodName(tp)).widenDealias match {
+ case warr: PolyType => warr.appliedTo(tp).finalResultType
+ case warr => warr.finalResultType
+ }
+ case Typed(expr, _) => argType(expr)
+ case NamedArg(nm, a) => argType(a)
+ case _ => x.tpe
+ }
+
+ val thisCallInfo = CallInfo(method, typeArguments.map(_.tpe), arguments.flatten.map(argType))
+ lazy val someThisCallInfo = Some(thisCallInfo)
+
+ // Create calls to wrapXArray for varArgs
+ val repeatedArgsCalls = tree match {
+ case Apply(fun, _) if fun.symbol.info.isVarArgsMethod =>
+ @tailrec def refine(tp: Type): Type = tp match {
+ case tp: TypeAlias => refine(tp.alias.dealias)
+ case tp: RefinedType if tp.parent == defn.RepeatedParamType => refine(tp.refinedInfo)
+ case tp: TypeBounds => refine(tp.hi)
+ case _ => tp
+ }
+ @tailrec def getVarArgTypes(tp: Type, acc: List[Type] = Nil): List[Type] = tp match {
+ case tp: PolyType => getVarArgTypes(tp.resultType, acc)
+ case tp: MethodType =>
+ val paramInfos = tp.paramInfos
+ lazy val lastParamType = paramInfos.last
+ if (paramInfos.isEmpty || !lastParamType.isRepeatedParam) acc
+ else getVarArgTypes(tp.resultType, refine(lastParamType) :: acc)
+ case _ => acc
+ }
+
+ getVarArgTypes(fun.tpe.widenDealias).map { tp =>
+ val wrapArrayName = TreeGen.wrapArrayMethodName(tp)
+ val targs = if (wrapArrayName == nme.wrapRefArray || wrapArrayName == nme.genericWrapArray) List(tp) else Nil
+ val args = List(defn.ArrayOf(tp))
+ CallInfo(wrapArrayTermRef(wrapArrayName), targs, args, someThisCallInfo)
+ }
+
+ case _ => Nil
+ }
+
+ val isInPredef =
+ ctx.owner.ownersIterator.exists(owner => owner == defn.ScalaPredefModule || owner.companionModule == defn.ScalaPredefModule)
+
+ val isMethodOnPredef = {
+ val funTpe = tree match {
+ case Apply(TypeApply(fun: Ident, _), _) => fun.tpe
+ case Apply(fun: Ident, _) => fun.tpe
+ case _ => tree.tpe
+ }
+ funTpe.normalizedPrefix == defn.ScalaPredefModuleRef
+ }
+
+ val loadPredefModule = if (!isInPredef && (repeatedArgsCalls.nonEmpty || isMethodOnPredef)) {
+ List(CallInfo(defn.ScalaPredefModuleRef, Nil, Nil, someThisCallInfo))
+ } else {
+ Nil
+ }
+
+ val sym = tree.symbol
+ val mixinConstructors: List[CallInfo] = {
+ if (!sym.isPrimaryConstructor) {
+ Nil
+ } else {
+ val directMixins = sym.owner.mixins.diff(sym.owner.info.parents.head.symbol.mixins)
+ directMixins.collect {
+ case mixin if !mixin.is(NoInits) =>
+ val decl = mixin.primaryConstructor
+ val (tparams, params) = decl.info match {
+ case tp: PolyType => (mixin.info.typeParams.map(_.paramRef), tp.resType.paramInfoss.flatten)
+ case tp => (Nil, tp.paramInfoss.flatten)
+ }
+ CallInfo(decl.termRef, tparams, params, someThisCallInfo)
+ }
+ }
+ }
+
+ val languageDefinedCalls = loadPredefModule ::: mixinConstructors ::: repeatedArgsCalls
+
+ curMethodSummary.addMethodsCalledBy(storedReceiver, thisCallInfo :: languageDefinedCalls)
+ }
+ }
+
+ override def transformIdent(tree: tpd.Ident)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if (!tree.symbol.is(Package)) {
+ registerModule(tree.symbol)
+ }
+ val select = tree.tpe match {
+ case TermRef(prefix: TermRef, name) =>
+ Some(tpd.ref(prefix).select(tree.symbol))
+ case TermRef(prefix: ThisType, name) =>
+ Some(tpd.This(prefix.cls).select(tree.symbol))
+ case TermRef(NoPrefix, name) =>
+ if (tree.symbol is Method | Lazy) { // todo: this kills dotty {
+ val widenedTp = tree.tpe.widen
+ if (widenedTp.isInstanceOf[MethodicType] && (!tree.symbol.exists || tree.symbol.info.isInstanceOf[MethodicType]))
+ return tree
+ registerCall(tree)
+ return tree
+ // Some(This(tree.symbol.topLevelClass.asClass).select(tree.symbol)) // workaround #342 todo: remove after fixed
+ }
+ else None
+ case _ => None
+ }
+
+ select.map(transformSelect)
+
+ tree
+ }
+
+ override def transformSelect(tree: tpd.Select)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ val sym = tree.symbol
+ if (!sym.is(Package | Label) && !sym.isClass && !sym.isType) {
+ registerModule(sym)
+ registerCall(tree)
+ }
+ // handle nullary methods
+ tree
+ }
+
+ override def transformThis(tree: tpd.This)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ curMethodSummary.setThisAccessed(true)
+ tree
+ }
+
+ override def transformApply(tree: tpd.Apply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if (!tree.symbol.is(Label))
+ registerCall(tree)
+ tree
+ }
+
+ override def transformTypeApply(tree: tpd.TypeApply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ registerCall(tree)
+ tree
+ }
+
+ def registerUnApply(selector: tpd.Tree, tree: tpd.UnApply)(implicit ctx: Context, info: TransformerInfo): Unit = {
+ def registerNestedUnapply(nestedSelector: Tree, nestedPattern: Tree): Unit = nestedPattern match {
+ case nestedUnapply: UnApply => registerUnApply(nestedSelector, nestedUnapply)
+ case _ =>
+ }
+
+ def registerNestedUnapplyFromProduct(product: Tree, patterns: List[Tree]): Unit =
+ for ((nestedPat, idx) <- patterns.zipWithIndex) {
+ val nestedSel = product.select(nme.selectorName(idx))
+ registerCall(nestedSel) // register call to Product._x
+ registerNestedUnapply(nestedSel, nestedPat)
+ }
+
+ def registerNestedUnapplyFromSeq(seq: Tree, patterns: List[Tree]): Unit = {
+ registerCall(seq.select(nme.lengthCompare).appliedTo(Literal(Constant(patterns.size))))
+
+ if (patterns.size >= 1) {
+ val headSel = seq.select(nme.head)
+ val tailSels = for (i <- 1 until patterns.size) yield seq.select(nme.apply).appliedTo(Literal(Constant(i)))
+ val nestedSels = Seq(headSel) ++ tailSels
+
+ for ((nestedSel, nestedPat) <- nestedSels zip patterns) {
+ registerCall(nestedSel)
+ registerNestedUnapply(nestedSel, nestedPat)
+ }
+ }
+ }
+
+ val unapplyCall = Apply(tree.fun, List(selector))
+ registerCall(unapplyCall)
+
+ val unapplyResultType = unapplyCall.tpe
+ val hasIsDefined = extractorMemberType(unapplyResultType, nme.isEmpty) isRef defn.BooleanClass
+ val hasGet = extractorMemberType(unapplyResultType, nme.get).exists
+
+ if (hasIsDefined && hasGet) { // if result of unapply is an Option
+ val getCall = unapplyCall.select(nme.get)
+
+ // register Option.isDefined and Option.get calls
+ registerCall(unapplyCall.select(nme.isEmpty))
+ registerCall(getCall)
+
+ if (tree.fun.symbol.name == nme.unapplySeq) // result of unapplySeq is Option[Seq[T]]
+ registerNestedUnapplyFromSeq(getCall, tree.patterns)
+ else if (tree.patterns.size == 1) // result of unapply is Option[T]
+ registerNestedUnapply(getCall, tree.patterns.head)
+ else // result of unapply is Option[(T1, ..., Tn)]
+ registerNestedUnapplyFromProduct(getCall, tree.patterns)
+
+ } else if (defn.isProductSubType(unapplyResultType)) {
+ // if result of unapply is a Product
+ registerNestedUnapplyFromProduct(unapplyCall, tree.patterns)
+ }
+ }
+
+ def collectMatch(selector: tpd.Tree, cases: List[tpd.CaseDef])(implicit ctx: Context, info: TransformerInfo): Unit = {
+ cases foreach { case CaseDef(pat, _, _) => pat match {
+ case unapply: tpd.UnApply => registerUnApply(selector, unapply)
+ case _ =>
+ }}
+ }
+
+ override def transformMatch(tree: tpd.Match)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ collectMatch(tree.selector, tree.cases)
+
+ tree
+ }
+
+ override def transformTry(tree: tpd.Try)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ // generate synthetic selector of Throwable type (from TryCatchPatterns.scala)
+ val exName = NameKinds.DefaultExceptionName.fresh()
+ val fallbackSelector = ctx.newSymbol(ctx.owner, exName, Flags.Synthetic | Flags.Case, defn.ThrowableType)
+ val sel = Ident(fallbackSelector.termRef)
+
+ collectMatch(sel, tree.cases)
+
+ tree
+ }
+
+
+ override def transformClosure(tree: tpd.Closure)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ if (curMethodSummary ne null) {
+ curMethodSummary.addDefinedClosure(new ClosureType(tree, tree.tpe, tree.meth.symbol))
+ }
+ tree
+ }
+
+ override def transformUnit(tree: tpd.Tree)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ TastySummaries.saveInTasty(methodSummaries.values.toList)
+ tree
+ }
+ }
+}
+
+object CollectSummaries {
+
+ def isPhaseRequired(implicit ctx: Context): Boolean = BuildCallGraph.isPhaseRequired
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/DeadCodeElimination.scala b/compiler/src/dotty/tools/dotc/transform/linker/DeadCodeElimination.scala
new file mode 100644
index 000000000000..ae2e7f2aebae
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/DeadCodeElimination.scala
@@ -0,0 +1,93 @@
+package dotty.tools.dotc
+package transform
+package linker
+
+import scala.language.postfixOps
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.Flags._
+import dotty.tools.dotc.core.Phases.Phase
+import dotty.tools.dotc.core.StdNames._
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.transform.SymUtils._
+import dotty.tools.dotc.transform.TreeTransforms._
+import dotty.tools.dotc.transform.linker.callgraph.CallGraph
+
+object DeadCodeElimination {
+ def isPhaseRequired(implicit ctx: Context): Boolean =
+ ctx.settings.linkDCE.value || ctx.settings.linkDCEAggressive.value
+}
+
+class DeadCodeElimination extends MiniPhaseTransform {
+ import tpd._
+
+ def phaseName: String = "dce"
+
+ override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[CallGraphChecks])
+
+ private var doTransform: Boolean = _
+ private var callGraph: CallGraph = _
+ private var buildCallGraphPhase: BuildCallGraph = _
+ private var exception: Tree = _
+ private var doNotDCEAnnotation: ClassSymbol = _
+ private var aggressive: Boolean = _
+
+ // TODO: Should this set be removed after Ycheck?
+ private var aggressivelyDCEd: Set[Symbol] = _
+
+ override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
+ if (DeadCodeElimination.isPhaseRequired) {
+ buildCallGraphPhase = ctx.phaseOfClass(classOf[BuildCallGraph]).asInstanceOf[BuildCallGraph]
+ callGraph = buildCallGraphPhase.getCallGraph
+ exception = Throw(New(ctx.requiredClassRef("dotty.runtime.DeadCodeEliminated"), Nil))
+ doNotDCEAnnotation = ctx.requiredClassRef("scala.annotation.internal.link.DoNotDeadCodeEliminate").symbol.asClass
+ aggressive = ctx.settings.linkDCEAggressive.value
+ doTransform = true
+ } else {
+ doTransform = false
+ }
+ this
+ }
+
+ override def transformUnit(tree: tpd.Tree)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ buildCallGraphPhase = null
+ callGraph = null
+ exception = null
+ doNotDCEAnnotation = null
+ doTransform = false
+ tree
+ }
+
+ override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val sym = tree.symbol
+ if (!doTransform || doNotEliminate(sym)) tree
+ else if (aggressive && !doNotEliminateAggressive(sym)) {
+ if (aggressivelyDCEd eq null)
+ aggressivelyDCEd = Set.empty
+ aggressivelyDCEd += sym
+ EmptyTree
+ } else tpd.cpy.DefDef(tree)(rhs = exception)
+ }
+
+ def wasAggressivelyDCEd(x: Symbol): Boolean = {
+ aggressivelyDCEd != null && aggressivelyDCEd.contains(x)
+ }
+
+ private def doNotEliminate(sym: Symbol)(implicit ctx: Context): Boolean = {
+ callGraph.isReachableMethod(sym) || sym.is(Label) || sym.isConstructor || keepAsNew(sym) ||
+ (sym.isSetter && callGraph.isReachableMethod(sym.getter)) || sym.hasAnnotation(doNotDCEAnnotation)
+ }
+
+ private def doNotEliminateAggressive(sym: Symbol)(implicit ctx: Context): Boolean = {
+ sym.owner.fullName.startsWith("scala.Predef") ||
+ defn.ArrayMethods.contains(sym) ||
+ defn.DottyArraysMethods.contains(sym) ||
+ (sym.is(Deferred) && sym.owner.is(Abstract)) ||
+ sym.owner.is(Lazy | Method) ||
+ sym.is(Implicit) || sym.is(Synthetic) || sym.owner.is(Trait)
+ }
+
+ private def keepAsNew(sym: Symbol)(implicit ctx: Context): Boolean =
+ sym.initial.validFor.firstPhaseId > buildCallGraphPhase.period.phaseId
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraph.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraph.scala
new file mode 100644
index 000000000000..6cb5dce9f290
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraph.scala
@@ -0,0 +1,84 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Types._
+
+import scala.collection.mutable
+
+class CallGraph(val entryPoints: Map[CallInfoWithContext, Int], val reachableMethods: Set[CallInfoWithContext],
+ val reachableTypes: Set[TypeWithContext], val casts: Set[Cast], val classOfs: Set[Symbol],
+ val outerMethods: Set[Symbol], val mode: Int, val specLimit: Int)(implicit ctx: Context) { self =>
+
+ private val reachableMethodSet: Set[Symbol] =
+ reachableMethods.map(_.callSymbol)
+
+ lazy val reachableClassesSet: Set[Symbol] = {
+ val reachableClasses = mutable.Set.empty[Symbol]
+ def collectClasses(cls: ClassSymbol): Unit = {
+ reachableClasses.add(cls)
+ cls.classParents.foreach(x => collectClasses(x.symbol.asClass))
+ }
+ reachableTypes.foreach(x => x.tp.classSymbols.foreach(collectClasses))
+ reachableClasses.toSet
+ }
+
+ def isReachableMethod(sym: Symbol): Boolean = reachableMethodSet.contains(sym)
+
+ def isReachableClass(sym: Symbol): Boolean = reachableClassesSet.contains(sym)
+
+ def isReachableClassOf(sym: Symbol): Boolean = classOfs.contains(sym)
+
+ def getInfo(): Info = new Info
+
+ class Info {
+
+ lazy val classesWithReachableMethods = reachableMethodSet.map(_.maybeOwner.info.widen.classSymbol)
+
+ lazy val reachableClasses = classesWithReachableMethods ++ reachableClassesSet
+
+ lazy val reachableDefs = reachableMethods.map(_.callSymbol)
+
+ lazy val reachableSpecs: Set[(Symbol, List[Type])] = reachableMethods.flatMap { x =>
+ val clas = x.callSymbol.maybeOwner.info.widen.classSymbol
+ val meth = x.callSymbol
+ if (mode >= CallGraphBuilder.AnalyseTypes) (meth, x.call.normalizedPrefix.baseArgInfos(clas)) :: Nil
+ else {
+ val clazSpecializationsCount =
+ if (clas.primaryConstructor.info.widenDealias.isInstanceOf[PolyType]) specLimit
+ else 1
+ val methodSpecializationsCount =
+ if (meth.info.widenDealias.isInstanceOf[PolyType]) specLimit
+ else 1
+ ctx.log(s"specializing $clas $meth for $clazSpecializationsCount * $methodSpecializationsCount")
+ (0 until clazSpecializationsCount*methodSpecializationsCount).map(x => (meth, ConstantType(Constant(x)):: Nil)).toList
+ }
+ }
+
+ private lazy val morphisms = reachableMethods.groupBy(x => x.callee).groupBy(x => x._2.map(_.callSymbol).toSet.size)
+
+ lazy val monomorphicCalls = if (morphisms.contains(1)) morphisms(1) else Map.empty
+
+ lazy val bimorphicCalls = if (morphisms.contains(2)) morphisms(2) else Map.empty
+
+ lazy val megamorphicCalls = morphisms - 1 - 2
+
+ def log()(implicit ctx: Context): Unit = {
+ ctx.log(
+ s"""
+ |Call graph info:
+ | Found: ${classesWithReachableMethods.size} classes with reachable methods, ${reachableClasses.size} reachable classes, ${reachableDefs.size} reachable methods, ${reachableSpecs.size} specializations
+ | mono: ${monomorphicCalls.size}, bi: ${bimorphicCalls.size}, mega: ${megamorphicCalls.map(_._2.size).sum}
+ | Found ${outerMethods.size} not defined calls: ${outerMethods.map(_.showFullName)}
+ | Reachable classes: ${reachableClasses.map(_.showFullName).mkString(", ")}
+ | Reachable methods: ${reachableDefs.map(_.showFullName).mkString(", ")}
+ | Classes with reachable methods: ${classesWithReachableMethods.map(_.showFullName).mkString(", ")}
+ | Reachable specs: ${reachableSpecs.toList.filter(_._2.nonEmpty).sortBy(-_._2.size).map(x => (x._1.showFullName, x._2.map(_.show))).mkString(", ")}
+ | Primary Constructor specs: ${reachableSpecs.filter(x => x._1.isPrimaryConstructor && x._2.nonEmpty).map(x => (x._1.showFullName, x._2))}
+ """.stripMargin
+ )
+ }
+
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraphBuilder.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraphBuilder.scala
new file mode 100644
index 000000000000..80fdfbae31c3
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallGraphBuilder.scala
@@ -0,0 +1,723 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Flags._
+import dotty.tools.dotc.core.Names._
+import dotty.tools.dotc.core.NameKinds._
+import dotty.tools.dotc.core.NameOps._
+import dotty.tools.dotc.core.StdNames._
+import dotty.tools.dotc.core.Symbols.{Symbol, _}
+import dotty.tools.dotc.core.TypeErasure
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.ResolveSuper
+import dotty.tools.dotc.transform.linker.summaries._
+import dotty.tools.dotc.transform.linker.types._
+
+import scala.annotation.tailrec
+import scala.collection.{immutable, mutable}
+
+object CallGraphBuilder {
+ final val AnalyseOrig = 1
+ final val AnalyseTypes = 2
+ final val AnalyseArgs = 3
+}
+
+class CallGraphBuilder(collectedSummaries: Map[Symbol, MethodSummary], mode: Int, specLimit: Int,
+ withJavaCallGraph: Boolean, withOutEdges: Boolean)(implicit ctx: Context) {
+ import OuterTargs.parentRefinements
+ import CallGraphBuilder._
+ import tpd._
+
+ private val tastySummaries = new TastySummaries
+
+ private var iteration = 0
+
+ private var entryPoints = immutable.Map.empty[CallInfoWithContext, Int]
+ private var reachableTypes = immutable.Set.empty[TypeWithContext]
+ private var reachableMethods = mutable.Set.empty[CallInfoWithContext]
+
+ private val reachableMethodsSymbols = new java.util.IdentityHashMap[Symbol, Unit]
+ private val outerMethods = new java.util.IdentityHashMap[Symbol, Unit]
+
+ private val classOfs = new java.util.IdentityHashMap[Symbol, Unit]
+
+ private val typesByMemberNameCache = new java.util.IdentityHashMap[Name, List[(Int, TypeWithContext)]]()
+
+ private var casts = immutable.Set.empty[Cast]
+ private val castsCache: mutable.HashMap[TypeWithContext, mutable.Set[Cast]] = mutable.HashMap.empty
+ private val castCache1 = new java.util.IdentityHashMap[ClassSymbol, Set[Cast]]
+
+ private val sizesCache = new java.util.IdentityHashMap[Symbol, Int]()
+ private val lastInstantiation = mutable.Map.empty[CallInfoWithContext, mutable.Map[CallInfo, Int]]
+
+ private var finished = false // TODO: once the crc is complete, remove finished and use addingOutEdges instead.
+ private var addingOutEdges = false
+
+ private val normalizeType: Type => Type = new TypeNormalizer
+
+ def pushEntryPoint(s: Symbol, entryPointId: Int): Unit = {
+ val tpe = ref(s).tpe.asInstanceOf[TermRef]
+ val targsSize = tpe.widen match {
+ case t: PolyType => t.paramNames.size
+ case _ => 0
+ }
+ val targs = (0 until targsSize).map(x => new ErazedType()).toList
+ val args = tpe.widenDealias.paramInfoss.flatten
+ val call = CallInfoWithContext(tpe, targs, args, OuterTargs.empty, None, None)
+ entryPoints = entryPoints.updated(call, entryPointId)
+ addReachableMethod(call)
+ val t = normalizeType(ref(s.owner).tpe)
+ val self = new TypeWithContext(t, parentRefinements(t))
+ addReachableType(self)
+ }
+
+ /** Builds the call graph based on the current reachable items, mainly entry points. */
+ def build(): Unit = {
+ ctx.log(s"Building call graph with ${entryPoints.values.toSet.size} entry points")
+ val startTime = System.currentTimeMillis()
+ @tailrec def buildLoop(): Unit = {
+ val loopStartTime = System.currentTimeMillis()
+
+ val reachableMethodsLastSize = reachableMethods.size
+ val reachableTypesLastSize = reachableTypes.size
+ val castsLastSize = casts.size
+ val classOfsLastSize = classOfs.size
+
+ processCallSites()
+
+ val numNewReachableMethods = reachableMethods.size - reachableMethodsLastSize
+ val numNewReachableTypes = reachableTypes.size - reachableTypesLastSize
+ val numNewCasts = casts.size - castsLastSize
+ val numNewClassOfs = classOfs.size - classOfsLastSize
+
+ iteration += 1
+ val loopEndTime = System.currentTimeMillis()
+ val loopTime = loopEndTime - loopStartTime
+ val totalTime = loopEndTime - startTime
+ val msgInfo = {
+ if (addingOutEdges) ""
+ else
+ s"""
+ |Found $numNewReachableTypes new instantiated types (${reachableTypes.size})
+ |Found $numNewReachableMethods new call sites (${reachableMethods.size})
+ |Found $numNewCasts new casts (${casts.size})
+ |Found $numNewClassOfs new classOfs (${classOfs.size})
+ """.stripMargin
+ }
+ ctx.log(
+ s"""Graph building iteration $iteration
+ |Iteration in ${loopTime/1000.0} seconds out of ${totalTime/1000.0} seconds (${loopTime.toDouble/totalTime})
+ |$msgInfo""".stripMargin)
+
+ // val outFile = new java.io.File(ctx.settings.d.value + s"/CallGraph-${reachableMethods.items.size}.html")
+ // GraphVisualization.outputGraphVisToFile(this.result(), outFile)
+
+ if (numNewReachableMethods != 0 || numNewReachableTypes != 0 || numNewCasts != 0)
+ buildLoop()
+ else if (!finished) {
+ // This last loop is only here to check the correctness on the crc map
+ // TODO: remove in production mode
+ ctx.log("[processing all call sites for crc check]")
+ finished = true
+ buildLoop()
+ } else if (withOutEdges && !addingOutEdges) {
+ ctx.log("[processing all call sites for to add out edges]")
+ addingOutEdges = true
+ buildLoop()
+ }
+ }
+
+ buildLoop()
+ }
+
+ /** Packages the current call graph into a CallGraph */
+ def result(): CallGraph = {
+ import scala.collection.JavaConversions._
+ val entryPoints = this.entryPoints
+ val reachableMethods = this.reachableMethods.toSet
+ val reachableTypes = this.reachableTypes
+ val casts = this.casts
+ val classOfs = this.classOfs.keySet().toSet
+ val outerMethods = this.outerMethods.keySet().toSet
+ new CallGraph(entryPoints, reachableMethods, reachableTypes, casts, classOfs, outerMethods, mode, specLimit)
+ }
+
+ private def registerTypeForSize(tp: Type): Unit = {
+ val classSymbols = mutable.Set.empty[Symbol]
+ def collectClasses(cls: ClassSymbol): Unit = {
+ classSymbols.add(cls)
+ cls.classParents.foreach(x => collectClasses(x.symbol.asClass))
+ }
+ tp.classSymbols.foreach(collectClasses)
+ classSymbols.foreach(sym => sizesCache.put(sym, sizesCache.getOrDefault(sym, 0) + 1))
+ }
+
+ private def addReachableType(x: TypeWithContext): Unit = {
+ if (!reachableTypes.contains(x)) {
+ assert(!finished)
+
+ registerTypeForSize(new SubstituteByParentMap(x.outerTargs).apply(x.tp))
+
+ reachableTypes += x
+
+ lazy val deepness = TypeDepth(x.tp)
+ val namesInType = x.tp.memberNames(takeAllFilter).filter(typesByMemberNameCache.containsKey)
+ for (name <- namesInType) {
+ typesByMemberNameCache.put(name, (deepness, x) :: typesByMemberNameCache.get(name))
+ }
+
+ val clas = x.tp match {
+ case t: ClosureType => t.u.classSymbol.asClass
+ case t: JavaAllocatedType => t.underlying.widenDealias.classSymbol.asClass
+ case _ => x.tp.classSymbol.asClass
+ }
+ if (!clas.is(JavaDefined) && clas.is(Module)) {
+ val fields = clas.classInfo.decls.filter(x => !x.is(Method) && !x.isType)
+ val parent = Some(CallInfoWithContext(x.tp.select(clas.primaryConstructor).asInstanceOf[TermRef], x.tp.baseArgInfos(clas), Nil, x.outerTargs, None, None))
+ fields.foreach { fieldSym =>
+ addReachableMethod(CallInfoWithContext(x.tp.select(fieldSym).asInstanceOf[TermRef], Nil, Nil, x.outerTargs, parent, None))
+ }
+ }
+ }
+ }
+
+ private def addReachableMethod(method: CallInfoWithContext): Unit = {
+ if (!reachableMethods.contains(method)) {
+ finished = false // TODO: replace with assert(!finished)
+ reachableMethods += method
+ val callSymbol = method.callSymbol
+ if (!reachableMethodsSymbols.containsKey(callSymbol)) {
+ reachableMethodsSymbols.put(callSymbol, ())
+ collectedSummaries.get(callSymbol).foreach { summary =>
+ summary.accessedModules.foreach(x => addReachableType(new TypeWithContext(normalizeType(x.info), parentRefinements(x.info))))
+ }
+ }
+ }
+ }
+
+ private def addReachableClosure(x: ClosureType, from: CallInfoWithContext): Unit = {
+ val substitution = new SubstituteByParentMap(from.outerTargs)
+ val tp = substitution(x)
+ addReachableType(new TypeWithContext(tp, parentRefinements(tp)))
+ }
+
+ private def getTypesByMemberName(x: Name): List[(Int, TypeWithContext)] = {
+ val ret1 = typesByMemberNameCache.get(x)
+ if (ret1 eq null) {
+ // not yet computed
+ val upd = reachableTypes.iterator.collect { case tp if tp.tp.member(x).exists => (TypeDepth(tp.tp), tp) }.toList
+ typesByMemberNameCache.put(x, upd)
+ upd
+ } else ret1
+ }
+
+ private def addCast(from: Type, to: Type) = {
+ if (!(from <:< to) && to.classSymbols.forall(!_.derivesFrom(defn.NothingClass))) {
+ val newCast = new Cast(from, to)
+ var addedCast = false
+ val classSymbols = from.classSymbols.toSet ++ to.classSymbols
+ for (tp <- reachableTypes) {
+ if (classSymbols.forall(x => tp.tp.classSymbols.exists(y => y.derivesFrom(x)))) {
+ val cached = castsCache.getOrElseUpdate(tp, mutable.Set.empty)
+ if (!cached.contains(newCast)) {
+ if (!addedCast) {
+ casts += newCast
+
+ def collectClasses(cls: ClassSymbol): Unit = {
+ castCache1.put(cls, castCache1.getOrDefault(cls, Set.empty) + newCast)
+ cls.classParents.foreach(x => collectClasses(x.symbol.asClass))
+ }
+ to.classSymbols.foreach(collectClasses)
+
+ addedCast = true
+ }
+ finished = false // TODO: replace with assert(!finished)
+ cached += newCast
+ }
+ }
+ }
+ }
+ }
+
+ private val registeredParentModules = mutable.Set.empty[Type]
+ private def registerParentModules(tp: Type): Unit = {
+ if ((tp ne NoType) && (tp ne NoPrefix) && !registeredParentModules.contains(tp)) {
+ if (tp.widen ne tp) registerParentModules(tp.widen)
+ if (tp.dealias ne tp) registerParentModules(tp.dealias)
+ if (tp.termSymbol.is(Module)) {
+ addReachableType(new TypeWithContext(tp.widenDealias, parentRefinements(tp.widenDealias)))
+ } else if (tp.typeSymbol.is(Module, butNot = Package)) {
+ val t = normalizeType(ref(tp.typeSymbol).tpe)
+ addReachableType(new TypeWithContext(t, parentRefinements(t)))
+ }
+ registeredParentModules += tp
+ registerParentModules(tp.normalizedPrefix): @tailrec
+ }
+ }
+
+ private def instantiateCallSite(caller: CallInfoWithContext, callee: CallInfo, registerCall: CallInfoWithContext => Boolean): Unit = {
+
+ def addCall(call: CallInfoWithContext) = {
+ if (registerCall(call)) {
+ if (addingOutEdges) caller.addOutEdges(callee, call)
+ else addReachableMethod(call)
+ }
+ }
+
+ lazy val someCaller = Some(caller)
+ lazy val someCallee = Some(callee)
+
+ val receiver = callee.call.normalizedPrefix
+
+ registerParentModules(receiver)
+
+ lazy val receiverDepth = TypeDepth(receiver)
+
+ val calleeSymbol = callee.call.termSymbol.asTerm
+ val callerSymbol = caller.call.termSymbol
+
+ val tpamsOuter = caller.call.widen match {
+ case t: PolyType =>
+ OuterTargs.empty.addAll(callerSymbol, t.paramNames, caller.targs)
+ case _ =>
+ OuterTargs.empty
+ }
+
+ lazy val outerParent = if (callerSymbol.owner ne caller.call.normalizedPrefix.classSymbol) {
+ val current = caller.call.normalizedPrefix
+ val superTpe = callerSymbol.owner.info
+ @tailrec def collectTypeMembers(classes: List[ClassSymbol], acc: Map[Name, Symbol]): Iterable[Symbol] = classes match {
+ case x :: xs =>
+ val typeDecls = x.unforcedDecls.filter(_.isType)
+ val acc2 = typeDecls.foldLeft(acc)((acc1, sym) => if (acc1.contains(sym.name)) acc1 else acc1.updated(sym.name, sym))
+ collectTypeMembers(xs, acc2)
+ case Nil => acc.values
+ }
+ val typeMembers = collectTypeMembers(current.baseClasses, Map.empty)
+ val outers = typeMembers.foldLeft(OuterTargs.empty) { (outerTargs: OuterTargs, x) =>
+ val old = superTpe.member(x.symbol.name)
+ if (old.exists) outerTargs.add(callerSymbol.owner, x.symbol.name, current.select(x).widen) else outerTargs
+ }
+ outers
+ } else OuterTargs.empty
+
+ lazy val outerPropagatedTargs = caller.outerTargs ++ tpamsOuter ++ outerParent
+ lazy val substitution = new SubstituteByParentMap(outerPropagatedTargs)
+
+ def propagateArgs(tp: Type): Type = {
+ tp match {
+ case x: TermRef if mode >= AnalyseArgs && x.symbol.is(Param) && x.symbol.owner == caller.call.termSymbol =>
+ val id = caller.call.termSymbol.info.paramNamess.iterator.flatten.indexWhere(_ == x.symbol.name)
+ caller.argumentsPassed(id)
+ case t => t
+ }
+ }
+
+ def propagateTargs(tp0: Type, isConstructor: Boolean = false): Type = {
+ val tp = propagateArgs(tp0)
+ val ret =
+ if (mode >= AnalyseTypes && (caller.targs.nonEmpty || caller.outerTargs.nonEmpty || (callerSymbol.owner ne caller.call.normalizedPrefix.classSymbol))) {
+ /* && tp.widenDealias.existsPart{x => val t = x.typeSymbol; t.exists && (t.owner == callerSymbol || caller.outerTargs.contains(t.owner))}*/
+
+ val refinedClassType = if (isConstructor) {
+ val refinedConstructedType = tp.typeMembers.foldLeft(tp){(acc, memberType) =>
+ val refinedInfo = substitution.apply(memberType.info)
+ if (refinedInfo ne memberType.info) RefinedType(acc, memberType.symbol.name, refinedInfo)
+ else acc
+ }
+ refinedConstructedType
+ } else if (mode >= AnalyseArgs && (tp.isInstanceOf[PreciseType] || tp.isInstanceOf[ClosureType])) tp
+ else tp.widenDealias
+ val r = substitution.apply(refinedClassType)
+ // for simplification only
+ if (r =:= tp) tp
+ else r
+ } else tp
+
+ assert(!(tp.isValueType ^ ret.isValueType))
+ ret
+ }
+
+ val outerTargs: OuterTargs =
+ if (mode < AnalyseTypes) OuterTargs.empty
+ else if (calleeSymbol.isProperlyContainedIn(callerSymbol)) {
+ parentRefinements(propagateTargs(receiver)) ++ caller.outerTargs ++ tpamsOuter
+ } else {
+ val t = parentRefinements(propagateTargs(receiver)) ++ caller.outerTargs
+ val (a, b) = t.mp.partition(x => calleeSymbol.isProperlyContainedIn(x._1))
+ new OuterTargs(a) combine new OuterTargs(b)
+ }
+
+ // if typearg of callee is a typeparam of caller, propagate typearg from caller to callee
+ lazy val targs = callee.targs map {
+ case t: TypeVar if mode >= AnalyseTypes && t.stripTypeVar.typeSymbol.maybeOwner == caller.call.termSymbol =>
+ assert(caller.call.termSymbol.exists)
+ val abstractSym = t.stripTypeVar.typeSymbol
+ val id = caller.call.termSymbol.info.asInstanceOf[PolyType].paramNames.indexOf(abstractSym.name)
+ propagateTargs(caller.targs(id).stripTypeVar)
+ case t if mode >= AnalyseTypes => propagateTargs(t.stripTypeVar)
+ case t => t.stripTypeVar
+ }
+ // if arg of callee is a param of caller, propagate arg fro caller to callee
+ val args = callee.argumentsPassed.map {
+ case x if mode < AnalyseArgs =>
+ val s = x.widenDealias.finalResultType.classSymbol.orElse(TypeErasure.erasure(x.widenDealias.finalResultType).classSymbol)
+ assert(s.exists)
+ ref(s).tpe
+ case x: PreciseType =>
+ x
+ case x: ClosureType =>
+ val utpe = normalizeType(propagateTargs(x.underlying, isConstructor = true))
+ val outer = parentRefinements(utpe) ++ caller.outerTargs
+ val closureT = new ClosureType(x.meth, utpe, x.implementedMethod)
+ addReachableType(new TypeWithContext(closureT, outer))
+ closureT
+ case x: TermRef if x.symbol.is(Param) && x.symbol.owner == caller.call.termSymbol =>
+ val id = caller.call.termSymbol.info.paramNamess.iterator.flatten.indexWhere(_ == x.symbol.name)
+ caller.argumentsPassed(id)
+ case x => propagateTargs(x)
+ }
+
+ def filterTypes(tp1: Type, tp2: Type, dtp1: Int, dtp2: Int): Boolean = {
+ if (dtp1 < dtp2) false
+ else if (mode >= AnalyseTypes) tp1 <:< tp2
+ else {
+ val tp1w = tp1.widenDealias
+ val tp2w = tp2.widenDealias
+ val tp2c = tp2w.classSymbol.orElse(TypeErasure.erasure(tp2).classSymbol)
+ tp1w.derivesFrom(tp2c)
+ }
+ }
+
+ def appliedToTargs(tp: Type): Type =
+ tp.widen.appliedTo(targs).widen
+
+ def preciseSelectCall(tp: Type, sym: Symbol): TermRef = {
+ def selectCall(tp1: Type) = {
+ if (sym.is(Private) || tp.typeSymbol == sym.owner) sym
+ else {
+ val selectByName = tp1.nonPrivateMember(sym.name)
+ selectByName.suchThat(x => x == sym || x.overriddenSymbol(sym.owner.asClass) == sym).symbol
+ }
+ }
+ val call = selectCall(tp).orElse(if (tp.givenSelfType.exists) selectCall(tp.givenSelfType) else NoSymbol)
+ assert(call.exists)
+ TermRef(tp, call.asTerm)
+ }
+
+ def dispatchCalls(receiverType: Type, dispatch: CallInfoWithContext => Unit = addCall): Unit = {
+ receiverType match {
+ case t: PreciseType =>
+ dispatch(CallInfoWithContext(preciseSelectCall(t.underlying, calleeSymbol), targs, args, outerTargs, someCaller, someCallee))
+ case t: ClosureType if calleeSymbol.name eq t.implementedMethod.name =>
+ val methodSym = t.meth.meth.symbol.asTerm
+ dispatch(CallInfoWithContext(TermRef.withFixedSym(t.underlying, methodSym.name, methodSym), targs, t.meth.env.map(_.tpe) ++ args, outerTargs, someCaller, someCallee))
+ case AndType(tp1, tp2) =>
+ val set1 = mutable.Set.empty[CallInfoWithContext]
+ val set2 = mutable.Set.empty[CallInfoWithContext]
+ dispatchCalls(tp1, x => set1.add(x))
+ dispatchCalls(tp2, x => set2.add(x))
+ set1.intersect(set2).foreach(dispatch)
+
+ case _ =>
+ // without casts
+ val receiverTypeWiden = receiverType.widenDealias match {
+ case t: TypeRefWithFixedSym if t.classSymbol.owner.is(Method) =>
+ new TypeRefWithFixedSym(t.classSymbol.owner.owner.typeRef, t.name, t.fixedSym)
+ case t => t
+ }
+
+ def denotMatch(tp: TypeWithContext, p: Symbol) = {
+ val d1 = p.asSeenFrom(tp.tp)
+ val d2 = calleeSymbol.asSeenFrom(tp.tp)
+ (d1 eq d2) || d1.matches(d2)
+ }
+
+ for ((dtp, tp) <- getTypesByMemberName(calleeSymbol.name)) {
+ if (filterTypes(tp.tp, receiverTypeWiden, dtp, receiverDepth)) {
+ for (alt <- tp.tp.member(calleeSymbol.name).altsWith(p => denotMatch(tp, p))) {
+ if (alt.exists)
+ dispatch(CallInfoWithContext(TermRef(tp.tp, alt.symbol.asTerm), targs, args, outerTargs ++ tp.outerTargs, someCaller, someCallee))
+ }
+ }
+ }
+
+ if (mode >= AnalyseTypes) {
+ lazy val filterCastCachedFilter = {
+ val receiverBases = receiverType.widen.classSymbols.iterator
+ val head = receiverBases.next()
+ receiverBases.foldLeft(castCache1.getOrDefault(head, Set.empty)){case (a,b) => a.intersect(castCache1.getOrDefault(b, Set.empty))}
+ }
+ for ((tpDepth, tp) <- getTypesByMemberName(calleeSymbol.name)) {
+ for (cast <- castsCache.getOrElse(tp, Set.empty[Cast])) {
+ if (filterCastCachedFilter.contains(cast)) {
+ if (filterTypes(tp.tp, cast.from, tpDepth, cast.fromDepth) && filterTypes(cast.to, receiverType, cast.toDepth, receiverDepth)) {
+ for (alt <- tp.tp.member(calleeSymbol.name).altsWith(p => p.matches(calleeSymbol.asSeenFrom(tp.tp)))) {
+ if (alt.exists) {
+ if (!addingOutEdges) {
+ // this additionally introduces a cast of result type and argument types
+ val uncastedSig = preciseSelectCall(tp.tp, alt.symbol).widen.appliedTo(targs).widen
+ val castedSig = preciseSelectCall(receiverType, calleeSymbol).widen.appliedTo(targs).widen
+ (uncastedSig.paramInfoss.iterator.flatten zip castedSig.paramInfoss.iterator.flatten) foreach (x => addCast(x._2, x._1))
+ addCast(uncastedSig.finalResultType, castedSig.finalResultType) // FIXME: this is added even in and tpe that are out of the intersection
+ }
+
+ dispatch(CallInfoWithContext(tp.tp.select(alt.symbol).asInstanceOf[TermRef], targs, args, outerTargs ++ tp.outerTargs, someCaller, someCallee))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ receiver match {
+ case _ if calleeSymbol == defn.Predef_classOf =>
+ classOfs.put(callee.targs.head.classSymbol, ())
+ case _ if calleeSymbol == ctx.definitions.throwMethod =>
+ case _ if calleeSymbol == ctx.definitions.Any_asInstanceOf =>
+ val from = propagateTargs(receiver)
+ val to = propagateTargs(targs.head)
+ addCast(from, to)
+ case _ if defn.ObjectMethods.contains(calleeSymbol) || defn.AnyMethods.contains(calleeSymbol) => Nil
+ case NoPrefix => // inner method
+ assert(calleeSymbol.is(ParamAccessor) || calleeSymbol.owner.is(Method) || calleeSymbol.owner.isLocalDummy)
+ addCall(CallInfoWithContext(TermRef.withFixedSym(caller.call.normalizedPrefix, calleeSymbol.name, calleeSymbol), targs, args, outerTargs, someCaller, someCallee))
+
+ case t if calleeSymbol.isConstructor =>
+
+ val constructedType = appliedToTargs(callee.call).finalResultType
+ val fixNoPrefix = if (constructedType.normalizedPrefix eq NoPrefix) {
+ @tailrec def getPrefix(currentPrefix: Type): Type = {
+ if (currentPrefix.classSymbol.exists) currentPrefix
+ else if (currentPrefix.termSymbol.is(Module)) getPrefix(currentPrefix.widenDealias)
+ else {
+ getPrefix(currentPrefix.normalizedPrefix match {
+ case t: ThisType => t.tref
+ case t => t
+ })
+ }
+ }
+ constructedType match {
+ case constructedType @ TypeRef(prefix, name) =>
+ constructedType.underlying match {
+ case ci: ClassInfo =>
+ val currentPrefix = getPrefix(caller.call.normalizedPrefix)
+ val nci = ci.derivedClassInfo(prefix = currentPrefix) // todo: do this only for inner anonym classes
+ TypeRef.withFixedSymAndInfo(currentPrefix, name, constructedType.symbol.asType, nci)
+ }
+ }
+ } else constructedType
+
+ val tpe = propagateTargs(fixNoPrefix, isConstructor = true)
+ addReachableType(new TypeWithContext(tpe, parentRefinements(tpe) ++ outerTargs))
+
+ val call = {
+ if (callerSymbol.isConstructor && callerSymbol.owner == calleeSymbol.owner)
+ new TermRefWithFixedSym(calleeSymbol.owner.typeRef, calleeSymbol.name, calleeSymbol)
+ else
+ propagateTargs(receiver).select(calleeSymbol).asInstanceOf[TermRef]
+ }
+
+ addCall(CallInfoWithContext(call, targs, args, outerTargs, someCaller, someCallee))
+
+ // super call in a class (know target precisely)
+ case st: SuperType =>
+ val thisTpe = st.thistpe
+ val targetClass = st.supertpe.baseClasses.find(clz =>
+ clz.info.decl(calleeSymbol.name).altsWith(p => p.signature == calleeSymbol.signature).nonEmpty
+ )
+ val targetMethod = targetClass.get.info.member(calleeSymbol.name).altsWith(p => p.signature == calleeSymbol.signature).head.symbol.asTerm
+ val thisTpePropagated = propagateTargs(thisTpe)
+
+
+ addCall(CallInfoWithContext(TermRef.withFixedSym(thisTpePropagated, targetMethod.name, targetMethod), targs, args, outerTargs, someCaller, someCallee))
+
+ // super call in a trait
+ case t if calleeSymbol.is(Scala2SuperAccessor) =>
+
+ // Taken from ResolveSuper.rebindSuper
+ val SuperAccessorName(memberName) = calleeSymbol.name.unexpandedName
+
+ val prev = t.widenDealias.classSymbol
+ getTypesByMemberName(memberName).foreach {
+ x =>
+ val s = x._2.tp.baseClasses.dropWhile(_ != prev)
+ if (s.nonEmpty) {
+ val parentMethod = ResolveSuper.rebindSuper(x._2.tp.widenDealias.classSymbol, calleeSymbol).asTerm
+ // todo: outerTargs are here defined in terms of location of the subclass. Is this correct?
+ addCall(CallInfoWithContext(TermRef.withFixedSym(t, parentMethod.name, parentMethod), targs, args, outerTargs, someCaller, someCallee))
+
+ }
+ }
+
+ case thisType: ThisType if !calleeSymbol.owner.flags.is(PackageCreationFlags) =>
+ val dropUntil = thisType.tref.classSymbol
+ @tailrec def getPreciseThis(currentThis: Type, currentOwner: Symbol): Type = {
+ if ((currentOwner eq dropUntil) || currentOwner.owner.is(Package) || (currentThis eq NoType)) currentThis
+ else if (currentOwner.is(Method)) getPreciseThis(currentThis, currentOwner.owner.enclosingClass)
+ else getPreciseThis(currentThis.normalizedPrefix, currentOwner.owner.enclosingClass)
+ }
+
+ val currentThis = getPreciseThis(caller.call.normalizedPrefix, caller.call.termSymbol.owner)
+
+ if (!currentThis.derivesFrom(thisType.cls))
+ dispatchCalls(propagateTargs(receiver.widenDealias))
+ else if (calleeSymbol.is(Private))
+ addCall(CallInfoWithContext(TermRef.withFixedSym(currentThis, calleeSymbol.name, calleeSymbol), targs, args, outerTargs, someCaller, someCallee))
+ else
+ dispatchCalls(propagateTargs(AndType.apply(currentThis, thisType.tref)))
+
+
+ case _: PreciseType =>
+ dispatchCalls(propagateTargs(receiver))
+ case _: ClosureType =>
+ dispatchCalls(propagateTargs(receiver))
+ case x: TermRef if x.symbol.is(Param) && x.symbol.owner == caller.call.termSymbol =>
+ val a = propagateTargs(receiver)
+ dispatchCalls(a)
+ case _ =>
+ dispatchCalls(propagateTargs(receiver.widenDealias))
+ }
+ }
+
+ private def processCallSites(): Unit = {
+ var processed = 0
+ var total = 0
+
+ def computeCRC(tp: Type) = tp.classSymbols.iterator.map(x => sizesCache.getOrDefault(x, 0)).sum
+
+ for (method <- reachableMethods) {
+ lazy val crcMap = lastInstantiation.getOrElseUpdate(method, mutable.Map.empty)
+ // Find new call sites
+
+ def needsCallSiteInstantiation(callSite: CallInfo): Boolean = {
+ total += 1
+ val receiver = callSite.call.normalizedPrefix
+ val recomputedCRC = computeCRC(receiver)
+ val needsInstantiation = recomputedCRC != crcMap.getOrElse(callSite, -1)
+ if (needsInstantiation)
+ crcMap(callSite) = recomputedCRC
+ needsInstantiation || addingOutEdges || finished // if finished==true we are checking the completeness of the CRC
+ }
+
+ collectedSummaries.get(method.callSymbol).orElse(tastySummaries(method.callSymbol)) match {
+ case Some(summary) =>
+ summary.definedClosures.foreach(x => addReachableClosure(x, method))
+
+ for (methodCalled <- summary.methodsCalled) {
+ for (callSite <- methodCalled._2) {
+ if (needsCallSiteInstantiation(callSite)) {
+ processed += 1
+ instantiateCallSite(method, callSite, _ => true)
+ }
+ }
+ }
+
+ case None =>
+
+ if (!outerMethods.containsKey(method.callSymbol)) {
+
+ outerMethods.put(method.callSymbol, ())
+
+ if (withJavaCallGraph && !method.callSymbol.is(Module | Package) && !method.parent.exists(_.isOnJavaAllocatedType)) {
+
+ addReachableJavaReturnType(method)
+
+ // Add all possible calls from java to object passed as parameters.
+ for (rec <- (method.call.normalizedPrefix :: method.argumentsPassed).distinct) {
+ for (potentialCall <- allPotentialCallsFor(rec)) {
+ if (needsCallSiteInstantiation(potentialCall) && method.getOutEdges(potentialCall).isEmpty) {
+ processed += 1
+ instantiateCallSite(method, potentialCall, call => collectedSummaries.contains(call.callSymbol))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ctx.log(s"Processed $processed calls out of $total")
+ }
+
+ private def addReachableJavaReturnType(method: CallInfoWithContext): Unit = {
+ val tParamNames = method.call.widenDealias.typeParams.map(_.paramName)
+ val newOuterTargs = method.outerTargs.addAll(method.callSymbol, tParamNames, method.targs)
+
+ def substituteOuterTargs = new SubstituteByParentMap(newOuterTargs)
+
+ // Add return type to reachable types
+ val methodTpe = method.call.widenDealias
+
+ val returnType = methodTpe match {
+ case t: PolyType => t.instantiate(method.targs).finalResultType
+ case _ => methodTpe.finalResultType
+ }
+
+ val javaAllocatedType = returnType match {
+ case returnType: JavaAllocatedType => returnType
+ case returnType: HKApply => new JavaAllocatedType(substituteOuterTargs(returnType.tycon.appliedTo(method.targs)))
+ case returnType => new JavaAllocatedType(substituteOuterTargs(returnType))
+ }
+ addReachableType(new TypeWithContext(javaAllocatedType, OuterTargs.empty))
+ }
+
+ private def allPotentialCallsFor(argType: Type): Set[CallInfo] = {
+ if (defn.isPrimitiveClass(argType.classSymbol)) {
+ Set.empty
+ } else {
+ def potentialCall(decl: Symbol): Option[CallInfo] = {
+ lazy val paramTypes = decl.info.paramInfoss.flatten
+ val call = new TermRefWithFixedSym(argType, decl.name.asTermName, decl.asTerm)
+ val targs = call.widenDealias match {
+ case call: PolyType =>
+ def erasedBounds(tp: TypeBounds): Type = tp.hi match {
+ case RefinedType(parent, refinedName, refinedInfo: TypeBounds) =>
+ RefinedType(parent, refinedName, TypeAlias(erasedBounds(refinedInfo)))
+ case t => t
+ }
+ call.paramInfos.map(erasedBounds)
+
+ case _ => Nil
+ }
+
+ def isDefinedInJavaClass(sym: Symbol) =
+ sym.owner == defn.AnyClass || sym.owner.is(JavaDefined)
+
+ val definedInJavaClass: Boolean =
+ isDefinedInJavaClass(decl) || decl.allOverriddenSymbols.exists(isDefinedInJavaClass)
+
+ argType match {
+ case argType: PreciseType =>
+ if (!definedInJavaClass) None
+ else Some(CallInfo(call, targs, paramTypes))
+
+ case _ =>
+ val argTypeWiden = argType.widenDealias
+ lazy val sym = argTypeWiden.classSymbol.requiredMethod(decl.name, paramTypes)
+ if (paramTypes.exists(_.typeSymbol.isTypeParam)) {
+ // println(s"Ignoring `${decl.name}` in java call graph construction because type parameters are not suported yet")
+ None
+ } else if (!argTypeWiden.member(decl.name).exists || !definedInJavaClass || (isDefinedInJavaClass(decl) && sym.isEffectivelyFinal)) None
+ else Some(CallInfo(TermRef(argType, sym), targs, paramTypes))
+
+ }
+ }
+
+ def allDecls(argType: Type) =
+ argType.decls.iterator.toSet ++ argType.parents.flatMap(_.decls.iterator)
+
+ for {
+ decl <- allDecls(argType)
+ if decl.isTerm && !decl.isConstructor && decl.name != nme.COMPANION_MODULE_METHOD
+ if decl.name != nme.isInstanceOf_ && decl.name != nme.asInstanceOf_ && decl.name != nme.synchronized_
+ callInfo <- potentialCall(decl)
+ } yield callInfo
+ }
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallInfoWithContext.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallInfoWithContext.scala
new file mode 100644
index 000000000000..cd9a57a984d9
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/CallInfoWithContext.scala
@@ -0,0 +1,62 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.linker.summaries.{AbstractCallInfo, CallInfo}
+import dotty.tools.dotc.transform.linker.types._
+
+import scala.collection.mutable
+
+class CallInfoWithContext private (val call: TermRef, val targs: List[Type], val argumentsPassed: List[Type],
+ val outerTargs: OuterTargs, val parent: Option[CallInfoWithContext], val callee: Option[CallInfo])
+ extends AbstractCallInfo {
+
+ private lazy val outEdges = mutable.HashMap[CallInfo, List[CallInfoWithContext]]().withDefault(x => Nil)
+
+ def outEdgesIterator: Iterator[(CallInfo, List[CallInfoWithContext])] = outEdges.iterator
+
+ def getOutEdges(callSite: CallInfo): List[CallInfoWithContext] = outEdges(callSite)
+
+ def addOutEdges(callSite: CallInfo, edges: Traversable[CallInfoWithContext]): Unit = {
+ var es = outEdges(callSite)
+ for (e <- edges) {
+ if (!es.contains(e))
+ es = e :: es
+ }
+ outEdges(callSite) = es
+ }
+
+ def addOutEdges(callSite: CallInfo, e: CallInfoWithContext): Unit = {
+ val es = outEdges(callSite)
+ if (!es.contains(e))
+ outEdges(callSite) = e :: es
+ }
+
+ def edgeCount: Int =
+ outEdges.values.foldLeft(0)(_ + _.size)
+
+ def source: Option[CallInfo] = callee.flatMap(_.source)
+
+ def isOnJavaAllocatedType: Boolean = call.prefix.isInstanceOf[JavaAllocatedType]
+
+ override def equals(obj: Any): Boolean = obj match {
+ case obj: CallInfoWithContext =>
+ call == obj.call && targs == obj.targs && argumentsPassed == obj.argumentsPassed && outerTargs == obj.outerTargs
+ case _ => false
+ }
+
+ override def hashCode(): Int = call.hashCode ^ targs.hashCode ^ argumentsPassed.hashCode ^ outerTargs.mp.hashCode
+
+ override def toString(): String = s"CallInfoWithContext($call, $targs, $argumentsPassed, $outerTargs, $parent, $callee)"
+}
+
+object CallInfoWithContext {
+
+ def apply(call: TermRef, targs: List[Type], argumentsPassed: List[Type], outerTargs: OuterTargs,
+ parent: Option[CallInfoWithContext], callee: Option[CallInfo])(implicit ctx: Context): CallInfoWithContext = {
+ val callInfo = new CallInfoWithContext(call, targs, argumentsPassed, outerTargs, parent, callee)
+ AbstractCallInfo.assertions(callInfo)
+ callInfo
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/Cast.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/Cast.scala
new file mode 100644
index 000000000000..eb8db3d9b949
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/Cast.scala
@@ -0,0 +1,27 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types.{MethodicType, Type}
+
+class Cast(val from: Type, val to: Type)(implicit ctx: Context) {
+
+ lazy val fromDepth = TypeDepth(from)
+ lazy val toDepth = TypeDepth(to)
+
+ assertNonMethodic("from", from.widenDealias)
+ assertNonMethodic("to", to.widenDealias)
+
+ override def equals(other: Any): Boolean = other match {
+ case other: Cast => fromDepth == other.fromDepth && toDepth == other.toDepth && other.from =:= from && other.to =:= to
+ case _ => false
+ }
+
+ override def hashCode(): Int =
+ from.typeSymbol.hashCode() * 31 + to.typeSymbol.hashCode()
+
+ override def toString: String = s"Cast($from, $to)"
+
+ private def assertNonMethodic(name: String, tpe: Type): Unit =
+ assert(!tpe.isInstanceOf[MethodicType], name + " = " + tpe)
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/GraphVisualization.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/GraphVisualization.scala
new file mode 100644
index 000000000000..742f3cdb1f8e
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/GraphVisualization.scala
@@ -0,0 +1,482 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts._
+import dotty.tools.dotc.core.Flags._
+import dotty.tools.dotc.core.Names._
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.linker.summaries.{AbstractCallInfo, CallInfo}
+
+import scala.collection.mutable
+
+object GraphVisualization {
+
+ @deprecated("replaced with outputGraphVis", "0")
+ def outputGraph(mode: Int, specLimit: Int)(callGraph: CallGraph)(implicit ctx: Context): String = {
+ val reachableMethods = callGraph.reachableMethods
+ val reachableTypes = callGraph.reachableTypes
+ val outerMethod = callGraph.outerMethods
+
+ val outGraph = new StringBuffer()
+ outGraph.append(s"digraph Gr${mode}_$specLimit {\n")
+ outGraph.append("graph [fontsize=10 fontname=\"Verdana\" compound=true];\n")
+ outGraph.append("label = \"" + reachableMethods.size + " nodes, " +
+ reachableMethods.foldLeft(0)(_ + _.edgeCount) + " edges, " + reachableTypes.size + " reachable types\";\n")
+
+ // add names and subraphs
+ reachableMethods.foreach { caller =>
+ val subgraphColor = if (outerMethod.contains(caller.callSymbol)) "red" else "blue"
+
+ outGraph.append("subgraph ").append(clusterName(caller)).append(" {\n")
+ outGraph.append(" label = ").append(slash + csWTToName(caller) + slash).append(";\n")
+ outGraph.append(" color = ").append(subgraphColor).append(";\n")
+ outGraph.append(" ").append(dummyName(caller)).append(" [shape=point style=invis];\n")
+ for ((call, _) <- caller.outEdgesIterator) {
+ outGraph.append(" ").append(csToName(caller, call))
+ outGraph.append(" [")
+ outGraph.append("label=").append(slash).append(callSiteLabel(call)).append(slash)
+ call.source match {
+ case Some(source) =>
+ outGraph.append(", color=")
+ val color =
+ if (source.call.widenDealias.classSymbol.is(JavaDefined)) "orange"
+ else "blue"
+ outGraph.append(color)
+ case None =>
+ }
+ outGraph.append("];\n")
+ }
+ outGraph.append("}\n\n")
+ }
+
+ // Add edges
+ reachableMethods.foreach { caller =>
+ for ((callInfo, edges) <- caller.outEdgesIterator)
+ edges.foreach { target =>
+ val from = csToName(caller, callInfo)
+ val to = dummyName(target)
+ outGraph.append(from).append(" -> ").append(to)
+ outGraph.append(" [")
+ outGraph.append("ltail=").append(clusterName(target))
+ outGraph.append("];\n")
+ }
+ outGraph.append("\n")
+ }
+ outGraph.append("}")
+ outGraph.toString
+ }
+
+ def outputGraphVisToFile(callGraph: CallGraph, outFile: java.io.File)(implicit ctx: Context): Unit = {
+ val p = new java.io.PrintWriter(outFile)
+ try {
+ outputGraphVis(callGraph, p)
+ } finally {
+ p.close()
+ }
+ }
+
+ private def outputGraphVis(callGraph: CallGraph, pw: java.io.PrintWriter)(implicit ctx: Context): Unit = {
+ val reachableMethods = callGraph.reachableMethods
+ val reachableTypes = callGraph.reachableTypes
+ val outerMethod = callGraph.outerMethods
+
+ val callInfoNodeId = mutable.Map.empty[CallInfoWithContext, String]
+
+ // add names and subraphs
+ val nodes = mutable.Map.empty[String, String]
+ val edges = mutable.Map.empty[String, List[String]]
+
+ def addNode(id: String, properties: String*): Unit = {
+ nodes(id) = (Iterator(s"id: '$id'") ++ properties).mkString("{ ", ", ", " }")
+ }
+
+ def addEdge(from: String, to: String, properties: String*): Unit = {
+ val newEntry = (Iterator(s"from: '$from'", s"to: '$to'") ++ properties).mkString("{ ", ", ", " }")
+ edges(from) = newEntry :: edges.getOrElse(from, Nil)
+ }
+
+ val red = "'rgb(255,150,150)'"
+ val lightRed = "'rgb(255,200,200)'"
+ val blue = "'rgb(150,150,255)'"
+ val lightBlue = "'rgb(200,200,255)'"
+ val green = "'rgb(150,255,150)'"
+ val grey = "'rgb(200,200,200)'"
+
+ def detailsHTML(info: CallInfoWithContext): String = {
+ htmlFormattedStringLabel(
+ s"""call: ${info.call.show}
+ |targs: ${info.targs.map(_.show)}
+ |arguments: ${info.argumentsPassed.map(_.show)}
+ |
+ |id: ${info.id}
+ """.stripMargin)
+ }
+
+ callGraph.entryPoints.values.toSet[Int].foreach { entryPointId =>
+ addNode("entry-" + entryPointId, "shape: 'diamond'", "color: " + green)
+ }
+
+ reachableMethods.map(_.call).foreach { call =>
+ val widenCall = call.widenDealias
+ val callId = "call-" + widenCall.uniqId
+
+ val label = htmlFormattedStringLabel(call.termSymbol.owner.name + "." + call.termSymbol.name + (widenCall match {
+ case widenCall: PolyType => widenCall.paramRefs.map(_.show).mkString("[", ",", "]") + widenCall.resType.show
+ case widenCall => widenCall.show
+ }))
+ addNode(callId, s"label: '$label'", s"color: $grey")
+ }
+
+ reachableMethods.foreach { caller =>
+
+ val color =
+ if (outerMethod.contains(caller.callSymbol)) red
+ else blue
+
+ val callId = "call-" + caller.call.widenDealias.uniqId
+ val callerId = callInfoNodeId.getOrElseUpdate(caller, caller.id.toString)
+
+ addNode(callerId, s"label: '${csWTToName(caller)}'", s"title: '${detailsHTML(caller)}'", s"color: $color")
+ addEdge(callerId, callId, s"title: 'actually calls'", s"color: $grey")
+
+ callGraph.entryPoints.get(caller) match {
+ case Some(entryPointId) =>
+ addEdge("entry-" + entryPointId, callerId)
+ case None =>
+ }
+
+ for ((call, callees) <- caller.outEdgesIterator) {
+ val callId = callerId + "-" + call.id
+ val color =
+ if (outerMethod.contains(caller.callSymbol)) lightRed
+ else lightBlue
+ addNode(callId, s"label: '${callSiteLabel(call)}'", s"color: $color")
+
+ if (call.source.isEmpty)
+ addEdge(callerId, callId, s"title: 'calls'")
+
+ callees.foreach { callee =>
+ val calleeId = callInfoNodeId.getOrElseUpdate(callee, callee.id.toString)
+ addEdge(callId, calleeId, s"title: 'dispatches to'")
+
+ callee.source.foreach { source =>
+ val actualCallerId = callerId + "-" + source.id
+ val calleeId = callee.id.toString
+ addEdge(actualCallerId, calleeId, s"title: 'also dispatches call to'")
+ }
+ }
+ }
+ }
+
+ def printNodesJSON(): Unit = {
+ def printNodes(nodes: List[(String, String)]): Unit = nodes match {
+ case n :: ns =>
+ pw.print("'" + n._1 + "': " + n._2)
+ if (ns.nonEmpty)
+ pw.print(",")
+ printNodes(ns)
+ case Nil =>
+ }
+ pw.println("{")
+ printNodes(nodes.toList)
+ pw.println("}")
+ }
+ def printEdgesJSON(): Unit = {
+ def printEdges(edges: List[(String, List[String])]): Unit = edges match {
+ case e :: es =>
+ pw.print("'" + e._1 + "': ")
+ pw.print("[")
+ pw.print(e._2.mkString(","))
+ pw.print("]")
+ if (es.nonEmpty)
+ pw.print(",")
+ printEdges(es)
+ case Nil =>
+ }
+ pw.println("{")
+ printEdges(edges.toList)
+ pw.println("}")
+ }
+
+ pw.println("""
+ |
+ |
+ |
+ | Callgraph
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
0%
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ """.stripMargin)
+ }
+
+ private def callSiteLabel(x: CallInfo)(implicit ctx: Context): String = {
+ val prefix = x.call.normalizedPrefix
+ val calleeSymbol = x.callSymbol
+ val prefixString = prefix match {
+ case NoPrefix => calleeSymbol.name.toString
+ case t if calleeSymbol.isPrimaryConstructor => calleeSymbol.showFullName
+ case st: SuperType => s"super[${st.supertpe.classSymbol.showFullName}].${calleeSymbol.name}"
+ /* case t if calleeSymbol.is(SuperAccessor) =>
+ val prev = t.classSymbol
+ types.flatMap {
+ x =>
+ val s = x.baseClasses.dropWhile(_ != prev)
+ if (s.nonEmpty) {
+ val parent = s.find(x => x.info.decl(calleeSymbol.name).altsWith(x => x.signature == calleeSymbol.signature).nonEmpty)
+ parent match {
+ case Some(p) if p.exists =>
+ val method = p.info.decl(calleeSymbol.name).altsWith(x => x.signature == calleeSymbol.signature)
+ // todo: outerTargs are here defined in terms of location of the subclass. Is this correct?
+ new CallWithContext(t.select(method.head.symbol), targs, args, outerTargs) :: Nil
+ case _ => Nil
+ }
+ } else Nil
+ } */
+
+ case thisType: ThisType =>
+ "this." + calleeSymbol.name
+ case t =>
+ typeName(t) + '.' + calleeSymbol.name
+ }
+
+ val targsString = typeArgumentsString(x.targs)
+ val vargsString = argumentsString(x.argumentsPassed)
+
+ htmlFormattedStringLabel(prefixString + targsString + vargsString)
+ }
+
+ private val slash = '"'
+
+ private def htmlFormattedStringLabel(str: String): String =
+ str.replace("\n", " ").replace("'", "\"")
+
+ private def escape(s: String) = s.replace("\\", "\\\\")
+
+ private def fullNameSeparated(symbol: Symbol)(separator: String)(implicit ctx: Context): Name = {
+ var sep = separator
+ val owner = symbol.owner
+ var name: Name = symbol.name
+ var stopAtPackage = false
+ if (sep.isEmpty) {
+ sep = "$"
+ stopAtPackage = true
+ }
+ if (symbol.isAnonymousClass || symbol.isAnonymousFunction)
+ name = name ++ symbol.id.toString
+ if (symbol == NoSymbol ||
+ owner == NoSymbol ||
+ owner.isEffectiveRoot ||
+ stopAtPackage && owner.is(PackageClass)) name
+ else {
+ var encl = owner
+ while (!encl.isClass && !encl.isPackageObject) {
+ encl = encl.owner
+ sep += "~"
+ }
+ if (owner.is(ModuleClass, butNot = Package) && sep == "$") sep = "" // duplicate scalac's behavior: don't write a double '$$' for module class members.
+ val fn = fullNameSeparated(encl)(separator) ++ sep ++ name
+ if (symbol.isType) fn.toTypeName else fn.toTermName
+ }
+ }
+
+ private def symbolName(sym: Symbol)(implicit ctx: Context): String = {
+ if (!sym.is(Method)) escape(sym.name.show)
+ else escape(fullNameSeparated(sym)(".").show)
+ }
+
+ private def typeName(x: Type)(implicit ctx: Context): String = {
+ x match {
+ case ConstantType(value) => escape(value.toString)
+ case _ =>
+ val t = x.termSymbol.orElse(x.typeSymbol)
+ if (t.exists)
+ symbolName(t)
+ else escape(x.show)
+ }
+ }
+
+ private def csWTToName(x: AbstractCallInfo)(implicit ctx: Context): String = {
+ val targs = typeArgumentsString(x.targs)
+ val vargs = typeParameterString(x.call.widenDealias.paramInfoss)
+ val resultType = typeName(x.call.widenDealias.finalResultType)
+ if (x.callSymbol.owner == x.call.normalizedPrefix.classSymbol) {
+ val callTypeName = typeName(x.call)
+ htmlFormattedStringLabel(callTypeName + targs + vargs + ": " + resultType)
+ } else {
+ val callTypeName = typeName(x.call.normalizedPrefix)
+ val symName = symbolName(x.callSymbol)
+ htmlFormattedStringLabel(callTypeName + ".super." + symName + targs + vargs + ": " + resultType)
+ }
+ }
+
+ private def csWTToShortName(x: AbstractCallInfo)(implicit ctx: Context): String = {
+ if (x.callSymbol.owner.name == x.call.normalizedPrefix.classSymbol.name) {
+ val callTypeName = typeName(x.call)
+ callTypeName
+ } else {
+ val callTypeName = typeName(x.call.normalizedPrefix)
+ symbolName(x.callSymbol)
+ }
+ }
+
+ private def csToName(parent: CallInfoWithContext, inner: CallInfo)(implicit ctx: Context): String = {
+ slash + csWTToName(parent) + escape(inner.call.show) + inner.hashCode() + slash
+ }
+
+ private def dummyName(x: AbstractCallInfo)(implicit ctx: Context): String = {
+ slash + csWTToName(x) + "_Dummy" + slash
+ }
+
+ private def clusterName(x: AbstractCallInfo)(implicit ctx: Context): String = {
+ slash + "cluster_" + csWTToName(x) + slash
+ }
+
+ private def argumentsString(args: List[Type])(implicit ctx: Context): String = {
+ if (args.isEmpty) ""
+ else args.map(typeName).mkString("(", ",", ")")
+ }
+
+ private def typeArgumentsString(targs: List[Type])(implicit ctx: Context): String = {
+ if (targs.isEmpty) ""
+ else targs.map(t => typeName(t.widenDealias)).mkString("[", ",", "]")
+ }
+
+ private def typeParameterString(paramTypess: List[List[Type]])(implicit ctx: Context): String = {
+ paramTypess.iterator.map { paramTypes =>
+ paramTypes.map(x => typeName(x)).mkString("(", ",", ")")
+ }.mkString("")
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/OuterTargs.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/OuterTargs.scala
new file mode 100644
index 000000000000..d48c39923c79
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/OuterTargs.scala
@@ -0,0 +1,60 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Names.Name
+import dotty.tools.dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.Types.{RefinedType, Type, TypeAccumulator, TypeAlias, TypeType}
+import dotty.tools.dotc.transform.linker.types.ClosureType
+
+object OuterTargs {
+ val empty = new OuterTargs(Map.empty)
+
+ def parentRefinements(tp: Type)(implicit ctx: Context): OuterTargs = {
+ new TypeAccumulator[OuterTargs]() {
+ def apply(x: OuterTargs, tp: Type): OuterTargs = tp match {
+ case t: RefinedType =>
+ val member = t.parent.member(t.refinedName).symbol
+ val parent = member.owner
+ val nList = x.add(parent, t.refinedName, t.refinedInfo)
+ apply(nList, t.parent)
+ case t: ClosureType =>
+ apply(x, t.u)
+ case _ =>
+ foldOver(x, tp)
+ }
+ }.apply(OuterTargs.empty, tp)
+ }
+}
+
+final class OuterTargs(val mp: Map[Symbol, Map[Name, Type]]) extends AnyVal {
+
+ def nonEmpty: Boolean = mp.nonEmpty
+
+ def add(parent: Symbol, tp: Type)(implicit ctx: Context): OuterTargs = {
+ assert(!parent.isClass || tp.isInstanceOf[TypeType], tp)
+ this.add(parent, tp.typeSymbol.name, tp)
+ }
+
+ def add(parent: Symbol, name: Name, tp: Type)(implicit ctx: Context): OuterTargs = {
+ val tp1 = if (parent.isClass && !tp.isInstanceOf[TypeType]) TypeAlias(tp) else tp
+ val old = mp.getOrElse(parent, Map.empty)
+ new OuterTargs(mp.updated(parent, old + (name -> tp1)))
+ }
+
+ def addAll(parent: Symbol, names: List[Name], tps: List[Type])(implicit ctx: Context): OuterTargs =
+ (names zip tps).foldLeft(this)((x, nameType) => x.add(parent, nameType._1, nameType._2))
+
+ def ++(other: OuterTargs)(implicit ctx: Context): OuterTargs = {
+ other.mp.foldLeft(this) { (x, y) =>
+ y._2.foldLeft(x: OuterTargs)((x: OuterTargs, z: (Name, Type)) => x.add(y._1, z._1, z._2))
+ }
+ }
+
+ def combine(environment: OuterTargs)(implicit ctx: Context): OuterTargs = {
+ val subst = new SubstituteByParentMap(environment)
+ val newMap = mp.map(x => (x._1, x._2.map(x => (x._1, subst.apply(x._2)))))
+ new OuterTargs(newMap)
+ }
+
+ override def toString: String = s"OuterTargs($mp)"
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/SubstituteByParentMap.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/SubstituteByParentMap.scala
new file mode 100644
index 000000000000..ce4cb6f30f3c
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/SubstituteByParentMap.scala
@@ -0,0 +1,58 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.linker.types.ClosureType
+
+class SubstituteByParentMap(substMap: OuterTargs)(implicit ctx1: Context) extends DeepTypeMap()(ctx1) {
+
+ def apply(tp: Type): Type = {
+ lazy val substitution = substMap.mp.getOrElse(tp.typeSymbol.owner, Nil)
+ def termTypeIfNeed(t: Type): Type = {
+ if (tp.isInstanceOf[TermType] && !t.isInstanceOf[TermType]) {
+ t match {
+ case t: TypeAlias =>
+ assert(t.underlying.isInstanceOf[TermType])
+ t.underlying
+ case t: ClassInfo =>
+ t.typeRef
+ case _ =>
+ assert(false)
+ null
+ }
+ } else t
+ }
+ val res = tp match {
+ case tp: RefinedType => mapOver(tp) // otherwise we will loose refinement
+ case tp: TypeAlias => mapOver(tp) // map underlying
+ case tp: HKApply => mapOver(tp)
+ case _ if tp.typeSymbol.exists && substitution.nonEmpty =>
+ var typ = tp
+ var id = substitution.find(x => x._1 == tp.typeSymbol.name)
+ var limit = 30
+ var stack: List[Type] = Nil
+ while (id.isEmpty && (limit > 0) && (typ.typeSymbol.info.typeSymbol ne typ.typeSymbol)) {
+ typ = typ.typeSymbol.info
+ stack = typ :: stack
+ id = substitution.find(x => x._1 == typ.typeSymbol.name)
+ limit -= 1
+ }
+
+ if (id.isDefined) {
+ val t = termTypeIfNeed(id.get._2.stripTypeVar)
+ if (!(t =:= typ))
+ apply(termTypeIfNeed(t))
+ else t
+ } else tp
+ case t: TypeRef if t.prefix.normalizedPrefix eq NoPrefix =>
+ val tmp = apply(t.info)
+ if (tmp ne t.info) termTypeIfNeed(tmp)
+ else mapOver(t)
+ case tp: ClosureType =>
+ new ClosureType(tp.meth, apply(tp.underlying), tp.implementedMethod)
+ case _ => mapOver(tp)
+ }
+ assert(!(tp.isInstanceOf[TypeType] ^ res.isInstanceOf[TypeType]), (tp, res))
+ res
+ }
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeDepth.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeDepth.scala
new file mode 100644
index 000000000000..08bae6655705
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeDepth.scala
@@ -0,0 +1,16 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.core.Types._
+
+object TypeDepth {
+
+ def apply(tp: Type)(implicit ctx: Context): Int =
+ max(tp.classSymbols.iterator.map(classDepth))
+
+ private def classDepth(cls: ClassSymbol)(implicit ctx: Context): Int =
+ 1 + max(cls.classParents.iterator.map(apply))
+
+ private def max(it: Iterator[Int]) = if (it.hasNext) it.max else 0
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeWithContext.scala b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeWithContext.scala
new file mode 100644
index 000000000000..debc3d615607
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/callgraph/TypeWithContext.scala
@@ -0,0 +1,15 @@
+package dotty.tools.dotc.transform.linker.callgraph
+
+import dotty.tools.dotc.core.Types.Type
+
+class TypeWithContext(val tp: Type, val outerTargs: OuterTargs) {
+
+ override def equals(obj: Any): Boolean = obj match {
+ case obj: TypeWithContext => tp == obj.tp && outerTargs == obj.outerTargs
+ case _ => false
+ }
+
+ override def hashCode(): Int = tp.hashCode() // ^ outerTargs.mp.hashCode()
+
+ override def toString: String = s"TypeWithContext($tp, $outerTargs)"
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/summaries/AbstractCallInfo.scala b/compiler/src/dotty/tools/dotc/transform/linker/summaries/AbstractCallInfo.scala
new file mode 100644
index 000000000000..43a8a65e45fa
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/summaries/AbstractCallInfo.scala
@@ -0,0 +1,47 @@
+package dotty.tools.dotc.transform.linker.summaries
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols.TermSymbol
+import dotty.tools.dotc.core.Types.{MethodType, PolyType, TermRef, Type, TypeBounds}
+import dotty.tools.dotc.transform.linker.types.ClosureType
+import dotty.tools.sharable
+
+abstract class AbstractCallInfo {
+
+ final val id: Int = AbstractCallInfo.nextId()
+
+ /** This is type of method, that includes full type of receiver, eg: TermRef(receiver, Method) */
+ val call: TermRef
+
+ /** Type arguments at call site */
+ val targs: List[Type]
+
+ /** Type of the arguments at call site */
+ val argumentsPassed: List[Type]
+
+ def callSymbol(implicit ctx: Context): TermSymbol = call.normalizedPrefix match {
+ case t: ClosureType => t.meth.meth.symbol.asTerm
+ case _ => call.termSymbol.asTerm
+ }
+}
+
+object AbstractCallInfo {
+
+ def assertions(callInfo: AbstractCallInfo)(implicit ctx: Context): Unit = {
+ callInfo.call.widenDealias match {
+ case t: PolyType => assert(t.paramNames.size == callInfo.targs.size)
+ case t: MethodType => assert(t.paramNamess.flatten.size == callInfo.argumentsPassed.size)
+ case _ =>
+ }
+ callInfo.argumentsPassed.foreach(arg => assert(arg.widen.isValueType, arg))
+ callInfo.targs.foreach(targ => assert(!targ.isInstanceOf[TypeBounds], targ))
+ }
+
+ @sharable private var lastId = 0
+
+ private[AbstractCallInfo] def nextId(): Int = {
+ lastId += 1
+ lastId
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/summaries/CallInfo.scala b/compiler/src/dotty/tools/dotc/transform/linker/summaries/CallInfo.scala
new file mode 100644
index 000000000000..1f9a998a168d
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/summaries/CallInfo.scala
@@ -0,0 +1,33 @@
+package dotty.tools.dotc.transform.linker.summaries
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types._
+import dotty.tools.dotc.transform.linker.types.TypeNormalizer
+
+/* When source is not None this call was generated as part of a call to source */
+class CallInfo private (val call: TermRef, val targs: List[Type], val argumentsPassed: List[Type],
+ val source: Option[CallInfo]) extends AbstractCallInfo {
+
+ override def equals(obj: Any): Boolean = obj match {
+ case obj: CallInfo =>
+ call == obj.call && targs == obj.targs && argumentsPassed == obj.argumentsPassed
+ case _ => false
+ }
+
+ override def hashCode(): Int = call.hashCode ^ targs.hashCode ^ argumentsPassed.hashCode
+
+}
+
+object CallInfo {
+
+ def apply(call: TermRef, targs: List[Type], argumentsPassed: List[Type], source: Option[CallInfo] = None)(implicit ctx: Context): CallInfo = {
+ val normalizeType = new TypeNormalizer()
+ val normalCall = normalizeType(call).asInstanceOf[TermRef]
+ val normalTargs = targs.map(x => normalizeType(x))
+ val normalArgumentsPassed = argumentsPassed.map(x => normalizeType(x))
+ val callInfo = new CallInfo(normalCall, normalTargs, normalArgumentsPassed, source)
+ AbstractCallInfo.assertions(callInfo)
+ callInfo
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummary.scala b/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummary.scala
new file mode 100644
index 000000000000..2ec43a2bddc9
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummary.scala
@@ -0,0 +1,14 @@
+package dotty.tools.dotc.transform.linker.summaries
+
+import dotty.tools.dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.Types.Type
+import dotty.tools.dotc.transform.linker.types.ClosureType
+
+class MethodSummary(val methodDef: Symbol,
+ val thisAccessed: Boolean,
+ val methodsCalled: Map[Type, List[CallInfo]],
+ val definedClosures: List[ClosureType],
+ val accessedModules: List[Symbol],
+ val argumentReturned: Byte, // -1 if not known
+ val argumentStoredToHeap: List[Boolean] // not currently collected
+ )
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummaryBuilder.scala b/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummaryBuilder.scala
new file mode 100644
index 000000000000..219c44c8ccca
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/summaries/MethodSummaryBuilder.scala
@@ -0,0 +1,37 @@
+package dotty.tools.dotc.transform.linker.summaries
+
+import dotty.tools.dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.Types.Type
+import dotty.tools.dotc.transform.linker.types.ClosureType
+
+import scala.collection.mutable
+
+class MethodSummaryBuilder(val methodDef: Symbol, argumentStoredToHeap: List[Boolean]) {
+
+ private val methodsCalled: mutable.Map[Type, List[CallInfo]] = mutable.Map.empty
+ private val argumentReturned: Byte = -1 // -1 if not known
+
+ private var thisAccessed: Boolean = false
+ private var accessedModules: List[Symbol] = Nil
+
+ private var definedClosures: List[ClosureType] = Nil
+
+ def setThisAccessed(b: Boolean): Unit = {
+ thisAccessed = b
+ }
+
+ def addAccessedModules(sym: Symbol): Unit = {
+ accessedModules = sym :: accessedModules
+ }
+
+ def addMethodsCalledBy(tpe: Type, methods: List[CallInfo]): Unit = {
+ methodsCalled(tpe) = methods ::: methodsCalled.getOrElse(tpe, Nil)
+ }
+
+ def addDefinedClosure(closure: ClosureType): Unit = {
+ definedClosures = closure :: definedClosures
+ }
+
+ def result(): MethodSummary =
+ new MethodSummary(methodDef, thisAccessed, methodsCalled.toMap, definedClosures, accessedModules, argumentReturned, argumentStoredToHeap)
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/summaries/TastySummaries.scala b/compiler/src/dotty/tools/dotc/transform/linker/summaries/TastySummaries.scala
new file mode 100644
index 000000000000..f22310337fd3
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/summaries/TastySummaries.scala
@@ -0,0 +1,223 @@
+package dotty.tools.dotc.transform.linker.summaries
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.ast.tpd.{Literal, ref}
+import dotty.tools.dotc.core.Constants.Constant
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols.{Symbol, defn}
+import dotty.tools.dotc.core.Decorators._
+import dotty.tools.dotc.core.Types.{TermRef, Type}
+import dotty.tools.dotc.core.tasty._
+import dotty.tools.dotc.transform.linker.types.{ClosureType, PreciseType}
+
+import scala.collection.mutable
+
+
+class TastySummaries {
+
+ private var noSummaryAvailable = Set[Symbol]()
+
+ private var loadedMethodSummaries: Map[Symbol, MethodSummary] = Map.empty
+
+ def apply(d: Symbol)(implicit ctx: Context): Option[MethodSummary] = {
+ if (noSummaryAvailable(d)) None
+ else {
+ if (!loadedMethodSummaries.contains(d)) {
+ val nw = retrieveSummary(d)
+ nw.foreach(ms => loadedMethodSummaries = loadedMethodSummaries.updated(ms.methodDef, ms))
+ if (!loadedMethodSummaries.contains(d))
+ noSummaryAvailable += d
+ }
+ loadedMethodSummaries.get(d)
+ }
+ }
+
+ private def retrieveSummary(sym: Symbol)(implicit ctx: Context): List[MethodSummary] = {
+ val topDenot = sym.topLevelClass.denot.asClass
+ topDenot.dottyUnpickler.fold[List[MethodSummary]](Nil)(_.summaries)
+ }
+
+}
+
+
+object TastySummaries {
+
+ val version = 1
+
+ val sectionName = "MethodSummaries"
+
+ private val argsFlagsSize = 2
+
+ def saveInTasty(methodSummaries: List[MethodSummary])(implicit ctx: Context): Unit = {
+ for (cls <- ctx.compilationUnit.picklers.keySet) {
+ val pickler = ctx.compilationUnit.picklers(cls)
+
+ if (!ctx.scala2Mode) {
+ val buf = new TastyBuffer(5000)
+ val treePickl = pickler.treePkl
+ val anchorTree = tpd.SyntheticValDef(sectionName.toTermName, Literal(Constant(sectionName)))
+
+ treePickl.preRegister(anchorTree)
+ treePickl.pickle(anchorTree :: Nil)
+
+ pickler.newSection(sectionName, buf)
+ val start = treePickl.buf.currentAddr
+
+ val methods = methodSummaries.filter(_.methodDef.topLevelClass == cls)
+
+ new SummaryWriter(treePickl, buf).write(methods)
+
+ val sz = treePickl.buf.currentAddr.index - start.index
+
+ ctx.debuglog("new section for " + cls + " size:"
+ + sz + "/" + buf.currentAddr.index + " increased by " + (sz + buf.length) * 1.0 / start.index)
+ // note: this is huge overestimate. This section contains a lot of refferences to already existing symbols and types
+ // and will be compressed during bytecode generation by TreePickler.compactify
+
+ }
+
+ pickler.treePkl.compactify()
+ }
+ }
+
+ class SummaryReader(tReader: SummariesTreeUnpickler#TreeReader, reader: TastyReader)(implicit ctx: Context) {
+
+ def read(): List[MethodSummary] = {
+ val version = reader.readInt()
+ val methodsSz = reader.readInt()
+ List.fill(methodsSz)(readMethodSummary(tReader, reader))
+ }
+
+ private def readSymbolRef = {
+ val sym = tReader.readType()
+ sym.termSymbol.orElse(sym.typeSymbol).orElse(sym.classSymbol)
+ }
+
+ private def readMethodSummary(tReader: SummariesTreeUnpickler#TreeReader, reader: TastyReader): MethodSummary = {
+ val sym = readSymbolRef
+ val methodsSz = reader.readInt()
+
+ val methodsCalled = new mutable.HashMap[Type, List[CallInfo]]()
+
+ for (_ <- 0 until methodsSz) {
+ val preciseReceiver = reader.readByte() == 1 // TODO use a single compact bits section for all receivers before the loop
+ val receiver = if (preciseReceiver) new PreciseType(tReader.readType()) else tReader.readType()
+
+ val listSz = reader.readInt()
+ methodsCalled(receiver) = List.fill(listSz)(readCallInfo)
+ }
+
+ val accessedModulesSz = reader.readInt()
+ val accessedModules = List.fill(accessedModulesSz)(readSymbolRef)
+
+ val argumentReturned = reader.readByte()
+
+ val bitsExpected = reader.readByte()
+ val (thisAccessed :: argumentStoredToHeap) = readCompactBits(reader, bitsExpected)
+
+ val definedClosures = Nil // TODO
+
+ new MethodSummary(sym, thisAccessed, methodsCalled.toMap, definedClosures, accessedModules, argumentReturned.toByte, argumentStoredToHeap.take(bitsExpected - 1))
+ }
+
+ private def readCallInfo: CallInfo = {
+ val call = tReader.readType()
+
+ val targsSz = reader.readByte()
+ val targs = List.fill(targsSz)(tReader.readType())
+
+ val argsSz = reader.readByte()
+ val argsFlags = readCompactBits(reader, argsFlagsSize * argsSz)
+ val argsPassed = argsFlags.sliding(argsFlagsSize, argsFlagsSize).map(readArg).toList
+
+ val source = None // TODO
+
+ CallInfo(call.asInstanceOf[TermRef], targs, argsPassed, source) // TODO no need to normalize the types
+ }
+
+ private def readArg(argFlags: List[Boolean]): Type = {
+ assert(argFlags.length == argsFlagsSize)
+ val precise :: closure :: _ = argFlags
+ if (precise) new PreciseType(tReader.readType())
+ else if (closure) new ClosureType(tReader.readTpt().asInstanceOf[tpd.Closure], tReader.readType(), readSymbolRef)
+ else tReader.readType()
+ }
+
+ private def readCompactBits(reader: TastyReader, bitsExpected: Int): List[Boolean] = {
+ val bytesExpected = bitsExpected / 8 + (if (bitsExpected % 8 > 0) 1 else 0)
+ val bytes = reader.readBytes(bytesExpected)
+ bytes.toIterator.flatMap { bt =>
+ List((bt & 1) != 0, (bt & 2) != 0, (bt & 4) != 0, (bt & 8) != 0,
+ (bt & 16) != 0, (bt & 32) != 0, (bt & 64) != 0, (bt & 128) != 0)
+ }.take(bitsExpected).toList
+ }
+ }
+
+ private class SummaryWriter(treePickl: TreePickler, buf: TastyBuffer)(implicit ctx: Context) {
+ def write(methods: List[MethodSummary]) = {
+ buf.writeInt(version) //1
+ buf.writeInt(methods.length) // 19
+ methods.foreach(serializeMethodSummary)
+ }
+
+ private def writeSymbolRef(sym: Symbol) =
+ treePickl.pickleType(ref(sym).tpe)
+
+ private def serializeMethodSummary(ms: MethodSummary) = {
+ writeSymbolRef(ms.methodDef) //26
+
+ buf.writeInt(ms.methodsCalled.size) //29
+ for ((receiver, methods) <- ms.methodsCalled) {
+ // TODO use a single compact bits section for all receivers before the loop
+ buf.writeByte(if (receiver.isInstanceOf[PreciseType]) 1 else 0)
+ val rec = receiver match {
+ case receiver: PreciseType => receiver.underlying
+ case _ => receiver
+ }
+ treePickl.pickleType(rec)
+ buf.writeInt(methods.size)
+
+ methods.foreach(writeCallInfo)
+ }
+
+ buf.writeInt(ms.accessedModules.length)
+ ms.accessedModules foreach writeSymbolRef
+
+ buf.writeByte(ms.argumentReturned)
+ val flags = ms.thisAccessed :: ms.argumentStoredToHeap
+ buf.writeByte(flags.length)
+ writeCompactBits(flags)
+ }
+
+ private def writeCallInfo(c: CallInfo): Unit = {
+ treePickl.pickleType(c.call)
+
+ buf.writeByte(c.targs.size)
+ c.targs.foreach(targ => treePickl.pickleType(targ))
+
+ buf.writeByte(c.argumentsPassed.size)
+ val argFlags =
+ c.argumentsPassed.flatMap(arg => List(arg.isInstanceOf[PreciseType], arg.isInstanceOf[ClosureType]))
+ assert(argFlags.size == argsFlagsSize * c.argumentsPassed.size)
+ writeCompactBits(argFlags)
+ c.argumentsPassed.foreach(writeArg)
+ }
+
+ private def writeArg(arg: Type): Unit = arg match {
+ case arg: PreciseType =>
+ treePickl.pickleType(arg.underlying)
+ case arg: ClosureType =>
+ treePickl.pickleTree(arg.meth)
+ treePickl.pickleType(arg.u)
+ writeSymbolRef(arg.implementedMethod)
+ case arg =>
+ treePickl.pickleType(arg)
+ }
+
+ private def writeCompactBits(ls: List[Boolean]): Unit = {
+ def foldByte(bt: List[Boolean]) = bt.foldRight(0)((bl: Boolean, acc: Int) => (if (bl) 1 else 0) + (acc << 1))
+ ls.grouped(8).map(foldByte).foreach(buf.writeByte)
+ }
+ }
+
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/types/ClosureType.scala b/compiler/src/dotty/tools/dotc/transform/linker/types/ClosureType.scala
new file mode 100644
index 000000000000..4687d7632fdf
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/types/ClosureType.scala
@@ -0,0 +1,30 @@
+package dotty.tools.dotc.transform.linker.types
+
+import dotty.tools.dotc.ast.tpd
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.Types.{SingletonType, Type}
+
+class ClosureType(val meth: tpd.Closure, val u: Type, val implementedMethod: Symbol)(implicit ctx: Context) extends SingletonType {
+
+ /** The type to which this proxy forwards operations. */
+ def underlying(implicit ctx: Context): Type = u
+
+ /** customized hash code of this type.
+ * NotCached for uncached types. Cached types
+ * compute hash and use it as the type's hashCode.
+ */
+ override val hash: Int = implementedMethod.hashCode() + meth.meth.symbol.hashCode()
+
+ override def hashCode() = hash
+
+ override def equals(other: Any): Boolean = other match {
+ case that: ClosureType =>
+ meth == that.meth &&
+ u == that.u &&
+ implementedMethod == that.implementedMethod
+ case _ => false
+ }
+
+ override def toString: String = s"ClosureType($meth, $u, $implementedMethod)"
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/types/ErazedType.scala b/compiler/src/dotty/tools/dotc/transform/linker/types/ErazedType.scala
new file mode 100644
index 000000000000..68d98e123d59
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/types/ErazedType.scala
@@ -0,0 +1,9 @@
+package dotty.tools.dotc.transform.linker.types
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Types.{Type, UncachedProxyType}
+
+class ErazedType extends UncachedProxyType {
+ /** The type to which this proxy forwards operations. */
+ def underlying(implicit ctx: Context): Type = ctx.definitions.AnyType
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/types/JavaAllocatedType.scala b/compiler/src/dotty/tools/dotc/transform/linker/types/JavaAllocatedType.scala
new file mode 100644
index 000000000000..b42485ad3324
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/types/JavaAllocatedType.scala
@@ -0,0 +1,34 @@
+package dotty.tools.dotc.transform.linker.types
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Hashable
+import dotty.tools.dotc.core.Types.{PolyType, SingletonType, Type, TypeParamRef}
+
+class JavaAllocatedType(private val u: Type)(implicit ctx: Context) extends SingletonType {
+
+ assert(!u.widenDealias.isInstanceOf[JavaAllocatedType], u.widenDealias)
+ assert(!u.widenDealias.isInstanceOf[TypeParamRef], u.widenDealias)
+ assert(!u.widenDealias.isInstanceOf[PolyType], u.widenDealias)
+
+ /** customized hash code of this type.
+ * NotCached for uncached types. Cached types
+ * compute hash and use it as the type's hashCode.
+ */
+ def hash: Int = {
+ val underlying = u.hash
+ if (underlying == Hashable.NotCached) Hashable.NotCached
+ else if (underlying == Hashable.NotCached - 1) underlying
+ else underlying + 1
+ }
+
+ override def hashCode(): Int = hash
+
+ def underlying(implicit ctx: Context): Type = u
+
+ override def equals(other: Any): Boolean = other match {
+ case that: JavaAllocatedType => this.u == that.u
+ case _ => false
+ }
+
+ override def toString: String = s"JavaAllocatedType($u)"
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/types/PreciseType.scala b/compiler/src/dotty/tools/dotc/transform/linker/types/PreciseType.scala
new file mode 100644
index 000000000000..78b00f94dea0
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/types/PreciseType.scala
@@ -0,0 +1,30 @@
+package dotty.tools.dotc.transform.linker.types
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Hashable
+import dotty.tools.dotc.core.Types.{SingletonType, Type}
+
+class PreciseType(private[PreciseType] val u: Type) extends SingletonType {
+
+ /** customized hash code of this type.
+ * NotCached for uncached types. Cached types
+ * compute hash and use it as the type's hashCode.
+ */
+ def hash: Int = {
+ val underlying = u.hash
+ if (underlying == Hashable.NotCached) Hashable.NotCached
+ else if (underlying == Hashable.NotCached - 1) underlying
+ else underlying + 1
+ }
+
+ override def hashCode(): Int = hash
+
+ def underlying(implicit ctx: Context): Type = u
+
+ override def equals(other: Any): Boolean = other match {
+ case that: PreciseType => this.u == that.u
+ case _ => false
+ }
+
+ override def toString: String = s"PreciseType($u)"
+}
diff --git a/compiler/src/dotty/tools/dotc/transform/linker/types/TypeNormalizer.scala b/compiler/src/dotty/tools/dotc/transform/linker/types/TypeNormalizer.scala
new file mode 100644
index 000000000000..92747d68851b
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/transform/linker/types/TypeNormalizer.scala
@@ -0,0 +1,25 @@
+package dotty.tools.dotc.transform.linker.types
+
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Names.Name
+import dotty.tools.dotc.core.Types._
+
+class TypeNormalizer(implicit ctx: Context) extends TypeMap {
+
+ override def apply(tp: Type): Type = tp match {
+ case tp: TypeRef if tp.typeSymbol.isClass && tp.typeSymbol.isStatic =>
+ val sym = tp.typeSymbol
+ NamedType(sym.owner.thisType, sym.name, sym.denot)
+
+ case tp: RefinedType =>
+ def listRefinements(tp: RefinedType, acc: List[(Name, Type)]): (Type, List[(Name, Type)]) = tp.parent match {
+ case p: RefinedType => listRefinements(p, (tp.refinedName, tp.refinedInfo) :: acc)
+ case p => (p, (tp.refinedName, tp.refinedInfo) :: acc)
+ }
+ val (parent, refinements) = listRefinements(tp, Nil)
+ val normalizedParent = apply(parent)
+ refinements.sortBy(_._1.toString).foldLeft[Type](normalizedParent)((acc, x) => RefinedType(acc, x._1, x._2))
+
+ case _ => mapOver(tp)
+ }
+}
diff --git a/compiler/test/dotc/dotty-library.whitelist b/compiler/test/dotc/dotty-library.whitelist
new file mode 100644
index 000000000000..7caae78a221b
--- /dev/null
+++ b/compiler/test/dotc/dotty-library.whitelist
@@ -0,0 +1,11 @@
+scala/Product0.scala
+scala/Eq.scala
+scala/FunctionXXL.scala
+
+dotty/DottyPredef.scala
+dotty/runtime/Arrays.scala
+dotty/runtime/DeadCodeEliminated.scala
+dotty/runtime/LazyHolders.scala
+dotty/runtime/LazyVals.scala
+#dotty/runtime/LegacyApp.scala
+dotty/runtime/vc/VCPrototype.scala
diff --git a/compiler/test/dotc/scala-collections.blacklist b/compiler/test/dotc/scala-collections.blacklist
index d6972a645ed3..8979868aeb21 100644
--- a/compiler/test/dotc/scala-collections.blacklist
+++ b/compiler/test/dotc/scala-collections.blacklist
@@ -20,7 +20,8 @@ scala/collection/parallel/ParMap.scala
scala/collection/parallel/ParMapLike.scala
# -Yno-deep-subtypes fails
-
+scala/sys/process/ProcessImpl.scala
+# Breaks in NameKinds
## Ycheck failures, presumably linked to TailCalls
diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala
index 8af721ca6cb5..08d7d2323fe1 100644
--- a/compiler/test/dotty/tools/dotc/CompilationTests.scala
+++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala
@@ -5,6 +5,7 @@ package dotc
import org.junit.{ Test, BeforeClass, AfterClass }
import java.nio.file._
+import dotty.tools.io.JFile
import java.util.stream.{ Stream => JStream }
import scala.collection.JavaConverters._
import scala.util.matching.Regex
@@ -28,8 +29,6 @@ class CompilationTests extends ParallelTesting {
// Positive tests ------------------------------------------------------------
@Test def compilePos: Unit = {
- compileList("compileStdLib", StdLibSources.whitelisted, scala2Mode.and("-migration", "-Yno-inline")) +
- compileDir("../collection-strawman/src/main", defaultOptions) +
compileDir("../compiler/src/dotty/tools/dotc/ast", defaultOptions) +
compileDir("../compiler/src/dotty/tools/dotc/config", defaultOptions) +
compileDir("../compiler/src/dotty/tools/dotc/core", allowDeepSubtypes) +
@@ -295,15 +294,83 @@ class CompilationTests extends ParallelTesting {
tests.delete()
}
+ @Test def linkAll: Unit = {
+ def commonLibraries = {
+ compileList("stdlib", StdLibSources.whitelisted, scala2Mode.and("-migration", "-Yno-inline")) +
+ compileList("strawman", strawmanSources, defaultOptions)
+ }
- private val (compilerSources, backendSources, backendJvmSources) = {
- def sources(paths: JStream[Path], excludedFiles: List[String] = Nil): List[String] =
- paths.iterator().asScala
- .filter(path =>
- (path.toString.endsWith(".scala") || path.toString.endsWith(".java"))
- && !excludedFiles.contains(path.getFileName.toString))
- .map(_.toString).toList
+ // Compile and setup libraries
+
+ val libraries = commonLibraries.keepOutput.checkCompile()
+
+ val commonLibrariesPath = defaultOutputDir + "commonLibraries/"
+
+ val utilsOnlyClassPath = mkClassPath(Jars.dottyTestDeps)
+ val stdlibClassPath = mkClassPath(commonLibrariesPath + "stdlib" :: Jars.dottyTestDeps)
+ val strawmanClassPath = mkClassPath(commonLibrariesPath + "strawman" :: Jars.dottyTestDeps)
+
+ def linkTests(dir: String, flags: Array[String], nameSuffix: String = ""): CompilationTest = {
+ val testsDir = new JFile(dir)
+ val tests = for (test <- testsDir.listFiles() if test.isDirectory || test.getName.endsWith(".scala")) yield {
+ val name = if (test.isDirectory) test.getName else test.getName.dropRight(6)
+ val files0 = sources(Files.walk(testsDir.toPath))
+ val files = if (test.isDirectory) files0 else test.getAbsolutePath :: Nil
+ compileList(name, files, flags, testsDir.getName + nameSuffix)
+ }
+ assert(tests.nonEmpty)
+ if (tests.length == 1) tests.head
+ else tests.reduce((a, b) => a + b)
+ }
+
+ // DCE tests
+
+ def linkDCETests = compileFilesInDir("../tests/link/dce", linkDCE ++ classPath)
+ def linkAggressiveDCETests = compileFilesInDir("../tests/link/dce", linkAggressiveDCE ++ classPath)
+ def linkStrawmanDCETests = linkTests("../tests/link/strawman-dce", linkDCE ++ strawmanClassPath)
+ def linkStrawmanAggressiveDCETests = linkTests("../tests/link/strawman-dce", linkAggressiveDCE ++ strawmanClassPath, "-aggressive")
+ def linkStdLibDCE = {
+ val testsDir = new JFile("../tests/link/stdlib-dce")
+ val tests = for (test <- testsDir.listFiles() if test.isDirectory) yield {
+ val files = sources(Files.walk(test.toPath))
+ compileList(test.getName, files, scala2Mode ++ linkDCE ++ stdlibClassPath)
+ }
+ tests.reduce((a, b) => a + b)
+ }
+
+ // specialization tests
+
+ def linkSpecializeTests = linkTests("../tests/link/specialize", linkSpecialize ++ utilsOnlyClassPath)
+ def linkStrawmanSpecializeTests = linkTests("../tests/link/strawman-specialize", linkSpecialize ++ strawmanClassPath)
+
+ // Plain strawman tests
+
+ def strawmanTest = compileFilesInDir("../tests/strawman", basicDefaultOptions ++ strawmanClassPath)
+
+ // Run all tests
+
+ {
+ linkDCETests +
+ linkAggressiveDCETests +
+ /* linkStrawmanDCETests +
+ linkStrawmanAggressiveDCETests + */
+ linkStdLibDCE +
+ linkSpecializeTests /* +
+ linkStrawmanSpecializeTests +
+ strawmanTest */
+ }.checkRuns()
+
+ // libraries.delete()
+ }
+
+ private def strawmanSources =
+ sources(Files.walk(Paths.get("../collection-strawman/src/main")))
+
+ private def testUtils =
+ sources(Files.walk(Paths.get("../tests/utils/")))
+
+ private val (compilerSources, backendSources, backendJvmSources) = {
val compilerDir = Paths.get("../compiler/src")
val compilerSources0 = sources(Files.walk(compilerDir))
@@ -323,6 +390,13 @@ class CompilationTests extends ParallelTesting {
(compilerSources0, backendSources0, backendJvmSources0)
}
+
+ private def sources(paths: JStream[Path], excludedFiles: List[String] = Nil): List[String] =
+ paths.iterator().asScala
+ .filter(path =>
+ (path.toString.endsWith(".scala") || path.toString.endsWith(".java"))
+ && !excludedFiles.contains(path.getFileName.toString))
+ .map(_.toString).toList
}
object CompilationTests {
diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
index dacc5646d3c4..6e5920c122e4 100644
--- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
+++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala
@@ -1079,8 +1079,7 @@ trait ParallelTesting extends RunnerOrchestration { self =>
* `testName` since files can be in separate directories and or be otherwise
* dissociated
*/
- def compileList(testName: String, files: List[String], flags: Array[String])(implicit outDirectory: String): CompilationTest = {
- val callingMethod = getCallingMethod
+ def compileList(testName: String, files: List[String], flags: Array[String], callingMethod: String = getCallingMethod)(implicit outDirectory: String): CompilationTest = {
val outDir = outDirectory + callingMethod + "/" + testName + "/"
// Directories in which to compile all containing files with `flags`:
diff --git a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala
index 440a0a629534..f0e8d55ba3ab 100644
--- a/compiler/test/dotty/tools/vulpix/TestConfiguration.scala
+++ b/compiler/test/dotty/tools/vulpix/TestConfiguration.scala
@@ -23,8 +23,10 @@ object TestConfiguration {
"-Yforce-sbt-phases"
)
- val classPath = {
- val paths = Jars.dottyTestDeps map { p =>
+ val classPath = mkClassPath(Jars.dottyTestDeps)
+
+ def mkClassPath(classPaths: List[String]): Array[String] = {
+ val paths = classPaths map { p =>
val file = new java.io.File(p)
assert(
file.exists,
@@ -52,7 +54,8 @@ object TestConfiguration {
private val yCheckOptions = Array("-Ycheck:tailrec,resolveSuper,mixin,arrayConstructors,labelDef")
- val defaultUnoptimised = noCheckOptions ++ checkOptions ++ yCheckOptions ++ classPath
+ val basicDefaultOptions = noCheckOptions ++ checkOptions ++ yCheckOptions
+ val defaultUnoptimised = basicDefaultOptions ++ classPath
val defaultOptions = defaultUnoptimised :+ "-optimise"
val allowDeepSubtypes = defaultOptions diff Array("-Yno-deep-subtypes")
val allowDoubleBindings = defaultOptions diff Array("-Yno-double-bindings")
@@ -64,4 +67,13 @@ object TestConfiguration {
val scala2Mode = defaultOptions ++ Array("-language:Scala2")
val explicitUTF8 = defaultOptions ++ Array("-encoding", "UTF8")
val explicitUTF16 = defaultOptions ++ Array("-encoding", "UTF16")
+
+ val stdlibMode = scala2Mode.and("-migration", "-Yno-inline")
+ val linkStdlibMode = stdlibMode.and("-Ylink-stdlib")
+
+ val linkCommon = Array("-link-vis", "-Ylog:callGraph") ++ basicDefaultOptions
+ val linkDCEcommon = Array("-link-java-conservative", "-Ylink-dce-checks") ++ linkCommon
+ val linkDCE = "-link-dce" +: linkDCEcommon
+ val linkAggressiveDCE = "-link-aggressive-dce" +: linkDCEcommon
+ val linkSpecialize = Array("-link-specialize", "-Ylog:specializeClass,specializeClassParents") ++ linkCommon
}
diff --git a/library/src/dotty/runtime/DeadCodeEliminated.scala b/library/src/dotty/runtime/DeadCodeEliminated.scala
new file mode 100644
index 000000000000..04df43074d1f
--- /dev/null
+++ b/library/src/dotty/runtime/DeadCodeEliminated.scala
@@ -0,0 +1,3 @@
+package dotty.runtime
+
+class DeadCodeEliminated extends RuntimeException
diff --git a/library/src/scala/EntryPoint.scala b/library/src/scala/EntryPoint.scala
new file mode 100644
index 000000000000..0bb8a62ba71e
--- /dev/null
+++ b/library/src/scala/EntryPoint.scala
@@ -0,0 +1,3 @@
+package scala
+
+final class EntryPoint extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/internal/link/AssertNotReachable.scala b/library/src/scala/annotation/internal/link/AssertNotReachable.scala
new file mode 100644
index 000000000000..8849f8dfa8d3
--- /dev/null
+++ b/library/src/scala/annotation/internal/link/AssertNotReachable.scala
@@ -0,0 +1,8 @@
+package scala.annotation.internal.link
+
+/** Assert at compile time that the symbol of a method is not reachable.
+ *
+ * This does not work on methods that get created later like getters,
+ * setters, bridges, ...
+ */
+final class AssertNotReachable extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/internal/link/AssertReachable.scala b/library/src/scala/annotation/internal/link/AssertReachable.scala
new file mode 100644
index 000000000000..441f0618116a
--- /dev/null
+++ b/library/src/scala/annotation/internal/link/AssertReachable.scala
@@ -0,0 +1,8 @@
+package scala.annotation.internal.link
+
+/** Assert at compile time that the symbol of a method is reachable.
+ *
+ * This does not work on methods that get created later like getters,
+ * setters, bridges, ...
+ */
+final class AssertReachable extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/internal/link/CallGraphBounds.scala b/library/src/scala/annotation/internal/link/CallGraphBounds.scala
new file mode 100644
index 000000000000..063bb8adc644
--- /dev/null
+++ b/library/src/scala/annotation/internal/link/CallGraphBounds.scala
@@ -0,0 +1,3 @@
+package scala.annotation.internal.link
+
+final class CallGraphBounds(reachableClasses: Int, classesWithReachableMethods: Int, reachableMethods: Int) extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/internal/link/DoNotDeadCodeEliminate.scala b/library/src/scala/annotation/internal/link/DoNotDeadCodeEliminate.scala
new file mode 100644
index 000000000000..54dc14cd6acd
--- /dev/null
+++ b/library/src/scala/annotation/internal/link/DoNotDeadCodeEliminate.scala
@@ -0,0 +1,4 @@
+package scala.annotation.internal.link
+
+/** Ignores dead code elimination of this method */
+final class DoNotDeadCodeEliminate extends scala.annotation.StaticAnnotation
diff --git a/project/Build.scala b/project/Build.scala
index fea9b5496547..c2827e5c53bc 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -229,6 +229,13 @@ object Build {
libraryDependencies := Seq()
)
+ lazy val linkBootstrappedSettings = Seq(
+ scalacOptions ++= Seq(
+ "-link-vis",
+ "-Ylog:callGraph"
+ )
+ )
+
/** Projects -------------------------------------------------------------- */
// Needed because the dotty project aggregates dotty-sbt-bridge but dotty-sbt-bridge
@@ -636,6 +643,7 @@ object Build {
dependsOn(`dotty-interfaces`).
dependsOn(`dotty-library-bootstrapped`).
settings(commonBootstrappedSettings).
+ // settings(linkBootstrappedSettings).
settings(dottyCompilerSettings).
settings(
packageAll := {
diff --git a/tests/link/dce-failing/link-closure-generic-context-1.check b/tests/link/dce-failing/link-closure-generic-context-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce-failing/link-closure-generic-context-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce-failing/link-closure-generic-context-1.scala b/tests/link/dce-failing/link-closure-generic-context-1.scala
new file mode 100644
index 000000000000..b2dd99e56b88
--- /dev/null
+++ b/tests/link/dce-failing/link-closure-generic-context-1.scala
@@ -0,0 +1,10 @@
+import scala.annotation.internal
+
+object Test {
+ class A[T] {
+ def f(y: T): T = ((x: T) => x)(y)
+ }
+
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 8, reachableMethods = 9)
+ def main(args: Array[String]): Unit = System.out.println((new A[Int]).f(42))
+}
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-closure-generic-context-2.check b/tests/link/dce-failing/link-closure-generic-context-2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce-failing/link-closure-generic-context-2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce-failing/link-closure-generic-context-2.scala b/tests/link/dce-failing/link-closure-generic-context-2.scala
new file mode 100644
index 000000000000..ec530c9f80c3
--- /dev/null
+++ b/tests/link/dce-failing/link-closure-generic-context-2.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ class A[T] {
+ def f(y: T): T = ((x: T) => x)(y)
+ }
+
+ class B[T] extends A[T]
+
+ // @internal.link.CallGraphBounds(reachableClasses = 1, classesWithReachableMethods = 1, reachableMethods = 1)
+ def main(args: Array[String]): Unit = System.out.println((new B[Int]).f(42))
+}
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-code-from-java-1.scala b/tests/link/dce-failing/link-code-from-java-1.scala
new file mode 100644
index 000000000000..79761b6b62a5
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-1.scala
@@ -0,0 +1,82 @@
+import java.io.File
+import java.io.FileFilter
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import java.lang.reflect.Type
+
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 139, classesWithReachableMethods = 23, reachableMethods = 85)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val a = new A
+ Test.shouldDCE(a.f1)
+ a.hashCode()
+ a.equals(a)
+ a.toString
+
+ val b = new B {}
+ Test.shouldDCE(b.f1)
+ b.hashCode()
+ b.equals(b)
+ b.toString
+
+ val c = new C {}
+ Test.shouldDCE(c.f1)
+ c.hashCode()
+ c.equals(c)
+ c.toString
+ }
+
+ @EntryPoint def entryPoint(): Unit = {
+ System.out.println(new A)
+ System.out.println(new B {})
+ System.out.println(new C {})
+ }
+}
+
+class A {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+}
+
+abstract class B {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+}
+
+trait C {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+}
diff --git a/tests/link/dce-failing/link-code-from-java-2-c.check b/tests/link/dce-failing/link-code-from-java-2-c.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-2-c.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce-failing/link-code-from-java-2-c.scala b/tests/link/dce-failing/link-code-from-java-2-c.scala
new file mode 100644
index 000000000000..2dc05b73a20b
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-2-c.scala
@@ -0,0 +1,52 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 106, classesWithReachableMethods = 19, reachableMethods = 70)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val c = new C {}
+ Test.shouldDCE(c.f1)
+ c.hashCode()
+ c.equals(c)
+ c.toString
+ c.update(new Observable, null)
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new C {})
+ }
+}
+
+trait C extends java.util.Observer {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+ override def update(o: Observable, arg: scala.Any): Unit = ()
+}
diff --git a/tests/link/dce-failing/link-code-from-java-3-a.check b/tests/link/dce-failing/link-code-from-java-3-a.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-a.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce-failing/link-code-from-java-3-a.scala b/tests/link/dce-failing/link-code-from-java-3-a.scala
new file mode 100644
index 000000000000..b281568ad055
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-a.scala
@@ -0,0 +1,54 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 1, classesWithReachableMethods = 1, reachableMethods = 1)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val a = new A[AA]
+ a.hasNext
+ a.next()
+ val aa = new AA
+ Test.shouldDCE(aa.f)
+ aa.toString
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new A[AA])
+ }
+}
+
+class AA {
+ def f = 42
+ override def toString: String = super.toString
+}
+
+class A[E] extends java.util.Iterator[E] {
+ override def next(): E = null.asInstanceOf[E]
+ override def hasNext: Boolean = false
+}
diff --git a/tests/link/dce-failing/link-code-from-java-3-b.check b/tests/link/dce-failing/link-code-from-java-3-b.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-b.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce-failing/link-code-from-java-3-b.scala b/tests/link/dce-failing/link-code-from-java-3-b.scala
new file mode 100644
index 000000000000..25823bbf3c47
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-b.scala
@@ -0,0 +1,54 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 1, classesWithReachableMethods = 1, reachableMethods = 1)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val b = new B[BB] {}
+ b.hasNext
+ b.next()
+ val bb = new BB
+ Test.shouldDCE(bb.f)
+ bb.toString
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new B[BB] {})
+ }
+}
+
+class BB {
+ def f = 43
+ override def toString: String = super.toString
+}
+
+abstract class B[E] extends java.util.Iterator[E] {
+ override def next(): E = null.asInstanceOf[E]
+ override def hasNext(): Boolean = false
+}
diff --git a/tests/link/dce-failing/link-code-from-java-3-c.check b/tests/link/dce-failing/link-code-from-java-3-c.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-c.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce-failing/link-code-from-java-3-c.scala b/tests/link/dce-failing/link-code-from-java-3-c.scala
new file mode 100644
index 000000000000..8b14750a84ac
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-3-c.scala
@@ -0,0 +1,54 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 1, classesWithReachableMethods = 1, reachableMethods = 1)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val c = new C[CC] {}
+ c.hasNext
+ c.next()
+ val cc = new CC
+ Test.shouldDCE(cc.f)
+ cc.toString
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new C[CC] {})
+ }
+}
+
+class CC {
+ def f = 44
+ override def toString: String = super.toString
+}
+
+trait C[E] extends java.util.Iterator[E] {
+ override def next(): E = null.asInstanceOf[E]
+ override def hasNext(): Boolean = false
+}
diff --git a/tests/link/dce-failing/link-code-from-java-4.scala b/tests/link/dce-failing/link-code-from-java-4.scala
new file mode 100644
index 000000000000..92c25c121e15
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-4.scala
@@ -0,0 +1,89 @@
+import java.util
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 1, classesWithReachableMethods = 1, reachableMethods = 1)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ val coll = new Coll[AA]
+ coll.removeAll(coll)
+ coll.retainAll(coll)
+ coll.clear()
+ coll.toArray
+ coll.toArray(new Array[AA](0))
+ coll.size()
+ coll.remove(new AA)
+ coll.contains(new AA)
+ coll.addAll(coll)
+ coll.iterator()
+ coll.isEmpty
+ coll.containsAll(coll)
+ coll.add(new AA)
+
+ val aa = new AA
+ Test.shouldDCE(aa.f)
+ aa.toString
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new Coll[AA])
+ }
+}
+
+class AA {
+ def f = 42
+ override def toString: String = super.toString
+}
+
+class Coll[E] extends java.util.Collection[E] {
+ def removeAll(c: util.Collection[_]): Boolean = false
+
+ def retainAll(c: util.Collection[_]): Boolean = false
+
+ def clear(): Unit = ()
+
+ def toArray: Array[Object] = null
+
+ // FIXME cannot compile due to issue #1747
+ def toArray[T](a: Array[T]): Array[T] = null
+
+ def size(): Int = 0
+
+ def remove(o: scala.Any): Boolean = false
+
+ def contains(o: scala.Any): Boolean = false
+
+ def addAll(c: util.Collection[_ <: E]): Boolean = false
+
+ def iterator(): util.Iterator[E] = null
+
+ def isEmpty: Boolean = false
+
+ def containsAll(c: util.Collection[_]): Boolean = false
+
+ def add(e: E): Boolean = false
+}
diff --git a/tests/link/dce-failing/link-code-from-java-5.check b/tests/link/dce-failing/link-code-from-java-5.check
new file mode 100644
index 000000000000..f70d7bba4ae1
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-5.check
@@ -0,0 +1 @@
+42
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-code-from-java-5.scala b/tests/link/dce-failing/link-code-from-java-5.scala
new file mode 100644
index 000000000000..3bf642a0d217
--- /dev/null
+++ b/tests/link/dce-failing/link-code-from-java-5.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+import scala.math.Ordering
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 91, classesWithReachableMethods = 24, reachableMethods = 93)
+ def main(args: Array[String]): Unit = {
+ val arr = new Array[Object](1)
+ arr(0) = 42
+ java.util.Arrays.sort(arr, Ordering.Int.asInstanceOf[Ordering[Object]]) // extracted from SeqLike.sorted
+ System.out.println(arr(0))
+ }
+}
diff --git a/tests/link/dce-failing/link-java-polimorphic-method-3.check b/tests/link/dce-failing/link-java-polimorphic-method-3.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce-failing/link-java-polimorphic-method-3.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce-failing/link-java-polimorphic-method-3/Bar.java b/tests/link/dce-failing/link-java-polimorphic-method-3/Bar.java
new file mode 100644
index 000000000000..f48a7e143589
--- /dev/null
+++ b/tests/link/dce-failing/link-java-polimorphic-method-3/Bar.java
@@ -0,0 +1,4 @@
+
+public class Bar {
+ public T get();
+}
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-java-polimorphic-method-3/Foo.java b/tests/link/dce-failing/link-java-polimorphic-method-3/Foo.java
new file mode 100644
index 000000000000..2ca7b6ce395c
--- /dev/null
+++ b/tests/link/dce-failing/link-java-polimorphic-method-3/Foo.java
@@ -0,0 +1,10 @@
+
+public class Foo {
+ public static String foo(Bar extends Foo> bar) {
+ return bar.get.string
+ }
+
+ public String string() {
+ return "42";
+ }
+}
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-java-polimorphic-method-3/Test.scala b/tests/link/dce-failing/link-java-polimorphic-method-3/Test.scala
new file mode 100644
index 000000000000..556b78789b5c
--- /dev/null
+++ b/tests/link/dce-failing/link-java-polimorphic-method-3/Test.scala
@@ -0,0 +1,15 @@
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 40, classesWithReachableMethods = 7, reachableMethods = 55)
+ def main(args: Array[String]): Unit = {
+ System.out.println(new Baz)
+ }
+}
+
+class Baz extends Bar[Foo] {
+
+ def get(): Foo = new Foo
+
+ override def toString(): String = Foo.foo(this)
+}
\ No newline at end of file
diff --git a/tests/link/dce-failing/link-predef-toList/MainGenericRunner.java b/tests/link/dce-failing/link-predef-toList/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/dce-failing/link-predef-toList/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/dce-failing/link-predef-toList/Predef.scala b/tests/link/dce-failing/link-predef-toList/Predef.scala
new file mode 100644
index 000000000000..536952779ea0
--- /dev/null
+++ b/tests/link/dce-failing/link-predef-toList/Predef.scala
@@ -0,0 +1,514 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic }
+import immutable.StringOps
+import mutable.ArrayOps
+import generic.CanBuildFrom
+import scala.annotation.{ elidable, implicitNotFound }
+import scala.annotation.elidable.ASSERTION
+import scala.language.{implicitConversions, existentials}
+import scala.io.StdIn
+
+/** The `Predef` object provides definitions that are accessible in all Scala
+ * compilation units without explicit qualification.
+ *
+ * === Commonly Used Types ===
+ * Predef provides type aliases for types which are commonly used, such as
+ * the immutable collection types [[scala.collection.immutable.Map]],
+ * [[scala.collection.immutable.Set]], and the [[scala.collection.immutable.List]]
+ * constructors ([[scala.collection.immutable.::]] and
+ * [[scala.collection.immutable.Nil]]).
+ *
+ * === Console I/O ===
+ * Predef provides a number of simple functions for console I/O, such as
+ * `print`, `println`, `readLine`, `readInt`, etc. These functions are all
+ * aliases of the functions provided by [[scala.Console]].
+ *
+ * === Assertions ===
+ *
+ * A set of `assert` functions are provided for use as a way to document
+ * and dynamically check invariants in code. `assert` statements can be elided
+ * at runtime by providing the command line argument `-Xdisable-assertions` to
+ * the `scala` command.
+ *
+ * Variants of `assert` intended for use with static analysis tools are also
+ * provided: `assume`, `require` and `ensuring`. `require` and `ensuring` are
+ * intended for use as a means of design-by-contract style specification
+ * of pre- and post-conditions on functions, with the intention that these
+ * specifications could be consumed by a static analysis tool. For instance,
+ *
+ * {{{
+ * def addNaturals(nats: List[Int]): Int = {
+ * require(nats forall (_ >= 0), "List contains negative numbers")
+ * nats.foldLeft(0)(_ + _)
+ * } ensuring(_ >= 0)
+ * }}}
+ *
+ * The declaration of `addNaturals` states that the list of integers passed should
+ * only contain natural numbers (i.e. non-negative), and that the result returned
+ * will also be natural. `require` is distinct from `assert` in that if the
+ * condition fails, then the caller of the function is to blame rather than a
+ * logical error having been made within `addNaturals` itself. `ensures` is a
+ * form of `assert` that declares the guarantee the function is providing with
+ * regards to it's return value.
+ *
+ * === Implicit Conversions ===
+ * A number of commonly applied implicit conversions are also defined here, and
+ * in the parent type [[scala.LowPriorityImplicits]]. Implicit conversions
+ * are provided for the "widening" of numeric values, for instance, converting a
+ * Short value to a Long value as required, and to add additional higher-order
+ * functions to Array values. These are described in more detail in the documentation of [[scala.Array]].
+ */
+object Predef extends LowPriorityImplicits with DeprecatedPredef {
+
+ // ADDED TO TEST DCE
+ println("Predef loaded")
+
+ /**
+ * Retrieve the runtime representation of a class type. `classOf[T]` is equivalent to
+ * the class literal `T.class` in Java.
+ *
+ * @example {{{
+ * val listClass = classOf[List[_]]
+ * // listClass is java.lang.Class[List[_]] = class scala.collection.immutable.List
+ *
+ * val mapIntString = classOf[Map[Int,String]]
+ * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map
+ * }}}
+ */
+ def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler.
+
+ type String = java.lang.String
+ type Class[T] = java.lang.Class[T]
+
+ // miscelleaneous -----------------------------------------------------
+ scala.`package` // to force scala package object to be seen.
+ scala.collection.immutable.List // to force Nil, :: to be seen.
+
+ type Function[-A, +B] = Function1[A, B]
+
+ type Map[A, +B] = immutable.Map[A, B]
+ type Set[A] = immutable.Set[A]
+ val Map = immutable.Map
+ val Set = immutable.Set
+
+ // Manifest types, companions, and incantations for summoning
+ @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.")
+ @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0")
+ type ClassManifest[T] = scala.reflect.ClassManifest[T]
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ type OptManifest[T] = scala.reflect.OptManifest[T]
+ @annotation.implicitNotFound(msg = "No Manifest available for ${T}.")
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+ type Manifest[T] = scala.reflect.Manifest[T]
+ @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0")
+ val ClassManifest = scala.reflect.ClassManifest
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+ // val Manifest = scala.reflect.Manifest
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ val NoManifest = scala.reflect.NoManifest
+
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("Use scala.reflect.classTag[T] and scala.reflect.runtime.universe.typeTag[T] instead", "2.10.0")
+ def manifest[T](implicit m: Manifest[T]) = m
+ @deprecated("Use scala.reflect.classTag[T] instead", "2.10.0")
+ def classManifest[T](implicit m: ClassManifest[T]) = m
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ def optManifest[T](implicit m: OptManifest[T]) = m
+
+ // Minor variations on identity functions
+ def identity[A](x: A): A = x // @see `conforms` for the implicit version
+ @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero`
+ @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements
+
+ // errors and asserts -------------------------------------------------
+
+ // !!! Remove this when possible - ideally for 2.11.
+ // We are stuck with it a while longer because sbt's compiler interface
+ // still calls it as of 0.12.2.
+ @deprecated("Use `sys.error(message)` instead", "2.9.0")
+ def error(message: String): Nothing = sys.error(message)
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * Calls to this method will not be generated if `-Xelide-below`
+ * is at least `ASSERTION`.
+ *
+ * @see elidable
+ * @param assertion the expression to test
+ */
+ @elidable(ASSERTION)
+ def assert(assertion: Boolean): Unit = {
+ if (!assertion)
+ throw new java.lang.AssertionError("assertion failed")
+ }
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * Calls to this method will not be generated if `-Xelide-below`
+ * is at least `ASSERTION`.
+ *
+ * @see elidable
+ * @param assertion the expression to test
+ * @param message a String to include in the failure message
+ */
+ @elidable(ASSERTION) @inline
+ final def assert(assertion: Boolean, message: => Any): Unit = {
+ if (!assertion)
+ throw new java.lang.AssertionError("assertion failed: "+ message)
+ }
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * This method differs from assert only in the intent expressed:
+ * assert contains a predicate which needs to be proven, while
+ * assume contains an axiom for a static checker. Calls to this method
+ * will not be generated if `-Xelide-below` is at least `ASSERTION`.
+ *
+ * @see elidable
+ * @param assumption the expression to test
+ */
+ @elidable(ASSERTION)
+ def assume(assumption: Boolean): Unit = {
+ if (!assumption)
+ throw new java.lang.AssertionError("assumption failed")
+ }
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * This method differs from assert only in the intent expressed:
+ * assert contains a predicate which needs to be proven, while
+ * assume contains an axiom for a static checker. Calls to this method
+ * will not be generated if `-Xelide-below` is at least `ASSERTION`.
+ *
+ * @see elidable
+ * @param assumption the expression to test
+ * @param message a String to include in the failure message
+ */
+ @elidable(ASSERTION) @inline
+ final def assume(assumption: Boolean, message: => Any): Unit = {
+ if (!assumption)
+ throw new java.lang.AssertionError("assumption failed: "+ message)
+ }
+
+ /** Tests an expression, throwing an `IllegalArgumentException` if false.
+ * This method is similar to `assert`, but blames the caller of the method
+ * for violating the condition.
+ *
+ * @param requirement the expression to test
+ */
+ def require(requirement: Boolean): Unit = {
+ if (!requirement)
+ throw new IllegalArgumentException("requirement failed")
+ }
+
+ /** Tests an expression, throwing an `IllegalArgumentException` if false.
+ * This method is similar to `assert`, but blames the caller of the method
+ * for violating the condition.
+ *
+ * @param requirement the expression to test
+ * @param message a String to include in the failure message
+ */
+ @inline final def require(requirement: Boolean, message: => Any): Unit = {
+ if (!requirement)
+ throw new IllegalArgumentException("requirement failed: "+ message)
+ }
+
+ /** `???` can be used for marking methods that remain to be implemented.
+ * @throws NotImplementedError
+ */
+ def ??? : Nothing = throw new NotImplementedError
+
+ // tupling ------------------------------------------------------------
+
+ @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0")
+ type Pair[+A, +B] = Tuple2[A, B]
+ @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0")
+ object Pair {
+ def apply[A, B](x: A, y: B) = Tuple2(x, y)
+ def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x)
+ }
+
+ @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0")
+ type Triple[+A, +B, +C] = Tuple3[A, B, C]
+ @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0")
+ object Triple {
+ def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z)
+ def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x)
+ }
+
+ // implicit classes -----------------------------------------------------
+
+ implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {
+ @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)
+ def →[B](y: B): Tuple2[A, B] = ->(y)
+ }
+
+ implicit final class Ensuring[A](private val self: A) extends AnyVal {
+ def ensuring(cond: Boolean): A = { assert(cond); self }
+ def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self }
+ def ensuring(cond: A => Boolean): A = { assert(cond(self)); self }
+ def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self }
+ }
+
+ implicit final class StringFormat[A](private val self: A) extends AnyVal {
+ /** Returns string formatted according to given `format` string.
+ * Format strings are as for `String.format`
+ * (@see java.lang.String.format).
+ */
+ @inline def formatted(fmtstr: String): String = fmtstr format self
+ }
+
+ // TODO: remove, only needed for binary compatibility of 2.11.0-RC1 with 2.11.0-M8
+ // note that `private[scala]` becomes `public` in bytecode
+ private[scala] final class StringAdd[A](private val self: A) extends AnyVal {
+ def +(other: String): String = String.valueOf(self) + other
+ }
+ private[scala] def StringAdd(x: Any): Any = new StringAdd(x)
+
+ // SI-8229 retaining the pre 2.11 name for source compatibility in shadowing this implicit
+ implicit final class any2stringadd[A](private val self: A) extends AnyVal {
+ def +(other: String): String = String.valueOf(self) + other
+ }
+
+ implicit final class RichException(private val self: Throwable) extends AnyVal {
+ import scala.compat.Platform.EOL
+ @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL)
+ }
+
+ implicit final class SeqCharSequence(val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence {
+ def length: Int = __sequenceOfChars.length
+ def charAt(index: Int): Char = __sequenceOfChars(index)
+ def subSequence(start: Int, end: Int): CharSequence = new SeqCharSequence(__sequenceOfChars.slice(start, end))
+ override def toString = __sequenceOfChars mkString ""
+ }
+
+ implicit final class ArrayCharSequence(val __arrayOfChars: Array[Char]) extends CharSequence {
+ def length: Int = __arrayOfChars.length
+ def charAt(index: Int): Char = __arrayOfChars(index)
+ def subSequence(start: Int, end: Int): CharSequence = new runtime.ArrayCharSequence(__arrayOfChars, start, end)
+ override def toString = __arrayOfChars mkString ""
+ }
+
+ implicit val StringCanBuildFrom: CanBuildFrom[String, Char, String] = new CanBuildFrom[String, Char, String] {
+ def apply(from: String) = apply()
+ def apply() = mutable.StringBuilder.newBuilder
+ }
+
+ @inline implicit def augmentString(x: String): StringOps = new StringOps(x)
+ @inline implicit def unaugmentString(x: StringOps): String = x.repr
+
+ // printing -----------------------------------------------------------
+
+ def print(x: Any) = Console.print(x)
+ def println() = Console.println()
+ def println(x: Any) = Console.println(x)
+ def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*))
+
+ // views --------------------------------------------------------------
+
+ implicit def tuple2ToZippedOps[T1, T2](x: (T1, T2)): runtime.Tuple2Zipped.Ops[T1, T2] = new runtime.Tuple2Zipped.Ops(x)
+ implicit def tuple3ToZippedOps[T1, T2, T3](x: (T1, T2, T3)): runtime.Tuple3Zipped.Ops[T1, T2, T3] = new runtime.Tuple3Zipped.Ops(x)
+
+ implicit def genericArrayOps[T](xs: Array[T]): ArrayOps[T] = (xs match {
+ case x: Array[AnyRef] => refArrayOps[AnyRef](x)
+ case x: Array[Boolean] => booleanArrayOps(x)
+ case x: Array[Byte] => byteArrayOps(x)
+ case x: Array[Char] => charArrayOps(x)
+ case x: Array[Double] => doubleArrayOps(x)
+ case x: Array[Float] => floatArrayOps(x)
+ case x: Array[Int] => intArrayOps(x)
+ case x: Array[Long] => longArrayOps(x)
+ case x: Array[Short] => shortArrayOps(x)
+ case x: Array[Unit] => unitArrayOps(x)
+ case null => null
+ }).asInstanceOf[ArrayOps[T]]
+
+ implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs)
+ implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs)
+ implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs)
+ implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs)
+ implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs)
+ implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs)
+ implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs)
+ implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs)
+ implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs)
+ implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs)
+
+ // "Autoboxing" and "Autounboxing" ---------------------------------------------------
+
+ implicit def byte2Byte(x: Byte): java.lang.Byte = java.lang.Byte.valueOf(x)
+ implicit def short2Short(x: Short): java.lang.Short = java.lang.Short.valueOf(x)
+ implicit def char2Character(x: Char): java.lang.Character = java.lang.Character.valueOf(x)
+ implicit def int2Integer(x: Int): java.lang.Integer = java.lang.Integer.valueOf(x)
+ implicit def long2Long(x: Long): java.lang.Long = java.lang.Long.valueOf(x)
+ implicit def float2Float(x: Float): java.lang.Float = java.lang.Float.valueOf(x)
+ implicit def double2Double(x: Double): java.lang.Double = java.lang.Double.valueOf(x)
+ implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = java.lang.Boolean.valueOf(x)
+
+ implicit def Byte2byte(x: java.lang.Byte): Byte = x.byteValue
+ implicit def Short2short(x: java.lang.Short): Short = x.shortValue
+ implicit def Character2char(x: java.lang.Character): Char = x.charValue
+ implicit def Integer2int(x: java.lang.Integer): Int = x.intValue
+ implicit def Long2long(x: java.lang.Long): Long = x.longValue
+ implicit def Float2float(x: java.lang.Float): Float = x.floatValue
+ implicit def Double2double(x: java.lang.Double): Double = x.doubleValue
+ implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
+
+ // Type Constraints --------------------------------------------------------------
+
+ /**
+ * An instance of `A <:< B` witnesses that `A` is a subtype of `B`.
+ * Requiring an implicit argument of the type `A <:< B` encodes
+ * the generalized constraint `A <: B`.
+ *
+ * @note we need a new type constructor `<:<` and evidence `conforms`,
+ * as reusing `Function1` and `identity` leads to ambiguities in
+ * case of type errors (`any2stringadd` is inferred)
+ *
+ * To constrain any abstract type T that's in scope in a method's
+ * argument list (not just the method's own type parameters) simply
+ * add an implicit argument of type `T <:< U`, where `U` is the required
+ * upper bound; or for lower-bounds, use: `L <:< T`, where `L` is the
+ * required lower bound.
+ *
+ * In part contributed by Jason Zaugg.
+ */
+ @implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.")
+ sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
+ private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
+ // The dollar prefix is to dodge accidental shadowing of this method
+ // by a user-defined method of the same name (SI-7788).
+ // The collections rely on this method.
+ implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
+
+ @deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0")
+ def conforms[A]: A <:< A = $conforms[A]
+
+ /** An instance of `A =:= B` witnesses that the types `A` and `B` are equal.
+ *
+ * @see `<:<` for expressing subtyping constraints
+ */
+ @implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
+ sealed abstract class =:=[From, To] extends (From => To) with Serializable
+ private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x }
+ object =:= {
+ implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A]
+ }
+
+ /** A type for which there is always an implicit value.
+ * @see [[scala.Array$]], method `fallbackCanBuildFrom`
+ */
+ class DummyImplicit
+
+ object DummyImplicit {
+
+ /** An implicit value yielding a `DummyImplicit`.
+ * @see [[scala.Array$]], method `fallbackCanBuildFrom`
+ */
+ implicit def dummyImplicit: DummyImplicit = new DummyImplicit
+ }
+}
+
+private[scala] trait DeprecatedPredef {
+ self: Predef.type =>
+
+ // Deprecated stubs for any who may have been calling these methods directly.
+ @deprecated("Use `ArrowAssoc`", "2.11.0") def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
+ @deprecated("Use `Ensuring`", "2.11.0") def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x)
+ @deprecated("Use `StringFormat`", "2.11.0") def any2stringfmt(x: Any): StringFormat[Any] = new StringFormat(x)
+ @deprecated("Use `Throwable` directly", "2.11.0") def exceptionWrapper(exc: Throwable) = new RichException(exc)
+ @deprecated("Use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs)
+ @deprecated("Use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs)
+
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*)
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readBoolean() = StdIn.readBoolean()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readByte() = StdIn.readByte()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readShort() = StdIn.readShort()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readChar() = StdIn.readChar()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readInt() = StdIn.readInt()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLong() = StdIn.readLong()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readFloat() = StdIn.readFloat()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readDouble() = StdIn.readDouble()
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf(format: String) = StdIn.readf(format)
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf1(format: String) = StdIn.readf1(format)
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf2(format: String) = StdIn.readf2(format)
+ @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf3(format: String) = StdIn.readf3(format)
+}
+
+/** The `LowPriorityImplicits` class provides implicit values that
+* are valid in all Scala compilation units without explicit qualification,
+* but that are partially overridden by higher-priority conversions in object
+* `Predef`.
+*
+* @author Martin Odersky
+* @since 2.8
+*/
+// SI-7335 Parents of Predef are defined in the same compilation unit to avoid
+// cyclic reference errors compiling the standard library *without* a previously
+// compiled copy on the classpath.
+private[scala] abstract class LowPriorityImplicits {
+ import mutable.WrappedArray
+ import immutable.WrappedString
+
+ /** We prefer the java.lang.* boxed types to these wrappers in
+ * any potential conflicts. Conflicts do exist because the wrappers
+ * need to implement ScalaNumber in order to have a symmetric equals
+ * method, but that implies implementing java.lang.Number as well.
+ *
+ * Note - these are inlined because they are value classes, but
+ * the call to xxxWrapper is not eliminated even though it does nothing.
+ * Even inlined, every call site does a no-op retrieval of Predef's MODULE$
+ * because maybe loading Predef has side effects!
+ */
+ @inline implicit def byteWrapper(x: Byte): runtime.RichByte = new runtime.RichByte(x)
+ @inline implicit def shortWrapper(x: Short): runtime.RichShort = new runtime.RichShort(x)
+ @inline implicit def intWrapper(x: Int): runtime.RichInt = new runtime.RichInt(x)
+ @inline implicit def charWrapper(c: Char): runtime.RichChar = new runtime.RichChar(c)
+ @inline implicit def longWrapper(x: Long): runtime.RichLong = new runtime.RichLong(x)
+ @inline implicit def floatWrapper(x: Float): runtime.RichFloat = new runtime.RichFloat(x)
+ @inline implicit def doubleWrapper(x: Double): runtime.RichDouble = new runtime.RichDouble(x)
+ @inline implicit def booleanWrapper(x: Boolean): runtime.RichBoolean = new runtime.RichBoolean(x)
+
+ implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] =
+ if (xs eq null) null
+ else WrappedArray.make(xs)
+
+ // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
+ // is as good as another for all T <: AnyRef. Instead of creating 100,000,000
+ // unique ones by way of this implicit, let's share one.
+ implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = {
+ if (xs eq null) null
+ else if (xs.length == 0) WrappedArray.empty[T]
+ else new WrappedArray.ofRef[T](xs)
+ }
+
+ implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null
+ implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null
+ implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null
+ implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null
+ implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null
+ implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null
+ implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null
+ implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null
+ implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null
+
+ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null
+ implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null
+
+ implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] =
+ new CanBuildFrom[String, T, immutable.IndexedSeq[T]] {
+ def apply(from: String) = immutable.IndexedSeq.newBuilder[T]
+ def apply() = immutable.IndexedSeq.newBuilder[T]
+ }
+}
diff --git a/tests/link/dce-failing/link-predef-toList/Test.scala b/tests/link/dce-failing/link-predef-toList/Test.scala
new file mode 100644
index 000000000000..230e370619da
--- /dev/null
+++ b/tests/link/dce-failing/link-predef-toList/Test.scala
@@ -0,0 +1,8 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println("start")
+ args.toList
+ println("end")
+ }
+}
diff --git a/tests/link/dce-failing/link-zipWithIndex-1.check b/tests/link/dce-failing/link-zipWithIndex-1.check
new file mode 100644
index 000000000000..10c09baa652b
--- /dev/null
+++ b/tests/link/dce-failing/link-zipWithIndex-1.check
@@ -0,0 +1,3 @@
+a 0
+b 1
+c 2
diff --git a/tests/link/dce-failing/link-zipWithIndex-1.scala b/tests/link/dce-failing/link-zipWithIndex-1.scala
new file mode 100644
index 000000000000..bf9f095e3fbd
--- /dev/null
+++ b/tests/link/dce-failing/link-zipWithIndex-1.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 31, classesWithReachableMethods = 7, reachableMethods = 55)
+ def main(args: Array[String]): Unit = {
+ val list = List('a', 'b', 'c')
+ for ((elem, idx) <- list.zipWithIndex) {
+ System.out.println(elem + " " + idx)
+ }
+ }
+
+}
diff --git a/tests/link/dce-failing/link-zipWithIndex-2.check b/tests/link/dce-failing/link-zipWithIndex-2.check
new file mode 100644
index 000000000000..10c09baa652b
--- /dev/null
+++ b/tests/link/dce-failing/link-zipWithIndex-2.check
@@ -0,0 +1,3 @@
+a 0
+b 1
+c 2
diff --git a/tests/link/dce-failing/link-zipWithIndex-2.scala b/tests/link/dce-failing/link-zipWithIndex-2.scala
new file mode 100644
index 000000000000..8ce14474406e
--- /dev/null
+++ b/tests/link/dce-failing/link-zipWithIndex-2.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 31, classesWithReachableMethods = 7, reachableMethods = 55)
+ def main(args: Array[String]): Unit = {
+ val list = List('a', 'b', 'c')
+ list.zipWithIndex.map { case (pname, idx) =>
+ System.out.println(pname + " " + idx)
+ }
+ }
+
+}
diff --git a/tests/link/dce/link-cast-1.check b/tests/link/dce/link-cast-1.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/dce/link-cast-1.scala b/tests/link/dce/link-cast-1.scala
new file mode 100644
index 000000000000..bc0ba3237c6e
--- /dev/null
+++ b/tests/link/dce/link-cast-1.scala
@@ -0,0 +1,28 @@
+import scala.annotation.internal
+
+object Test {
+ // @internal.link.CallGraphBounds(reachableClasses = 31, classesWithReachableMethods = 7, reachableMethods = 55)
+ def main(args: Array[String]): Unit = {
+ val box = new Box[Foo](null)
+ box.x = new Foo
+ val box2 = box.asInstanceOf[Box[Bar]]
+ box2.x = new Bar
+ f(box.asInstanceOf[Box[Bla]])
+ f(box2.asInstanceOf[Box[Bla]])
+ }
+ def f(b: Box[Bla]) = b.x.bla
+}
+
+class Box[T](var x: T)
+
+class Foo extends Bla {
+ override def bla: String = getClass.toString
+}
+
+class Bar extends Bla {
+ override def bla: String = getClass.toString
+}
+
+trait Bla {
+ def bla: String = ???
+}
diff --git a/tests/link/dce/link-classOf.check b/tests/link/dce/link-classOf.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/dce/link-classOf.scala b/tests/link/dce/link-classOf.scala
new file mode 100644
index 000000000000..e4d4c51cf0b0
--- /dev/null
+++ b/tests/link/dce/link-classOf.scala
@@ -0,0 +1,11 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 31, classesWithReachableMethods = 7, reachableMethods = 55)
+ def main(args: Array[String]): Unit = {
+ classOf[Foo]
+ }
+}
+
+class Foo
+class Bar
diff --git a/tests/link/dce/link-code-from-java-1.check b/tests/link/dce/link-code-from-java-1.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-1.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce/link-code-from-java-10.check b/tests/link/dce/link-code-from-java-10.check
new file mode 100644
index 000000000000..7af67a01e447
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-10.check
@@ -0,0 +1 @@
+Foo.toString
diff --git a/tests/link/dce/link-code-from-java-10.scala b/tests/link/dce/link-code-from-java-10.scala
new file mode 100644
index 000000000000..7dcfd9cb06bb
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-10.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 35, classesWithReachableMethods = 9, reachableMethods = 59)
+ def main(args: Array[String]): Unit = {
+ println(new Foo) // In this test case the standard lib is compiled separately.
+ }
+
+}
+
+class Foo {
+ @internal.link.AssertReachable
+ override def toString: String = "Foo.toString"
+}
diff --git a/tests/link/dce/link-code-from-java-11.check b/tests/link/dce/link-code-from-java-11.check
new file mode 100644
index 000000000000..7af67a01e447
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-11.check
@@ -0,0 +1 @@
+Foo.toString
diff --git a/tests/link/dce/link-code-from-java-11.scala b/tests/link/dce/link-code-from-java-11.scala
new file mode 100644
index 000000000000..c22cd4bad86f
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-11.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 20, classesWithReachableMethods = 7, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ System.out.println((new Foo): Object)
+ }
+
+}
+
+class Foo {
+ @internal.link.AssertReachable
+ override def toString: String = "Foo.toString"
+}
diff --git a/tests/link/dce/link-code-from-java-2-a.check b/tests/link/dce/link-code-from-java-2-a.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-2-a.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce/link-code-from-java-2-a.scala b/tests/link/dce/link-code-from-java-2-a.scala
new file mode 100644
index 000000000000..9d6fac9ec394
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-2-a.scala
@@ -0,0 +1,53 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 101, classesWithReachableMethods = 14, reachableMethods = 67)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ case _: java.lang.NoSuchMethodError => // agressive DCE
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val a = new A
+ Test.shouldDCE(a.f1)
+ a.hashCode()
+ a.equals(a)
+ a.toString
+ a.update(new Observable, null)
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new A)
+ }
+}
+
+class A extends java.util.Observer {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+ override def update(o: Observable, arg: scala.Any): Unit = ()
+}
diff --git a/tests/link/dce/link-code-from-java-2-b.check b/tests/link/dce/link-code-from-java-2-b.check
new file mode 100644
index 000000000000..3b8b09974056
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-2-b.check
@@ -0,0 +1 @@
+dceTest
diff --git a/tests/link/dce/link-code-from-java-2-b.scala b/tests/link/dce/link-code-from-java-2-b.scala
new file mode 100644
index 000000000000..6d34c1e7575f
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-2-b.scala
@@ -0,0 +1,53 @@
+import java.util.Observable
+
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 102, classesWithReachableMethods = 18, reachableMethods = 68)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ case _: java.lang.NoSuchMethodError => // agressive DCE
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val b = new B {}
+ Test.shouldDCE(b.f1)
+ b.hashCode()
+ b.equals(b)
+ b.toString
+ b.update(new Observable, null)
+ }
+
+ @scala.EntryPoint def entryPoint(): Unit = {
+ System.out.print(new B {})
+ }
+}
+
+abstract class B extends java.util.Observer {
+ def f1 = 42
+ override def hashCode(): Int = super.hashCode()
+ override def equals(obj: scala.Any): Boolean = super.equals(obj)
+ override def toString: String = super.toString
+ override def update(o: Observable, arg: scala.Any): Unit = ()
+}
diff --git a/tests/link/dce/link-code-from-java-6.check b/tests/link/dce/link-code-from-java-6.check
new file mode 100644
index 000000000000..9364ec4f3096
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-6.check
@@ -0,0 +1,3 @@
+1
+3
+4
diff --git a/tests/link/dce/link-code-from-java-6.scala b/tests/link/dce/link-code-from-java-6.scala
new file mode 100644
index 000000000000..a52fdf509376
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-6.scala
@@ -0,0 +1,20 @@
+import scala.annotation.internal
+
+class MyInt(val x: Int) extends java.lang.Comparable[MyInt] {
+ override def compareTo(that: MyInt) = this.x - that.x
+ override def toString = x.toString
+}
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 27, classesWithReachableMethods = 10, reachableMethods = 15)
+ def main(args: Array[String]): Unit = {
+ val a = new Array[java.lang.Object](3)
+ a(0) = new MyInt(1)
+ a(1) = new MyInt(4)
+ a(2) = new MyInt(3)
+ java.util.Arrays.sort(a)
+ System.out.println(a(0))
+ System.out.println(a(1))
+ System.out.println(a(2))
+ }
+}
diff --git a/tests/link/dce/link-code-from-java-7.check b/tests/link/dce/link-code-from-java-7.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-7.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-code-from-java-7.scala b/tests/link/dce/link-code-from-java-7.scala
new file mode 100644
index 000000000000..a5d9c3fc0899
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-7.scala
@@ -0,0 +1,20 @@
+import scala.annotation.internal
+
+import java.lang.InheritableThreadLocal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 27, classesWithReachableMethods = 10, reachableMethods = 14)
+ def main(args: Array[String]): Unit = {
+ val a = new DynamicVariable2(42)
+ System.out.println(a.value)
+ }
+}
+
+
+class DynamicVariable2[T](init: T) {
+ private val tl = new InheritableThreadLocal[T] {
+ override def initialValue = init.asInstanceOf[T with AnyRef]
+ }
+
+ def value: T = tl.get.asInstanceOf[T]
+}
diff --git a/tests/link/dce/link-code-from-java-8.check b/tests/link/dce/link-code-from-java-8.check
new file mode 100644
index 000000000000..7af67a01e447
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-8.check
@@ -0,0 +1 @@
+Foo.toString
diff --git a/tests/link/dce/link-code-from-java-8.scala b/tests/link/dce/link-code-from-java-8.scala
new file mode 100644
index 000000000000..299fa85ac8fd
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-8.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 6, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ System.out.println(new Foo)
+ }
+
+}
+
+class Foo {
+ @internal.link.AssertReachable
+ override def toString: String = "Foo.toString"
+}
diff --git a/tests/link/dce/link-code-from-java-9.check b/tests/link/dce/link-code-from-java-9.check
new file mode 100644
index 000000000000..7af67a01e447
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-9.check
@@ -0,0 +1 @@
+Foo.toString
diff --git a/tests/link/dce/link-code-from-java-9.scala b/tests/link/dce/link-code-from-java-9.scala
new file mode 100644
index 000000000000..8e7eee465461
--- /dev/null
+++ b/tests/link/dce/link-code-from-java-9.scala
@@ -0,0 +1,18 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ foo(new Foo)
+ }
+
+ def foo(s: Object) = {
+ System.out.println(s)
+ }
+
+}
+
+class Foo {
+ @internal.link.AssertReachable
+ override def toString: String = "Foo.toString"
+}
diff --git a/tests/link/dce/link-constructorParams.check b/tests/link/dce/link-constructorParams.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-constructorParams.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-constructorParams.scala b/tests/link/dce/link-constructorParams.scala
new file mode 100644
index 000000000000..eaea6cff384e
--- /dev/null
+++ b/tests/link/dce/link-constructorParams.scala
@@ -0,0 +1,11 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 23, classesWithReachableMethods = 8, reachableMethods = 10)
+ def main(args: Array[String]): Unit = {
+ System.out.println(new Foo(42).x)
+ }
+}
+
+class Foo(x: Int) extends Bar(x)
+class Bar(@internal.link.AssertReachable val x: Int)
diff --git a/tests/link/dce/link-entry-point-1.check b/tests/link/dce/link-entry-point-1.check
new file mode 100644
index 000000000000..b0c9defbb9fb
--- /dev/null
+++ b/tests/link/dce/link-entry-point-1.check
@@ -0,0 +1,2 @@
+dceTest
+42
diff --git a/tests/link/dce/link-entry-point-1.scala b/tests/link/dce/link-entry-point-1.scala
new file mode 100644
index 000000000000..856222f2f7e0
--- /dev/null
+++ b/tests/link/dce/link-entry-point-1.scala
@@ -0,0 +1,41 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 99, classesWithReachableMethods = 14, reachableMethods = 62)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ case _: java.lang.NoSuchMethodError => // agressive DCE
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+
+ val x = new Foo
+ Test.shouldDCE(x.bar())
+ x.foo()
+ }
+}
+
+class Foo {
+ @scala.EntryPoint def foo(): Unit = System.out.println(42)
+ @internal.link.AssertNotReachable def bar(): Unit = System.out.println(43)
+}
diff --git a/tests/link/dce/link-entry-point-2.check b/tests/link/dce/link-entry-point-2.check
new file mode 100644
index 000000000000..b0c9defbb9fb
--- /dev/null
+++ b/tests/link/dce/link-entry-point-2.check
@@ -0,0 +1,2 @@
+dceTest
+42
diff --git a/tests/link/dce/link-entry-point-2.scala b/tests/link/dce/link-entry-point-2.scala
new file mode 100644
index 000000000000..ea5ab6dcd52b
--- /dev/null
+++ b/tests/link/dce/link-entry-point-2.scala
@@ -0,0 +1,39 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 99, classesWithReachableMethods = 14, reachableMethods = 63)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ case _: java.lang.NoSuchMethodError => // agressive DCE
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+ Test.shouldDCE(Foo.bar())
+ Foo.foo()
+ }
+}
+
+object Foo {
+ @scala.EntryPoint def foo(): Unit = System.out.println(42)
+ @internal.link.AssertNotReachable def bar(): Unit = System.out.println(43)
+}
diff --git a/tests/link/dce/link-entry-point-3-a.check b/tests/link/dce/link-entry-point-3-a.check
new file mode 100644
index 000000000000..677051eb2f1a
--- /dev/null
+++ b/tests/link/dce/link-entry-point-3-a.check
@@ -0,0 +1,3 @@
+43
+43
+42
diff --git a/tests/link/dce/link-entry-point-3-a.scala b/tests/link/dce/link-entry-point-3-a.scala
new file mode 100644
index 000000000000..7c969713c169
--- /dev/null
+++ b/tests/link/dce/link-entry-point-3-a.scala
@@ -0,0 +1,31 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 99, classesWithReachableMethods = 14, reachableMethods = 64)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ Foo.bar()
+ Foo.foo()
+ }
+}
+
+object Foo {
+
+ bar()
+
+ @scala.EntryPoint def foo(): Unit = System.out.println(42)
+ @internal.link.AssertReachable def bar(): Unit = System.out.println(43)
+}
diff --git a/tests/link/dce/link-entry-point-3-b.check b/tests/link/dce/link-entry-point-3-b.check
new file mode 100644
index 000000000000..677051eb2f1a
--- /dev/null
+++ b/tests/link/dce/link-entry-point-3-b.check
@@ -0,0 +1,3 @@
+43
+43
+42
diff --git a/tests/link/dce/link-entry-point-3-b.scala b/tests/link/dce/link-entry-point-3-b.scala
new file mode 100644
index 000000000000..b8c0393b0f6f
--- /dev/null
+++ b/tests/link/dce/link-entry-point-3-b.scala
@@ -0,0 +1,36 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 100, classesWithReachableMethods = 19, reachableMethods = 66)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ foo.Foo.bar()
+ foo.Foo.foo()
+ }
+}
+
+package foo {
+
+ object Foo {
+
+ bar()
+
+ @scala.EntryPoint def foo(): Unit = System.out.println(42)
+
+ @internal.link.AssertReachable def bar(): Unit = System.out.println(43)
+ }
+
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-entry-point-4.check b/tests/link/dce/link-entry-point-4.check
new file mode 100644
index 000000000000..885a51e592eb
--- /dev/null
+++ b/tests/link/dce/link-entry-point-4.check
@@ -0,0 +1,4 @@
+dceTest
+43
+43
+42
diff --git a/tests/link/dce/link-entry-point-4.scala b/tests/link/dce/link-entry-point-4.scala
new file mode 100644
index 000000000000..a17434956093
--- /dev/null
+++ b/tests/link/dce/link-entry-point-4.scala
@@ -0,0 +1,42 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 99, classesWithReachableMethods = 14, reachableMethods = 65)
+ def main(args: Array[String]): Unit = {
+ val classLoader = Test.getClass.getClassLoader()
+
+ try {
+ val mainClass = classLoader.loadClass("Test")
+ val mainMethod = mainClass.getMethod("dceTest")
+ mainMethod.invoke(null);
+ } catch {
+ case e: java.lang.Exception => e.getCause.printStackTrace()
+ }
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def shouldDCE(expr: => Any): Unit = try {
+ expr
+ throw new Exception("Expected DCE")
+ } catch {
+ case dce: dotty.runtime.DeadCodeEliminated =>
+ }
+
+ @internal.link.AssertNotReachable
+ @internal.link.DoNotDeadCodeEliminate
+ def dceTest: Unit = {
+ System.out.println("dceTest")
+ Foo.bar()
+ Foo.foo()
+ }
+
+ object Foo {
+
+ bar()
+
+ @scala.EntryPoint def foo(): Unit = System.out.println(42)
+ @internal.link.AssertReachable def bar(): Unit = System.out.println(43)
+ }
+}
+
diff --git a/tests/link/dce/link-field-lambda.check b/tests/link/dce/link-field-lambda.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-field-lambda.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-field-lambda.scala b/tests/link/dce/link-field-lambda.scala
new file mode 100644
index 000000000000..08f3edb3093a
--- /dev/null
+++ b/tests/link/dce/link-field-lambda.scala
@@ -0,0 +1,13 @@
+import scala.annotation.internal
+
+object Test {
+ val f = (x: Int) => 2 * x
+ val g = (x: Int) => 3 * x
+
+ def lala(x: Boolean): Int=>Int = if (x) f else g
+
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 7, reachableMethods = 11)
+ def main(args: Array[String]): Unit = {
+ System.out.println(lala(true)(21))
+ }
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-fillStackTrace-0.check b/tests/link/dce/link-fillStackTrace-0.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-fillStackTrace-0.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-fillStackTrace-0.scala b/tests/link/dce/link-fillStackTrace-0.scala
new file mode 100644
index 000000000000..0ac3b6e75b8b
--- /dev/null
+++ b/tests/link/dce/link-fillStackTrace-0.scala
@@ -0,0 +1,17 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 23, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ try {
+ throw new ThrowableFoo
+ } catch {
+ case _: ThrowableFoo => System.out.println(42)
+ }
+ }
+}
+
+class ThrowableFoo extends Throwable {
+ @internal.link.AssertReachable
+ override def fillInStackTrace(): Throwable = this
+}
diff --git a/tests/link/dce/link-fillStackTrace-1.check b/tests/link/dce/link-fillStackTrace-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-fillStackTrace-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-fillStackTrace-1.scala b/tests/link/dce/link-fillStackTrace-1.scala
new file mode 100644
index 000000000000..49c929d3a79c
--- /dev/null
+++ b/tests/link/dce/link-fillStackTrace-1.scala
@@ -0,0 +1,18 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 24, classesWithReachableMethods = 9, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ try {
+ throw new BreakControl
+ } catch {
+ case _: BreakControl => System.out.println(42)
+ }
+ }
+}
+
+class BreakControl extends NoStackTrace
+
+trait NoStackTrace extends Throwable {
+ override def fillInStackTrace(): Throwable = this
+}
diff --git a/tests/link/dce/link-implicit-constructor.check b/tests/link/dce/link-implicit-constructor.check
new file mode 100644
index 000000000000..b6fc4c620b67
--- /dev/null
+++ b/tests/link/dce/link-implicit-constructor.check
@@ -0,0 +1 @@
+hello
\ No newline at end of file
diff --git a/tests/link/dce/link-implicit-constructor.scala b/tests/link/dce/link-implicit-constructor.scala
new file mode 100644
index 000000000000..375fc5ef7bee
--- /dev/null
+++ b/tests/link/dce/link-implicit-constructor.scala
@@ -0,0 +1,13 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 35, classesWithReachableMethods = 10, reachableMethods = 60)
+ def main(args: Array[String]): Unit = {
+ implicit def s: String = "hello"
+ new Foo
+ }
+}
+
+class Foo(implicit str: String) {
+ println(str)
+}
diff --git a/tests/link/dce/link-initial-values.check b/tests/link/dce/link-initial-values.check
new file mode 100644
index 000000000000..920a13966480
--- /dev/null
+++ b/tests/link/dce/link-initial-values.check
@@ -0,0 +1 @@
+43
diff --git a/tests/link/dce/link-initial-values.scala b/tests/link/dce/link-initial-values.scala
new file mode 100644
index 000000000000..238263fddfaf
--- /dev/null
+++ b/tests/link/dce/link-initial-values.scala
@@ -0,0 +1,18 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 8, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ new Bar
+ }
+}
+
+
+class Bar extends Foo
+
+trait Foo {
+ val foo: Int = {
+ System.out.println(43)
+ 43
+ }
+}
diff --git a/tests/link/dce/link-inner-class-call-outer-0.check b/tests/link/dce/link-inner-class-call-outer-0.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-0.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-inner-class-call-outer-0.scala b/tests/link/dce/link-inner-class-call-outer-0.scala
new file mode 100644
index 000000000000..eb057e9e8434
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-0.scala
@@ -0,0 +1,25 @@
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ System.out.println(new OfInt().iterator.next())
+ }
+}
+
+class OfInt extends IndexedSeqLike2[Int] {
+ def foo(index: Int): Int = 42
+}
+
+trait IndexedSeqLike2[A] {
+
+ def foo(index: Int): A
+ def iterator: Elements = new Elements
+
+ class Elements extends Iterator2[A] {
+ def next(): A = foo(0)
+ }
+}
+
+trait Iterator2[A] {
+ def next(): A
+}
diff --git a/tests/link/dce/link-inner-class-call-outer-1.check b/tests/link/dce/link-inner-class-call-outer-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-inner-class-call-outer-1.scala b/tests/link/dce/link-inner-class-call-outer-1.scala
new file mode 100644
index 000000000000..0e8375dc1af8
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-1.scala
@@ -0,0 +1,25 @@
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ System.out.println(new OfInt().iterator.next())
+ }
+}
+
+class OfInt extends IndexedSeqLike2[Int] {
+ def foo(index: Int): Int = 42
+}
+
+trait IndexedSeqLike2[A] {
+
+ def foo(index: Int): A
+ def iterator: Elements[A] = new Elements[A]
+
+ class Elements[B >: A] extends Iterator2[B] {
+ def next(): B = foo(0)
+ }
+}
+
+trait Iterator2[A] {
+ def next(): A
+}
diff --git a/tests/link/dce/link-inner-class-call-outer-2.check b/tests/link/dce/link-inner-class-call-outer-2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-inner-class-call-outer-2.scala b/tests/link/dce/link-inner-class-call-outer-2.scala
new file mode 100644
index 000000000000..8e678aab129b
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-2.scala
@@ -0,0 +1,25 @@
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ System.out.println(new OfInt().iterator.next())
+ }
+}
+
+class OfInt extends IndexedSeqLike2 {
+ def foo(index: Int): Int = 42
+}
+
+trait IndexedSeqLike2 {
+
+ def foo(index: Int): Int
+ def iterator: Elements = new Elements
+
+ class Elements extends Iterator2[Int] {
+ def next(): Int = foo(0)
+ }
+}
+
+trait Iterator2[A] {
+ def next(): Int
+}
diff --git a/tests/link/dce/link-inner-class-call-outer-3.check b/tests/link/dce/link-inner-class-call-outer-3.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-3.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-inner-class-call-outer-3.scala b/tests/link/dce/link-inner-class-call-outer-3.scala
new file mode 100644
index 000000000000..a0f7c7911eed
--- /dev/null
+++ b/tests/link/dce/link-inner-class-call-outer-3.scala
@@ -0,0 +1,25 @@
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ System.out.println(new OfInt().iterator.next())
+ }
+}
+
+class OfInt extends IndexedSeqLike2 {
+ def foo(index: Int): Int = 42
+}
+
+trait IndexedSeqLike2 {
+
+ def foo(index: Int): Int
+ def iterator: Elements = new Elements
+
+ class Elements extends Iterator2 {
+ def next(): Int = foo(0)
+ }
+}
+
+trait Iterator2 {
+ def next(): Int
+}
diff --git a/tests/link/dce/link-inner-object.check b/tests/link/dce/link-inner-object.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-inner-object.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-inner-object.scala b/tests/link/dce/link-inner-object.scala
new file mode 100644
index 000000000000..30d141ef656c
--- /dev/null
+++ b/tests/link/dce/link-inner-object.scala
@@ -0,0 +1,11 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 19, classesWithReachableMethods = 8, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ object Foo {
+ def test() = 42
+ }
+ System.out.println(Foo.test())
+ }
+}
diff --git a/tests/link/dce/link-innerClass-0.check b/tests/link/dce/link-innerClass-0.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-innerClass-0.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-innerClass-0.scala b/tests/link/dce/link-innerClass-0.scala
new file mode 100644
index 000000000000..e4d1cb897ee8
--- /dev/null
+++ b/tests/link/dce/link-innerClass-0.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 19, classesWithReachableMethods = 7, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ class Foo {
+ @internal.link.AssertReachable
+ def bar: Int = 42
+ }
+
+ val foo = new Foo
+ System.out.println(foo.bar)
+ }
+}
diff --git a/tests/link/dce/link-innerClass-1.check b/tests/link/dce/link-innerClass-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-innerClass-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-innerClass-1.scala b/tests/link/dce/link-innerClass-1.scala
new file mode 100644
index 000000000000..b4e3f8a7dc44
--- /dev/null
+++ b/tests/link/dce/link-innerClass-1.scala
@@ -0,0 +1,20 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 8, reachableMethods = 10)
+ def main(args: Array[String]): Unit = {
+ new Bar().test()
+ }
+}
+
+class Bar {
+ def test() = {
+ class Foo {
+ @internal.link.AssertReachable
+ def bar: Int = 42
+ }
+
+ val foo = new Foo
+ System.out.println(foo.bar)
+ }
+}
diff --git a/tests/link/dce/link-innerFunction-0.check b/tests/link/dce/link-innerFunction-0.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-innerFunction-0.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-innerFunction-0.scala b/tests/link/dce/link-innerFunction-0.scala
new file mode 100644
index 000000000000..453efed98237
--- /dev/null
+++ b/tests/link/dce/link-innerFunction-0.scala
@@ -0,0 +1,24 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 9, reachableMethods = 11)
+ def main(args: Array[String]): Unit = {
+ val bar = new Bar
+ bar.foo1(42)
+ }
+}
+
+class Bar extends Baz[Int]
+
+class Baz[A] {
+
+ @internal.link.AssertReachable def foo1(x: A): Unit = {
+ @internal.link.AssertReachable def innerFoo(x: A): Unit = foo2(x)
+ innerFoo(x)
+ }
+
+ @internal.link.AssertReachable def foo2(elem: A): Unit = {
+ System.out.println(elem.toString)
+ }
+
+}
diff --git a/tests/link/dce/link-interface-no-init.check b/tests/link/dce/link-interface-no-init.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-interface-no-init.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-interface-no-init/Foo.java b/tests/link/dce/link-interface-no-init/Foo.java
new file mode 100644
index 000000000000..679a958225e4
--- /dev/null
+++ b/tests/link/dce/link-interface-no-init/Foo.java
@@ -0,0 +1,4 @@
+
+interface Foo {
+
+}
diff --git a/tests/link/dce/link-interface-no-init/MainGenericRunner.java b/tests/link/dce/link-interface-no-init/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/dce/link-interface-no-init/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/dce/link-interface-no-init/Test.scala b/tests/link/dce/link-interface-no-init/Test.scala
new file mode 100644
index 000000000000..21754ff01cd9
--- /dev/null
+++ b/tests/link/dce/link-interface-no-init/Test.scala
@@ -0,0 +1,17 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 23, classesWithReachableMethods = 8, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ new Baz
+ }
+
+}
+
+class Baz extends Foo with Bar1 with Bar2
+
+trait Bar1
+
+trait Bar2 {
+ System.out.println(42)
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-java-polimorphic-method-1.check b/tests/link/dce/link-java-polimorphic-method-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-java-polimorphic-method-1/Foo.java b/tests/link/dce/link-java-polimorphic-method-1/Foo.java
new file mode 100644
index 000000000000..df96d414ffb9
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-1/Foo.java
@@ -0,0 +1,4 @@
+
+public interface Foo {
+ public T foo(T t);
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-java-polimorphic-method-1/Test.scala b/tests/link/dce/link-java-polimorphic-method-1/Test.scala
new file mode 100644
index 000000000000..9543db0e9323
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-1/Test.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ System.out.println(new Bar)
+ }
+}
+
+class Bar extends Foo {
+ def foo[T](t: T): T = t
+
+ override def toString(): String = foo("42")
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-java-polimorphic-method-2.check b/tests/link/dce/link-java-polimorphic-method-2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-java-polimorphic-method-2/Foo.java b/tests/link/dce/link-java-polimorphic-method-2/Foo.java
new file mode 100644
index 000000000000..c729cf6e193b
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-2/Foo.java
@@ -0,0 +1,6 @@
+
+public interface Foo {
+ public String foo(T t);
+
+ public String string();
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-java-polimorphic-method-2/Test.scala b/tests/link/dce/link-java-polimorphic-method-2/Test.scala
new file mode 100644
index 000000000000..a0208e997e3c
--- /dev/null
+++ b/tests/link/dce/link-java-polimorphic-method-2/Test.scala
@@ -0,0 +1,16 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 7, reachableMethods = 10)
+ def main(args: Array[String]): Unit = {
+ System.out.println(new Bar)
+ }
+}
+
+class Bar extends Foo {
+ def foo[T <: Foo](t: T): String = t.string()
+
+ def string(): String = "42"
+
+ override def toString(): String = foo(this)
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-lib-1.check b/tests/link/dce/link-lib-1.check
new file mode 100644
index 000000000000..b4db3ed707d8
--- /dev/null
+++ b/tests/link/dce/link-lib-1.check
@@ -0,0 +1,2 @@
+43
+44
diff --git a/tests/link/dce/link-lib-1/App_2.scala b/tests/link/dce/link-lib-1/App_2.scala
new file mode 100644
index 000000000000..71c7faada4f9
--- /dev/null
+++ b/tests/link/dce/link-lib-1/App_2.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ new Foo().foo
+ }
+}
diff --git a/tests/link/dce/link-lib-1/Lib_1.scala b/tests/link/dce/link-lib-1/Lib_1.scala
new file mode 100644
index 000000000000..cfd9f1b9cfbd
--- /dev/null
+++ b/tests/link/dce/link-lib-1/Lib_1.scala
@@ -0,0 +1,13 @@
+
+class Foo {
+
+ def foo = {
+ println(43)
+ bar
+ }
+
+ def bar = println(44)
+
+ def baz = println(45)
+
+}
diff --git a/tests/link/dce/link-lib-2.check b/tests/link/dce/link-lib-2.check
new file mode 100644
index 000000000000..b4db3ed707d8
--- /dev/null
+++ b/tests/link/dce/link-lib-2.check
@@ -0,0 +1,2 @@
+43
+44
diff --git a/tests/link/dce/link-lib-2/App_3.scala b/tests/link/dce/link-lib-2/App_3.scala
new file mode 100644
index 000000000000..e6a1290bd4ae
--- /dev/null
+++ b/tests/link/dce/link-lib-2/App_3.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ new Bar().barbar
+ }
+}
diff --git a/tests/link/dce/link-lib-2/Lib_1.scala b/tests/link/dce/link-lib-2/Lib_1.scala
new file mode 100644
index 000000000000..cfd9f1b9cfbd
--- /dev/null
+++ b/tests/link/dce/link-lib-2/Lib_1.scala
@@ -0,0 +1,13 @@
+
+class Foo {
+
+ def foo = {
+ println(43)
+ bar
+ }
+
+ def bar = println(44)
+
+ def baz = println(45)
+
+}
diff --git a/tests/link/dce/link-lib-2/Lib_2.scala b/tests/link/dce/link-lib-2/Lib_2.scala
new file mode 100644
index 000000000000..04bd951db93c
--- /dev/null
+++ b/tests/link/dce/link-lib-2/Lib_2.scala
@@ -0,0 +1,4 @@
+
+class Bar extends Foo {
+ def barbar = foo
+}
diff --git a/tests/link/dce/link-local-lambda.check b/tests/link/dce/link-local-lambda.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-local-lambda.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-local-lambda.scala b/tests/link/dce/link-local-lambda.scala
new file mode 100644
index 000000000000..b617a3d6a2f0
--- /dev/null
+++ b/tests/link/dce/link-local-lambda.scala
@@ -0,0 +1,8 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 7, reachableMethods = 7)
+ def main(args: Array[String]): Unit = {
+ System.out.println((() => 42)())
+ }
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-local-lazy-val.check b/tests/link/dce/link-local-lazy-val.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-local-lazy-val.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-local-lazy-val.scala b/tests/link/dce/link-local-lazy-val.scala
new file mode 100644
index 000000000000..1b78648debc9
--- /dev/null
+++ b/tests/link/dce/link-local-lazy-val.scala
@@ -0,0 +1,9 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 7, reachableMethods = 7)
+ def main(args: Array[String]): Unit = {
+ lazy val x = 42
+ System.out.println(x)
+ }
+}
\ No newline at end of file
diff --git a/tests/link/dce/link-main-module-load.check b/tests/link/dce/link-main-module-load.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-main-module-load.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-main-module-load.scala b/tests/link/dce/link-main-module-load.scala
new file mode 100644
index 000000000000..3bcc492c200a
--- /dev/null
+++ b/tests/link/dce/link-main-module-load.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+
+ @internal.link.CallGraphBounds(reachableClasses = 19, classesWithReachableMethods = 6, reachableMethods = 7)
+ def main(args: Array[String]): Unit = ()
+
+ @internal.link.AssertReachable def foo() = System.out.println(42)
+
+ foo()
+
+}
diff --git a/tests/link/dce/link-mixinInit-1.check b/tests/link/dce/link-mixinInit-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-1.scala b/tests/link/dce/link-mixinInit-1.scala
new file mode 100644
index 000000000000..1d534951985b
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-1.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 8, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ new Bar
+ }
+}
+
+class Bar extends Foo
+
+trait Foo {
+ System.out.println(42)
+}
diff --git a/tests/link/dce/link-mixinInit-2.check b/tests/link/dce/link-mixinInit-2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-2.scala b/tests/link/dce/link-mixinInit-2.scala
new file mode 100644
index 000000000000..9729407df373
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-2.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 8, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ new Bar
+ }
+}
+
+class Bar extends Foo(42)
+
+trait Foo(n: Int) {
+ System.out.println(n)
+}
diff --git a/tests/link/dce/link-mixinInit-3.check b/tests/link/dce/link-mixinInit-3.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-3.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-3.scala b/tests/link/dce/link-mixinInit-3.scala
new file mode 100644
index 000000000000..f25ac2ea98e5
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-3.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 21, classesWithReachableMethods = 8, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ new Bar
+ }
+}
+
+class Bar extends Foo[Int]
+
+trait Foo[T] {
+ System.out.println(42)
+}
diff --git a/tests/link/dce/link-mixinInit-4.check b/tests/link/dce/link-mixinInit-4.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-4.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-4.scala b/tests/link/dce/link-mixinInit-4.scala
new file mode 100644
index 000000000000..74216fa71cdb
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-4.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 23, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ new Bar
+ }
+}
+
+class Bar extends Foo[Int](42)
+
+trait Foo[T](n: Int) {
+ System.out.println(n)
+}
diff --git a/tests/link/dce/link-mixinInit-5.check b/tests/link/dce/link-mixinInit-5.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-5.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-5.scala b/tests/link/dce/link-mixinInit-5.scala
new file mode 100644
index 000000000000..4b624d83780b
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-5.scala
@@ -0,0 +1,19 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 24, classesWithReachableMethods = 7, reachableMethods = 10)
+ def main(args: Array[String]): Unit = {
+ new Foo
+ }
+}
+
+class Foo extends Bar {
+ def foo(): Unit = System.out.println(42)
+}
+
+trait Bar extends Baz
+
+trait Baz {
+ foo()
+ def foo(): Unit
+}
diff --git a/tests/link/dce/link-mixinInit-6.check b/tests/link/dce/link-mixinInit-6.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-6.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-mixinInit-6.scala b/tests/link/dce/link-mixinInit-6.scala
new file mode 100644
index 000000000000..33b5e877a630
--- /dev/null
+++ b/tests/link/dce/link-mixinInit-6.scala
@@ -0,0 +1,21 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 25, classesWithReachableMethods = 8, reachableMethods = 11)
+ def main(args: Array[String]): Unit = {
+ new Foo
+ }
+}
+
+class Foo extends Foo2 with Bar {
+ def foo(): Unit = System.out.println(42)
+}
+
+abstract class Foo2 extends Baz
+
+trait Bar extends Baz
+
+trait Baz {
+ foo()
+ def foo(): Unit
+}
diff --git a/tests/link/dce/link-predef-toList.check b/tests/link/dce/link-predef-toList.check
new file mode 100644
index 000000000000..600d9f049192
--- /dev/null
+++ b/tests/link/dce/link-predef-toList.check
@@ -0,0 +1,3 @@
+start
+Predef loaded
+end
diff --git a/tests/link/dce/link-secondary-constructor-0.check b/tests/link/dce/link-secondary-constructor-0.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-secondary-constructor-0.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-secondary-constructor-0.scala b/tests/link/dce/link-secondary-constructor-0.scala
new file mode 100644
index 000000000000..f9dc06beb5d8
--- /dev/null
+++ b/tests/link/dce/link-secondary-constructor-0.scala
@@ -0,0 +1,15 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 7, reachableMethods = 10)
+ def main(args: Array[String]): Unit = {
+ new Foo()
+ }
+}
+
+class Foo(n: Int) {
+ def this() = this(42)
+
+ @internal.link.AssertReachable def foo() = System.out.println(n)
+ foo()
+}
diff --git a/tests/link/dce/link-super-call-1.check b/tests/link/dce/link-super-call-1.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/dce/link-super-call-1.scala b/tests/link/dce/link-super-call-1.scala
new file mode 100644
index 000000000000..ea86cd22ab1d
--- /dev/null
+++ b/tests/link/dce/link-super-call-1.scala
@@ -0,0 +1,18 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 10, classesWithReachableMethods = 4, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ val a = new Foo
+ a.foo()
+ }
+}
+
+class Foo extends Bar {
+ @internal.link.AssertReachable def foo(): Unit = super.bar()
+}
+
+trait Bar {
+ @internal.link.AssertReachable def bar(): Unit = baz()
+ @internal.link.AssertReachable def baz(): Unit = ()
+}
diff --git a/tests/link/dce/link-system-println.check b/tests/link/dce/link-system-println.check
new file mode 100644
index 000000000000..20b841e036ab
--- /dev/null
+++ b/tests/link/dce/link-system-println.check
@@ -0,0 +1,3 @@
+hello
+1
+true
diff --git a/tests/link/dce/link-system-println.scala b/tests/link/dce/link-system-println.scala
new file mode 100644
index 000000000000..31a937ab5cd1
--- /dev/null
+++ b/tests/link/dce/link-system-println.scala
@@ -0,0 +1,10 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 20, classesWithReachableMethods = 6, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ System.out.println("hello")
+ System.out.println(1)
+ System.out.println(true)
+ }
+}
diff --git a/tests/link/dce/link-trait-overrides.check b/tests/link/dce/link-trait-overrides.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-trait-overrides.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-trait-overrides.scala b/tests/link/dce/link-trait-overrides.scala
new file mode 100644
index 000000000000..06788356235f
--- /dev/null
+++ b/tests/link/dce/link-trait-overrides.scala
@@ -0,0 +1,19 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 24, classesWithReachableMethods = 7, reachableMethods = 8)
+ def main(args: Array[String]): Unit = {
+ new Foo().foo
+ }
+}
+
+class Foo extends Bar
+
+trait Bar extends Baz {
+ override def foo = System.out.println(42)
+}
+
+trait Baz {
+ @internal.link.AssertNotReachable
+ def foo = System.out.println(5)
+}
diff --git a/tests/link/dce/link-val-init-1.check b/tests/link/dce/link-val-init-1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-val-init-1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-val-init-1.scala b/tests/link/dce/link-val-init-1.scala
new file mode 100644
index 000000000000..a00369cc9efb
--- /dev/null
+++ b/tests/link/dce/link-val-init-1.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+class Foo {
+ @internal.link.AssertReachable
+ def foo = System.out.println(42)
+ val bar = foo
+}
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ new Foo
+ }
+}
diff --git a/tests/link/dce/link-val-init-2.check b/tests/link/dce/link-val-init-2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-val-init-2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-val-init-2.scala b/tests/link/dce/link-val-init-2.scala
new file mode 100644
index 000000000000..699a4ce2349f
--- /dev/null
+++ b/tests/link/dce/link-val-init-2.scala
@@ -0,0 +1,17 @@
+import scala.annotation.internal
+
+class Foo {
+ @internal.link.AssertReachable
+ def foo = System.out.println(42)
+
+ {
+ val bar = foo
+ }
+}
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 8, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ new Foo
+ }
+}
diff --git a/tests/link/dce/link-val-init-3.check b/tests/link/dce/link-val-init-3.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/dce/link-val-init-3.scala b/tests/link/dce/link-val-init-3.scala
new file mode 100644
index 000000000000..c30e79f46e42
--- /dev/null
+++ b/tests/link/dce/link-val-init-3.scala
@@ -0,0 +1,14 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 10, classesWithReachableMethods = 4, reachableMethods = 6)
+ def main(args: Array[String]): Unit = {
+ new Foo
+ }
+}
+
+final class Foo extends Bar[Int]
+
+trait Bar[T] {
+ val value: Int = 42
+}
diff --git a/tests/link/dce/link-var-setters-1.check b/tests/link/dce/link-var-setters-1.check
new file mode 100644
index 000000000000..192e9d9a1f33
--- /dev/null
+++ b/tests/link/dce/link-var-setters-1.check
@@ -0,0 +1,2 @@
+1
+42
diff --git a/tests/link/dce/link-var-setters-1.scala b/tests/link/dce/link-var-setters-1.scala
new file mode 100644
index 000000000000..64fa304333fe
--- /dev/null
+++ b/tests/link/dce/link-var-setters-1.scala
@@ -0,0 +1,21 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 22, classesWithReachableMethods = 7, reachableMethods = 9)
+ def main(args: Array[String]): Unit = {
+ val foo = new Foo
+ System.out.println(foo.bar)
+ foo.baz()
+ System.out.println(foo.bar)
+ }
+}
+
+
+class Foo {
+ var bar = 1
+
+ @internal.link.AssertReachable
+ def baz(): Unit = {
+ bar = 42
+ }
+}
diff --git a/tests/link/dce/link-varargs-Any-empty.check b/tests/link/dce/link-varargs-Any-empty.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any-empty.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-Any-empty/MainGenericRunner.java b/tests/link/dce/link-varargs-Any-empty/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any-empty/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-Any-empty/Test.scala b/tests/link/dce/link-varargs-Any-empty/Test.scala
new file mode 100644
index 000000000000..66a3cae92a3a
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any-empty/Test.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 171, classesWithReachableMethods = 50, reachableMethods = 211)
+ def main(args: Array[String]): Unit = {
+ foo()
+ }
+
+ def foo(ns: Any*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-Any.check b/tests/link/dce/link-varargs-Any.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-Any/MainGenericRunner.java b/tests/link/dce/link-varargs-Any/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-Any/link-varargs-Any.scala b/tests/link/dce/link-varargs-Any/link-varargs-Any.scala
new file mode 100644
index 000000000000..dd64a0564235
--- /dev/null
+++ b/tests/link/dce/link-varargs-Any/link-varargs-Any.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 170, classesWithReachableMethods = 49, reachableMethods = 210)
+ def main(args: Array[String]): Unit = {
+ foo("a", "b", "c")
+ }
+
+ def foo(ns: Any*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-AnyRef-empty.check b/tests/link/dce/link-varargs-AnyRef-empty.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef-empty.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-AnyRef-empty/MainGenericRunner.java b/tests/link/dce/link-varargs-AnyRef-empty/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef-empty/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-AnyRef-empty/Test.scala b/tests/link/dce/link-varargs-AnyRef-empty/Test.scala
new file mode 100644
index 000000000000..cd5904553e00
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef-empty/Test.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 172, classesWithReachableMethods = 55, reachableMethods = 177)
+ def main(args: Array[String]): Unit = {
+ foo()
+ }
+
+ def foo(ns: AnyRef*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-AnyRef.check b/tests/link/dce/link-varargs-AnyRef.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-AnyRef/MainGenericRunner.java b/tests/link/dce/link-varargs-AnyRef/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-AnyRef/Test.scala b/tests/link/dce/link-varargs-AnyRef/Test.scala
new file mode 100644
index 000000000000..def3ad9e8458
--- /dev/null
+++ b/tests/link/dce/link-varargs-AnyRef/Test.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 171, classesWithReachableMethods = 50, reachableMethods = 211)
+ def main(args: Array[String]): Unit = {
+ foo(new Object)
+ }
+
+ def foo(ns: AnyRef*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-int-empty.check b/tests/link/dce/link-varargs-int-empty.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-int-empty.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-int-empty/MainGenericRunner.java b/tests/link/dce/link-varargs-int-empty/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-int-empty/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-int-empty/Test.scala b/tests/link/dce/link-varargs-int-empty/Test.scala
new file mode 100644
index 000000000000..75af6600b41a
--- /dev/null
+++ b/tests/link/dce/link-varargs-int-empty/Test.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 171, classesWithReachableMethods = 50, reachableMethods = 210)
+ def main(args: Array[String]): Unit = {
+ foo()
+ }
+
+ def foo(ns: Int*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-int.check b/tests/link/dce/link-varargs-int.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-int.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-int/MainGenericRunner.java b/tests/link/dce/link-varargs-int/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-int/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-int/Test.scala b/tests/link/dce/link-varargs-int/Test.scala
new file mode 100644
index 000000000000..d6ad3446fbc2
--- /dev/null
+++ b/tests/link/dce/link-varargs-int/Test.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 173, classesWithReachableMethods = 54, reachableMethods = 176)
+ def main(args: Array[String]): Unit = {
+ foo(1, 2, 3)
+ }
+
+ def foo(ns: Int*): Unit = {
+ System.out.println(42)
+ }
+}
diff --git a/tests/link/dce/link-varargs-poly1.check b/tests/link/dce/link-varargs-poly1.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly1.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-poly1/MainGenericRunner.java b/tests/link/dce/link-varargs-poly1/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly1/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-poly1/Test.scala b/tests/link/dce/link-varargs-poly1/Test.scala
new file mode 100644
index 000000000000..0ea94307024f
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly1/Test.scala
@@ -0,0 +1,15 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 170, classesWithReachableMethods = 49, reachableMethods = 210)
+ def main(args: Array[String]): Unit = {
+ foo(1)
+ }
+
+ def bar[T](x: T) = foo(x)
+
+ def foo(ns: Any*): Unit = {
+ System.out.println(42)
+ }
+
+}
diff --git a/tests/link/dce/link-varargs-poly2-empty.check b/tests/link/dce/link-varargs-poly2-empty.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2-empty.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-poly2-empty/MainGenericRunner.java b/tests/link/dce/link-varargs-poly2-empty/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2-empty/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-poly2-empty/Test.scala b/tests/link/dce/link-varargs-poly2-empty/Test.scala
new file mode 100644
index 000000000000..67e65af68d78
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2-empty/Test.scala
@@ -0,0 +1,15 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 171, classesWithReachableMethods = 50, reachableMethods = 210)
+ def main(args: Array[String]): Unit = {
+ foo(1)
+ }
+
+ def bar[T](x: T) = foo()
+
+ def foo[U](ns: U*): Unit = {
+ System.out.println(42)
+ }
+
+}
diff --git a/tests/link/dce/link-varargs-poly2.check b/tests/link/dce/link-varargs-poly2.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/dce/link-varargs-poly2/MainGenericRunner.java b/tests/link/dce/link-varargs-poly2/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-poly2/Test.scala b/tests/link/dce/link-varargs-poly2/Test.scala
new file mode 100644
index 000000000000..18013dbb5505
--- /dev/null
+++ b/tests/link/dce/link-varargs-poly2/Test.scala
@@ -0,0 +1,15 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 171, classesWithReachableMethods = 50, reachableMethods = 210)
+ def main(args: Array[String]): Unit = {
+ foo(1)
+ }
+
+ def bar[T](x: T) = foo(x)
+
+ def foo[U](ns: U*): Unit = {
+ System.out.println(42)
+ }
+
+}
diff --git a/tests/link/dce/link-varargs-tupple.check b/tests/link/dce/link-varargs-tupple.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/dce/link-varargs-tupple/MainGenericRunner.java b/tests/link/dce/link-varargs-tupple/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/dce/link-varargs-tupple/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/dce/link-varargs-tupple/Test.scala b/tests/link/dce/link-varargs-tupple/Test.scala
new file mode 100644
index 000000000000..d31426c14a75
--- /dev/null
+++ b/tests/link/dce/link-varargs-tupple/Test.scala
@@ -0,0 +1,8 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ // scala.collection.immutable.Map[Int, Int]((1, 2), (3, 4), (5, 6))
+ tupples((1, 2))
+ }
+ def tupples[A, B](elems: (A, B)*): Unit = ()
+}
diff --git a/tests/link/dce/link-while-loop-1.check b/tests/link/dce/link-while-loop-1.check
new file mode 100644
index 000000000000..9dfcf39f5a78
--- /dev/null
+++ b/tests/link/dce/link-while-loop-1.check
@@ -0,0 +1,5 @@
+0
+1
+2
+3
+4
diff --git a/tests/link/dce/link-while-loop-1.scala b/tests/link/dce/link-while-loop-1.scala
new file mode 100644
index 000000000000..606e15896a6a
--- /dev/null
+++ b/tests/link/dce/link-while-loop-1.scala
@@ -0,0 +1,12 @@
+import scala.annotation.{internal, tailrec}
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 19, classesWithReachableMethods = 6, reachableMethods = 6)
+ def main(args: Array[String]): Unit = {
+ var i = 0
+ while (i < 5) {
+ System.out.println(i)
+ i += 1
+ }
+ }
+}
diff --git a/tests/link/dce/link-while-loop-2.check b/tests/link/dce/link-while-loop-2.check
new file mode 100644
index 000000000000..9dfcf39f5a78
--- /dev/null
+++ b/tests/link/dce/link-while-loop-2.check
@@ -0,0 +1,5 @@
+0
+1
+2
+3
+4
diff --git a/tests/link/dce/link-while-loop-2.scala b/tests/link/dce/link-while-loop-2.scala
new file mode 100644
index 000000000000..e4cbdfde52d8
--- /dev/null
+++ b/tests/link/dce/link-while-loop-2.scala
@@ -0,0 +1,12 @@
+import scala.annotation.internal
+
+object Test {
+ @internal.link.CallGraphBounds(reachableClasses = 19, classesWithReachableMethods = 6, reachableMethods = 6)
+ def main(args: Array[String]): Unit = {
+ var i = 0
+ do {
+ System.out.println(i)
+ i += 1
+ } while (i < 5)
+ }
+}
diff --git a/tests/link/specialize/link-specialize-method-1.check b/tests/link/specialize/link-specialize-method-1.check
new file mode 100644
index 000000000000..ab4a19b21010
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-1.check
@@ -0,0 +1,3 @@
+42
+string
+Foo
diff --git a/tests/link/specialize/link-specialize-method-1.scala b/tests/link/specialize/link-specialize-method-1.scala
new file mode 100644
index 000000000000..54ad95561aa8
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-1.scala
@@ -0,0 +1,31 @@
+import SpecializeUtils._
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val foo = new Foo
+ System.out.println(foo.f(42))
+ System.out.println(foo.f("string"))
+ System.out.println(foo.f(foo))
+
+ checkMethodExists(classOf[Foo], "f", List(classOf[Object]), classOf[Object], specialized = false)
+ checkMethodExists(classOf[Foo], "f", List(classOf[Int]), classOf[Int])
+ checkMethodExists(classOf[Foo], "f", List(classOf[String]), classOf[String])
+ checkMethodExists(classOf[Foo], "f", List(classOf[Foo]), classOf[Foo])
+ }
+}
+
+class Foo {
+ def f[T](e: T): T = e
+
+ override def toString: String = "Foo"
+}
+
+object SpecializeUtils {
+
+ def checkMethodExists(cls: Class[_], name: String, params: List[Class[_]], ret: Class[_], specialized: Boolean = true): Unit = {
+ val nameMatch = if (specialized) name + "\\$spec\\d*" else name
+ val methods = cls.getDeclaredMethods
+ assert(methods.count(x => x.getName.matches(nameMatch) && x.getParameterTypes.toList == params && x.getReturnType == ret) == 1)
+ }
+
+}
diff --git a/tests/link/specialize/link-specialize-method-2.check b/tests/link/specialize/link-specialize-method-2.check
new file mode 100644
index 000000000000..ab4a19b21010
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-2.check
@@ -0,0 +1,3 @@
+42
+string
+Foo
diff --git a/tests/link/specialize/link-specialize-method-2.scala b/tests/link/specialize/link-specialize-method-2.scala
new file mode 100644
index 000000000000..991e3a3d4d37
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-2.scala
@@ -0,0 +1,38 @@
+import SpecializeUtils._
+
+object Test {
+
+ def main(args: Array[String]): Unit = {
+ val foo = new Foo
+ System.out.println(foo.f(42))
+ System.out.println(foo.f("string"))
+ System.out.println(foo.f(foo))
+
+ checkMethodExists(classOf[Foo], "f", List(classOf[Object]), classOf[Object], specialized = false)
+ checkMethodExists(classOf[Foo], "f", List(classOf[Int]), classOf[Int])
+ checkMethodExists(classOf[Foo], "f", List(classOf[String]), classOf[String])
+ checkMethodExists(classOf[Foo], "f", List(classOf[Foo]), classOf[Foo])
+
+ checkMethodExists(classOf[Foo], "g", List(classOf[Object]), classOf[Object], specialized = false)
+ checkMethodExists(classOf[Foo], "g", List(classOf[Int]), classOf[Int])
+ checkMethodExists(classOf[Foo], "g", List(classOf[String]), classOf[String])
+ checkMethodExists(classOf[Foo], "g", List(classOf[Foo]), classOf[Foo])
+ }
+}
+
+class Foo {
+ def f[T](e: T): T = g(e)
+ def g[T](e: T): T = e
+
+ override def toString: String = "Foo"
+}
+
+object SpecializeUtils {
+
+ def checkMethodExists(cls: Class[_], name: String, params: List[Class[_]], ret: Class[_], specialized: Boolean = true): Unit = {
+ val nameMatch = if (specialized) name + "\\$spec\\d*" else name
+ val methods = cls.getDeclaredMethods
+ assert(methods.count(x => x.getName.matches(nameMatch) && x.getParameterTypes.toList == params && x.getReturnType == ret) == 1)
+ }
+
+}
diff --git a/tests/link/specialize/link-specialize-method-3.check b/tests/link/specialize/link-specialize-method-3.check
new file mode 100644
index 000000000000..05c910ede53c
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-3.check
@@ -0,0 +1,2 @@
+Bar
+Bar
diff --git a/tests/link/specialize/link-specialize-method-3.scala b/tests/link/specialize/link-specialize-method-3.scala
new file mode 100644
index 000000000000..b9ec59de26d0
--- /dev/null
+++ b/tests/link/specialize/link-specialize-method-3.scala
@@ -0,0 +1,35 @@
+import SpecializeUtils._
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val foo = new Foo
+ System.out.println(foo.fun1(new Bar))
+ System.out.println(foo.fun2(new Bar))
+
+ checkMethodExists(classOf[Foo], "fun1", List(classOf[Foo]), classOf[Foo], specialized = false)
+ checkMethodExists(classOf[Foo], "fun1", List(classOf[Bar]), classOf[Bar])
+
+ checkMethodExists(classOf[Foo], "fun2", List(classOf[Foo]), classOf[Foo], specialized = false)
+ }
+
+}
+
+class Foo {
+ def fun1[F <: Foo](x: F) = x // Specialized
+ def fun2(x: Foo) = x // Not specialized
+
+}
+
+class Bar extends Foo {
+ override def toString: String = "Bar"
+}
+
+object SpecializeUtils {
+
+ def checkMethodExists(cls: Class[_], name: String, params: List[Class[_]], ret: Class[_], specialized: Boolean = true): Unit = {
+ val nameMatch = if (specialized) name + "\\$spec\\d*" else name
+ val methods = cls.getDeclaredMethods
+ assert(methods.count(x => x.getName.matches(nameMatch) && x.getParameterTypes.toList == params && x.getReturnType == ret) == 1)
+ }
+
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString.check
new file mode 100644
index 000000000000..2739d724db3b
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString.check
@@ -0,0 +1 @@
+1, 2, 3
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/Test.scala
new file mode 100644
index 000000000000..202104713c3e
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ System.out.println(Array(1, 2, 3).mkString(", "))
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-array-mkString/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/Test.scala
new file mode 100644
index 000000000000..5795cdfdeca1
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/Test.scala
@@ -0,0 +1,8 @@
+import scala.annotation.internal
+import scala.collection.mutable
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ mutable.HashMap[String, String]()
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-hashmap/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/Test.scala
new file mode 100644
index 000000000000..e8d664f8ffb1
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.List(1, 2, 3)
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-list-3/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/Test.scala
new file mode 100644
index 000000000000..27978b534311
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.mutable.Set.empty[Int]
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-0/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/Test.scala
new file mode 100644
index 000000000000..2255dc339da9
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.mutable.Set[Int]()
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-1/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/Test.scala
new file mode 100644
index 000000000000..e8587a9569c3
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.mutable.Set[Int](1, 2, 2)
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-mutable-set-2/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/Test.scala
new file mode 100644
index 000000000000..6dfaa2117076
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Set[Int]()
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-1/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/Test.scala
new file mode 100644
index 000000000000..a566331cdbee
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Set[Int](1, 2, 2)
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-set-2/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/Test.scala
new file mode 100644
index 000000000000..bca85d6bf3fd
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Vector.empty[Int] :+ 1
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-2/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/Test.scala
new file mode 100644
index 000000000000..941387f2d2fd
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Vector(1, 2, 3)
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-3/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/Test.scala
new file mode 100644
index 000000000000..14f3912ea652
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/Test.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Vector[Int](1, 3, 42) :+ 1
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/App.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-4/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5.check b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5.check
new file mode 100644
index 000000000000..1c4872563001
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5.check
@@ -0,0 +1,2 @@
+864
+46
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/MainGenericRunner.java b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/Test.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/Test.scala
new file mode 100644
index 000000000000..19773ff26573
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/Test.scala
@@ -0,0 +1,9 @@
+import scala.collection.immutable._
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val vec = Vector[Int](1, 3, 42)
+ System.out.println(vec.map(0 until _).flatMap(x => x).sum)
+ System.out.println(vec.fold(0)(_ + _))
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/OVERWRITES b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-compile/stdlib-link-vector-5/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/MainGenericRunner.java b/tests/link/stdlib-dce-fail-run/stdlib-link-App/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-App/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/Test.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-App/Test.scala
new file mode 100644
index 000000000000..525c3de08885
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-App/Test.scala
@@ -0,0 +1,4 @@
+
+object Test extends App {
+ System.out.println(42)
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/OVERWRITES b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-App/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList.check b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/MainGenericRunner.java b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/Test.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/Test.scala
new file mode 100644
index 000000000000..5a2aff46ef13
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/Test.scala
@@ -0,0 +1,8 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ args.toList
+ }
+
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/App.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/OVERWRITES b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-array-toList/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2.check b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/MainGenericRunner.java b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/Test.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/Test.scala
new file mode 100644
index 000000000000..0f6f25e3752a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/Test.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Map[Int, Int]((1, 2), (3, 4), (5, 6))
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/OVERWRITES b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-map-2/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4.check b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/MainGenericRunner.java b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/Test.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/Test.scala
new file mode 100644
index 000000000000..7184318b57b5
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/Test.scala
@@ -0,0 +1,12 @@
+
+object Test {
+ object TestSeq {
+ def unapplySeq(x: Int): Option[Seq[Int]] = Some(List(x, x, x))
+ }
+
+ def main(args: Array[String]): Unit = {
+ 42 match {
+ case TestSeq(42, x, 42) => System.out.println(x)
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/App.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/App.scala
new file mode 100644
index 000000000000..b0f3a2afa531
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/App.scala
@@ -0,0 +1,84 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2010-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.compat.Platform.currentTime
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ * Here, object `Main` inherits the `main` method of `App`.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * It should also be noted that the `main` method should not be overridden:
+ * the whole class body becomes the “main method”.
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * @author Martin Odersky
+ * @version 2.1, 15/02/2011
+ */
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ @deprecatedOverriding("executionStart should not be overridden", "2.11.0")
+ val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ @deprecatedOverriding("args should not be overridden", "2.11.0")
+ protected def args: Array[String] = _args
+
+ private var _args: Array[String] = _
+
+ private val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("The delayedInit mechanism will disappear.", "2.11.0")
+ override def delayedInit(body: => Unit) {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ /* DISABELED FOR CALLGRAPH DCE
+ @deprecatedOverriding("main should not be overridden", "2.11.0")
+ def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/Enumeration.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/OVERWRITES b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/util/Properties.scala b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/util/Properties.scala
new file mode 100644
index 000000000000..8254f062619a
--- /dev/null
+++ b/tests/link/stdlib-dce-fail-run/stdlib-link-patmatch-4/scala/util/Properties.scala
@@ -0,0 +1,199 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package util
+
+import java.io.{ IOException, PrintWriter }
+import java.util.jar.Attributes.{ Name => AttributeName }
+
+/** Loads `library.properties` from the jar. */
+object Properties extends PropertiesTrait {
+ protected def propCategory = "library"
+ protected def pickJarBasedOn = classOf[Option[_]]
+
+ /** Scala manifest attributes.
+ */
+ val ScalaCompilerVersion = new AttributeName("Scala-Compiler-Version")
+}
+
+private[scala] trait PropertiesTrait {
+ protected def propCategory: String // specializes the remainder of the values
+ protected def pickJarBasedOn: Class[_] // props file comes from jar containing this
+
+ /** The name of the properties file */
+ protected val propFilename = "/" + propCategory + ".properties"
+
+ /** The loaded properties */
+ protected lazy val scalaProps: java.util.Properties = {
+ val props = new java.util.Properties
+ val stream = pickJarBasedOn getResourceAsStream propFilename
+ if (stream ne null)
+ quietlyDispose(props load stream, stream.close)
+
+ props
+ }
+
+ private def quietlyDispose(action: => Unit, disposal: => Unit) =
+ try { action }
+ finally {
+ try { disposal }
+ catch { case _: IOException => }
+ }
+
+ def propIsSet(name: String) = System.getProperty(name) != null
+ def propIsSetTo(name: String, value: String) = propOrNull(name) == value
+ def propOrElse(name: String, alt: String) = System.getProperty(name, alt)
+ def propOrEmpty(name: String) = propOrElse(name, "")
+ def propOrNull(name: String) = propOrElse(name, null)
+ def propOrNone(name: String) = Option(propOrNull(name))
+ def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase)
+ def setProp(name: String, value: String) = System.setProperty(name, value)
+ def clearProp(name: String) = System.clearProperty(name)
+
+ def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt
+ def envOrNone(name: String) = Option(System getenv name)
+
+ def envOrSome(name: String, alt: Option[String]) = envOrNone(name) orElse alt
+
+ // for values based on propFilename, falling back to System properties
+ def scalaPropOrElse(name: String, alt: String): String = scalaPropOrNone(name).getOrElse(alt)
+ def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "")
+ def scalaPropOrNone(name: String): Option[String] = Option(scalaProps.getProperty(name)).orElse(propOrNone("scala." + name))
+
+ /** The numeric portion of the runtime Scala version, if this is a final
+ * release. If for instance the versionString says "version 2.9.0.final",
+ * this would return Some("2.9.0").
+ *
+ * @return Some(version) if this is a final release build, None if
+ * it is an RC, Beta, etc. or was built from source, or if the version
+ * cannot be read.
+ */
+ val releaseVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if !(v endsWith "-SNAPSHOT")
+ } yield v
+
+ /** The development Scala version, if this is not a final release.
+ * The precise contents are not guaranteed, but it aims to provide a
+ * unique repository identifier (currently the svn revision) in the
+ * fourth dotted segment if the running version was built from source.
+ *
+ * @return Some(version) if this is a non-final version, None if this
+ * is a final release or the version cannot be read.
+ */
+ val developmentVersion =
+ for {
+ v <- scalaPropOrNone("maven.version.number")
+ if v endsWith "-SNAPSHOT"
+ ov <- scalaPropOrNone("version.number")
+ } yield ov
+
+ /** Either the development or release version if known, otherwise
+ * the empty string.
+ */
+ def versionNumberString = scalaPropOrEmpty("version.number")
+
+ /** The version number of the jar this was loaded from plus "version " prefix,
+ * or "version (unknown)" if it cannot be determined.
+ */
+ val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2013, LAMP/EPFL")
+
+ /** This is the encoding to use reading in source files, overridden with -encoding.
+ * Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
+ */
+ def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8")
+ def sourceReader = scalaPropOrElse("source.reader", "scala.tools.nsc.io.SourceReader")
+
+ /** This is the default text encoding, overridden (unreliably) with
+ * `JAVA_OPTS="-Dfile.encoding=Foo"`
+ */
+ def encodingString = propOrElse("file.encoding", "UTF-8")
+
+ /** The default end of line character.
+ */
+ def lineSeparator = propOrElse("line.separator", "\n")
+
+ /* Various well-known properties. */
+ def javaClassPath = propOrEmpty("java.class.path")
+ def javaHome = propOrEmpty("java.home")
+ def javaVendor = propOrEmpty("java.vendor")
+ def javaVersion = propOrEmpty("java.version")
+ def javaVmInfo = propOrEmpty("java.vm.info")
+ def javaVmName = propOrEmpty("java.vm.name")
+ def javaVmVendor = propOrEmpty("java.vm.vendor")
+ def javaVmVersion = propOrEmpty("java.vm.version")
+ def javaSpecVersion = propOrEmpty("java.specification.version")
+ def javaSpecVendor = propOrEmpty("java.specification.vendor")
+ def javaSpecName = propOrEmpty("java.specification.name")
+ def osName = propOrEmpty("os.name")
+ def scalaHome = propOrEmpty("scala.home")
+ def tmpDir = propOrEmpty("java.io.tmpdir")
+ def userDir = propOrEmpty("user.dir")
+ def userHome = propOrEmpty("user.home")
+ def userName = propOrEmpty("user.name")
+
+ /* Some derived values. */
+ /** Returns `true` iff the underlying operating system is a version of Microsoft Windows. */
+ def isWin = osName startsWith "Windows"
+ // See http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005148.html for
+ // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110.
+ /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */
+ def isMac = osName startsWith "Mac OS X"
+
+ /* Some runtime values. */
+ private[scala] def isAvian = javaVmName contains "Avian"
+
+ // This is looking for javac, tools.jar, etc.
+ // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME,
+ // and finally the system property based javaHome.
+ def jdkHome = envOrElse("JDK_HOME", envOrElse("JAVA_HOME", javaHome))
+
+ // private[scala] for 2.12
+ private[this] def versionFor(command: String) = f"Scala $command $versionString -- $copyrightString"
+
+ def versionMsg = versionFor(propCategory)
+ def scalaCmd = if (isWin) "scala.bat" else "scala"
+ def scalacCmd = if (isWin) "scalac.bat" else "scalac"
+
+ /** Compares the given specification version to the specification version of the platform.
+ *
+ * @param version a specification version of the form "major.minor"
+ * @return `true` iff the specification version of the current runtime
+ * is equal to or higher than the version denoted by the given string.
+ * @throws NumberFormatException if the given string is not a version string
+ *
+ * @example {{{
+ * // In this example, the runtime's Java specification is assumed to be at version 1.7.
+ * isJavaAtLeast("1.6") // true
+ * isJavaAtLeast("1.7") // true
+ * isJavaAtLeast("1.8") // false
+ * }}}
+ */
+ def isJavaAtLeast(version: String): Boolean = {
+ def parts(x: String) = {
+ val i = x.indexOf('.')
+ if (i < 0) throw new NumberFormatException("Not a version: " + x)
+ (x.substring(0, i), x.substring(i+1, x.length))
+ }
+ val (v, _v) = parts(version)
+ val (s, _s) = parts(javaSpecVersion)
+ s.toInt >= v.toInt && _s.toInt >= _v.toInt
+ }
+
+ // provide a main method so version info can be obtained by running this
+ /* DISABELED FOR CALLGRAPH DCE
+ def main(args: Array[String]) {
+ val writer = new PrintWriter(Console.err, true)
+ writer println versionMsg
+ }
+ */
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-3xqmark.check b/tests/link/stdlib-dce/stdlib-link-3xqmark.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-3xqmark.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/stdlib-dce/stdlib-link-list.check b/tests/link/stdlib-dce/stdlib-link-list.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-list/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-list/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-list/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-list/Test.scala b/tests/link/stdlib-dce/stdlib-link-list/Test.scala
new file mode 100644
index 000000000000..94de904643ea
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-list/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ 1 :: scala.collection.immutable.List.empty[Int]
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-map.check b/tests/link/stdlib-dce/stdlib-link-map.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-map/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-map/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-map/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-map/Test.scala b/tests/link/stdlib-dce/stdlib-link-map/Test.scala
new file mode 100644
index 000000000000..12ca4d78737f
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-map/Test.scala
@@ -0,0 +1,8 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Map.empty[Int, Int]
+ scala.collection.immutable.Map[Int, Int]()
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init.check b/tests/link/stdlib-dce/stdlib-link-module-init.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-module-init/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-module-init/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init/Test.scala b/tests/link/stdlib-dce/stdlib-link-module-init/Test.scala
new file mode 100644
index 000000000000..20a5fdf2943b
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-module-init/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ Predef // Just load Predef module
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init/scala/Enumeration.scala b/tests/link/stdlib-dce/stdlib-link-module-init/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-module-init/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init/scala/OVERWRITES b/tests/link/stdlib-dce/stdlib-link-module-init/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-module-init/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce/stdlib-link-module-init/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-module-init/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce/stdlib-link-mutable-set.check b/tests/link/stdlib-dce/stdlib-link-mutable-set.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-patmatch.check b/tests/link/stdlib-dce/stdlib-link-patmatch.check
new file mode 100644
index 000000000000..573105485fa9
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-patmatch.check
@@ -0,0 +1,4 @@
+21
+7
+42
+43
diff --git a/tests/link/stdlib-dce/stdlib-link-patmatch/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-patmatch/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-patmatch/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-patmatch/Test.scala b/tests/link/stdlib-dce/stdlib-link-patmatch/Test.scala
new file mode 100644
index 000000000000..9223c670ef00
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-patmatch/Test.scala
@@ -0,0 +1,34 @@
+import scala.annotation.internal
+
+object Test {
+ object Twice {
+ def unapply(x: Int): Option[Int] = if (x % 2 == 0) Some(x / 2) else None
+ }
+
+ object Thrice {
+ def unapply(x: Int): Option[Int] = if (x % 3 == 0) Some(x / 3) else None
+ }
+
+ object In2 {
+ def unapply(x: Int): Option[(Int, Int)] = if (x % 2 == 0) Some(x / 2, x / 2) else None
+ }
+
+ case class Foo(x: Int)
+
+ def main(args: Array[String]): Unit = {
+ 84 match {
+ case In2(Twice(x), Twice(Thrice(y))) =>
+ System.out.println(x)
+ System.out.println(y)
+ case _ =>
+ }
+
+ val Twice(x) = 84
+ System.out.println(x)
+
+ Foo(43) match {
+ case Foo(x) => System.out.println(x)
+ case _ =>
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-predef.check b/tests/link/stdlib-dce/stdlib-link-predef.check
new file mode 100644
index 000000000000..4aaf59bb6139
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-predef.check
@@ -0,0 +1,3 @@
+break
+???
+42
diff --git a/tests/link/stdlib-dce/stdlib-link-predef/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-predef/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-predef/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-predef/Test.scala b/tests/link/stdlib-dce/stdlib-link-predef/Test.scala
new file mode 100644
index 000000000000..545ee85b8458
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-predef/Test.scala
@@ -0,0 +1,24 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+
+ // Loading Predef requires breaks
+ import scala.util.control.Breaks._
+ breakable {
+ while (true) {
+ System.out.println("break")
+ break()
+ }
+ }
+
+
+ try {
+ ???
+ } catch {
+ case _: NotImplementedError => System.out.println("???")
+ }
+
+ println(42)
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-predef/scala/Enumeration.scala b/tests/link/stdlib-dce/stdlib-link-predef/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-predef/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-predef/scala/OVERWRITES b/tests/link/stdlib-dce/stdlib-link-predef/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-predef/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce/stdlib-link-predef/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-predef/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/stdlib-dce/stdlib-link-set.check b/tests/link/stdlib-dce/stdlib-link-set.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-set/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-set/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-set/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-set/Test.scala b/tests/link/stdlib-dce/stdlib-link-set/Test.scala
new file mode 100644
index 000000000000..a0695eddc740
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-set/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Set.empty[Int]
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-trycatch-unapply.check b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Bar.scala b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Bar.scala
new file mode 100644
index 000000000000..4ea702381e76
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Bar.scala
@@ -0,0 +1 @@
+class Bar extends Exception("BarException")
diff --git a/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Foo.scala b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Foo.scala
new file mode 100644
index 000000000000..2470224390e5
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Foo.scala
@@ -0,0 +1 @@
+class Foo(e: Throwable) extends Exception(e)
diff --git a/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/MainGenericRunner.java
new file mode 100644
index 000000000000..aad9122fe31c
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex.getCause());
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Test.scala b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Test.scala
new file mode 100644
index 000000000000..2e6cec0d1425
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-trycatch-unapply/Test.scala
@@ -0,0 +1,16 @@
+import scala.annotation.internal
+
+object Test {
+
+ object CausedBy {
+ def unapply(e: Throwable): Option[Throwable] = Option(e.getCause)
+ }
+
+ def main(args: Array[String]): Unit = {
+ try {
+ throw new Foo(new Bar)
+ } catch {
+ case CausedBy(x: Bar) => System.out.println(42)
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-vector.check b/tests/link/stdlib-dce/stdlib-link-vector.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-vector/MainGenericRunner.java b/tests/link/stdlib-dce/stdlib-link-vector/MainGenericRunner.java
new file mode 100644
index 000000000000..ac1b4feaeb3a
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-vector/MainGenericRunner.java
@@ -0,0 +1,18 @@
+package scala.tools.nsc;
+
+// Override the MainGenericRunner for link deadcode elimination tests
+public class MainGenericRunner {
+ public static void main(String[] args) {
+ try {
+ java.lang.Class.forName("Test").getMethod("main", String[].class).invoke(null, (Object) args);
+ } catch (ClassNotFoundException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (NoSuchMethodException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new java.lang.RuntimeException(ex);
+ } catch (java.lang.reflect.InvocationTargetException ex) {
+ throw new java.lang.RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-vector/Test.scala b/tests/link/stdlib-dce/stdlib-link-vector/Test.scala
new file mode 100644
index 000000000000..ececf2c62249
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-vector/Test.scala
@@ -0,0 +1,7 @@
+import scala.annotation.internal
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ scala.collection.immutable.Vector.empty
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-vector/scala/Enumeration.scala b/tests/link/stdlib-dce/stdlib-link-vector/scala/Enumeration.scala
new file mode 100644
index 000000000000..b81ee74d1586
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-vector/scala/Enumeration.scala
@@ -0,0 +1,292 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+
+import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet }
+import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField }
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the evaluation.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * @example {{{
+ * object Main extends App {
+ *
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * }
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ * @author Matthias Zenger
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString() =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+// private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private val nmap: mutable.Map[Int, String] = ??? // new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = ??? /* {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ } */
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = ??? // vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.find(_.toString == s).getOrElse(
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap() = {
+ val fields = getClass.getDeclaredFields
+ def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
+ // nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = ??? // synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any) = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value) = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+// assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+// vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id = i
+ override def toString() =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = ??? /* {
+ val enum = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enum.vmap == null) this
+ else enum.vmap(i)
+ }*/
+ }
+
+ /** An ordering by id for values of this set */
+ object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with SortedSetLike[Value, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty = ValueSet.empty
+ def contains(v: Value) = nnIds contains (v.id - bottomId)
+ def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
+ def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def stringPrefix = thisenum + ".ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+ }
+
+ /** A factory object for value sets */
+ object ValueSet {
+ import generic.CanBuildFrom
+
+ /** The empty value set */
+ val empty = new ValueSet(immutable.BitSet.empty)
+ /** A value set consisting of given elements */
+ def apply(elems: Value*): ValueSet = (newBuilder ++= elems).result()
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def += (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ /** The implicit builder for value sets */
+ implicit def canBuildFrom: CanBuildFrom[ValueSet, Value, ValueSet] =
+ new CanBuildFrom[ValueSet, Value, ValueSet] {
+ def apply(from: ValueSet) = newBuilder
+ def apply() = newBuilder
+ }
+ }
+}
diff --git a/tests/link/stdlib-dce/stdlib-link-vector/scala/OVERWRITES b/tests/link/stdlib-dce/stdlib-link-vector/scala/OVERWRITES
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/link/stdlib-dce/stdlib-link-vector/scala/sys/SystemProperties.scala b/tests/link/stdlib-dce/stdlib-link-vector/scala/sys/SystemProperties.scala
new file mode 100644
index 000000000000..5c770af5608d
--- /dev/null
+++ b/tests/link/stdlib-dce/stdlib-link-vector/scala/sys/SystemProperties.scala
@@ -0,0 +1,85 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala
+package sys
+
+import scala.collection.{ mutable, Iterator }
+import scala.collection.JavaConverters._
+import java.security.AccessControlException
+import scala.language.implicitConversions
+
+
+/** A bidirectional map wrapping the java System properties.
+ * Changes to System properties will be immediately visible in the map,
+ * and modifications made to the map will be immediately applied to the
+ * System properties. If a security manager is in place which prevents
+ * the properties from being read or written, the AccessControlException
+ * will be caught and discarded.
+ * @define Coll `collection.mutable.Map`
+ * @define coll mutable map
+ *
+ * @author Paul Phillips
+ * @version 2.9
+ * @since 2.9
+ */
+class SystemProperties
+extends mutable.AbstractMap[String, String]
+ with mutable.Map[String, String] {
+
+ override def empty = new SystemProperties
+ override def default(key: String): String = null
+
+ def iterator: Iterator[(String, String)] =
+ wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty
+ def get(key: String) =
+ wrapAccess(Option(System.getProperty(key))) flatMap (x => x)
+ override def contains(key: String) =
+ wrapAccess(super.contains(key)) exists (x => x)
+
+ def -= (key: String): this.type = { wrapAccess(System.clearProperty(key)) ; this }
+ def += (kv: (String, String)): this.type = { wrapAccess(System.setProperty(kv._1, kv._2)) ; this }
+
+ def wrapAccess[T](body: => T): Option[T] =
+ try Some(body) catch { case _: AccessControlException => None }
+}
+
+/** The values in SystemProperties can be used to access and manipulate
+ * designated system properties. See `scala.sys.Prop` for particulars.
+ * @example {{{
+ * if (!headless.isSet) headless.enable()
+ * }}}
+ */
+object SystemProperties {
+ /** An unenforceable, advisory only place to do some synchronization when
+ * mutating system properties.
+ */
+ def exclusively[T](body: => T) = this synchronized body
+
+ implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this
+ // FIXME: A PolyParam ends up in a CallInfoWithContext
+ // private lazy val propertyHelp = mutable.Map[String, String]()
+ private def addHelp[P <: Prop[_]](p: P, helpText: String): P = {
+// propertyHelp(p.key) = helpText
+ p
+ }
+ private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp](
+ if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key),
+ helpText
+ )
+// def help(key: String) = propertyHelp.getOrElse(key, "")
+
+ // Todo: bring some sanity to the intersection of system properties aka "mutable
+ // state shared by everyone and everything" and the reality that there is no other
+ // mechanism for accomplishing some things on the jvm.
+ lazy val headless = bool("java.awt.headless", "system should not utilize a display device")
+ lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets")
+ lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses")
+ lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation")
+}
+
diff --git a/tests/link/strawman-dce-failing/link-strawman-dce-list-1.check b/tests/link/strawman-dce-failing/link-strawman-dce-list-1.check
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/tests/link/strawman-dce-failing/link-strawman-dce-list-1.check
@@ -0,0 +1 @@
+hello
diff --git a/tests/link/strawman-dce-failing/link-strawman-dce-list-1.scala b/tests/link/strawman-dce-failing/link-strawman-dce-list-1.scala
new file mode 100644
index 000000000000..f371637dcc8f
--- /dev/null
+++ b/tests/link/strawman-dce-failing/link-strawman-dce-list-1.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(strawman.collection.immutable.List.empty)
+ }
+}
diff --git a/tests/link/strawman-dce/link-strawman-dce-all.check b/tests/link/strawman-dce/link-strawman-dce-all.check
new file mode 100644
index 000000000000..d81cc0710eb6
--- /dev/null
+++ b/tests/link/strawman-dce/link-strawman-dce-all.check
@@ -0,0 +1 @@
+42
diff --git a/tests/link/strawman-dce/link-strawman-dce-all.scala b/tests/link/strawman-dce/link-strawman-dce-all.scala
new file mode 100644
index 000000000000..0674797e1801
--- /dev/null
+++ b/tests/link/strawman-dce/link-strawman-dce-all.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(42) // Dummy println
+ }
+}
\ No newline at end of file
diff --git a/tests/link/strawman-dce/link-strawman-dce-iterator-1.check b/tests/link/strawman-dce/link-strawman-dce-iterator-1.check
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/tests/link/strawman-dce/link-strawman-dce-iterator-1.check
@@ -0,0 +1 @@
+hello
diff --git a/tests/link/strawman-dce/link-strawman-dce-iterator-1.scala b/tests/link/strawman-dce/link-strawman-dce-iterator-1.scala
new file mode 100644
index 000000000000..2eaeef2dd088
--- /dev/null
+++ b/tests/link/strawman-dce/link-strawman-dce-iterator-1.scala
@@ -0,0 +1,11 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(new Foo().next)
+ }
+}
+
+class Foo extends strawman.collection.Iterator[String] {
+ def hasNext = true
+ def next = "hello"
+}
\ No newline at end of file
diff --git a/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.check b/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.check
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.check
@@ -0,0 +1 @@
+hello
diff --git a/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.scala b/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.scala
new file mode 100644
index 000000000000..1a4ad6f3bd05
--- /dev/null
+++ b/tests/link/strawman-specialize-failing/link-strawman-specialize-iterator-1.scala
@@ -0,0 +1,11 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(new Foo("hello").next)
+ }
+}
+
+class Foo[T](e: T) extends strawman.collection.Iterator[T] {
+ def hasNext = true
+ def next: T = e
+}
\ No newline at end of file
diff --git a/tests/link/strawman-specialize/link-strawman-specialize-none.check b/tests/link/strawman-specialize/link-strawman-specialize-none.check
new file mode 100644
index 000000000000..ce013625030b
--- /dev/null
+++ b/tests/link/strawman-specialize/link-strawman-specialize-none.check
@@ -0,0 +1 @@
+hello
diff --git a/tests/link/strawman-specialize/link-strawman-specialize-none.scala b/tests/link/strawman-specialize/link-strawman-specialize-none.scala
new file mode 100644
index 000000000000..1bfe115f690c
--- /dev/null
+++ b/tests/link/strawman-specialize/link-strawman-specialize-none.scala
@@ -0,0 +1,6 @@
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println("hello")
+ }
+}