summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build/genprod.scala1
-rw-r--r--src/build/pack.xml18
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reshape.scala8
-rw-r--r--src/compiler/scala/reflect/reify/utils/Extractors.scala65
-rw-r--r--src/compiler/scala/tools/cmd/gen/Codegen.scala2
-rw-r--r--src/compiler/scala/tools/cmd/gen/CodegenSpec.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala19
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala20
-rw-r--r--src/compiler/scala/tools/nsc/backend/opt/Inliners.scala5
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaParsers.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala232
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala18
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala64
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala16
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/Logic.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala18
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Checkable.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala20
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala129
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala15
-rw-r--r--src/compiler/scala/tools/nsc/util/SimpleTracer.scala2
-rw-r--r--src/compiler/scala/tools/reflect/MacroImplementations.scala3
-rw-r--r--src/intellij/repl.iml.SAMPLE25
-rw-r--r--src/intellij/scala-lang.ipr.SAMPLE1
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala12
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala4
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala2
-rw-r--r--src/library/scala/Function0.scala2
-rw-r--r--src/library/scala/Tuple1.scala1
-rw-r--r--src/library/scala/Tuple10.scala1
-rw-r--r--src/library/scala/Tuple11.scala1
-rw-r--r--src/library/scala/Tuple12.scala1
-rw-r--r--src/library/scala/Tuple13.scala1
-rw-r--r--src/library/scala/Tuple14.scala1
-rw-r--r--src/library/scala/Tuple15.scala1
-rw-r--r--src/library/scala/Tuple16.scala1
-rw-r--r--src/library/scala/Tuple17.scala1
-rw-r--r--src/library/scala/Tuple18.scala1
-rw-r--r--src/library/scala/Tuple19.scala1
-rw-r--r--src/library/scala/Tuple2.scala1
-rw-r--r--src/library/scala/Tuple20.scala1
-rw-r--r--src/library/scala/Tuple21.scala1
-rw-r--r--src/library/scala/Tuple22.scala1
-rw-r--r--src/library/scala/Tuple3.scala1
-rw-r--r--src/library/scala/Tuple4.scala1
-rw-r--r--src/library/scala/Tuple5.scala1
-rw-r--r--src/library/scala/Tuple6.scala1
-rw-r--r--src/library/scala/Tuple7.scala1
-rw-r--r--src/library/scala/Tuple8.scala1
-rw-r--r--src/library/scala/Tuple9.scala1
-rw-r--r--src/library/scala/collection/Iterator.scala54
-rw-r--r--src/library/scala/collection/parallel/package.scala7
-rwxr-xr-xsrc/library/scala/reflect/NameTransformer.scala9
-rw-r--r--src/partest/scala/tools/partest/nest/Diff.java873
-rw-r--r--src/partest/scala/tools/partest/nest/DiffPrint.java606
-rw-r--r--src/partest/scala/tools/partest/nest/FileManager.scala41
-rw-r--r--src/partest/scala/tools/partest/nest/PathSettings.scala3
-rw-r--r--src/partest/scala/tools/partest/nest/ReflectiveRunner.scala7
-rw-r--r--src/partest/scala/tools/partest/nest/RunnerManager.scala1
-rw-r--r--src/reflect/scala/reflect/internal/ClassfileConstants.scala5
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala50
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala27
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala119
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala102
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala27
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala13
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala20
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverse.scala2
-rwxr-xr-xsrc/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala18
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala6
85 files changed, 772 insertions, 2053 deletions
diff --git a/src/build/genprod.scala b/src/build/genprod.scala
index aec840c262..cd01363cb6 100644
--- a/src/build/genprod.scala
+++ b/src/build/genprod.scala
@@ -319,6 +319,7 @@ class Tuple(val i: Int) extends Group("Tuple") with Arity {
* @constructor Create a new tuple with {i} elements.{idiomatic}
{params}
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class {className}{covariantArgs}({fields})
extends {Product.className(i)}{invariantArgs}
{{
diff --git a/src/build/pack.xml b/src/build/pack.xml
index 79611b55a2..381d3f1931 100644
--- a/src/build/pack.xml
+++ b/src/build/pack.xml
@@ -179,41 +179,41 @@ MAIN DISTRIBUTION PACKAGING
<target name="pack-maven.srcs" depends="pack-maven.libs">
<!-- Add missing src jars. -->
- <jar destfile="${dists.dir}/maven/${version.number}/jline/jline-src.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/jline/jline-src.jar"
basedir="${src.dir}/jline/src/main/java">
<include name="**/*"/>
</jar>
<!-- Continuations plugin -->
- <jar destfile="${dists.dir}/maven/${version.number}/plugins/continuations/continuations-src.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/plugins/continuations/continuations-src.jar"
basedir="${src.dir}/continuations/plugin">
<include name="**/*"/>
</jar>
</target>
<target name="pack-maven.docs" depends="pack-maven.libs, pack-maven.plugins">
- <jar destfile="${dists.dir}/maven/${version.number}/jline/jline-docs.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/jline/jline-docs.jar"
basedir="${build-docs.dir}/jline">
<include name="**/*"/>
</jar>
- <jar destfile="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/scala-library/scala-library-docs.jar"
basedir="${build-docs.dir}/library">
<include name="**/*"/>
</jar>
- <jar destfile="${dists.dir}/maven/${version.number}/scala-compiler/scala-compiler-docs.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/scala-compiler/scala-compiler-docs.jar"
basedir="${build-docs.dir}/compiler">
<include name="**/*"/>
</jar>
- <jar destfile="${dists.dir}/maven/${version.number}/scalap/scalap-docs.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/scalap/scalap-docs.jar"
basedir="${build-docs.dir}/scalap">
<include name="**/*"/>
</jar>
- <jar destfile="${dists.dir}/maven/${version.number}/scala-partest/scala-partest-docs.jar"
- basedir="${build-docs.dir}/scala-partest">
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/scala-partest/scala-partest-docs.jar"
+ basedir="${build-docs.dir}/partest">
<include name="**/*"/>
</jar>
- <jar destfile="${dists.dir}/maven/${version.number}/plugins/continuations/continuations-docs.jar"
+ <jar whenmanifestonly="fail" destfile="${dists.dir}/maven/${version.number}/plugins/continuations/continuations-docs.jar"
basedir="${build-docs.dir}/continuations-plugin">
<include name="**/*"/>
</jar>
diff --git a/src/compiler/scala/reflect/reify/phases/Reshape.scala b/src/compiler/scala/reflect/reify/phases/Reshape.scala
index bb5cb53d7d..bc2dbeed3e 100644
--- a/src/compiler/scala/reflect/reify/phases/Reshape.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reshape.scala
@@ -254,7 +254,7 @@ trait Reshape {
case _ => rhs // unit or trait case
}
val DefDef(mods0, name0, _, _, tpt0, rhs0) = ddef
- val name1 = nme.dropLocalSuffix(name0)
+ val name1 = name0.dropLocal
val Modifiers(flags0, privateWithin0, annotations0) = mods0
val flags1 = (flags0 & GetterFlags) & ~(STABLE | ACCESSOR | METHOD)
val mods1 = Modifiers(flags1, privateWithin0, annotations0) setPositions mods0.positions
@@ -273,7 +273,9 @@ trait Reshape {
if (defdef.name.startsWith(prefix)) {
val name = defdef.name.toString.substring(prefix.length)
def uncapitalize(s: String) = if (s.length == 0) "" else { val chars = s.toCharArray; chars(0) = chars(0).toLower; new String(chars) }
- def findValDef(name: String) = (symdefs.values collect { case vdef: ValDef if nme.dropLocalSuffix(vdef.name).toString == name => vdef }).headOption
+ def findValDef(name: String) = symdefs.values collectFirst {
+ case vdef: ValDef if vdef.name.dropLocal string_== name => vdef
+ }
val valdef = findValDef(name).orElse(findValDef(uncapitalize(name))).orNull
if (valdef != null) accessors(valdef) = accessors.getOrElse(valdef, Nil) :+ defdef
}
@@ -297,7 +299,7 @@ trait Reshape {
mods
}
val mods2 = toPreTyperModifiers(mods1, vdef.symbol)
- val name1 = nme.dropLocalSuffix(name)
+ val name1 = name.dropLocal
val vdef1 = ValDef(mods2, name1.toTermName, tpt, rhs)
if (reifyDebug) println("resetting visibility of field: %s => %s".format(vdef, vdef1))
Some(vdef1) // no copyAttrs here, because new ValDef and old symbols are now out of sync
diff --git a/src/compiler/scala/reflect/reify/utils/Extractors.scala b/src/compiler/scala/reflect/reify/utils/Extractors.scala
index d57188bf6e..7338df1f72 100644
--- a/src/compiler/scala/reflect/reify/utils/Extractors.scala
+++ b/src/compiler/scala/reflect/reify/utils/Extractors.scala
@@ -164,51 +164,30 @@ trait Extractors {
}
}
- object FreeDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case FreeTermDef(uref, name, binding, flags, origin) =>
- Some((uref, name, binding, flags, origin))
- case FreeTypeDef(uref, name, binding, flags, origin) =>
- Some((uref, name, binding, flags, origin))
- case _ =>
- None
- }
- }
-
- object FreeTermDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case
- ValDef(_, name, _, Apply(
- Select(Select(uref1 @ Ident(_), build1), newFreeTerm),
- List(
- _,
- _,
- Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
- Literal(Constant(origin: String)))))
- if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeTerm == nme.newFreeTerm &&
- uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
- Some((uref1, name, reifyBinding(tree), flags, origin))
- case _ =>
- None
- }
- }
-
- object FreeTypeDef {
- def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = tree match {
- case
- ValDef(_, name, _, Apply(
- Select(Select(uref1 @ Ident(_), build1), newFreeType),
- List(
- _,
- Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))),
- Literal(Constant(origin: String)))))
- if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && newFreeType == nme.newFreeType &&
- uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
- Some((uref1, name, reifyBinding(tree), flags, origin))
- case _ =>
- None
+ sealed abstract class FreeDefExtractor(acceptTerms: Boolean, acceptTypes: Boolean) {
+ def unapply(tree: Tree): Option[(Tree, TermName, Tree, Long, String)] = {
+ def acceptFreeTermFactory(name: Name) = {
+ (acceptTerms && name == nme.newFreeTerm) ||
+ (acceptTypes && name == nme.newFreeType)
+ }
+ tree match {
+ case
+ ValDef(_, name, _, Apply(
+ Select(Select(uref1 @ Ident(_), build1), freeTermFactory),
+ _ :+
+ Apply(Select(Select(uref2 @ Ident(_), build2), flagsFromBits), List(Literal(Constant(flags: Long)))) :+
+ Literal(Constant(origin: String))))
+ if uref1.name == nme.UNIVERSE_SHORT && build1 == nme.build && acceptFreeTermFactory(freeTermFactory) &&
+ uref2.name == nme.UNIVERSE_SHORT && build2 == nme.build && flagsFromBits == nme.flagsFromBits =>
+ Some((uref1, name, reifyBinding(tree), flags, origin))
+ case _ =>
+ None
+ }
}
}
+ object FreeDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = true)
+ object FreeTermDef extends FreeDefExtractor(acceptTerms = true, acceptTypes = false)
+ object FreeTypeDef extends FreeDefExtractor(acceptTerms = false, acceptTypes = true)
object FreeRef {
def unapply(tree: Tree): Option[(Tree, TermName)] = tree match {
diff --git a/src/compiler/scala/tools/cmd/gen/Codegen.scala b/src/compiler/scala/tools/cmd/gen/Codegen.scala
index 4ca9b6cac7..b49322ab4a 100644
--- a/src/compiler/scala/tools/cmd/gen/Codegen.scala
+++ b/src/compiler/scala/tools/cmd/gen/Codegen.scala
@@ -23,7 +23,7 @@ object Codegen {
return println (CodegenSpec.helpMsg)
val out = outDir getOrElse { return println("--out is required.") }
- val all = genall || (!anyvals && !products)
+ val all = genall || !anyvals
echo("Generating sources into " + out)
diff --git a/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala b/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala
index ee7e605425..4b4a1e482d 100644
--- a/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala
+++ b/src/compiler/scala/tools/cmd/gen/CodegenSpec.scala
@@ -14,13 +14,9 @@ trait CodegenSpec extends Spec with Meta.StdOpts with Interpolation {
help("Usage: codegen [<options>]")
- // val inDir = "in" / "directory containing templates" --^ ExistingDir
val outDir = "out" / "directory for generated files" --^ ExistingDir
- // val install = "install" / "write source files directly to src/library/scala"
val anyvals = "anyvals" / "generate sources for AnyVal types" --?
- val products = "products" / "generate sources for ProductN, FunctionN, etc." --?
val genall = "all" / "generate sources for everything" --?
- val stamp = "stamp" / "add a timestamp to the generated files" --?
}
object CodegenSpec extends CodegenSpec with Reference {
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index e471f4256b..0a18adcf4f 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -172,6 +172,7 @@ trait Members {
var returnType: TypeKind = _
var recursive: Boolean = false
var bytecodeHasEHs = false // set by ICodeReader only, used by Inliner to prevent inlining (SI-6188)
+ var bytecodeHasInvokeDynamic = false // set by ICodeReader only, used by Inliner to prevent inlining until we have proper invoke dynamic support
/** local variables and method parameters */
var locals: List[Local] = Nil
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
index d8aac8e9db..ff118be3c4 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -394,6 +394,25 @@ trait Opcodes { self: ICodes =>
override def category = mthdsCat
}
+
+ /**
+ * A place holder entry that allows us to parse class files with invoke dynamic
+ * instructions. Because the compiler doesn't yet really understand the
+ * behavior of invokeDynamic, this op acts as a poison pill. Any attempt to analyze
+ * this instruction will cause a failure. The only optimization that
+ * should ever look at non-Scala generated icode is the inliner, and it
+ * has been modified to not examine any method with invokeDynamic
+ * instructions. So if this poison pill ever causes problems then
+ * there's been a serious misunderstanding
+ */
+ // TODO do the real thing
+ case class INVOKE_DYNAMIC(poolEntry: Char) extends Instruction {
+ private def error = sys.error("INVOKE_DYNAMIC is not fully implemented and should not be analyzed")
+ override def consumed = error
+ override def produced = error
+ override def producedTypes = error
+ override def category = error
+ }
case class BOX(boxType: TypeKind) extends Instruction {
assert(boxType.isValueType && (boxType ne UNIT)) // documentation
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 2aa874b567..0c098edf98 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -290,7 +290,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
def inameToSymbol(iname: String): Symbol = {
val name = global.newTypeName(iname)
val res0 =
- if (nme.isModuleName(name)) rootMirror.getModule(nme.stripModuleSuffix(name))
+ if (nme.isModuleName(name)) rootMirror.getModule(name.dropModule)
else rootMirror.getClassByName(name.replace('/', '.')) // TODO fails for inner classes (but this hasn't been tested).
assert(res0 != NoSymbol)
val res = jsymbol(res0)
@@ -2251,16 +2251,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// info calls so that types are up to date; erasure may add lateINTERFACE to traits
hostSymbol.info ; methodOwner.info
- def isInterfaceCall(sym: Symbol) = (
- sym.isInterface && methodOwner != ObjectClass
+ def needsInterfaceCall(sym: Symbol) = (
+ sym.isInterface
|| sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass)
)
// whether to reference the type of the receiver or
- // the type of the method owner (if not an interface!)
+ // the type of the method owner
val useMethodOwner = (
style != Dynamic
- || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol)
|| hostSymbol.isBottomClass
+ || methodOwner == ObjectClass
)
val receiver = if (useMethodOwner) methodOwner else hostSymbol
val jowner = javaName(receiver)
@@ -2283,11 +2283,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
style match {
- case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype)
- case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype)
- case Dynamic if isInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype)
- case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype)
- case SuperCall(_) =>
+ case Static(true) => dbg("invokespecial"); jcode.invokespecial (jowner, jname, jtype)
+ case Static(false) => dbg("invokestatic"); jcode.invokestatic (jowner, jname, jtype)
+ case Dynamic if needsInterfaceCall(receiver) => dbg("invokinterface"); jcode.invokeinterface(jowner, jname, jtype)
+ case Dynamic => dbg("invokevirtual"); jcode.invokevirtual (jowner, jname, jtype)
+ case SuperCall(_) =>
dbg("invokespecial")
jcode.invokespecial(jowner, jname, jtype)
initModule()
diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
index 38040d921f..557ef925a7 100644
--- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
+++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala
@@ -382,7 +382,7 @@ abstract class Inliners extends SubComponent {
val shouldWarn = hasInline(i.method)
def warnNoInline(reason: String): Boolean = {
- def msg = "Could not inline required method %s because %s.".format(i.method.originalName.decode, reason)
+ def msg = "Could not inline required method %s because %s.".format(i.method.unexpandedName.decode, reason)
if (settings.debug.value)
inlineLog("fail", i.method.fullName, reason)
if (shouldWarn)
@@ -565,7 +565,7 @@ abstract class Inliners extends SubComponent {
while (retry && count < MAX_INLINE_RETRY)
for(inlFail <- tfa.warnIfInlineFails) {
- warn(inlFail.pos, "At the end of the day, could not inline @inline-marked method " + inlFail.method.originalName.decode)
+ warn(inlFail.pos, "At the end of the day, could not inline @inline-marked method " + inlFail.method.unexpandedName.decode)
}
m.normalize()
@@ -958,6 +958,7 @@ abstract class Inliners extends SubComponent {
if(isInlineForbidden) { rs ::= "is annotated @noinline" }
if(inc.isSynchronized) { rs ::= "is synchronized method" }
if(inc.m.bytecodeHasEHs) { rs ::= "bytecode contains exception handlers / finally clause" } // SI-6188
+ if(inc.m.bytecodeHasInvokeDynamic) { rs ::= "bytecode contains invoke dynamic" }
if(rs.isEmpty) null else rs.mkString("", ", and ", "")
}
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index cf40fe90fa..f1b1d1a9a7 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -755,13 +755,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
val pos = in.currentPos
val name = identForType()
val (statics, body) = typeBody(AT, name)
- def getValueMethodType(tree: Tree) = tree match {
- case DefDef(_, nme.value, _, _, tpt, _) => Some(tpt.duplicate)
- case _ => None
- }
- var templ = makeTemplate(annotationParents, body)
- for (stat <- templ.body; tpt <- getValueMethodType(stat))
- templ = makeTemplate(annotationParents, makeConstructor(List(tpt)) :: templ.body)
+ val templ = makeTemplate(annotationParents, body)
addCompanionObject(statics, atPos(pos) {
ClassDef(mods, name, List(), templ)
})
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 30851f1d46..d75be92f36 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -43,7 +43,7 @@ abstract class ClassfileParser {
def srcfile = srcfile0
- private def currentIsTopLevel = currentClass.toString.indexOf('$') < 0
+ private def currentIsTopLevel = !(currentClass.decodedName containsChar '$')
private object unpickler extends scala.reflect.internal.pickling.UnPickler {
val global: ClassfileParser.this.global.type = ClassfileParser.this.global
@@ -136,10 +136,13 @@ abstract class ClassfileParser {
(in.nextByte.toInt: @switch) match {
case CONSTANT_UTF8 | CONSTANT_UNICODE =>
in.skip(in.nextChar)
- case CONSTANT_CLASS | CONSTANT_STRING =>
+ case CONSTANT_CLASS | CONSTANT_STRING | CONSTANT_METHODTYPE=>
in.skip(2)
+ case CONSTANT_METHODHANDLE =>
+ in.skip(3)
case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF
- | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT =>
+ | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT
+ | CONSTANT_INVOKEDYNAMIC =>
in.skip(4)
case CONSTANT_LONG | CONSTANT_DOUBLE =>
in.skip(8)
@@ -185,7 +188,7 @@ abstract class ClassfileParser {
if (in.buf(start).toInt != CONSTANT_CLASS) errorBadTag(start)
val name = getExternalName(in.getChar(start + 1))
if (nme.isModuleName(name))
- c = rootMirror.getModuleByName(nme.stripModuleSuffix(name))
+ c = rootMirror.getModuleByName(name.dropModule)
else
c = classNameToSymbol(name)
@@ -238,7 +241,7 @@ abstract class ClassfileParser {
if (f == NoSymbol)
f = rootMirror.getModuleByName(name dropRight 1)
} else {
- val origName = nme.originalName(name)
+ val origName = nme.unexpandedName(name)
val owner = if (static) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol
// println("\t" + owner.info.member(name).tpe.widen + " =:= " + tpe)
f = owner.info.findMember(origName, 0, 0, stableOnly = false).suchThat(_.tpe.widen =:= tpe)
@@ -435,63 +438,59 @@ abstract class ClassfileParser {
sym
}
- /** Return the class symbol of the given name. */
- def classNameToSymbol(name: Name): Symbol = {
- def loadClassSymbol(name: Name): Symbol = {
- val file = global.classPath findSourceFile ("" +name) getOrElse {
- // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
- // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
- // that are not in their correct place (see bug for details)
- if (!settings.isScaladoc)
- warning("Class " + name + " not found - continuing with a stub.")
- return NoSymbol.newClass(name.toTypeName)
- }
- val completer = new global.loaders.ClassfileLoader(file)
- var owner: Symbol = rootMirror.RootClass
- var sym: Symbol = NoSymbol
- var ss: Name = null
- var start = 0
- var end = name indexOf '.'
-
- while (end > 0) {
- ss = name.subName(start, end)
- sym = owner.info.decls lookup ss
- if (sym == NoSymbol) {
- sym = owner.newPackage(ss.toTermName) setInfo completer
- sym.moduleClass setInfo completer
- owner.info.decls enter sym
- }
- owner = sym.moduleClass
- start = end + 1
- end = name.indexOf('.', start)
- }
- ss = name.subName(0, start)
- owner.info.decls lookup ss orElse {
- sym = owner.newClass(ss.toTypeName) setInfoAndEnter completer
- debuglog("loaded "+sym+" from file "+file)
- sym
+ private def loadClassSymbol(name: Name): Symbol = {
+ val file = global.classPath findSourceFile ("" +name) getOrElse {
+ // SI-5593 Scaladoc's current strategy is to visit all packages in search of user code that can be documented
+ // therefore, it will rummage through the classpath triggering errors whenever it encounters package objects
+ // that are not in their correct place (see bug for details)
+ if (!settings.isScaladoc)
+ warning(s"Class $name not found - continuing with a stub.")
+ return NoSymbol.newClass(name.toTypeName)
+ }
+ val completer = new global.loaders.ClassfileLoader(file)
+ var owner: Symbol = rootMirror.RootClass
+ var sym: Symbol = NoSymbol
+ var ss: Name = null
+ var start = 0
+ var end = name indexOf '.'
+
+ while (end > 0) {
+ ss = name.subName(start, end)
+ sym = owner.info.decls lookup ss
+ if (sym == NoSymbol) {
+ sym = owner.newPackage(ss.toTermName) setInfo completer
+ sym.moduleClass setInfo completer
+ owner.info.decls enter sym
}
+ owner = sym.moduleClass
+ start = end + 1
+ end = name.indexOf('.', start)
}
-
- def lookupClass(name: Name) = try {
- if (name.pos('.') == name.length)
- definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
- else
- rootMirror.getClassByName(name) // see tickets #2464, #3756
- } catch {
- case _: FatalError => loadClassSymbol(name)
+ ss = name.subName(0, start)
+ owner.info.decls lookup ss orElse {
+ sym = owner.newClass(ss.toTypeName) setInfoAndEnter completer
+ debuglog("loaded "+sym+" from file "+file)
+ sym
}
+ }
- innerClasses.get(name) match {
- case Some(entry) =>
- //println("found inner class " + name)
- val res = innerClasses.classSymbol(entry.externalName)
- //println("\trouted to: " + res)
- res
- case None =>
- //if (name.toString.contains("$")) println("No inner class: " + name + innerClasses + " while parsing " + in.file.name)
- lookupClass(name)
- }
+ /** FIXME - we shouldn't be doing ad hoc lookups in the empty package.
+ * The method called "getClassByName" should either return the class or not.
+ */
+ private def lookupClass(name: Name) = (
+ if (name containsChar '.')
+ rootMirror getClassByName name // see tickets #2464, #3756
+ else
+ definitions.getMember(rootMirror.EmptyPackageClass, name.toTypeName)
+ )
+
+ /** Return the class symbol of the given name. */
+ def classNameToSymbol(name: Name): Symbol = {
+ if (innerClasses contains name)
+ innerClasses innerSymbol name
+ else
+ try lookupClass(name)
+ catch { case _: FatalError => loadClassSymbol(name) }
}
var sawPrivateConstructor = false
@@ -647,7 +646,7 @@ abstract class ClassfileParser {
info match {
case MethodType(params, restpe) =>
// if this is a non-static inner class, remove the explicit outer parameter
- val newParams = innerClasses.get(currentClass) match {
+ val newParams = innerClasses getEntry currentClass match {
case Some(entry) if !isScalaRaw && !isStatic(entry.jflags) =>
/* About `clazz.owner.isPackage` below: SI-5957
* For every nested java class A$B, there are two symbols in the scala compiler.
@@ -747,7 +746,7 @@ abstract class ClassfileParser {
// raw type - existentially quantify all type parameters
else logResult(s"raw type from $classSym")(definitions.unsafeClassExistentialType(classSym))
case tp =>
- assert(sig.charAt(index) != '<', tp)
+ assert(sig.charAt(index) != '<', s"sig=$sig, index=$index, tp=$tp")
tp
}
@@ -1108,7 +1107,7 @@ abstract class ClassfileParser {
unlinkIfPresent(cName.toTypeName)
}
- for (entry <- innerClasses.values) {
+ for (entry <- innerClasses.entries) {
// create a new class member for immediate inner classes
if (entry.outerName == currentClass) {
val file = global.classPath.findSourceFile(entry.externalName.toString) getOrElse {
@@ -1146,14 +1145,9 @@ abstract class ClassfileParser {
case tpnme.InnerClassesATTR if !isScala =>
val entries = in.nextChar.toInt
for (i <- 0 until entries) {
- val innerIndex = in.nextChar.toInt
- val outerIndex = in.nextChar.toInt
- val nameIndex = in.nextChar.toInt
- val jflags = in.nextChar.toInt
- if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0) {
- val entry = InnerClassEntry(innerIndex, outerIndex, nameIndex, jflags)
- innerClasses += (pool.getClassName(innerIndex) -> entry)
- }
+ val innerIndex, outerIndex, nameIndex, jflags = in.nextChar.toInt
+ if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0)
+ innerClasses add InnerClassEntry(innerIndex, outerIndex, nameIndex, jflags)
}
case _ =>
in.skip(attrLen)
@@ -1167,58 +1161,58 @@ abstract class ClassfileParser {
def externalName = pool getClassName external
def outerName = pool getClassName outer
def originalName = pool getName name
-
- override def toString =
- originalName + " in " + outerName + "(" + externalName +")"
+ def isStatic = ClassfileParser.this.isStatic(jflags)
+ def isModule = originalName.isTermName
+ def scope = if (isStatic) staticScope else instanceScope
+ def enclosing = if (isStatic) enclModule else enclClass
+
+ // The name of the outer class, without its trailing $ if it has one.
+ private def strippedOuter = nme stripModuleSuffix outerName
+ private def isInner = innerClasses contains strippedOuter
+ private def enclClass = if (isInner) innerClasses innerSymbol strippedOuter else classNameToSymbol(strippedOuter)
+ private def enclModule = enclClass.companionModule
}
- object innerClasses extends mutable.HashMap[Name, InnerClassEntry] {
- /** Return the class symbol for `externalName`. It looks it up in its outer class.
- * Forces all outer class symbols to be completed.
- *
- * If the given name is not an inner class, it returns the symbol found in `definitions`.
- */
- def classSymbol(externalName: Name): Symbol = {
- /* Return the symbol of `innerName`, having the given `externalName`. */
- def innerSymbol(externalName: Name, innerName: Name, static: Boolean): Symbol = {
- def getMember(sym: Symbol, name: Name): Symbol =
- if (static)
- if (sym == clazz) staticScope.lookup(name)
- else sym.companionModule.info.member(name)
- else
- if (sym == clazz) instanceScope.lookup(name)
- else sym.info.member(name)
-
- innerClasses.get(externalName) match {
- case Some(entry) =>
- val outerName = nme.stripModuleSuffix(entry.outerName)
- val sym = classSymbol(outerName)
- val s =
- // if loading during initialization of `definitions` typerPhase is not yet set.
- // in that case we simply load the member at the current phase
- if (currentRun.typerPhase != null)
- enteringTyper(getMember(sym, innerName.toTypeName))
- else
- getMember(sym, innerName.toTypeName)
-
- assert(s ne NoSymbol,
- "" + ((externalName, outerName, innerName, sym.fullLocationString)) + " / " +
- " while parsing " + ((in.file, busy)) +
- sym + "." + innerName + " linkedModule: " + sym.companionModule + sym.companionModule.info.members
- )
- s
-
- case None =>
- classNameToSymbol(externalName)
- }
- }
-
- get(externalName) match {
- case Some(entry) =>
- innerSymbol(entry.externalName, entry.originalName, isStatic(entry.jflags))
- case None =>
- classNameToSymbol(externalName)
- }
+ /** Return the class symbol for the given name. It looks it up in its outer class.
+ * Forces all outer class symbols to be completed.
+ *
+ * If the given name is not an inner class, it returns the symbol found in `definitions`.
+ */
+ object innerClasses {
+ private val inners = mutable.HashMap[Name, InnerClassEntry]()
+
+ def contains(name: Name) = inners contains name
+ def getEntry(name: Name) = inners get name
+ def entries = inners.values
+
+ def add(entry: InnerClassEntry): Unit = {
+ inners get entry.externalName foreach (existing =>
+ debugwarn(s"Overwriting inner class entry! Was $existing, now $entry")
+ )
+ inners(entry.externalName) = entry
+ }
+ def innerSymbol(externalName: Name): Symbol = this getEntry externalName match {
+ case Some(entry) => innerSymbol(entry)
+ case _ => NoSymbol
+ }
+ // if loading during initialization of `definitions` typerPhase is not yet set.
+ // in that case we simply load the member at the current phase
+ @inline private def enteringTyperIfPossible(body: => Symbol): Symbol =
+ if (currentRun.typerPhase eq null) body else enteringTyper(body)
+
+ private def innerSymbol(entry: InnerClassEntry): Symbol = {
+ val name = entry.originalName.toTypeName
+ val enclosing = entry.enclosing
+ def getMember = (
+ if (enclosing == clazz) entry.scope lookup name
+ else enclosing.info member name
+ )
+ enteringTyperIfPossible(getMember)
+ /** There used to be an assertion that this result is not NoSymbol; changing it to an error
+ * revealed it had been going off all the time, but has been swallowed by a catch t: Throwable
+ * in Repository.scala. Since it has been accomplishing nothing except misleading anyone who
+ * thought it wasn't triggering, I removed it entirely.
+ */
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 86f034223d..80a810703c 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -164,7 +164,7 @@ abstract class ICodeReader extends ClassfileParser {
rootMirror.getClassByName(name)
}
else if (nme.isModuleName(name)) {
- val strippedName = nme.stripModuleSuffix(name)
+ val strippedName = name.dropModule
forceMangledName(newTermName(strippedName.decode), module = true) orElse rootMirror.getModuleByName(strippedName)
}
else {
@@ -501,6 +501,13 @@ abstract class ICodeReader extends ClassfileParser {
code.emit(UNBOX(toTypeKind(m.info.resultType)))
else
code.emit(CALL_METHOD(m, Static(onInstance = false)))
+ case JVM.invokedynamic =>
+ // TODO, this is just a place holder. A real implementation must parse the class constant entry
+ debuglog("Found JVM invokedynamic instructionm, inserting place holder ICode INVOKE_DYNAMIC.")
+ containsInvokeDynamic = true
+ val poolEntry = in.nextChar
+ in.skip(2)
+ code.emit(INVOKE_DYNAMIC(poolEntry))
case JVM.new_ =>
code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar))))
@@ -639,6 +646,7 @@ abstract class ICodeReader extends ClassfileParser {
var containsDUPX = false
var containsNEW = false
var containsEHs = false
+ var containsInvokeDynamic = false
def emit(i: Instruction) {
instrs += ((pc, i))
@@ -657,6 +665,7 @@ abstract class ICodeReader extends ClassfileParser {
val code = new Code(method)
method.setCode(code)
method.bytecodeHasEHs = containsEHs
+ method.bytecodeHasInvokeDynamic = containsInvokeDynamic
var bb = code.startBlock
def makeBasicBlocks: mutable.Map[Int, BasicBlock] =
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 768c9b6989..06367009b6 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -94,8 +94,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val paramAccessors = clazz.constrParamAccessors
// The constructor parameter corresponding to an accessor
- def parameter(acc: Symbol): Symbol =
- parameterNamed(nme.getterName(acc.originalName.toTermName))
+ def parameter(acc: Symbol): Symbol = parameterNamed(acc.unexpandedName.getterName)
// The constructor parameter with given name. This means the parameter
// has given name, or starts with given name, and continues with a `$` afterwards.
@@ -191,8 +190,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
stat match {
case ValDef(mods, name, _, _) if (mods hasFlag PRESUPER) =>
// stat is the constructor-local definition of the field value
- val fields = presupers filter (
- vdef => nme.localToGetter(vdef.name) == name)
+ val fields = presupers filter (_.getterName == name)
assert(fields.length == 1)
val to = fields.head.symbol
if (!to.tpe.isInstanceOf[ConstantType])
@@ -314,10 +312,8 @@ abstract class Constructors extends Transform with ast.TreeDSL {
def specializedAssignFor(sym: Symbol): Option[Tree] =
specializedStats find {
- case Assign(sel @ Select(This(_), _), rhs) =>
- ( (sel.symbol hasFlag SPECIALIZED)
- && (nme.unspecializedName(nme.localToGetter(sel.symbol.name.toTermName)) == nme.localToGetter(sym.name.toTermName))
- )
+ case Assign(sel @ Select(This(_), _), _) =>
+ sel.symbol.isSpecialized && (nme.unspecializedName(sel.symbol.getterName) == sym.getterName)
case _ => false
}
@@ -432,8 +428,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
}
def addGetter(sym: Symbol): Symbol = {
- val getr = addAccessor(
- sym, nme.getterName(sym.name.toTermName), getterFlags(sym.flags))
+ val getr = addAccessor(sym, sym.getterName, getterFlags(sym.flags))
getr setInfo MethodType(List(), sym.tpe)
defBuf += localTyper.typedPos(sym.pos)(DefDef(getr, Select(This(clazz), sym)))
getr
@@ -441,8 +436,7 @@ abstract class Constructors extends Transform with ast.TreeDSL {
def addSetter(sym: Symbol): Symbol = {
sym setFlag MUTABLE
- val setr = addAccessor(
- sym, nme.getterToSetter(nme.getterName(sym.name.toTermName)), setterFlags(sym.flags))
+ val setr = addAccessor(sym, sym.setterName, setterFlags(sym.flags))
setr setInfo MethodType(setr.newSyntheticValueParams(List(sym.tpe)), UnitClass.tpe)
defBuf += localTyper.typed {
//util.trace("adding setter def for "+setr) {
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 857c01c49a..e6cf5e6346 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -730,7 +730,7 @@ abstract class Erasure extends AddInterfaces
else if (tree.symbol == Any_isInstanceOf)
adaptMember(atPos(tree.pos)(Select(qual, Object_isInstanceOf)))
else if (tree.symbol.owner == AnyClass)
- adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, name))))
+ adaptMember(atPos(tree.pos)(Select(qual, getMember(ObjectClass, tree.symbol.name))))
else {
var qual1 = typedQualifier(qual)
if ((isPrimitiveValueType(qual1.tpe) && !isPrimitiveValueMember(tree.symbol)) ||
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 124dd6c995..367825c251 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -41,26 +41,24 @@ abstract class ExplicitOuter extends InfoTransform
private def isInner(clazz: Symbol) =
!clazz.isPackageClass && !clazz.outerClass.isStaticOwner
- private def haveSameOuter(parent: Type, clazz: Symbol) = parent match {
- case TypeRef(pre, sym, _) =>
- val owner = clazz.owner
+ private def haveSameOuter(parent: Type, clazz: Symbol) = {
+ val owner = clazz.owner
+ val parentSym = parent.typeSymbol
- //println(s"have same outer $parent $clazz $sym ${sym.owner} $owner $pre")
-
- sym.isClass && owner.isClass &&
- (owner isSubClass sym.owner) &&
- owner.thisType =:= pre
-
- case _ => false
+ parentSym.isClass && owner.isClass &&
+ (owner isSubClass parentSym.owner) &&
+ owner.thisType =:= parent.prefix
}
/** Does given clazz define an outer field? */
def hasOuterField(clazz: Symbol) = {
- val parents = clazz.info.parents
+ val parent = clazz.info.firstParent
- isInner(clazz) && !clazz.isTrait && {
- parents.isEmpty || !haveSameOuter(parents.head, clazz)
- }
+ // space optimization: inherit the $outer pointer from the parent class if
+ // we know that it will point to the correct instance.
+ def canReuseParentOuterField = !parent.typeSymbol.isJavaDefined && haveSameOuter(parent, clazz)
+
+ isInner(clazz) && !clazz.isTrait && !canReuseParentOuterField
}
private def outerField(clazz: Symbol): Symbol = {
@@ -100,6 +98,29 @@ abstract class ExplicitOuter extends InfoTransform
sym setInfo clazz.outerClass.thisType
}
+ /**
+ * Will the outer accessor of the `clazz` subsume the outer accessor of
+ * `mixin`?
+ *
+ * This arises when an inner object mixes in its companion trait.
+ *
+ * {{{
+ * class C {
+ * trait T { C.this } // C$T$$$outer$ : C
+ * object T extends T { C.this } // C$T$$$outer$ : C.this.type
+ * }
+ * }}}
+ *
+ * See SI-7242.
+ }}
+ */
+ private def skipMixinOuterAccessor(clazz: Symbol, mixin: Symbol) = {
+ // Reliant on the current scheme for name expansion, the expanded name
+ // of the outer accessors in a trait and its companion object are the same.
+ // If the assumption is one day falsified, run/t7424.scala will let us know.
+ clazz.fullName == mixin.fullName
+ }
+
/** <p>
* The type transformation method:
* </p>
@@ -162,10 +183,14 @@ abstract class ExplicitOuter extends InfoTransform
for (mc <- clazz.mixinClasses) {
val mixinOuterAcc: Symbol = exitingExplicitOuter(outerAccessor(mc))
if (mixinOuterAcc != NoSymbol) {
- if (decls1 eq decls) decls1 = decls.cloneScope
- val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED)
- newAcc setInfo (clazz.thisType memberType mixinOuterAcc)
- decls1 enter newAcc
+ if (skipMixinOuterAccessor(clazz, mc))
+ debuglog(s"Reusing outer accessor symbol of $clazz for the mixin outer accessor of $mc")
+ else {
+ if (decls1 eq decls) decls1 = decls.cloneScope
+ val newAcc = mixinOuterAcc.cloneSymbol(clazz, mixinOuterAcc.flags & ~DEFERRED)
+ newAcc setInfo (clazz.thisType memberType mixinOuterAcc)
+ decls1 enter newAcc
+ }
}
}
}
@@ -370,6 +395,7 @@ abstract class ExplicitOuter extends InfoTransform
val outerAcc = outerAccessor(mixinClass) overridingSymbol currentClass
def mixinPrefix = (currentClass.thisType baseType mixinClass).prefix
assert(outerAcc != NoSymbol, "No outer accessor for inner mixin " + mixinClass + " in " + currentClass)
+ assert(outerAcc.alternatives.size == 1, s"Multiple outer accessors match inner mixin $mixinClass in $currentClass : ${outerAcc.alternatives.map(_.defString)}")
// I added the mixinPrefix.typeArgs.nonEmpty condition to address the
// crash in SI-4970. I feel quite sure this can be improved.
val path = (
@@ -404,7 +430,7 @@ abstract class ExplicitOuter extends InfoTransform
}
if (!currentClass.isTrait)
for (mc <- currentClass.mixinClasses)
- if (outerAccessor(mc) != NoSymbol)
+ if (outerAccessor(mc) != NoSymbol && !skipMixinOuterAccessor(currentClass, mc))
newDefs += mixinOuterAccessorDef(mc)
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index e6c9afb042..69a93b482c 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -183,7 +183,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
if (bmps.isEmpty) rhs else rhs match {
case Block(assign, l @ LabelDef(name, params, _))
- if name.toString == ("_" + methSym.name) && isMatch(params) =>
+ if (name string_== "_" + methSym.name) && isMatch(params) =>
Block(assign, deriveLabelDef(l)(rhs => typed(prependStats(bmps, rhs))))
case _ => prependStats(bmps, rhs)
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index e0b30ab9f9..8971e27bda 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -185,11 +185,6 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
newSym updateInfo (mixinMember.info cloneInfo newSym)
}
- def needsExpandedSetterName(field: Symbol) = !field.isLazy && (
- if (field.isMethod) field.hasStableFlag
- else !field.isMutable
- )
-
/** Add getters and setters for all non-module fields of an implementation
* class to its interface unless they are already present. This is done
* only once per class. The mixedin flag is used to remember whether late
@@ -207,19 +202,19 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// println("creating new getter for "+ field +" : "+ field.info +" at "+ field.locationString+(field hasFlag MUTABLE))
val newFlags = field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED | ( if (field.isMutable) 0 else STABLE )
// TODO preserve pre-erasure info?
- clazz.newMethod(nme.getterName(field.name.toTermName), field.pos, newFlags) setInfo MethodType(Nil, field.info)
+ clazz.newMethod(field.getterName, field.pos, newFlags) setInfo MethodType(Nil, field.info)
}
/* Create a new setter. Setters are never private or local. They are
* always accessors and deferred. */
def newSetter(field: Symbol): Symbol = {
//println("creating new setter for "+field+field.locationString+(field hasFlag MUTABLE))
- val setterName = nme.getterToSetter(nme.getterName(field.name.toTermName))
+ val setterName = field.setterName
val newFlags = field.flags & ~PrivateLocal | ACCESSOR | lateDEFERRED
val setter = clazz.newMethod(setterName, field.pos, newFlags)
// TODO preserve pre-erasure info?
setter setInfo MethodType(setter.newSyntheticValueParams(List(field.info)), UnitClass.tpe)
- if (needsExpandedSetterName(field))
+ if (field.needsExpandedSetterName)
setter.name = nme.expandedSetterName(setter.name, clazz)
setter
@@ -237,7 +232,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val getter = member.getter(clazz)
if (getter == NoSymbol) addMember(clazz, newGetter(member))
if (!member.tpe.isInstanceOf[ConstantType] && !member.isLazy) {
- val setter = member.setter(clazz, needsExpandedSetterName(member))
+ val setter = member.setter(clazz)
if (setter == NoSymbol) addMember(clazz, newSetter(member))
}
}
@@ -315,7 +310,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// carries over the current entry in the type history)
val sym = enteringErasure {
// so we have a type history entry before erasure
- clazz.newValue(nme.getterToLocal(mixinMember.name.toTermName), mixinMember.pos).setInfo(mixinMember.tpe.resultType)
+ clazz.newValue(mixinMember.localName, mixinMember.pos).setInfo(mixinMember.tpe.resultType)
}
sym updateInfo mixinMember.tpe.resultType // info at current phase
@@ -1236,10 +1231,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case Assign(Apply(lhs @ Select(qual, _), List()), rhs) =>
// assign to fields in some implementation class via an abstract
// setter in the interface.
- def setter = lhs.symbol.setter(
- toInterface(lhs.symbol.owner.tpe).typeSymbol,
- needsExpandedSetterName(lhs.symbol)
- ) setPos lhs.pos
+ def setter = lhs.symbol.setter(toInterface(lhs.symbol.owner.tpe).typeSymbol) setPos lhs.pos
typedPos(tree.pos)((qual DOT setter)(rhs))
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 15fe9f0a24..91a03009bc 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -322,20 +322,20 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
/** Specialize name for the two list of types. The first one denotes
* specialization on method type parameters, the second on outer environment.
*/
- private def specializedName(name: Name, types1: List[Type], types2: List[Type]): TermName = {
- if (nme.INITIALIZER == name || (types1.isEmpty && types2.isEmpty))
+ private def specializedName(name: Name, types1: List[Type], types2: List[Type]): TermName = (
+ if (name == nme.CONSTRUCTOR || (types1.isEmpty && types2.isEmpty))
name.toTermName
else if (nme.isSetterName(name))
- nme.getterToSetter(specializedName(nme.setterToGetter(name.toTermName), types1, types2))
+ specializedName(name.getterName, types1, types2).setterName
else if (nme.isLocalName(name))
- nme.getterToLocal(specializedName(nme.localToGetter(name.toTermName), types1, types2))
+ specializedName(name.getterName, types1, types2).localName
else {
val (base, cs, ms) = nme.splitSpecializedName(name)
newTermName(base.toString + "$"
+ "m" + ms + types1.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "")
+ "c" + cs + types2.map(t => definitions.abbrvTag(t.typeSymbol)).mkString("", "", "$sp"))
}
- }
+ )
lazy val specializableTypes = ScalaValueClasses map (_.tpe) sorted
@@ -714,7 +714,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name))
if (nme.isLocalName(m.name)) {
- val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name.toTermName)) setInfo MethodType(Nil, specVal.info)
+ val specGetter = mkAccessor(specVal, specVal.getterName) setInfo MethodType(Nil, specVal.info)
val origGetter = overrideIn(sClass, m.getter(clazz))
info(origGetter) = Forward(specGetter)
enterMember(specGetter)
@@ -729,7 +729,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
if (specVal.isVariable && m.setter(clazz) != NoSymbol) {
- val specSetter = mkAccessor(specVal, nme.getterToSetter(specGetter.name))
+ val specSetter = mkAccessor(specVal, specGetter.setterName)
.resetFlag(STABLE)
specSetter.setInfo(MethodType(specSetter.newSyntheticValueParams(List(specVal.info)),
UnitClass.tpe))
@@ -1805,7 +1805,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
*/
def initializesSpecializedField(f: Symbol) = (
(f.name endsWith nme.SPECIALIZED_SUFFIX)
- && clazz.info.member(nme.originalName(f.name)).isPublic
+ && clazz.info.member(f.unexpandedName).isPublic
&& clazz.info.decl(f.name).suchThat(_.isGetter) != NoSymbol
)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 8fd1df7cea..11bd0665b1 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -347,10 +347,14 @@ abstract class UnCurry extends InfoTransform
}
else {
log(s"Argument '$arg' at line ${arg.pos.safeLine} is $formal from ${fun.fullName}")
+ def canUseDirectly(recv: Tree) = (
+ recv.tpe.typeSymbol.isSubClass(FunctionClass(0))
+ && treeInfo.isExprSafeToInline(recv)
+ )
arg match {
// don't add a thunk for by-name argument if argument already is an application of
// a Function0. We can then remove the application and use the existing Function0.
- case Apply(Select(recv, nme.apply), Nil) if recv.tpe.typeSymbol isSubClass FunctionClass(0) =>
+ case Apply(Select(recv, nme.apply), Nil) if canUseDirectly(recv) =>
recv
case _ =>
newFunction0(arg)
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
index 0371df3b10..92b7700c04 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/Logic.scala
@@ -573,6 +573,7 @@ trait ScalaLogic extends Interface with Logic with TreeAndTypeAnalysis {
assert(tp.isInstanceOf[SingletonType])
val toString = tp match {
case ConstantType(c) => c.escapedStringValue
+ case _ if tp.typeSymbol.isModuleClass => tp.typeSymbol.name.toString
case _ => tp.toString
}
Const.unique(tp, new ValueConst(tp, tp.widen, toString))
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
index 125e9a3b65..31b04d0bd6 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchOptimization.scala
@@ -15,9 +15,9 @@ import scala.reflect.internal.util.Position
/** Optimize and analyze matches based on their TreeMaker-representation.
*
* The patmat translation doesn't rely on this, so it could be disabled in principle.
- *
- * TODO: split out match analysis
+ * - well, not quite: the backend crashes if we emit duplicates in switches (e.g. SI-7290)
*/
+// TODO: split out match analysis
trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
import global._
import global.definitions._
@@ -435,7 +435,7 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
case SwitchableTreeMaker(pattern) :: GuardAndBodyTreeMakers(guard, body) =>
Some(CaseDef(pattern, guard, body))
// alternatives
- case AlternativesTreeMaker(_, altss, _) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported =>
+ case AlternativesTreeMaker(_, altss, pos) :: GuardAndBodyTreeMakers(guard, body) if alternativesSupported =>
val switchableAlts = altss map {
case SwitchableTreeMaker(pattern) :: Nil =>
Some(pattern)
@@ -445,7 +445,17 @@ trait MatchOptimization extends MatchTreeMaking with MatchAnalysis {
// succeed if they were all switchable
sequence(switchableAlts) map { switchableAlts =>
- CaseDef(Alternative(switchableAlts), guard, body)
+ def extractConst(t: Tree) = t match {
+ case Literal(const) => const
+ case _ => t
+ }
+ // SI-7290 Discard duplicate alternatives that would crash the backend
+ val distinctAlts = distinctBy(switchableAlts)(extractConst)
+ if (distinctAlts.size < switchableAlts.size) {
+ val duplicated = switchableAlts.groupBy(extractConst).flatMap(_._2.drop(1).take(1)) // report the first duplicated
+ global.currentUnit.warning(pos, s"Pattern contains duplicate alternatives: ${duplicated.mkString(", ")}")
+ }
+ CaseDef(Alternative(distinctAlts), guard, body)
}
case _ =>
// debug.patmat("can't emit switch for "+ makers)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
index 88bfa6099d..026f5f7bc8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Checkable.scala
@@ -195,11 +195,18 @@ trait Checkable {
* so I will consult with moors about the optimal time to be doing this.
*/
def areIrreconcilableAsParents(sym1: Symbol, sym2: Symbol): Boolean = areUnrelatedClasses(sym1, sym2) && (
- sym1.initialize.isEffectivelyFinal // initialization important
- || sym2.initialize.isEffectivelyFinal
+ isEffectivelyFinal(sym1) // initialization important
+ || isEffectivelyFinal(sym2)
|| !sym1.isTrait && !sym2.isTrait
|| sym1.isSealed && sym2.isSealed && allChildrenAreIrreconcilable(sym1, sym2) && !currentRun.compiles(sym1) && !currentRun.compiles(sym2)
)
+ private def isEffectivelyFinal(sym: Symbol): Boolean = (
+ // initialization important
+ sym.initialize.isEffectivelyFinal || (
+ settings.future.value && isTupleSymbol(sym) // SI-7294 step into the future and treat TupleN as final.
+ )
+ )
+
def isNeverSubClass(sym1: Symbol, sym2: Symbol) = areIrreconcilableAsParents(sym1, sym2)
private def isNeverSubArgs(tps1: List[Type], tps2: List[Type], tparams: List[Symbol]): Boolean = /*logResult(s"isNeverSubArgs($tps1, $tps2, $tparams)")*/ {
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 8723046728..85c44a7ec4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -1058,9 +1058,6 @@ trait ContextErrors {
issueSymbolTypeError(currentSym, prevSym.name + " is already defined as " + s2 + s3 + where)
}
- def MaxParametersCaseClassError(tree: Tree) =
- issueNormalTypeError(tree, "Implementation restriction: case classes cannot have more than " + definitions.MaxFunctionArity + " parameters.")
-
def MissingParameterOrValTypeError(vparam: Tree) =
issueNormalTypeError(vparam, "missing parameter type")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 9d5a9c819c..272e7af48b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -912,7 +912,25 @@ trait Contexts { self: Analyzer =>
def lookupImport(imp: ImportInfo, requireExplicit: Boolean) =
importedAccessibleSymbol(imp, name, requireExplicit) filter qualifies
- while (!impSym.exists && imports.nonEmpty && imp1.depth > symbolDepth) {
+ // Java: A single-type-import declaration d in a compilation unit c of package p
+ // that imports a type named n shadows, throughout c, the declarations of:
+ //
+ // 1) any top level type named n declared in another compilation unit of p
+ //
+ // A type-import-on-demand declaration never causes any other declaration to be shadowed.
+ //
+ // Scala: Bindings of different kinds have a precedence defined on them:
+ //
+ // 1) Definitions and declarations that are local, inherited, or made available by a
+ // package clause in the same compilation unit where the definition occurs have
+ // highest precedence.
+ // 2) Explicit imports have next highest precedence.
+ def depthOk(imp: ImportInfo) = (
+ imp.depth > symbolDepth
+ || (unit.isJava && imp.isExplicitImport(name) && imp.depth == symbolDepth)
+ )
+
+ while (!impSym.exists && imports.nonEmpty && depthOk(imports.head)) {
impSym = lookupImport(imp1, requireExplicit = false)
if (!impSym.exists)
imports = imports.tail
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index 282dd8a99d..4075aa26f7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -98,6 +98,7 @@ trait EtaExpansion { self: Analyzer =>
case TypeApply(fn, args) =>
treeCopy.TypeApply(tree, liftoutPrefix(fn), args).clearType()
case Select(qual, name) =>
+ val name = tree.symbol.name // account for renamed imports, SI-7233
treeCopy.Select(tree, liftout(qual, byName = false), name).clearType() setSymbol NoSymbol
case Ident(name) =>
tree
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index 5999a64b36..50383a1e78 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -471,7 +471,7 @@ trait MethodSynthesis {
}
}
case class Setter(tree: ValDef) extends DerivedSetter {
- def name = nme.getterToSetter(tree.name)
+ def name = tree.setterName
def category = SetterTargetClass
def flagsMask = SetterFlags
def flagsExtra = ACCESSOR
@@ -479,7 +479,7 @@ trait MethodSynthesis {
override def derivedSym = basisSym.setter(enclClass)
}
case class Field(tree: ValDef) extends DerivedFromValDef {
- def name = nme.getterToLocal(tree.name)
+ def name = tree.localName
def category = FieldTargetClass
def flagsMask = FieldFlags
def flagsExtra = PrivateLocal
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index e966cc9060..7d12744cc7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -184,7 +184,7 @@ trait Namers extends MethodSynthesis {
(newS.owner.isTypeParameter || newS.owner.isAbstractType)
// FIXME: name comparisons not successful, are these underscores
// sometimes nme.WILDCARD and sometimes tpnme.WILDCARD?
- && (newS.name.toString == nme.WILDCARD.toString)
+ && (newS.name string_== nme.WILDCARD)
)
)
@@ -323,7 +323,7 @@ trait Namers extends MethodSynthesis {
}
}
private def createFieldSymbol(tree: ValDef): TermSymbol =
- owner.newValue(nme.getterToLocal(tree.name), tree.pos, tree.mods.flags & FieldFlags | PrivateLocal)
+ owner.newValue(tree.localName, tree.pos, tree.mods.flags & FieldFlags | PrivateLocal)
private def createImportSymbol(tree: Tree) =
NoSymbol.newImport(tree.pos) setInfo completerOf(tree)
@@ -523,14 +523,20 @@ trait Namers extends MethodSynthesis {
if (from != nme.WILDCARD && base != ErrorType) {
if (isValid(from)) {
// for Java code importing Scala objects
- if (!nme.isModuleName(from) || isValid(nme.stripModuleSuffix(from))) {
+ if (!nme.isModuleName(from) || isValid(from.dropModule)) {
typer.TyperErrorGen.NotAMemberError(tree, expr, from)
}
}
// Setting the position at the import means that if there is
// more than one hidden name, the second will not be warned.
// So it is the position of the actual hidden name.
- checkNotRedundant(tree.pos withPoint fromPos, from, to)
+ //
+ // Note: java imports have precence over definitions in the same package
+ // so don't warn for them. There is a corresponding special treatment
+ // in the shadowing rules in typedIdent to (SI-7232). In any case,
+ // we shouldn't be emitting warnings for .java source files.
+ if (!context.unit.isJava)
+ checkNotRedundant(tree.pos withPoint fromPos, from, to)
}
}
@@ -654,9 +660,6 @@ trait Namers extends MethodSynthesis {
tree.symbol setInfo completerOf(tree)
if (mods.isCase) {
- if (primaryConstructorArity > MaxFunctionArity)
- MaxParametersCaseClassError(tree)
-
val m = ensureCompanionObject(tree, caseModuleDef)
m.moduleClass.updateAttachment(new ClassForCaseCompanionAttachment(tree))
}
@@ -1373,7 +1376,9 @@ trait Namers extends MethodSynthesis {
if (!cdef.symbol.hasAbstractFlag)
namer.enterSyntheticSym(caseModuleApplyMeth(cdef))
- namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
+ val primaryConstructorArity = treeInfo.firstConstructorArgs(cdef.impl.body).size
+ if (primaryConstructorArity <= MaxTupleArity)
+ namer.enterSyntheticSym(caseModuleUnapplyMeth(cdef))
}
def addCopyMethod(cdef: ClassDef, namer: Namer) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index d5ecb687b0..6921f8ce27 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -499,7 +499,7 @@ trait NamesDefaults { self: Analyzer =>
// disable conforms as a view...
val errsBefore = reporter.ERROR.count
try typer.silent { tpr =>
- val res = tpr.typed(arg, subst(paramtpe))
+ val res = tpr.typed(arg.duplicate, subst(paramtpe))
// better warning for SI-5044: if `silent` was not actually silent give a hint to the user
// [H]: the reason why `silent` is not silent is because the cyclic reference exception is
// thrown in a context completely different from `context` here. The exception happens while
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index c967fed0b9..fb692a1954 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -388,7 +388,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
assert(clazz != NoSymbol, sym)
debuglog("Decided for host class: " + clazz)
- val accName = nme.protName(sym.originalName)
+ val accName = nme.protName(sym.unexpandedName)
val hasArgs = sym.tpe.paramSectionCount > 0
val memberType = refChecks.toScalaRepeatedParam(sym.tpe) // fix for #2413
@@ -406,7 +406,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
val protAcc = clazz.info.decl(accName).suchThat(s => s == NoSymbol || s.tpe =:= accType(s)) orElse {
- val newAcc = clazz.newMethod(nme.protName(sym.originalName), tree.pos, newFlags = ARTIFACT)
+ val newAcc = clazz.newMethod(nme.protName(sym.unexpandedName), tree.pos, newFlags = ARTIFACT)
newAcc setInfoAndEnter accType(newAcc)
val code = DefDef(newAcc, {
@@ -466,7 +466,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
assert(clazz != NoSymbol, field)
debuglog("Decided for host class: " + clazz)
- val accName = nme.protSetterName(field.originalName)
+ val accName = nme.protSetterName(field.unexpandedName)
val protectedAccessor = clazz.info decl accName orElse {
val protAcc = clazz.newMethod(accName, field.pos, newFlags = ARTIFACT)
val paramTypes = List(clazz.typeOfThis, field.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 0e57145343..7436a244bd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -944,6 +944,57 @@ trait Typers extends Adaptations with Tags {
// due to wrapClassTagUnapply, but when we support parameterized extractors, it will become
// more common place)
val extractor = overloadedExtractorOfObject orElse unapplyMember(tree.tpe)
+ def convertToCaseConstructor(clazz: Symbol): TypeTree = {
+ // convert synthetic unapply of case class to case class constructor
+ val prefix = tree.tpe.prefix
+ val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner))
+ .setOriginal(tree)
+
+ val skolems = new mutable.ListBuffer[TypeSymbol]
+ object variantToSkolem extends TypeMap(trackVariance = true) {
+ def apply(tp: Type) = mapOver(tp) match {
+ // !!! FIXME - skipping this when variance.isInvariant allows unsoundness, see SI-5189
+ case TypeRef(NoPrefix, tpSym, Nil) if !variance.isInvariant && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm =>
+ // must initialize or tpSym.tpe might see random type params!!
+ // without this, we'll get very weird types inferred in test/scaladoc/run/SI-5933.scala
+ // TODO: why is that??
+ tpSym.initialize
+ val bounds = if (variance.isPositive) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe)
+ // origin must be the type param so we can deskolemize
+ val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds)
+ // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree )
+ skolems += skolem
+ skolem.tpe
+ case tp1 => tp1
+ }
+ }
+
+ // have to open up the existential and put the skolems in scope
+ // can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance)
+ val ptSafe = variantToSkolem(pt) // TODO: pt.skolemizeExistential(context.owner, tree) ?
+ val freeVars = skolems.toList
+
+ // use "tree" for the context, not context.tree: don't make another CaseDef context,
+ // as instantiateTypeVar's bounds would end up there
+ val ctorContext = context.makeNewScope(tree, context.owner)
+ freeVars foreach ctorContext.scope.enter
+ newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe)
+
+ // simplify types without losing safety,
+ // so that we get rid of unnecessary type slack, and so that error messages don't unnecessarily refer to skolems
+ val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type)
+ val extrapolated = tree1.tpe match {
+ case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node
+ ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type
+ copyMethodType(tree1.tpe, ctorArgs, extrapolate(res))
+ case tp => tp
+ }
+
+ // once the containing CaseDef has been type checked (see typedCase),
+ // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems)
+ tree1 setType extrapolated
+ }
+
if (extractor != NoSymbol) {
// if we did some ad-hoc overloading resolution, update the tree's symbol
// do not update the symbol if the tree's symbol's type does not define an unapply member
@@ -959,59 +1010,16 @@ trait Typers extends Adaptations with Tags {
val clazz = unapplyParameterType(unapply)
if (unapply.isCase && clazz.isCase) {
- // convert synthetic unapply of case class to case class constructor
- val prefix = tree.tpe.prefix
- val tree1 = TypeTree(clazz.primaryConstructor.tpe.asSeenFrom(prefix, clazz.owner))
- .setOriginal(tree)
-
- val skolems = new mutable.ListBuffer[TypeSymbol]
- object variantToSkolem extends TypeMap(trackVariance = true) {
- def apply(tp: Type) = mapOver(tp) match {
- // !!! FIXME - skipping this when variance.isInvariant allows unsoundness, see SI-5189
- case TypeRef(NoPrefix, tpSym, Nil) if !variance.isInvariant && tpSym.isTypeParameterOrSkolem && tpSym.owner.isTerm =>
- // must initialize or tpSym.tpe might see random type params!!
- // without this, we'll get very weird types inferred in test/scaladoc/run/SI-5933.scala
- // TODO: why is that??
- tpSym.initialize
- val bounds = if (variance.isPositive) TypeBounds.upper(tpSym.tpe) else TypeBounds.lower(tpSym.tpe)
- // origin must be the type param so we can deskolemize
- val skolem = context.owner.newGADTSkolem(unit.freshTypeName("?"+tpSym.name), tpSym, bounds)
- // println("mapping "+ tpSym +" to "+ skolem + " : "+ bounds +" -- pt= "+ pt +" in "+ context.owner +" at "+ context.tree )
- skolems += skolem
- skolem.tpe
- case tp1 => tp1
- }
- }
-
- // have to open up the existential and put the skolems in scope
- // can't simply package up pt in an ExistentialType, because that takes us back to square one (List[_ <: T] == List[T] due to covariance)
- val ptSafe = variantToSkolem(pt) // TODO: pt.skolemizeExistential(context.owner, tree) ?
- val freeVars = skolems.toList
-
- // use "tree" for the context, not context.tree: don't make another CaseDef context,
- // as instantiateTypeVar's bounds would end up there
- val ctorContext = context.makeNewScope(tree, context.owner)
- freeVars foreach ctorContext.scope.enter
- newTyper(ctorContext).infer.inferConstructorInstance(tree1, clazz.typeParams, ptSafe)
-
- // simplify types without losing safety,
- // so that we get rid of unnecessary type slack, and so that error messages don't unnecessarily refer to skolems
- val extrapolate = new ExistentialExtrapolation(freeVars) extrapolate (_: Type)
- val extrapolated = tree1.tpe match {
- case MethodType(ctorArgs, res) => // ctorArgs are actually in a covariant position, since this is the type of the subpatterns of the pattern represented by this Apply node
- ctorArgs foreach (p => p.info = extrapolate(p.info)) // no need to clone, this is OUR method type
- copyMethodType(tree1.tpe, ctorArgs, extrapolate(res))
- case tp => tp
- }
-
- // once the containing CaseDef has been type checked (see typedCase),
- // tree1's remaining type-slack skolems will be deskolemized (to the method type parameter skolems)
- tree1 setType extrapolated
+ convertToCaseConstructor(clazz)
} else {
tree
}
} else {
- CaseClassConstructorError(tree)
+ val clazz = tree.tpe.typeSymbol.linkedClassOfClass
+ if (clazz.isCase)
+ convertToCaseConstructor(clazz)
+ else
+ CaseClassConstructorError(tree)
}
}
@@ -1324,8 +1332,7 @@ trait Typers extends Adaptations with Tags {
def adaptToMemberWithArgs(tree: Tree, qual: Tree, name: Name, mode: Mode, reportAmbiguous: Boolean, saveErrors: Boolean): Tree = {
def onError(reportError: => Tree): Tree = context.tree match {
case Apply(tree1, args) if (tree1 eq tree) && args.nonEmpty =>
- ( silent (_.typedArgs(args, mode))
- map (_.asInstanceOf[List[Tree]])
+ ( silent (_.typedArgs(args.map(_.duplicate), mode))
filter (xs => !(xs exists (_.isErrorTyped)))
map (xs => adaptToArguments(qual, name, xs, WildcardType, reportAmbiguous, saveErrors))
orElse ( _ => reportError)
@@ -3558,7 +3565,7 @@ trait Typers extends Adaptations with Tags {
// If there are dummy type arguments in typeFun part, it suggests we
// must type the actual constructor call, not only the select. The value
// arguments are how the type arguments will be inferred.
- if (targs.isEmpty && typedFun0.exists(t => isDummyAppliedType(t.tpe)))
+ if (targs.isEmpty && typedFun0.exists(t => t.tpe != null && isDummyAppliedType(t.tpe)))
logResult(s"Retyped $typedFun0 to find type args")(typed(argss.foldLeft(fun0)(Apply(_, _))))
else
typedFun0
@@ -4211,7 +4218,7 @@ trait Typers extends Adaptations with Tags {
if (treeInfo.mayBeVarGetter(varsym)) {
lhs1 match {
case treeInfo.Applied(Select(qual, name), _, _) =>
- val sel = Select(qual, nme.getterToSetter(name.toTermName)) setPos lhs.pos
+ val sel = Select(qual, name.setterName) setPos lhs.pos
val app = Apply(sel, List(rhs)) setPos tree.pos
return typed(app, mode, pt)
@@ -4372,6 +4379,12 @@ trait Typers extends Adaptations with Tags {
treeCopy.New(tree, tpt1).setType(tp)
}
+ def functionTypeWildcard(tree: Tree, arity: Int): Type = {
+ val tp = functionType(List.fill(arity)(WildcardType), WildcardType)
+ if (tp == NoType) MaxFunctionArityError(tree)
+ tp
+ }
+
def typedEta(expr1: Tree): Tree = expr1.tpe match {
case TypeRef(_, ByNameParamClass, _) =>
val expr2 = Function(List(), expr1) setPos expr1.pos
@@ -4383,10 +4396,10 @@ trait Typers extends Adaptations with Tags {
typed1(expr2, mode, pt)
case PolyType(_, MethodType(formals, _)) =>
if (isFunctionType(pt)) expr1
- else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
+ else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length))
case MethodType(formals, _) =>
if (isFunctionType(pt)) expr1
- else adapt(expr1, mode, functionType(formals map (t => WildcardType), WildcardType))
+ else adapt(expr1, mode, functionTypeWildcard(expr1, formals.length))
case ErrorType =>
expr1
case _ =>
@@ -4692,11 +4705,13 @@ trait Typers extends Adaptations with Tags {
def handleMissing: Tree = {
def errorTree = missingSelectErrorTree(tree, qual, name)
def asTypeSelection = (
- if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
+ if (context.unit.isJava && name.isTypeName) {
+ // SI-3120 Java uses the same syntax, A.B, to express selection from the
+ // value A and from the type A. We have to try both.
atPos(tree.pos)(gen.convertToSelectFromType(qual, name)) match {
case EmptyTree => None
case tree1 => Some(typed1(tree1, mode, pt))
- }
+ }
}
else None
)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 589e5ce6fd..d55dce70c7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -115,11 +115,16 @@ trait Unapplies extends ast.TreeDSL
/** The module corresponding to a case class; overrides toString to show the module's name
*/
def caseModuleDef(cdef: ClassDef): ModuleDef = {
- // > MaxFunctionArity is caught in Namers, but for nice error reporting instead of
- // an abrupt crash we trim the list here.
- def primaries = constrParamss(cdef).head take MaxFunctionArity map (_.tpt)
- def inheritFromFun = !cdef.mods.hasAbstractFlag && cdef.tparams.isEmpty && constrParamss(cdef).length == 1
- def createFun = gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true)
+ val params = constrParamss(cdef)
+ def inheritFromFun = !cdef.mods.hasAbstractFlag && cdef.tparams.isEmpty && (params match {
+ case List(ps) if ps.length <= MaxFunctionArity => true
+ case _ => false
+ })
+ def createFun = {
+ def primaries = params.head map (_.tpt)
+ gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true)
+ }
+
def parents = if (inheritFromFun) List(createFun) else Nil
def toString = DefDef(
Modifiers(OVERRIDE | FINAL | SYNTHETIC),
diff --git a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala
index 6997dbd402..4e1cf02a6e 100644
--- a/src/compiler/scala/tools/nsc/util/SimpleTracer.scala
+++ b/src/compiler/scala/tools/nsc/util/SimpleTracer.scala
@@ -10,7 +10,7 @@ import java.io.PrintStream
* @param enabled: A condition that must be true for trace info to be produced.
*/
class SimpleTracer(out: PrintStream, enabled: Boolean = true) {
- def apply[T](msg: String)(value: T): T = {
+ def apply[T](msg: => String)(value: T): T = {
if (enabled) out.println(msg+value)
value
}
diff --git a/src/compiler/scala/tools/reflect/MacroImplementations.scala b/src/compiler/scala/tools/reflect/MacroImplementations.scala
index 002a3fce82..4e8f02084d 100644
--- a/src/compiler/scala/tools/reflect/MacroImplementations.scala
+++ b/src/compiler/scala/tools/reflect/MacroImplementations.scala
@@ -117,7 +117,8 @@ abstract class MacroImplementations {
if (!strIsEmpty) {
val len = str.length
while (idx < len) {
- if (str(idx) == '%') {
+ def notPercentN = str(idx) != '%' || (idx + 1 < len && str(idx + 1) != 'n')
+ if (str(idx) == '%' && notPercentN) {
bldr append (str substring (start, idx)) append "%%"
start = idx + 1
}
diff --git a/src/intellij/repl.iml.SAMPLE b/src/intellij/repl.iml.SAMPLE
new file mode 100644
index 0000000000..5e11ff1cf6
--- /dev/null
+++ b/src/intellij/repl.iml.SAMPLE
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="scala" name="Scala">
+ <configuration>
+ <option name="compilerLibraryLevel" value="Project" />
+ <option name="compilerLibraryName" value="compiler-locker" />
+ <option name="maximumHeapSize" value="1536" />
+ <option name="vmOptions" value="-Xms1536m -Xss1m -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=256m -XX:+CMSClassUnloadingEnabled -XX:+UseCompressedOops -XX:+UseParallelGC" />
+ </configuration>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$/../repl">
+ <sourceFolder url="file://$MODULE_DIR$/../repl" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module" module-name="library" />
+ <orderEntry type="module" module-name="reflect" />
+ <orderEntry type="module" module-name="compiler" />
+ </component>
+</module>
+
diff --git a/src/intellij/scala-lang.ipr.SAMPLE b/src/intellij/scala-lang.ipr.SAMPLE
index e470e019c9..61c813df01 100644
--- a/src/intellij/scala-lang.ipr.SAMPLE
+++ b/src/intellij/scala-lang.ipr.SAMPLE
@@ -206,6 +206,7 @@
<module fileurl="file://$PROJECT_DIR$/manual.iml" filepath="$PROJECT_DIR$/manual.iml" />
<module fileurl="file://$PROJECT_DIR$/partest.iml" filepath="$PROJECT_DIR$/partest.iml" />
<module fileurl="file://$PROJECT_DIR$/reflect.iml" filepath="$PROJECT_DIR$/reflect.iml" />
+ <module fileurl="file://$PROJECT_DIR$/repl.iml" filepath="$PROJECT_DIR$/repl.iml" />
<module fileurl="file://$PROJECT_DIR$/scala.iml" filepath="$PROJECT_DIR$/scala.iml" />
<module fileurl="file://$PROJECT_DIR$/scaladoc.iml" filepath="$PROJECT_DIR$/scaladoc.iml" />
<module fileurl="file://$PROJECT_DIR$/scalap.iml" filepath="$PROJECT_DIR$/scalap.iml" />
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala b/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
index a4a2de9b51..f30d896fb7 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/InteractiveTest.scala
@@ -74,7 +74,7 @@ abstract class InteractiveTest
/** Test's entry point */
def main(args: Array[String]) {
try execute()
- finally shutdown()
+ finally askShutdown()
}
protected def execute(): Unit = {
@@ -110,14 +110,4 @@ abstract class InteractiveTest
tester.run()
}
****/
-
- /** shutdown the presentation compiler. */
- protected def shutdown() {
- askShutdown()
-
- // this is actually needed to force exit on test completion.
- // Note: May be a bug on either the testing framework or (less likely)
- // the presentation compiler
- sys.exit(0)
- }
}
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
index 9085eb56e6..c0ad245091 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
@@ -17,7 +17,7 @@ private[tests] trait CoreTestDefs
with AskCompletionAt {
def memberPrinter(member: compiler.Member): String =
- "[accessible: %5s] ".format(member.accessible) + "`" + (member.sym.toString() + member.tpe.toString()).trim() + "`"
+ "[accessible: %5s] ".format(member.accessible) + "`" + (member.sym.toString.trim + member.tpe.toString()).trim + "`"
override def runTest() {
askAllSources(CompletionMarker) { pos =>
@@ -29,7 +29,7 @@ private[tests] trait CoreTestDefs
// universal check file that we can provide for this to work
reporter.println("retrieved %d members".format(members.size))
compiler ask { () =>
- val filtered = members.filterNot(member => member.sym.name.toString == "getClass" || member.sym.isConstructor)
+ val filtered = members.filterNot(member => (member.sym.name string_== "getClass") || member.sym.isConstructor)
reporter.println(filtered.map(memberPrinter).sortBy(_.toString()).mkString("\n"))
}
}
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala
index 676feeba8a..40cfc111a1 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/SourcesCollector.scala
@@ -11,7 +11,7 @@ private[tests] object SourcesCollector {
* With the default `filter` only .scala and .java files are collected.
* */
def apply(base: Path, filter: SourceFilter): Array[SourceFile] = {
- assert(base.isDirectory)
+ assert(base.isDirectory, base + " is not a directory")
base.walk.filter(filter).map(source).toList.toArray.sortBy(_.file.name)
}
diff --git a/src/library/scala/Function0.scala b/src/library/scala/Function0.scala
index 2223091eb3..54cba021e0 100644
--- a/src/library/scala/Function0.scala
+++ b/src/library/scala/Function0.scala
@@ -6,7 +6,7 @@
** |/ **
\* */
// GENERATED CODE: DO NOT EDIT.
-// genprod generated these sources at: Tue Aug 07 11:54:44 CEST 2012
+// genprod generated these sources at: Sun Mar 24 14:14:12 CET 2013
package scala
diff --git a/src/library/scala/Tuple1.scala b/src/library/scala/Tuple1.scala
index 6776e4fbff..5898b63e21 100644
--- a/src/library/scala/Tuple1.scala
+++ b/src/library/scala/Tuple1.scala
@@ -15,6 +15,7 @@ package scala
* @constructor Create a new tuple with 1 elements.
* @param _1 Element 1 of this Tuple1
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple1[@specialized(Int, Long, Double) +T1](_1: T1)
extends Product1[T1]
{
diff --git a/src/library/scala/Tuple10.scala b/src/library/scala/Tuple10.scala
index e016dea63d..2b0239561d 100644
--- a/src/library/scala/Tuple10.scala
+++ b/src/library/scala/Tuple10.scala
@@ -24,6 +24,7 @@ package scala
* @param _9 Element 9 of this Tuple10
* @param _10 Element 10 of this Tuple10
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10)
extends Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]
{
diff --git a/src/library/scala/Tuple11.scala b/src/library/scala/Tuple11.scala
index 87e759fc0a..0d5294d547 100644
--- a/src/library/scala/Tuple11.scala
+++ b/src/library/scala/Tuple11.scala
@@ -25,6 +25,7 @@ package scala
* @param _10 Element 10 of this Tuple11
* @param _11 Element 11 of this Tuple11
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11)
extends Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]
{
diff --git a/src/library/scala/Tuple12.scala b/src/library/scala/Tuple12.scala
index 7c95f8aa5f..d36c8275c1 100644
--- a/src/library/scala/Tuple12.scala
+++ b/src/library/scala/Tuple12.scala
@@ -26,6 +26,7 @@ package scala
* @param _11 Element 11 of this Tuple12
* @param _12 Element 12 of this Tuple12
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12)
extends Product12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]
{
diff --git a/src/library/scala/Tuple13.scala b/src/library/scala/Tuple13.scala
index 9f2ecd86da..edc37456fe 100644
--- a/src/library/scala/Tuple13.scala
+++ b/src/library/scala/Tuple13.scala
@@ -27,6 +27,7 @@ package scala
* @param _12 Element 12 of this Tuple13
* @param _13 Element 13 of this Tuple13
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13)
extends Product13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]
{
diff --git a/src/library/scala/Tuple14.scala b/src/library/scala/Tuple14.scala
index f03e279743..9896e736c9 100644
--- a/src/library/scala/Tuple14.scala
+++ b/src/library/scala/Tuple14.scala
@@ -28,6 +28,7 @@ package scala
* @param _13 Element 13 of this Tuple14
* @param _14 Element 14 of this Tuple14
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14)
extends Product14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]
{
diff --git a/src/library/scala/Tuple15.scala b/src/library/scala/Tuple15.scala
index 6074a40cd0..45cd4f751f 100644
--- a/src/library/scala/Tuple15.scala
+++ b/src/library/scala/Tuple15.scala
@@ -29,6 +29,7 @@ package scala
* @param _14 Element 14 of this Tuple15
* @param _15 Element 15 of this Tuple15
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15)
extends Product15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]
{
diff --git a/src/library/scala/Tuple16.scala b/src/library/scala/Tuple16.scala
index 0c38bd783f..2e370a5b31 100644
--- a/src/library/scala/Tuple16.scala
+++ b/src/library/scala/Tuple16.scala
@@ -30,6 +30,7 @@ package scala
* @param _15 Element 15 of this Tuple16
* @param _16 Element 16 of this Tuple16
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16)
extends Product16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]
{
diff --git a/src/library/scala/Tuple17.scala b/src/library/scala/Tuple17.scala
index 7cc7ea8f7e..2242a15fda 100644
--- a/src/library/scala/Tuple17.scala
+++ b/src/library/scala/Tuple17.scala
@@ -31,6 +31,7 @@ package scala
* @param _16 Element 16 of this Tuple17
* @param _17 Element 17 of this Tuple17
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17)
extends Product17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]
{
diff --git a/src/library/scala/Tuple18.scala b/src/library/scala/Tuple18.scala
index 7404349989..68f245c6ce 100644
--- a/src/library/scala/Tuple18.scala
+++ b/src/library/scala/Tuple18.scala
@@ -32,6 +32,7 @@ package scala
* @param _17 Element 17 of this Tuple18
* @param _18 Element 18 of this Tuple18
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18)
extends Product18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]
{
diff --git a/src/library/scala/Tuple19.scala b/src/library/scala/Tuple19.scala
index ca8f2ba401..a8a49549fb 100644
--- a/src/library/scala/Tuple19.scala
+++ b/src/library/scala/Tuple19.scala
@@ -33,6 +33,7 @@ package scala
* @param _18 Element 18 of this Tuple19
* @param _19 Element 19 of this Tuple19
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19)
extends Product19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]
{
diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala
index 4337e62a53..9ea1469c5c 100644
--- a/src/library/scala/Tuple2.scala
+++ b/src/library/scala/Tuple2.scala
@@ -16,6 +16,7 @@ package scala
* @param _1 Element 1 of this Tuple2
* @param _2 Element 2 of this Tuple2
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2)
extends Product2[T1, T2]
{
diff --git a/src/library/scala/Tuple20.scala b/src/library/scala/Tuple20.scala
index 9d6e2f71ff..0118d382ab 100644
--- a/src/library/scala/Tuple20.scala
+++ b/src/library/scala/Tuple20.scala
@@ -34,6 +34,7 @@ package scala
* @param _19 Element 19 of this Tuple20
* @param _20 Element 20 of this Tuple20
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20)
extends Product20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]
{
diff --git a/src/library/scala/Tuple21.scala b/src/library/scala/Tuple21.scala
index 6173ddb118..ceae94af41 100644
--- a/src/library/scala/Tuple21.scala
+++ b/src/library/scala/Tuple21.scala
@@ -35,6 +35,7 @@ package scala
* @param _20 Element 20 of this Tuple21
* @param _21 Element 21 of this Tuple21
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21)
extends Product21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]
{
diff --git a/src/library/scala/Tuple22.scala b/src/library/scala/Tuple22.scala
index d426a548e5..ecd567a710 100644
--- a/src/library/scala/Tuple22.scala
+++ b/src/library/scala/Tuple22.scala
@@ -36,6 +36,7 @@ package scala
* @param _21 Element 21 of this Tuple22
* @param _22 Element 22 of this Tuple22
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21, _22: T22)
extends Product22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]
{
diff --git a/src/library/scala/Tuple3.scala b/src/library/scala/Tuple3.scala
index 3c7e2af0d1..6e71d3ae8c 100644
--- a/src/library/scala/Tuple3.scala
+++ b/src/library/scala/Tuple3.scala
@@ -17,6 +17,7 @@ package scala
* @param _2 Element 2 of this Tuple3
* @param _3 Element 3 of this Tuple3
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3)
extends Product3[T1, T2, T3]
{
diff --git a/src/library/scala/Tuple4.scala b/src/library/scala/Tuple4.scala
index b6913dbf48..4c84cfc674 100644
--- a/src/library/scala/Tuple4.scala
+++ b/src/library/scala/Tuple4.scala
@@ -18,6 +18,7 @@ package scala
* @param _3 Element 3 of this Tuple4
* @param _4 Element 4 of this Tuple4
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple4[+T1, +T2, +T3, +T4](_1: T1, _2: T2, _3: T3, _4: T4)
extends Product4[T1, T2, T3, T4]
{
diff --git a/src/library/scala/Tuple5.scala b/src/library/scala/Tuple5.scala
index 4f83f44cb9..fe8e853f12 100644
--- a/src/library/scala/Tuple5.scala
+++ b/src/library/scala/Tuple5.scala
@@ -19,6 +19,7 @@ package scala
* @param _4 Element 4 of this Tuple5
* @param _5 Element 5 of this Tuple5
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5)
extends Product5[T1, T2, T3, T4, T5]
{
diff --git a/src/library/scala/Tuple6.scala b/src/library/scala/Tuple6.scala
index ac2ec43bd6..6bf1c73d4b 100644
--- a/src/library/scala/Tuple6.scala
+++ b/src/library/scala/Tuple6.scala
@@ -20,6 +20,7 @@ package scala
* @param _5 Element 5 of this Tuple6
* @param _6 Element 6 of this Tuple6
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple6[+T1, +T2, +T3, +T4, +T5, +T6](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6)
extends Product6[T1, T2, T3, T4, T5, T6]
{
diff --git a/src/library/scala/Tuple7.scala b/src/library/scala/Tuple7.scala
index 62407b1d9b..ea42709cb7 100644
--- a/src/library/scala/Tuple7.scala
+++ b/src/library/scala/Tuple7.scala
@@ -21,6 +21,7 @@ package scala
* @param _6 Element 6 of this Tuple7
* @param _7 Element 7 of this Tuple7
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple7[+T1, +T2, +T3, +T4, +T5, +T6, +T7](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7)
extends Product7[T1, T2, T3, T4, T5, T6, T7]
{
diff --git a/src/library/scala/Tuple8.scala b/src/library/scala/Tuple8.scala
index 0611fefd16..c24f9454e0 100644
--- a/src/library/scala/Tuple8.scala
+++ b/src/library/scala/Tuple8.scala
@@ -22,6 +22,7 @@ package scala
* @param _7 Element 7 of this Tuple8
* @param _8 Element 8 of this Tuple8
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8)
extends Product8[T1, T2, T3, T4, T5, T6, T7, T8]
{
diff --git a/src/library/scala/Tuple9.scala b/src/library/scala/Tuple9.scala
index 52f27f7c46..ed02b30df2 100644
--- a/src/library/scala/Tuple9.scala
+++ b/src/library/scala/Tuple9.scala
@@ -23,6 +23,7 @@ package scala
* @param _8 Element 8 of this Tuple9
* @param _9 Element 9 of this Tuple9
*/
+@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0")
case class Tuple9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9)
extends Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9]
{
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index c85a4fb6e7..72a23a0dd0 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -161,6 +161,41 @@ object Iterator {
def hasNext = true
def next = elem
}
+
+ /** Avoid stack overflows when applying ++ to lots of iterators by
+ * flattening the unevaluated iterators out into a vector of closures.
+ */
+ private[scala] final class ConcatIterator[+A](initial: Vector[() => Iterator[A]]) extends Iterator[A] {
+ // current set to null when all iterators are exhausted
+ private[this] var current: Iterator[A] = Iterator.empty
+ private[this] var queue: Vector[() => Iterator[A]] = initial
+ // Advance current to the next non-empty iterator
+ private[this] def advance(): Boolean = {
+ if (queue.isEmpty) {
+ current = null
+ false
+ }
+ else {
+ current = queue.head()
+ queue = queue.tail
+ current.hasNext || advance()
+ }
+ }
+ def hasNext = (current ne null) && (current.hasNext || advance())
+ def next() = if (hasNext) current.next else Iterator.empty.next
+
+ override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] =
+ new ConcatIterator(queue :+ (() => that.toIterator))
+ }
+
+ private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] {
+ private[this] lazy val rhs: Iterator[A] = that.toIterator
+ def hasNext = lhs.hasNext || rhs.hasNext
+ def next = if (lhs.hasNext) lhs.next else rhs.next
+
+ override def ++[B >: A](that: => GenTraversableOnce[B]) =
+ new ConcatIterator(Vector(() => this, () => that.toIterator))
+ }
}
import Iterator.empty
@@ -338,24 +373,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
* @usecase def ++(that: => Iterator[A]): Iterator[A]
* @inheritdoc
*/
- def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
- // optimize a little bit to prevent n log n behavior.
- private var cur : Iterator[B] = self
- private var selfExhausted : Boolean = false
- // since that is by-name, make sure it's only referenced once -
- // if "val it = that" is inside the block, then hasNext on an empty
- // iterator will continually reevaluate it. (ticket #3269)
- lazy val it = that.toIterator
- // the eq check is to avoid an infinite loop on "x ++ x"
- def hasNext = cur.hasNext || (!selfExhausted && {
- it.hasNext && {
- cur = it
- selfExhausted = true
- true
- }
- })
- def next() = { hasNext; cur.next() }
- }
+ def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.JoinIterator(self, that)
/** Creates a new iterator by applying a function to all values produced by this iterator
* and concatenating the results.
diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala
index d91f70da75..85c620239a 100644
--- a/src/library/scala/collection/parallel/package.scala
+++ b/src/library/scala/collection/parallel/package.scala
@@ -42,11 +42,8 @@ package object parallel {
private[parallel] def outofbounds(idx: Int) = throw new IndexOutOfBoundsException(idx.toString)
private[parallel] def getTaskSupport: TaskSupport =
- if (scala.util.Properties.isJavaAtLeast("1.6")) {
- val vendor = scala.util.Properties.javaVmVendor
- if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinTaskSupport
- else new ThreadPoolTaskSupport
- } else new ThreadPoolTaskSupport
+ if (scala.util.Properties.isJavaAtLeast("1.6")) new ForkJoinTaskSupport
+ else new ThreadPoolTaskSupport
val defaultTaskSupport: TaskSupport = getTaskSupport
diff --git a/src/library/scala/reflect/NameTransformer.scala b/src/library/scala/reflect/NameTransformer.scala
index 8a1cce6b02..6192971c74 100755
--- a/src/library/scala/reflect/NameTransformer.scala
+++ b/src/library/scala/reflect/NameTransformer.scala
@@ -15,9 +15,12 @@ package reflect
object NameTransformer {
// XXX Short term: providing a way to alter these without having to recompile
// the compiler before recompiling the compiler.
- val MODULE_SUFFIX_STRING = sys.props.getOrElse("SCALA_MODULE_SUFFIX_STRING", "$")
- val NAME_JOIN_STRING = sys.props.getOrElse("SCALA_NAME_JOIN_STRING", "$")
- val MODULE_INSTANCE_NAME = "MODULE$"
+ val MODULE_SUFFIX_STRING = sys.props.getOrElse("SCALA_MODULE_SUFFIX_STRING", "$")
+ val NAME_JOIN_STRING = sys.props.getOrElse("SCALA_NAME_JOIN_STRING", "$")
+ val MODULE_INSTANCE_NAME = "MODULE$"
+ val LOCAL_SUFFIX_STRING = " "
+ val SETTER_SUFFIX_STRING = "_$eq"
+ val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
private val nops = 128
private val ncodes = 26 * 26
diff --git a/src/partest/scala/tools/partest/nest/Diff.java b/src/partest/scala/tools/partest/nest/Diff.java
deleted file mode 100644
index f69fc6858b..0000000000
--- a/src/partest/scala/tools/partest/nest/Diff.java
+++ /dev/null
@@ -1,873 +0,0 @@
-
-package scala.tools.partest.nest;
-
-import java.util.Hashtable;
-
-/** A class to compare IndexedSeqs of objects. The result of comparison
- is a list of <code>change</code> objects which form an
- edit script. The objects compared are traditionally lines
- of text from two files. Comparison options such as "ignore
- whitespace" are implemented by modifying the <code>equals</code>
- and <code>hashcode</code> methods for the objects compared.
-<p>
- The basic algorithm is described in: </br>
- "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
- Algorithmica Vol. 1 No. 2, 1986, p 251.
-<p>
- This class outputs different results from GNU diff 1.15 on some
- inputs. Our results are actually better (smaller change list, smaller
- total size of changes), but it would be nice to know why. Perhaps
- there is a memory overwrite bug in GNU diff 1.15.
-
- @author Stuart D. Gathman, translated from GNU diff 1.15
- Copyright (C) 2000 Business Management Systems, Inc.
-<p>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-<p>
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-<p>
- You should have received a copy of the <a href=COPYING.txt>
- GNU General Public License</a>
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
-public class Diff {
-
- /** Prepare to find differences between two arrays. Each element of
- the arrays is translated to an "equivalence number" based on
- the result of <code>equals</code>. The original Object arrays
- are no longer needed for computing the differences. They will
- be needed again later to print the results of the comparison as
- an edit script, if desired.
- */
- public Diff(Object[] a,Object[] b) {
- Hashtable<Object, Integer> h = new Hashtable<Object, Integer>(a.length + b.length);
- filevec[0] = new file_data(a,h);
- filevec[1] = new file_data(b,h);
- }
-
- /** 1 more than the maximum equivalence value used for this or its
- sibling file. */
- private int equiv_max = 1;
-
- /** When set to true, the comparison uses a heuristic to speed it up.
- With this heuristic, for files with a constant small density
- of changes, the algorithm is linear in the file size. */
- public boolean heuristic = false;
-
- /** When set to true, the algorithm returns a guarranteed minimal
- set of changes. This makes things slower, sometimes much slower. */
- public boolean no_discards = false;
-
- private int[] xvec, yvec; /* IndexedSeqs being compared. */
- private int[] fdiag; /* IndexedSeq, indexed by diagonal, containing
- the X coordinate of the point furthest
- along the given diagonal in the forward
- search of the edit matrix. */
- private int[] bdiag; /* IndexedSeq, indexed by diagonal, containing
- the X coordinate of the point furthest
- along the given diagonal in the backward
- search of the edit matrix. */
- private int fdiagoff, bdiagoff;
- private final file_data[] filevec = new file_data[2];
- private int cost;
-
- /** Find the midpoint of the shortest edit script for a specified
- portion of the two files.
-
- We scan from the beginnings of the files, and simultaneously from the ends,
- doing a breadth-first search through the space of edit-sequence.
- When the two searches meet, we have found the midpoint of the shortest
- edit sequence.
-
- The value returned is the number of the diagonal on which the midpoint lies.
- The diagonal number equals the number of inserted lines minus the number
- of deleted lines (counting only lines before the midpoint).
- The edit cost is stored into COST; this is the total number of
- lines inserted or deleted (counting only lines before the midpoint).
-
- This function assumes that the first lines of the specified portions
- of the two files do not match, and likewise that the last lines do not
- match. The caller must trim matching lines from the beginning and end
- of the portions it is going to specify.
-
- Note that if we return the "wrong" diagonal value, or if
- the value of bdiag at that diagonal is "wrong",
- the worst this can do is cause suboptimal diff output.
- It cannot cause incorrect diff output. */
-
- private int diag (int xoff, int xlim, int yoff, int ylim) {
- final int[] fd = fdiag; // Give the compiler a chance.
- final int[] bd = bdiag; // Additional help for the compiler.
- final int[] xv = xvec; // Still more help for the compiler.
- final int[] yv = yvec; // And more and more . . .
- final int dmin = xoff - ylim; // Minimum valid diagonal.
- final int dmax = xlim - yoff; // Maximum valid diagonal.
- final int fmid = xoff - yoff; // Center diagonal of top-down search.
- final int bmid = xlim - ylim; // Center diagonal of bottom-up search.
- int fmin = fmid, fmax = fmid; // Limits of top-down search.
- int bmin = bmid, bmax = bmid; // Limits of bottom-up search.
- /* True if southeast corner is on an odd
- diagonal with respect to the northwest. */
- final boolean odd = (fmid - bmid & 1) != 0;
-
- fd[fdiagoff + fmid] = xoff;
- bd[bdiagoff + bmid] = xlim;
-
- for (int c = 1;; ++c)
- {
- int d; /* Active diagonal. */
- boolean big_snake = false;
-
- /* Extend the top-down search by an edit step in each diagonal. */
- if (fmin > dmin)
- fd[fdiagoff + --fmin - 1] = -1;
- else
- ++fmin;
- if (fmax < dmax)
- fd[fdiagoff + ++fmax + 1] = -1;
- else
- --fmax;
- for (d = fmax; d >= fmin; d -= 2)
- {
- int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1];
-
- if (tlo >= thi)
- x = tlo + 1;
- else
- x = thi;
- oldx = x;
- y = x - d;
- while (x < xlim && y < ylim && xv[x] == yv[y]) {
- ++x; ++y;
- }
- if (x - oldx > 20)
- big_snake = true;
- fd[fdiagoff + d] = x;
- if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
- {
- cost = 2 * c - 1;
- return d;
- }
- }
-
- /* Similar extend the bottom-up search. */
- if (bmin > dmin)
- bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE;
- else
- ++bmin;
- if (bmax < dmax)
- bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE;
- else
- --bmax;
- for (d = bmax; d >= bmin; d -= 2)
- {
- int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1];
-
- if (tlo < thi)
- x = tlo;
- else
- x = thi - 1;
- oldx = x;
- y = x - d;
- while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) {
- --x; --y;
- }
- if (oldx - x > 20)
- big_snake = true;
- bd[bdiagoff + d] = x;
- if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
- {
- cost = 2 * c;
- return d;
- }
- }
-
- /* Heuristic: check occasionally for a diagonal that has made
- lots of progress compared with the edit distance.
- If we have any such, find the one that has made the most
- progress and return it as if it had succeeded.
-
- With this heuristic, for files with a constant small density
- of changes, the algorithm is linear in the file size. */
-
- if (c > 200 && big_snake && heuristic)
- {
- int best = 0;
- int bestpos = -1;
-
- for (d = fmax; d >= fmin; d -= 2)
- {
- int dd = d - fmid;
- if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
- {
- if (fd[fdiagoff + d] * 2 - dd > best
- && fd[fdiagoff + d] - xoff > 20
- && fd[fdiagoff + d] - d - yoff > 20)
- {
- int k;
- int x = fd[fdiagoff + d];
-
- /* We have a good enough best diagonal;
- now insist that it end with a significant snake. */
- for (k = 1; k <= 20; k++)
- if (xvec[x - k] != yvec[x - d - k])
- break;
-
- if (k == 21)
- {
- best = fd[fdiagoff + d] * 2 - dd;
- bestpos = d;
- }
- }
- }
- }
- if (best > 0)
- {
- cost = 2 * c - 1;
- return bestpos;
- }
-
- best = 0;
- for (d = bmax; d >= bmin; d -= 2)
- {
- int dd = d - bmid;
- if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
- {
- if ((xlim - bd[bdiagoff + d]) * 2 + dd > best
- && xlim - bd[bdiagoff + d] > 20
- && ylim - (bd[bdiagoff + d] - d) > 20)
- {
- /* We have a good enough best diagonal;
- now insist that it end with a significant snake. */
- int k;
- int x = bd[bdiagoff + d];
-
- for (k = 0; k < 20; k++)
- if (xvec[x + k] != yvec[x - d + k])
- break;
- if (k == 20)
- {
- best = (xlim - bd[bdiagoff + d]) * 2 + dd;
- bestpos = d;
- }
- }
- }
- }
- if (best > 0)
- {
- cost = 2 * c - 1;
- return bestpos;
- }
- }
- }
- }
-
- /** Compare in detail contiguous subsequences of the two files
- which are known, as a whole, to match each other.
-
- The results are recorded in the IndexedSeqs filevec[N].changed_flag, by
- storing a 1 in the element for each line that is an insertion or deletion.
-
- The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
-
- Note that XLIM, YLIM are exclusive bounds.
- All line numbers are origin-0 and discarded lines are not counted. */
-
- private void compareseq (int xoff, int xlim, int yoff, int ylim) {
- /* Slide down the bottom initial diagonal. */
- while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) {
- ++xoff; ++yoff;
- }
- /* Slide up the top initial diagonal. */
- while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) {
- --xlim; --ylim;
- }
-
- /* Handle simple cases. */
- if (xoff == xlim)
- while (yoff < ylim)
- filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true;
- else if (yoff == ylim)
- while (xoff < xlim)
- filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true;
- else
- {
- /* Find a point of correspondence in the middle of the files. */
-
- int d = diag (xoff, xlim, yoff, ylim);
- int c = cost;
- int f = fdiag[fdiagoff + d];
- int b = bdiag[bdiagoff + d];
-
- if (c == 1)
- {
- /* This should be impossible, because it implies that
- one of the two subsequences is empty,
- and that case was handled above without calling `diag'.
- Let's verify that this is true. */
- throw new IllegalArgumentException("Empty subsequence");
- }
- else
- {
- /* Use that point to split this problem into two subproblems. */
- compareseq (xoff, b, yoff, b - d);
- /* This used to use f instead of b,
- but that is incorrect!
- It is not necessarily the case that diagonal d
- has a snake from b to f. */
- compareseq (b, xlim, b - d, ylim);
- }
- }
- }
-
- /** Discard lines from one file that have no matches in the other file.
- */
-
- private void discard_confusing_lines() {
- filevec[0].discard_confusing_lines(filevec[1]);
- filevec[1].discard_confusing_lines(filevec[0]);
- }
-
- private boolean inhibit = false;
-
- /** Adjust inserts/deletes of blank lines to join changes
- as much as possible.
- */
-
- private void shift_boundaries() {
- if (inhibit)
- return;
- filevec[0].shift_boundaries(filevec[1]);
- filevec[1].shift_boundaries(filevec[0]);
- }
-
- public interface ScriptBuilder {
- /** Scan the tables of which lines are inserted and deleted,
- producing an edit script.
- @param changed0 true for lines in first file which do not match 2nd
- @param len0 number of lines in first file
- @param changed1 true for lines in 2nd file which do not match 1st
- @param len1 number of lines in 2nd file
- @return a linked list of changes - or null
- */
- public change build_script(
- boolean[] changed0,int len0,
- boolean[] changed1,int len1
- );
- }
-
- /** Scan the tables of which lines are inserted and deleted,
- producing an edit script in reverse order. */
-
- static class ReverseScript implements ScriptBuilder {
- public change build_script(
- final boolean[] changed0,int len0,
- final boolean[] changed1,int len1)
- {
- change script = null;
- int i0 = 0, i1 = 0;
- while (i0 < len0 || i1 < len1) {
- if (changed0[1+i0] || changed1[1+i1]) {
- int line0 = i0, line1 = i1;
-
- /* Find # lines changed here in each file. */
- while (changed0[1+i0]) ++i0;
- while (changed1[1+i1]) ++i1;
-
- /* Record this change. */
- script = new change(line0, line1, i0 - line0, i1 - line1, script);
- }
-
- /* We have reached lines in the two files that match each other. */
- i0++; i1++;
- }
-
- return script;
- }
- }
-
- static class ForwardScript implements ScriptBuilder {
- /** Scan the tables of which lines are inserted and deleted,
- producing an edit script in forward order. */
- public change build_script(
- final boolean[] changed0,int len0,
- final boolean[] changed1,int len1)
- {
- change script = null;
- int i0 = len0, i1 = len1;
-
- while (i0 >= 0 || i1 >= 0)
- {
- if (changed0[i0] || changed1[i1])
- {
- int line0 = i0, line1 = i1;
-
- /* Find # lines changed here in each file. */
- while (changed0[i0]) --i0;
- while (changed1[i1]) --i1;
-
- /* Record this change. */
- script = new change(i0, i1, line0 - i0, line1 - i1, script);
- }
-
- /* We have reached lines in the two files that match each other. */
- i0--; i1--;
- }
-
- return script;
- }
- }
-
- /** Standard ScriptBuilders. */
- public final static ScriptBuilder
- forwardScript = new ForwardScript(),
- reverseScript = new ReverseScript();
-
- /* Report the differences of two files. DEPTH is the current directory
- depth. */
- public final change diff_2(final boolean reverse) {
- return diff(reverse ? reverseScript : forwardScript);
- }
-
- /** Get the results of comparison as an edit script. The script
- is described by a list of changes. The standard ScriptBuilder
- implementations provide for forward and reverse edit scripts.
- Alternate implementations could, for instance, list common elements
- instead of differences.
- @param bld an object to build the script from change flags
- @return the head of a list of changes
- */
- public change diff(final ScriptBuilder bld) {
-
- /* Some lines are obviously insertions or deletions
- because they don't match anything. Detect them now,
- and avoid even thinking about them in the main comparison algorithm. */
-
- discard_confusing_lines ();
-
- /* Now do the main comparison algorithm, considering just the
- undiscarded lines. */
-
- xvec = filevec[0].undiscarded;
- yvec = filevec[1].undiscarded;
-
- int diags =
- filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
- fdiag = new int[diags];
- fdiagoff = filevec[1].nondiscarded_lines + 1;
- bdiag = new int[diags];
- bdiagoff = filevec[1].nondiscarded_lines + 1;
-
- compareseq (0, filevec[0].nondiscarded_lines,
- 0, filevec[1].nondiscarded_lines);
- fdiag = null;
- bdiag = null;
-
- /* Modify the results slightly to make them prettier
- in cases where that can validly be done. */
-
- shift_boundaries ();
-
- /* Get the results of comparison in the form of a chain
- of `struct change's -- an edit script. */
- return bld.build_script(
- filevec[0].changed_flag,
- filevec[0].buffered_lines,
- filevec[1].changed_flag,
- filevec[1].buffered_lines
- );
-
- }
-
- /** The result of comparison is an "edit script": a chain of change objects.
- Each change represents one place where some lines are deleted
- and some are inserted.
-
- LINE0 and LINE1 are the first affected lines in the two files (origin 0).
- DELETED is the number of lines deleted here from file 0.
- INSERTED is the number of lines inserted here in file 1.
-
- If DELETED is 0 then LINE0 is the number of the line before
- which the insertion was done; vice versa for INSERTED and LINE1. */
-
- public static class change {
- /** Previous or next edit command. */
- public change link;
- /** # lines of file 1 changed here. */
- public final int inserted;
- /** # lines of file 0 changed here. */
- public final int deleted;
- /** Line number of 1st deleted line. */
- public final int line0;
- /** Line number of 1st inserted line. */
- public final int line1;
-
- /** Cons an additional entry onto the front of an edit script OLD.
- LINE0 and LINE1 are the first affected lines in the two files (origin 0).
- DELETED is the number of lines deleted here from file 0.
- INSERTED is the number of lines inserted here in file 1.
-
- If DELETED is 0 then LINE0 is the number of the line before
- which the insertion was done; vice versa for INSERTED and LINE1. */
- public change(int line0, int line1, int deleted, int inserted, change old) {
- this.line0 = line0;
- this.line1 = line1;
- this.inserted = inserted;
- this.deleted = deleted;
- this.link = old;
- //System.err.println(line0+","+line1+","+inserted+","+deleted);
- }
- }
-
- /** Data on one input file being compared.
- */
-
- class file_data {
-
- /** Allocate changed array for the results of comparison. */
- void clear() {
- /* Allocate a flag for each line of each file, saying whether that line
- is an insertion or deletion.
- Allocate an extra element, always zero, at each end of each IndexedSeq.
- */
- changed_flag = new boolean[buffered_lines + 2];
- }
-
- /** Return equiv_count[I] as the number of lines in this file
- that fall in equivalence class I.
- @return the array of equivalence class counts.
- */
- int[] equivCount() {
- int[] equiv_count = new int[equiv_max];
- for (int i = 0; i < buffered_lines; ++i)
- ++equiv_count[equivs[i]];
- return equiv_count;
- }
-
- /** Discard lines that have no matches in another file.
-
- A line which is discarded will not be considered by the actual
- comparison algorithm; it will be as if that line were not in the file.
- The file's `realindexes' table maps virtual line numbers
- (which don't count the discarded lines) into real line numbers;
- this is how the actual comparison algorithm produces results
- that are comprehensible when the discarded lines are counted.
-<p>
- When we discard a line, we also mark it as a deletion or insertion
- so that it will be printed in the output.
- @param f the other file
- */
- void discard_confusing_lines(file_data f) {
- clear();
- /* Set up table of which lines are going to be discarded. */
- final byte[] discarded = discardable(f.equivCount());
-
- /* Don't really discard the provisional lines except when they occur
- in a run of discardables, with nonprovisionals at the beginning
- and end. */
- filterDiscards(discarded);
-
- /* Actually discard the lines. */
- discard(discarded);
- }
-
- /** Mark to be discarded each line that matches no line of another file.
- If a line matches many lines, mark it as provisionally discardable.
- @see equivCount()
- @param counts The count of each equivalence number for the other file.
- @return 0=nondiscardable, 1=discardable or 2=provisionally discardable
- for each line
- */
-
- private byte[] discardable(final int[] counts) {
- final int end = buffered_lines;
- final byte[] discards = new byte[end];
- final int[] equivs = this.equivs;
- int many = 5;
- int tem = end / 64;
-
- /* Multiply MANY by approximate square root of number of lines.
- That is the threshold for provisionally discardable lines. */
- while ((tem = tem >> 2) > 0)
- many *= 2;
-
- for (int i = 0; i < end; i++)
- {
- int nmatch;
- if (equivs[i] == 0)
- continue;
- nmatch = counts[equivs[i]];
- if (nmatch == 0)
- discards[i] = 1;
- else if (nmatch > many)
- discards[i] = 2;
- }
- return discards;
- }
-
- /** Don't really discard the provisional lines except when they occur
- in a run of discardables, with nonprovisionals at the beginning
- and end. */
-
- private void filterDiscards(final byte[] discards) {
- final int end = buffered_lines;
-
- for (int i = 0; i < end; i++)
- {
- /* Cancel provisional discards not in middle of run of discards. */
- if (discards[i] == 2)
- discards[i] = 0;
- else if (discards[i] != 0)
- {
- /* We have found a nonprovisional discard. */
- int j;
- int length;
- int provisional = 0;
-
- /* Find end of this run of discardable lines.
- Count how many are provisionally discardable. */
- for (j = i; j < end; j++)
- {
- if (discards[j] == 0)
- break;
- if (discards[j] == 2)
- ++provisional;
- }
-
- /* Cancel provisional discards at end, and shrink the run. */
- while (j > i && discards[j - 1] == 2) {
- discards[--j] = 0; --provisional;
- }
-
- /* Now we have the length of a run of discardable lines
- whose first and last are not provisional. */
- length = j - i;
-
- /* If 1/4 of the lines in the run are provisional,
- cancel discarding of all provisional lines in the run. */
- if (provisional * 4 > length)
- {
- while (j > i)
- if (discards[--j] == 2)
- discards[j] = 0;
- }
- else
- {
- int consec;
- int minimum = 1;
- int tem = length / 4;
-
- /* MINIMUM is approximate square root of LENGTH/4.
- A subrun of two or more provisionals can stand
- when LENGTH is at least 16.
- A subrun of 4 or more can stand when LENGTH >= 64. */
- while ((tem = tem >> 2) > 0)
- minimum *= 2;
- minimum++;
-
- /* Cancel any subrun of MINIMUM or more provisionals
- within the larger run. */
- for (j = 0, consec = 0; j < length; j++)
- if (discards[i + j] != 2)
- consec = 0;
- else if (minimum == ++consec)
- /* Back up to start of subrun, to cancel it all. */
- j -= consec;
- else if (minimum < consec)
- discards[i + j] = 0;
-
- /* Scan from beginning of run
- until we find 3 or more nonprovisionals in a row
- or until the first nonprovisional at least 8 lines in.
- Until that point, cancel any provisionals. */
- for (j = 0, consec = 0; j < length; j++)
- {
- if (j >= 8 && discards[i + j] == 1)
- break;
- if (discards[i + j] == 2) {
- consec = 0; discards[i + j] = 0;
- }
- else if (discards[i + j] == 0)
- consec = 0;
- else
- consec++;
- if (consec == 3)
- break;
- }
-
- /* I advances to the last line of the run. */
- i += length - 1;
-
- /* Same thing, from end. */
- for (j = 0, consec = 0; j < length; j++)
- {
- if (j >= 8 && discards[i - j] == 1)
- break;
- if (discards[i - j] == 2) {
- consec = 0; discards[i - j] = 0;
- }
- else if (discards[i - j] == 0)
- consec = 0;
- else
- consec++;
- if (consec == 3)
- break;
- }
- }
- }
- }
- }
-
- /** Actually discard the lines.
- @param discards flags lines to be discarded
- */
- private void discard(final byte[] discards) {
- final int end = buffered_lines;
- int j = 0;
- for (int i = 0; i < end; ++i)
- if (no_discards || discards[i] == 0)
- {
- undiscarded[j] = equivs[i];
- realindexes[j++] = i;
- }
- else
- changed_flag[1+i] = true;
- nondiscarded_lines = j;
- }
-
- file_data(Object[] data, Hashtable<Object, Integer> h) {
- buffered_lines = data.length;
-
- equivs = new int[buffered_lines];
- undiscarded = new int[buffered_lines];
- realindexes = new int[buffered_lines];
-
- for (int i = 0; i < data.length; ++i) {
- Integer ir = h.get(data[i]);
- if (ir == null)
- h.put(data[i], new Integer(equivs[i] = equiv_max++));
- else
- equivs[i] = ir.intValue();
- }
- }
-
- /** Adjust inserts/deletes of blank lines to join changes
- as much as possible.
-
- We do something when a run of changed lines include a blank
- line at one end and have an excluded blank line at the other.
- We are free to choose which blank line is included.
- `compareseq' always chooses the one at the beginning,
- but usually it is cleaner to consider the following blank line
- to be the "change". The only exception is if the preceding blank line
- would join this change to other changes.
- @param f the file being compared against
- */
-
- void shift_boundaries(file_data f) {
- final boolean[] changed = changed_flag;
- final boolean[] other_changed = f.changed_flag;
- int i = 0;
- int j = 0;
- int i_end = buffered_lines;
- int preceding = -1;
- int other_preceding = -1;
-
- for (;;)
- {
- int start, end, other_start;
-
- /* Scan forwards to find beginning of another run of changes.
- Also keep track of the corresponding point in the other file. */
-
- while (i < i_end && !changed[1+i])
- {
- while (other_changed[1+j++])
- /* Non-corresponding lines in the other file
- will count as the preceding batch of changes. */
- other_preceding = j;
- i++;
- }
-
- if (i == i_end)
- break;
-
- start = i;
- other_start = j;
-
- for (;;)
- {
- /* Now find the end of this run of changes. */
-
- while (i < i_end && changed[1+i]) i++;
- end = i;
-
- /* If the first changed line matches the following unchanged one,
- and this run does not follow right after a previous run,
- and there are no lines deleted from the other file here,
- then classify the first changed line as unchanged
- and the following line as changed in its place. */
-
- /* You might ask, how could this run follow right after another?
- Only because the previous run was shifted here. */
-
- if (end != i_end
- && equivs[start] == equivs[end]
- && !other_changed[1+j]
- && end != i_end
- && !((preceding >= 0 && start == preceding)
- || (other_preceding >= 0
- && other_start == other_preceding)))
- {
- changed[1+end++] = true;
- changed[1+start++] = false;
- ++i;
- /* Since one line-that-matches is now before this run
- instead of after, we must advance in the other file
- to keep in synch. */
- ++j;
- }
- else
- break;
- }
-
- preceding = i;
- other_preceding = j;
- }
- }
-
- /** Number of elements (lines) in this file. */
- final int buffered_lines;
-
- /** IndexedSeq, indexed by line number, containing an equivalence code for
- each line. It is this IndexedSeq that is actually compared with that
- of another file to generate differences. */
- private final int[] equivs;
-
- /** IndexedSeq, like the previous one except that
- the elements for discarded lines have been squeezed out. */
- final int[] undiscarded;
-
- /** IndexedSeq mapping virtual line numbers (not counting discarded lines)
- to real ones (counting those lines). Both are origin-0. */
- final int[] realindexes;
-
- /** Total number of nondiscarded lines. */
- int nondiscarded_lines;
-
- /** Array, indexed by real origin-1 line number,
- containing true for a line that is an insertion or a deletion.
- The results of comparison are stored here. */
- boolean[] changed_flag;
-
- }
-}
diff --git a/src/partest/scala/tools/partest/nest/DiffPrint.java b/src/partest/scala/tools/partest/nest/DiffPrint.java
deleted file mode 100644
index 31f9a1bc79..0000000000
--- a/src/partest/scala/tools/partest/nest/DiffPrint.java
+++ /dev/null
@@ -1,606 +0,0 @@
-
-package scala.tools.partest.nest;
-
-import java.io.*;
-import java.util.Vector;
-import java.util.Date;
-//import com.objectspace.jgl.predicates.UnaryPredicate;
-
-interface UnaryPredicate {
- boolean execute(Object obj);
-}
-
-/** A simple framework for printing change lists produced by <code>Diff</code>.
- @see bmsi.util.Diff
- @author Stuart D. Gathman
- Copyright (C) 2000 Business Management Systems, Inc.
-<p>
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-<p>
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-<p>
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-public class DiffPrint {
- /** A Base class for printing edit scripts produced by Diff.
- This class divides the change list into "hunks", and calls
- <code>print_hunk</code> for each hunk. Various utility methods
- are provided as well.
- */
- public static abstract class Base {
- protected Base(Object[] a,Object[] b, Writer w) {
- outfile = new PrintWriter(w);
- file0 = a;
- file1 = b;
- }
- /** Set to ignore certain kinds of lines when printing
- an edit script. For example, ignoring blank lines or comments.
- */
- protected UnaryPredicate ignore = null;
-
- /** Set to the lines of the files being compared.
- */
- protected Object[] file0, file1;
-
- /** Divide SCRIPT into pieces by calling HUNKFUN and
- print each piece with PRINTFUN.
- Both functions take one arg, an edit script.
-
- PRINTFUN takes a subscript which belongs together (with a null
- link at the end) and prints it. */
- public void print_script(Diff.change script) {
- Diff.change next = script;
-
- while (next != null)
- {
- Diff.change t, end;
-
- /* Find a set of changes that belong together. */
- t = next;
- end = hunkfun(next);
-
- /* Disconnect them from the rest of the changes,
- making them a hunk, and remember the rest for next iteration. */
- next = end.link;
- end.link = null;
- //if (DEBUG)
- // debug_script(t);
-
- /* Print this hunk. */
- print_hunk(t);
-
- /* Reconnect the script so it will all be freed properly. */
- end.link = next;
- }
- outfile.flush();
- }
-
- /** Called with the tail of the script
- and returns the last link that belongs together with the start
- of the tail. */
-
- protected Diff.change hunkfun(Diff.change hunk) {
- return hunk;
- }
-
- protected int first0, last0, first1, last1, deletes, inserts;
- protected PrintWriter outfile;
-
- /** Look at a hunk of edit script and report the range of lines in each file
- that it applies to. HUNK is the start of the hunk, which is a chain
- of `struct change'. The first and last line numbers of file 0 are stored
- in *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
- Note that these are internal line numbers that count from 0.
-
- If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
-
- Also set *DELETES nonzero if any lines of file 0 are deleted
- and set *INSERTS nonzero if any lines of file 1 are inserted.
- If only ignorable lines are inserted or deleted, both are
- set to 0. */
-
- protected void analyze_hunk(Diff.change hunk) {
- int f0, l0 = 0, f1, l1 = 0, show_from = 0, show_to = 0;
- int i;
- Diff.change next;
- boolean nontrivial = (ignore == null);
-
- show_from = show_to = 0;
-
- f0 = hunk.line0;
- f1 = hunk.line1;
-
- for (next = hunk; next != null; next = next.link)
- {
- l0 = next.line0 + next.deleted - 1;
- l1 = next.line1 + next.inserted - 1;
- show_from += next.deleted;
- show_to += next.inserted;
- for (i = next.line0; i <= l0 && ! nontrivial; i++)
- if (!ignore.execute(file0[i]))
- nontrivial = true;
- for (i = next.line1; i <= l1 && ! nontrivial; i++)
- if (!ignore.execute(file1[i]))
- nontrivial = true;
- }
-
- first0 = f0;
- last0 = l0;
- first1 = f1;
- last1 = l1;
-
- /* If all inserted or deleted lines are ignorable,
- tell the caller to ignore this hunk. */
-
- if (!nontrivial)
- show_from = show_to = 0;
-
- deletes = show_from;
- inserts = show_to;
- }
-
- /** Print the script header which identifies the files compared. */
- protected void print_header(String filea, String fileb) { }
-
- protected abstract void print_hunk(Diff.change hunk);
-
- protected void print_1_line(String pre,Object linbuf) {
- outfile.println(pre + linbuf.toString());
- }
-
- /** Print a pair of line numbers with SEPCHAR, translated for file FILE.
- If the two numbers are identical, print just one number.
-
- Args A and B are internal line numbers.
- We print the translated (real) line numbers. */
-
- protected void print_number_range (char sepchar, int a, int b) {
- /* Note: we can have B < A in the case of a range of no lines.
- In this case, we should print the line number before the range,
- which is B. */
- if (++b > ++a)
- outfile.print("" + a + sepchar + b);
- else
- outfile.print(b);
- }
-
- public static char change_letter(int inserts, int deletes) {
- if (inserts == 0)
- return 'd';
- else if (deletes == 0)
- return 'a';
- else
- return 'c';
- }
- }
-
- /** Print a change list in the standard diff format.
- */
- public static class NormalPrint extends Base {
-
- public NormalPrint(Object[] a,Object[] b, Writer w) {
- super(a,b,w);
- }
-
- /** Print a hunk of a normal diff.
- This is a contiguous portion of a complete edit script,
- describing changes in consecutive lines. */
-
- protected void print_hunk (Diff.change hunk) {
-
- /* Determine range of line numbers involved in each file. */
- analyze_hunk(hunk);
- if (deletes == 0 && inserts == 0)
- return;
-
- /* Print out the line number header for this hunk */
- print_number_range (',', first0, last0);
- outfile.print(change_letter(inserts, deletes));
- print_number_range (',', first1, last1);
- outfile.println();
-
- /* Print the lines that the first file has. */
- if (deletes != 0)
- for (int i = first0; i <= last0; i++)
- print_1_line ("< ", file0[i]);
-
- if (inserts != 0 && deletes != 0)
- outfile.println("---");
-
- /* Print the lines that the second file has. */
- if (inserts != 0)
- for (int i = first1; i <= last1; i++)
- print_1_line ("> ", file1[i]);
- }
- }
-
- /** Prints an edit script in a format suitable for input to <code>ed</code>.
- The edit script must be generated with the reverse option to
- be useful as actual <code>ed</code> input.
- */
- public static class EdPrint extends Base {
-
- public EdPrint(Object[] a,Object[] b, Writer w) {
- super(a,b,w);
- }
-
- /** Print a hunk of an ed diff */
- protected void print_hunk(Diff.change hunk) {
-
- /* Determine range of line numbers involved in each file. */
- analyze_hunk (hunk);
- if (deletes == 0 && inserts == 0)
- return;
-
- /* Print out the line number header for this hunk */
- print_number_range (',', first0, last0);
- outfile.println(change_letter(inserts, deletes));
-
- /* Print new/changed lines from second file, if needed */
- if (inserts != 0)
- {
- boolean inserting = true;
- for (int i = first1; i <= last1; i++)
- {
- /* Resume the insert, if we stopped. */
- if (! inserting)
- outfile.println(i - first1 + first0 + "a");
- inserting = true;
-
- /* If the file's line is just a dot, it would confuse `ed'.
- So output it with a double dot, and set the flag LEADING_DOT
- so that we will output another ed-command later
- to change the double dot into a single dot. */
-
- if (".".equals(file1[i]))
- {
- outfile.println("..");
- outfile.println(".");
- /* Now change that double dot to the desired single dot. */
- outfile.println(i - first1 + first0 + 1 + "s/^\\.\\././");
- inserting = false;
- }
- else
- /* Line is not `.', so output it unmodified. */
- print_1_line ("", file1[i]);
- }
-
- /* End insert mode, if we are still in it. */
- if (inserting)
- outfile.println(".");
- }
- }
- }
-
- /** Prints an edit script in context diff format. This and its
- 'unified' variation is used for source code patches.
- */
- public static class ContextPrint extends Base {
-
- protected int context = 3;
-
- public ContextPrint(Object[] a,Object[] b, Writer w) {
- super(a,b,w);
- }
-
- protected void print_context_label (String mark, File inf, String label) {
- if (label != null)
- outfile.println(mark + ' ' + label);
- else if (inf.lastModified() > 0)
- // FIXME: use DateFormat to get precise format needed.
- outfile.println(
- mark + ' ' + inf.getPath() + '\t' + new Date(inf.lastModified())
- );
- else
- /* Don't pretend that standard input is ancient. */
- outfile.println(mark + ' ' + inf.getPath());
- }
-
- public void print_header(String filea,String fileb) {
- print_context_label ("***", new File(filea), filea);
- print_context_label ("---", new File(fileb), fileb);
- }
-
- /** If function_regexp defined, search for start of function. */
- private String find_function(Object[] lines, int start) {
- return null;
- }
-
- protected void print_function(Object[] file,int start) {
- String function = find_function (file0, first0);
- if (function != null) {
- outfile.print(" ");
- outfile.print(
- (function.length() < 40) ? function : function.substring(0,40)
- );
- }
- }
-
- protected void print_hunk(Diff.change hunk) {
-
- /* Determine range of line numbers involved in each file. */
-
- analyze_hunk (hunk);
-
- if (deletes == 0 && inserts == 0)
- return;
-
- /* Include a context's width before and after. */
-
- first0 = Math.max(first0 - context, 0);
- first1 = Math.max(first1 - context, 0);
- last0 = Math.min(last0 + context, file0.length - 1);
- last1 = Math.min(last1 + context, file1.length - 1);
-
-
- outfile.print("***************");
-
- /* If we looked for and found a function this is part of,
- include its name in the header of the diff section. */
- print_function (file0, first0);
-
- outfile.println();
- outfile.print("*** ");
- print_number_range (',', first0, last0);
- outfile.println(" ****");
-
- if (deletes != 0) {
- Diff.change next = hunk;
-
- for (int i = first0; i <= last0; i++) {
- /* Skip past changes that apply (in file 0)
- only to lines before line I. */
-
- while (next != null && next.line0 + next.deleted <= i)
- next = next.link;
-
- /* Compute the marking for line I. */
-
- String prefix = " ";
- if (next != null && next.line0 <= i)
- /* The change NEXT covers this line.
- If lines were inserted here in file 1, this is "changed".
- Otherwise it is "deleted". */
- prefix = (next.inserted > 0) ? "!" : "-";
-
- print_1_line (prefix, file0[i]);
- }
- }
-
- outfile.print("--- ");
- print_number_range (',', first1, last1);
- outfile.println(" ----");
-
- if (inserts != 0) {
- Diff.change next = hunk;
-
- for (int i = first1; i <= last1; i++) {
- /* Skip past changes that apply (in file 1)
- only to lines before line I. */
-
- while (next != null && next.line1 + next.inserted <= i)
- next = next.link;
-
- /* Compute the marking for line I. */
-
- String prefix = " ";
- if (next != null && next.line1 <= i)
- /* The change NEXT covers this line.
- If lines were deleted here in file 0, this is "changed".
- Otherwise it is "inserted". */
- prefix = (next.deleted > 0) ? "!" : "+";
-
- print_1_line (prefix, file1[i]);
- }
- }
- }
- }
-
- /** Prints an edit script in context diff format. This and its
- 'unified' variation is used for source code patches.
- */
- public static class UnifiedPrint extends ContextPrint {
-
- public UnifiedPrint(Object[] a,Object[] b, Writer w) {
- super(a,b,w);
- }
-
- public void print_header(String filea,String fileb) {
- print_context_label ("---", new File(filea), filea);
- print_context_label ("+++", new File(fileb), fileb);
- }
-
- private void print_number_range (int a, int b) {
- //translate_range (file, a, b, &trans_a, &trans_b);
-
- /* Note: we can have B < A in the case of a range of no lines.
- In this case, we should print the line number before the range,
- which is B. */
- if (b < a)
- outfile.print(b + ",0");
- else
- super.print_number_range(',',a,b);
- }
-
- protected void print_hunk(Diff.change hunk) {
- /* Determine range of line numbers involved in each file. */
- analyze_hunk (hunk);
-
- if (deletes == 0 && inserts == 0)
- return;
-
- /* Include a context's width before and after. */
-
- first0 = Math.max(first0 - context, 0);
- first1 = Math.max(first1 - context, 0);
- last0 = Math.min(last0 + context, file0.length - 1);
- last1 = Math.min(last1 + context, file1.length - 1);
-
-
-
- outfile.print("@@ -");
- print_number_range (first0, last0);
- outfile.print(" +");
- print_number_range (first1, last1);
- outfile.print(" @@");
-
- /* If we looked for and found a function this is part of,
- include its name in the header of the diff section. */
- print_function(file0,first0);
-
- outfile.println();
-
- Diff.change next = hunk;
- int i = first0;
- int j = first1;
-
- while (i <= last0 || j <= last1) {
-
- /* If the line isn't a difference, output the context from file 0. */
-
- if (next == null || i < next.line0) {
- outfile.print(' ');
- print_1_line ("", file0[i++]);
- j++;
- }
- else {
- /* For each difference, first output the deleted part. */
-
- int k = next.deleted;
- while (k-- > 0) {
- outfile.print('-');
- print_1_line ("", file0[i++]);
- }
-
- /* Then output the inserted part. */
-
- k = next.inserted;
- while (k-- > 0) {
- outfile.print('+');
- print_1_line ("", file1[j++]);
- }
-
- /* We're done with this hunk, so on to the next! */
-
- next = next.link;
- }
- }
- }
- }
-
-
- /** Read a text file into an array of String. This provides basic diff
- functionality. A more advanced diff utility will use specialized
- objects to represent the text lines, with options to, for example,
- convert sequences of whitespace to a single space for comparison
- purposes.
- */
- static String[] slurp(String file) throws IOException {
- BufferedReader rdr = new BufferedReader(new FileReader(file));
- Vector<String> s = new Vector<String>();
- for (;;) {
- String line = rdr.readLine();
- if (line == null) break;
- s.addElement(line);
- }
- String[] a = new String[s.size()];
- s.copyInto(a);
- return a;
- }
-
- public static void main(String[] argv) throws IOException {
- String filea = argv[argv.length - 2];
- String fileb = argv[argv.length - 1];
- String[] a = slurp(filea);
- String[] b = slurp(fileb);
- Diff d = new Diff(a,b);
- char style = 'n';
- for (int i = 0; i < argv.length - 2; ++i) {
- String f = argv[i];
- if (f.startsWith("-")) {
- for (int j = 1; j < f.length(); ++j) {
- switch (f.charAt(j)) {
- case 'e': // Ed style
- style = 'e'; break;
- case 'c': // Context diff
- style = 'c'; break;
- case 'u':
- style = 'u'; break;
- }
- }
- }
- }
- boolean reverse = style == 'e';
- Diff.change script = d.diff_2(reverse);
- if (script == null)
- System.err.println("No differences");
- else {
- Base p;
- Writer w = new OutputStreamWriter(System.out);
- switch (style) {
- case 'e':
- p = new EdPrint(a,b,w); break;
- case 'c':
- p = new ContextPrint(a,b,w); break;
- case 'u':
- p = new UnifiedPrint(a,b,w); break;
- default:
- p = new NormalPrint(a,b,w);
- }
- p.print_header(filea,fileb);
- p.print_script(script);
- }
- }
-
- public static void doDiff(String[] argv, Writer w) throws IOException {
- String filea = argv[argv.length - 2];
- String fileb = argv[argv.length - 1];
- String[] a = slurp(filea);
- String[] b = slurp(fileb);
- Diff d = new Diff(a,b);
- char style = 'n';
- for (int i = 0; i < argv.length - 2; ++i) {
- String f = argv[i];
- if (f.startsWith("-")) {
- for (int j = 1; j < f.length(); ++j) {
- switch (f.charAt(j)) {
- case 'e': // Ed style
- style = 'e'; break;
- case 'c': // Context diff
- style = 'c'; break;
- case 'u':
- style = 'u'; break;
- }
- }
- }
- }
- boolean reverse = style == 'e';
- Diff.change script = d.diff_2(reverse);
- if (script == null)
- w.write("No differences\n");
- else {
- Base p;
- switch (style) {
- case 'e':
- p = new EdPrint(a,b,w); break;
- case 'c':
- p = new ContextPrint(a,b,w); break;
- case 'u':
- p = new UnifiedPrint(a,b,w); break;
- default:
- p = new NormalPrint(a,b,w);
- }
- p.print_header(filea,fileb);
- p.print_script(script);
- }
- }
-
-}
diff --git a/src/partest/scala/tools/partest/nest/FileManager.scala b/src/partest/scala/tools/partest/nest/FileManager.scala
index a32c56e973..23546c6511 100644
--- a/src/partest/scala/tools/partest/nest/FileManager.scala
+++ b/src/partest/scala/tools/partest/nest/FileManager.scala
@@ -17,34 +17,31 @@ import scala.collection.mutable
trait FileUtil {
/**
- * Compares two files using a Java implementation of the GNU diff
- * available at http://www.bmsi.com/java/#diff.
+ * Compares two files using difflib to produce a unified diff.
*
* @param f1 the first file to be compared
* @param f2 the second file to be compared
- * @return the text difference between the compared files
+ * @return the unified diff of the compared files or the empty string if they're equal
*/
def compareFiles(f1: File, f2: File): String = {
- val diffWriter = new StringWriter
- val args = Array(f1.getAbsolutePath(), f2.getAbsolutePath())
-
- DiffPrint.doDiff(args, diffWriter)
- val res = diffWriter.toString
- if (res startsWith "No") "" else res
+ compareContents(io.Source.fromFile(f1).getLines.toSeq, io.Source.fromFile(f2).getLines.toSeq, f1.getName, f2.getName)
}
- def compareContents(lines1: Seq[String], lines2: Seq[String]): String = {
- val xs1 = lines1.toArray[AnyRef]
- val xs2 = lines2.toArray[AnyRef]
-
- val diff = new Diff(xs1, xs2)
- val change = diff.diff_2(false)
- val writer = new StringWriter
- val p = new DiffPrint.NormalPrint(xs1, xs2, writer)
-
- p.print_script(change)
- val res = writer.toString
- if (res startsWith "No ") ""
- else res
+
+ /**
+ * Compares two lists of lines using difflib to produce a unified diff.
+ *
+ * @param origLines the first seq of lines to be compared
+ * @param newLines the second seq of lines to be compared
+ * @param origName file name to be used in unified diff for `origLines`
+ * @param newName file name to be used in unified diff for `newLines`
+ * @return the unified diff of the `origLines` and `newLines` or the empty string if they're equal
+ */
+ def compareContents(origLines: Seq[String], newLines: Seq[String], origName: String = "a", newName: String = "b"): String = {
+ import collection.JavaConverters._
+
+ val diff = difflib.DiffUtils.diff(origLines.asJava, newLines.asJava)
+ if (diff.getDeltas.isEmpty) ""
+ else difflib.DiffUtils.generateUnifiedDiff(origName, newName, origLines.asJava, diff, 1).asScala.mkString("\n")
}
}
object FileUtil extends FileUtil { }
diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala
index 02651c527b..7c005b4f61 100644
--- a/src/partest/scala/tools/partest/nest/PathSettings.scala
+++ b/src/partest/scala/tools/partest/nest/PathSettings.scala
@@ -71,6 +71,9 @@ object PathSettings {
findJar(buildPackLibDir.files ++ srcLibDir.files, "scalacheck") getOrElse {
sys.error("No scalacheck jar found in '%s' or '%s'".format(buildPackLibDir, srcLibDir))
}
+
+ lazy val diffUtils: File =
+ findJar(buildPackLibDir.files, "diffutils") getOrElse sys.error(s"No diffutils.jar found in '$buildPackLibDir'.")
}
class PathSettings() {
diff --git a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
index 05cae7b238..9780e82cd9 100644
--- a/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
+++ b/src/partest/scala/tools/partest/nest/ReflectiveRunner.scala
@@ -51,10 +51,13 @@ class ReflectiveRunner {
new ConsoleFileManager
// this is a workaround for https://issues.scala-lang.org/browse/SI-5433
- // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed
+ // when that bug is fixed, the addition of PathSettings.srcCodeLib can be removed
// we hack into the classloader that will become parent classloader for scalac
// this way we ensure that reflective macro lookup will pick correct Code.lift
- val sepUrls = PathSettings.srcCodeLib.toURI.toURL :: fileManager.latestUrls
+ // it's also used to inject diffutils into the classpath when running partest from the test/partest script
+ val srcCodeLibAndDiff = List(PathSettings.srcCodeLib, PathSettings.diffUtils)
+ val sepUrls = srcCodeLibAndDiff.map(_.toURI.toURL) ::: fileManager.latestUrls
+ // this seems to be the core classloader that determines which classes can be found when running partest from the test/partest script
val sepLoader = new URLClassLoader(sepUrls.toArray, null)
if (isPartestDebug)
diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala
index 8f28277a6c..a63a81c47b 100644
--- a/src/partest/scala/tools/partest/nest/RunnerManager.scala
+++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala
@@ -78,6 +78,7 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP
val compileMgr = new CompileManager(fileManager)
fileManager.CLASSPATH += File.pathSeparator + PathSettings.scalaCheck
+ fileManager.CLASSPATH += File.pathSeparator + PathSettings.diffUtils // needed to put diffutils on test/partest's classpath
private def compareFiles(f1: File, f2: File): String =
try fileManager.compareFiles(f1, f2)
diff --git a/src/reflect/scala/reflect/internal/ClassfileConstants.scala b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
index 78f7438429..faf61e5205 100644
--- a/src/reflect/scala/reflect/internal/ClassfileConstants.scala
+++ b/src/reflect/scala/reflect/internal/ClassfileConstants.scala
@@ -72,6 +72,9 @@ object ClassfileConstants {
final val CONSTANT_METHODREF = 10
final val CONSTANT_INTFMETHODREF = 11
final val CONSTANT_NAMEANDTYPE = 12
+ final val CONSTANT_METHODHANDLE = 15
+ final val CONSTANT_METHODTYPE = 16
+ final val CONSTANT_INVOKEDYNAMIC = 18
// tags describing the type of a literal in attribute values
final val BYTE_TAG = 'B'
@@ -306,7 +309,7 @@ object ClassfileConstants {
final val invokespecial = 0xb7
final val invokestatic = 0xb8
final val invokeinterface = 0xb9
- final val xxxunusedxxxx = 0xba
+ final val invokedynamic = 0xba
final val new_ = 0xbb
final val newarray = 0xbc
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 55954196f6..5392daf674 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -244,8 +244,8 @@ trait Definitions extends api.StandardDefinitions {
(sym eq NoSymbol)
|| sym.isConstructor
|| sym.isPrivateLocal
- || isUniversalMember(sym)
)
+ def isUnimportableUnlessRenamed(sym: Symbol) = isUnimportable(sym) || isUniversalMember(sym)
def isImportable(sym: Symbol) = !isUnimportable(sym)
/** Is this type equivalent to Any, AnyVal, or AnyRef? */
@@ -973,7 +973,7 @@ trait Definitions extends api.StandardDefinitions {
getMemberIfDefined(owner, name) orElse {
if (phase.flatClasses && name.isTypeName && !owner.isPackageObjectOrClass) {
val pkg = owner.owner
- val flatname = nme.flattenedName(owner.name, name)
+ val flatname = tpnme.flattenedName(owner.name, name)
getMember(pkg, flatname)
}
else fatalMissingSymbol(owner, name)
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index f8598dca7a..b8141d25f5 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -177,6 +177,12 @@ trait Names extends api.Names {
/** @return the hash value of this name */
final override def hashCode(): Int = index
+ /** @return true if the string value of this name is equal
+ * to the string value of the given name or String.
+ */
+ def string_==(that: Name): Boolean = (that ne null) && (toString == that.toString)
+ def string_==(that: String): Boolean = (that ne null) && (toString == that)
+
/****
* This has been quite useful to find places where people are comparing
* a TermName and a TypeName, or a Name and a String.
@@ -210,7 +216,7 @@ trait Names extends api.Names {
/** @return the index of first occurrence of char c in this name, length if not found */
final def pos(c: Char): Int = pos(c, 0)
- /** @return the index of first occurrence of char c in this name, length if not found */
+ /** @return the index of first occurrence of s in this name, length if not found */
final def pos(s: String): Int = pos(s, 0)
/** Returns the index of the first occurrence of character c in
@@ -319,15 +325,18 @@ trait Names extends api.Names {
final def endsWith(char: Char): Boolean = len > 0 && endChar == char
final def endsWith(name: String): Boolean = endsWith(newTermName(name))
- def indexOf(ch: Char) = {
- val idx = pos(ch)
- if (idx == length) -1 else idx
- }
- def indexOf(ch: Char, fromIndex: Int) = {
- val idx = pos(ch, fromIndex)
- if (idx == length) -1 else idx
- }
- def lastIndexOf(ch: Char) = lastPos(ch)
+ /** Rewrite the confusing failure indication via result == length to
+ * the normal failure indication via result == -1.
+ */
+ private def fixIndexOf(idx: Int): Int = if (idx == length) -1 else idx
+
+ def indexOf(ch: Char) = fixIndexOf(pos(ch))
+ def indexOf(ch: Char, fromIndex: Int) = fixIndexOf(pos(ch, fromIndex))
+ def indexOf(s: String) = fixIndexOf(pos(s))
+
+ /** The lastPos methods already return -1 on failure. */
+ def lastIndexOf(ch: Char): Int = lastPos(ch)
+ def lastIndexOf(s: String): Int = toString lastIndexOf s
/** Replace all occurrences of `from` by `to` in
* name; result is always a term name.
@@ -392,9 +401,24 @@ trait Names extends api.Names {
* reap the benefits because an (unused) $outer pointer so it is not single-field.
*/
final class NameOps[T <: Name](name: T) {
- def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name
- def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T]
- def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T]
+ import NameTransformer._
+ def stripSuffix(suffix: String): T = stripSuffix(suffix: TermName)
+ def stripSuffix(suffix: Name): T = if (name endsWith suffix) dropRight(suffix.length) else name
+ def take(n: Int): T = name.subName(0, n).asInstanceOf[T]
+ def drop(n: Int): T = name.subName(n, name.length).asInstanceOf[T]
+ def dropRight(n: Int): T = name.subName(0, name.length - n).asInstanceOf[T]
+ def dropLocal: TermName = name.toTermName stripSuffix LOCAL_SUFFIX_STRING
+ def dropSetter: TermName = name.toTermName stripSuffix SETTER_SUFFIX_STRING
+ def dropModule: T = this stripSuffix MODULE_SUFFIX_STRING
+ def localName: TermName = getterName append LOCAL_SUFFIX_STRING
+ def setterName: TermName = getterName append SETTER_SUFFIX_STRING
+ def getterName: TermName = dropTraitSetterSeparator.dropSetter.dropLocal
+
+ private def dropTraitSetterSeparator: TermName =
+ name indexOf TRAIT_SETTER_SEPARATOR_STRING match {
+ case -1 => name.toTermName
+ case idx => name.toTermName drop idx drop TRAIT_SETTER_SEPARATOR_STRING.length
+ }
}
implicit val NameTag = ClassTag[Name](classOf[Name])
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index 28837c4ae8..e1ef6d6365 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -29,18 +29,19 @@ trait Printers extends api.Printers { self: SymbolTable =>
def quotedName(name: String): String = quotedName(newTermName(name), decode = false)
private def symNameInternal(tree: Tree, name: Name, decoded: Boolean): String = {
- val sym = tree.symbol
- if (sym.name.toString == nme.ERROR.toString) {
- "<" + quotedName(name, decoded) + ": error>"
- } else if (sym != null && sym != NoSymbol) {
- val prefix = if (sym.isMixinConstructor) "/*%s*/".format(quotedName(sym.owner.name, decoded)) else ""
- var suffix = ""
- if (settings.uniqid.value) suffix += ("#" + sym.id)
- if (settings.Yshowsymkinds.value) suffix += ("#" + sym.abbreviatedKindString)
- prefix + quotedName(tree.symbol.decodedName) + suffix
- } else {
- quotedName(name, decoded)
- }
+ val sym = tree.symbol
+ def qname = quotedName(name.dropLocal, decoded)
+ def qowner = quotedName(sym.owner.name.dropLocal, decoded)
+ def qsymbol = quotedName(sym.nameString)
+
+ if (sym.name.toTermName == nme.ERROR)
+ s"<$qname: error>"
+ else if (sym == null || sym == NoSymbol)
+ qname
+ else if (sym.isMixinConstructor)
+ s"/*$qowner*/$qsymbol"
+ else
+ qsymbol
}
def decodedSymName(tree: Tree, name: Name) = symNameInternal(tree, name, decoded = true)
@@ -546,7 +547,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
print("pendingSuperCall")
case tree: Tree =>
val hasSymbolField = tree.hasSymbolField && tree.symbol != NoSymbol
- val isError = hasSymbolField && tree.symbol.name.toString == nme.ERROR.toString
+ val isError = hasSymbolField && (tree.symbol.name string_== nme.ERROR)
printProduct(
tree,
preamble = _ => {
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index a894bd649c..4fd86aa8b1 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -86,8 +86,12 @@ trait StdNames {
def flattenedName(segments: Name*): NameType =
compactify(segments mkString NAME_JOIN_STRING)
- val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING
- val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING
+ val NAME_JOIN_STRING: String = NameTransformer.NAME_JOIN_STRING
+ val MODULE_SUFFIX_STRING: String = NameTransformer.MODULE_SUFFIX_STRING
+ val SETTER_SUFFIX_STRING: String = NameTransformer.SETTER_SUFFIX_STRING
+ val LOCAL_SUFFIX_STRING: String = NameTransformer.LOCAL_SUFFIX_STRING
+ val TRAIT_SETTER_SEPARATOR_STRING: String = NameTransformer.TRAIT_SETTER_SEPARATOR_STRING
+
val SINGLETON_SUFFIX: String = ".type"
val ANON_CLASS_NAME: NameType = "$anon"
@@ -265,7 +269,7 @@ trait StdNames {
val BITMAP_PREFIX = "bitmap$"
val CHECK_IF_REFUTABLE_STRING = "check$ifrefutable$"
val DEFAULT_GETTER_STRING = "$default$"
- val DEFAULT_GETTER_INIT_STRING = "$lessinit$greater" // CONSTRUCTOR.encoded, less is more
+ val DEFAULT_GETTER_INIT_STRING = NameTransformer.encode("<init>") + DEFAULT_GETTER_STRING
val DO_WHILE_PREFIX = "doWhile$"
val EVIDENCE_PARAM_PREFIX = "evidence$"
val EXCEPTION_RESULT_PREFIX = "exceptionResult"
@@ -275,7 +279,6 @@ trait StdNames {
val PROTECTED_PREFIX = "protected$"
val PROTECTED_SET_PREFIX = PROTECTED_PREFIX + "set"
val SUPER_PREFIX_STRING = "super$"
- val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
val WHILE_PREFIX = "while$"
// Compiler internal names
@@ -284,10 +287,8 @@ trait StdNames {
val DEFAULT_CASE: NameType = "defaultCase$"
val EQEQ_LOCAL_VAR: NameType = "eqEqTemp$"
val FAKE_LOCAL_THIS: NameType = "this$"
- val INITIALIZER: NameType = CONSTRUCTOR // Is this buying us something?
val LAZY_LOCAL: NameType = "$lzy"
val LAZY_SLOW_SUFFIX: NameType = "$lzycompute"
- val LOCAL_SUFFIX_STRING = " "
val UNIVERSE_BUILD_PREFIX: NameType = "$u.build."
val UNIVERSE_PREFIX: NameType = "$u."
val UNIVERSE_SHORT: NameType = "$u"
@@ -301,21 +302,16 @@ trait StdNames {
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: NameType = "$outer"
- val OUTER_LOCAL: NameType = OUTER + LOCAL_SUFFIX_STRING // "$outer ", note the space
+ val OUTER_LOCAL: NameType = OUTER.localName
val OUTER_SYNTH: NameType = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter
val ROOTPKG: NameType = "_root_"
val SELECTOR_DUMMY: NameType = "<unapply-selector>"
val SELF: NameType = "$this"
- val SETTER_SUFFIX: NameType = encode("_=")
+ val SETTER_SUFFIX: NameType = NameTransformer.SETTER_SUFFIX_STRING
val SPECIALIZED_INSTANCE: NameType = "specInstance$"
val STAR: NameType = "*"
val THIS: NameType = "_$this"
- @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
- def SPECIALIZED_SUFFIX_STRING = SPECIALIZED_SUFFIX.toString
- @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
- def SPECIALIZED_SUFFIX_NAME: TermName = SPECIALIZED_SUFFIX.toTermName
-
def isConstructorName(name: Name) = name == CONSTRUCTOR || name == MIXIN_CONSTRUCTOR
def isExceptionResultName(name: Name) = name startsWith EXCEPTION_RESULT_PREFIX
def isImplClassName(name: Name) = name endsWith IMPL_CLASS_SUFFIX
@@ -345,31 +341,52 @@ trait StdNames {
name.endChar == '=' && name.startChar != '=' && isOperatorPart(name.startChar)
}
- /** The expanded name of `name` relative to this class `base` with given `separator`
- */
- def expandedName(name: TermName, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): TermName =
+ private def expandedNameInternal(name: TermName, base: Symbol, separator: String): TermName =
newTermNameCached(base.fullName('$') + separator + name)
+ /** The expanded name of `name` relative to this class `base`
+ */
+ def expandedName(name: TermName, base: Symbol) = expandedNameInternal(name, base, EXPAND_SEPARATOR_STRING)
+
/** The expanded setter name of `name` relative to this class `base`
*/
- def expandedSetterName(name: TermName, base: Symbol): TermName =
- expandedName(name, base, separator = TRAIT_SETTER_SEPARATOR_STRING)
+ def expandedSetterName(name: TermName, base: Symbol) = expandedNameInternal(name, base, TRAIT_SETTER_SEPARATOR_STRING)
- /** If `name` is an expandedName name, the original name.
- * Otherwise `name` itself.
- */
- def originalName(name: Name): Name = {
- var i = name.length
- while (i >= 2 && !(name.charAt(i - 1) == '$' && name.charAt(i - 2) == '$')) i -= 1
- if (i >= 2) {
- while (i >= 3 && name.charAt(i - 3) == '$') i -= 1
- name.subName(i, name.length)
- } else name
+ /** If `name` is an expandedName name, the original (unexpanded) name.
+ * Otherwise `name` itself.
+ * Look backward from the end of the string for "$$", and take the
+ * part of the string after that; but if the string is "$$$" or longer,
+ * be sure to retain the extra dollars.
+ */
+ def unexpandedName(name: Name): Name = name lastIndexOf "$$" match {
+ case -1 => name
+ case idx0 =>
+ // Sketchville - We've found $$ but if it's part of $$$ or $$$$
+ // or something we need to keep the bonus dollars, so e.g. foo$$$outer
+ // has an original name of $outer.
+ var idx = idx0
+ while (idx > 0 && name.charAt(idx - 1) == '$')
+ idx -= 1
+ name drop idx + 2
}
+ @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
+ def SPECIALIZED_SUFFIX_STRING = SPECIALIZED_SUFFIX.toString
+ @deprecated("Use SPECIALIZED_SUFFIX", "2.10.0")
+ def SPECIALIZED_SUFFIX_NAME: TermName = SPECIALIZED_SUFFIX.toTermName
+
+ @deprecated("Use unexpandedName", "2.11.0") def originalName(name: Name): Name = unexpandedName(name)
+ @deprecated("Use Name#dropModule", "2.11.0") def stripModuleSuffix(name: Name): Name = name.dropModule
+ @deprecated("Use Name#dropLocal", "2.11.0") def localToGetter(name: TermName): TermName = name.dropLocal
+ @deprecated("Use Name#dropLocal", "2.11.0") def dropLocalSuffix(name: Name): TermName = name.dropLocal
+ @deprecated("Use Name#localName", "2.11.0") def getterToLocal(name: TermName): TermName = name.localName
+ @deprecated("Use Name#setterName", "2.11.0") def getterToSetter(name: TermName): TermName = name.setterName
+ @deprecated("Use Name#getterName", "2.11.0") def getterName(name: TermName): TermName = name.getterName
+ @deprecated("Use Name#getterName", "2.11.0") def setterToGetter(name: TermName): TermName = name.getterName
+
def unspecializedName(name: Name): Name = (
if (name endsWith SPECIALIZED_SUFFIX)
- name.subName(0, name.lastIndexOf('m') - 1)
+ name.subName(0, name.lastIndexOf('m') - 1)
else name
)
@@ -394,39 +411,23 @@ trait StdNames {
} else
(name, "", "")
- def getterName(name: TermName): TermName = if (isLocalName(name)) localToGetter(name) else name
- def getterToLocal(name: TermName): TermName = name append LOCAL_SUFFIX_STRING
- def getterToSetter(name: TermName): TermName = name append SETTER_SUFFIX
- def localToGetter(name: TermName): TermName = name dropRight LOCAL_SUFFIX_STRING.length
-
- def dropLocalSuffix(name: Name): Name = if (name endsWith ' ') name dropRight 1 else name
-
- def setterToGetter(name: TermName): TermName = {
- val p = name.pos(TRAIT_SETTER_SEPARATOR_STRING)
- if (p < name.length)
- setterToGetter(name drop (p + TRAIT_SETTER_SEPARATOR_STRING.length))
- else
- name.subName(0, name.length - SETTER_SUFFIX.length)
- }
-
// Nominally, name$default$N, encoded for <init>
- def defaultGetterName(name: Name, pos: Int): TermName = {
- val prefix = if (isConstructorName(name)) DEFAULT_GETTER_INIT_STRING else name
- newTermName(prefix + DEFAULT_GETTER_STRING + pos)
- }
+ def defaultGetterName(name: Name, pos: Int): TermName = (
+ if (isConstructorName(name))
+ DEFAULT_GETTER_INIT_STRING + pos
+ else
+ name + DEFAULT_GETTER_STRING + pos
+ )
// Nominally, name from name$default$N, CONSTRUCTOR for <init>
- def defaultGetterToMethod(name: Name): TermName = {
- val p = name.pos(DEFAULT_GETTER_STRING)
- if (p < name.length) {
- val q = name.toTermName.subName(0, p)
- // i.e., if (q.decoded == CONSTRUCTOR.toString) CONSTRUCTOR else q
- if (q.toString == DEFAULT_GETTER_INIT_STRING) CONSTRUCTOR else q
- } else name.toTermName
- }
-
- def stripModuleSuffix(name: Name): Name = (
- if (isModuleName(name)) name dropRight MODULE_SUFFIX_STRING.length else name
+ def defaultGetterToMethod(name: Name): TermName = (
+ if (name startsWith DEFAULT_GETTER_INIT_STRING)
+ nme.CONSTRUCTOR
+ else name indexOf DEFAULT_GETTER_STRING match {
+ case -1 => name.toTermName
+ case idx => name.toTermName take idx
+ }
)
+
def localDummyName(clazz: Symbol): TermName = newTermName(LOCALDUMMY_PREFIX + clazz.name + ">")
def superName(name: Name): TermName = newTermName(SUPER_PREFIX_STRING + name)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index c881de7830..ad7a0d45eb 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -761,16 +761,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0)
/** Is this symbol an accessor method for outer? */
- final def isOuterAccessor = {
- hasFlag(STABLE | ARTIFACT) &&
- originalName == nme.OUTER
- }
+ final def isOuterAccessor = hasFlag(STABLE | ARTIFACT) && (unexpandedName == nme.OUTER)
/** Is this symbol an accessor method for outer? */
- final def isOuterField = {
- hasFlag(ARTIFACT) &&
- originalName == nme.OUTER_LOCAL
- }
+ final def isOuterField = isArtifact && (unexpandedName == nme.OUTER_LOCAL)
/** Does this symbol denote a stable value? */
def isStable = false
@@ -995,10 +989,12 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ name attribute --------------------------------------------------------------
- /** If this symbol has an expanded name, its original name, otherwise its name itself.
- * @see expandName
+ @deprecated("Use unexpandedName", "2.11.0") def originalName: Name = unexpandedName
+
+ /** If this symbol has an expanded name, its original (unexpanded) name,
+ * otherwise the name itself.
*/
- def originalName: Name = nme.originalName(nme.dropLocalSuffix(name))
+ def unexpandedName: Name = nme.unexpandedName(name)
/** The name of the symbol before decoding, e.g. `\$eq\$eq` instead of `==`.
*/
@@ -1006,7 +1002,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The decoded name of the symbol, e.g. `==` instead of `\$eq\$eq`.
*/
- def decodedName: String = nme.dropLocalSuffix(name).decode
+ def decodedName: String = name.decode
private def addModuleSuffix(n: Name): Name =
if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n
@@ -1025,7 +1021,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
/** These should be moved somewhere like JavaPlatform.
*/
- def javaSimpleName: Name = addModuleSuffix(nme.dropLocalSuffix(simpleName))
+ def javaSimpleName: Name = addModuleSuffix(simpleName.dropLocal)
def javaBinaryName: Name = addModuleSuffix(fullNameInternal('/'))
def javaClassName: String = addModuleSuffix(fullNameInternal('.')).toString
@@ -1046,7 +1042,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
else ((effectiveOwner.enclClass.fullNameAsName(separator) append separator): Name) append name
)
- def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator))
+ def fullNameAsName(separator: Char): Name = fullNameInternal(separator).dropLocal
/** The encoded full path name of this symbol, where outer names and inner names
* are separated by periods.
@@ -1823,7 +1819,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
//
// The slightly more principled approach of using the paramss of the
// primary constructor leads to cycles in, for example, pos/t5084.scala.
- val primaryNames = constrParamAccessors.map(acc => nme.dropLocalSuffix(acc.name))
+ val primaryNames = constrParamAccessors map (_.name.dropLocal)
caseFieldAccessorsUnsorted.sortBy { acc =>
primaryNames indexWhere { orig =>
(acc.name == orig) || (acc.name startsWith (orig append "$"))
@@ -1842,7 +1838,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The symbol accessed by this accessor function, but with given owner type. */
final def accessed(ownerTp: Type): Symbol = {
assert(hasAccessorFlag, this)
- ownerTp decl nme.getterToLocal(getterName.toTermName)
+ ownerTp decl localName
}
/** The module corresponding to this module class (note that this
@@ -2199,22 +2195,23 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The getter of this value or setter definition in class `base`, or NoSymbol if
* none exists.
*/
- final def getter(base: Symbol): Symbol = base.info.decl(getterName) filter (_.hasAccessorFlag)
+ final def getter(base: Symbol): Symbol =
+ base.info decl getterName filter (_.hasAccessorFlag)
- def getterName: TermName = (
- if (isSetter) nme.setterToGetter(name.toTermName)
- else if (nme.isLocalName(name)) nme.localToGetter(name.toTermName)
- else name.toTermName
- )
+ def getterName: TermName = name.getterName
+ def setterName: TermName = name.setterName
+ def localName: TermName = name.localName
/** The setter of this value or getter definition, or NoSymbol if none exists */
- final def setter(base: Symbol): Symbol = setter(base, hasExpandedName = false)
+ final def setter(base: Symbol, hasExpandedName: Boolean = needsExpandedSetterName): Symbol =
+ base.info decl setterNameInBase(base, hasExpandedName) filter (_.hasAccessorFlag)
- final def setter(base: Symbol, hasExpandedName: Boolean): Symbol = {
- var sname = nme.getterToSetter(nme.getterName(name.toTermName))
- if (hasExpandedName) sname = nme.expandedSetterName(sname, base)
- base.info.decl(sname) filter (_.hasAccessorFlag)
- }
+ def needsExpandedSetterName = (
+ if (isMethod) hasStableFlag && !isLazy
+ else hasNoFlags(LAZY | MUTABLE)
+ )
+ def setterNameInBase(base: Symbol, expanded: Boolean): TermName =
+ if (expanded) nme.expandedSetterName(setterName, base) else setterName
/** If this is a derived value class, return its unbox method
* or NoSymbol if it does not exist.
@@ -2391,12 +2388,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* If settings.uniqid, adds id.
* If settings.Yshowsymkinds, adds abbreviated symbol kind.
*/
- def nameString: String = (
- if (!settings.uniqid.value && !settings.Yshowsymkinds.value) "" + originalName.decode
- else if (settings.uniqid.value && !settings.Yshowsymkinds.value) originalName.decode + "#" + id
- else if (!settings.uniqid.value && settings.Yshowsymkinds.value) originalName.decode + "#" + abbreviatedKindString
- else originalName.decode + "#" + id + "#" + abbreviatedKindString
- )
+ def nameString: String = {
+ val name_s = if (settings.debug.value) "" + unexpandedName else unexpandedName.dropLocal.decode
+ val id_s = if (settings.uniqid.value) "#" + id else ""
+ val kind_s = if (settings.Yshowsymkinds.value) "#" + abbreviatedKindString else ""
+
+ name_s + id_s + kind_s
+ }
def fullNameString: String = {
def recur(sym: Symbol): String = {
@@ -2623,20 +2621,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** change name by appending $$<fully-qualified-name-of-class `base`>
- * Do the same for any accessed symbols or setters/getters
+ * Do the same for any accessed symbols or setters/getters.
+ * If the accessor to be renamed is overriding a base symbol, enter
+ * a cloned symbol with the original name but without ACCESSOR flag.
*/
override def expandName(base: Symbol) {
- if (!hasFlag(EXPANDEDNAME)) {
- setFlag(EXPANDEDNAME)
- if (hasAccessorFlag && !isDeferred) {
- accessed.expandName(base)
- }
- else if (hasGetter) {
- getter(owner).expandName(base)
- setter(owner).expandName(base)
- }
- name = nme.expandedName(name.toTermName, base)
+ def expand(sym: Symbol) {
+ if ((sym eq NoSymbol) || (sym hasFlag EXPANDEDNAME)) () // skip
+ else sym setFlag EXPANDEDNAME setName nme.expandedName(sym.name.toTermName, base)
+ }
+ def cloneAndExpand(accessor: Symbol) {
+ val clone = accessor.cloneSymbol(accessor.owner, (accessor.flags | ARTIFACT) & ~ACCESSOR)
+ expand(accessor)
+ log(s"Expanded overriding accessor to $accessor, but cloned $clone to preserve override")
+ accessor.owner.info.decls enter clone
+ }
+ def expandAccessor(accessor: Symbol) {
+ if (accessor.isOverridingSymbol) cloneAndExpand(accessor) else expand(accessor)
+ }
+ if (hasAccessorFlag && !isDeferred) {
+ expand(accessed)
+ }
+ else if (hasGetter) {
+ expandAccessor(getter(owner))
+ expandAccessor(setter(owner))
}
+ expand(this)
}
}
implicit val TermSymbolTag = ClassTag[TermSymbol](classOf[TermSymbol])
@@ -3065,7 +3075,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
if (Statistics.canEnable) Statistics.incCounter(nameCount)
if (needsFlatClasses) {
if (flatname eq null)
- flatname = nme.flattenedName(rawowner.name, rawname).toTypeName
+ flatname = tpnme.flattenedName(rawowner.name, rawname)
flatname
}
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index e96fcc90df..b1f58814c7 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -188,7 +188,7 @@ abstract class TreeInfo {
def isVariableOrGetter(tree: Tree) = {
def sym = tree.symbol
def isVar = sym.isVariable
- def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(nme.getterToSetter(sym.name.toTermName)) != NoSymbol
+ def isGetter = mayBeVarGetter(sym) && sym.owner.info.member(sym.setterName) != NoSymbol
tree match {
case Ident(_) => isVar
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index c00337e578..410bc738e2 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -242,6 +242,9 @@ trait Trees extends api.Trees { self: SymbolTable =>
trait NameTree extends Tree with NameTreeApi {
def name: Name
+ def getterName: TermName = name.getterName
+ def setterName: TermName = name.setterName
+ def localName: TermName = name.localName
}
trait RefTree extends SymTree with NameTree with RefTreeApi {
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index d7ff4faa5d..611873efc0 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -2422,20 +2422,28 @@ trait Types
override def kind = "TypeRef"
}
+ // No longer defined as anonymous classes in `object TypeRef` to avoid an unnecessary outer pointer.
+ private final class AliasArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AliasTypeRef
+ private final class AbstractArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with AbstractTypeRef
+ private final class ClassArgsTypeRef(pre: Type, sym: Symbol, args: List[Type]) extends ArgsTypeRef(pre, sym, args) with ClassTypeRef
+ private final class AliasNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AliasTypeRef
+ private final class AbstractNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ private final class ClassNoArgsTypeRef(pre: Type, sym: Symbol) extends NoArgsTypeRef(pre, sym) with ClassTypeRef
+
object TypeRef extends TypeRefExtractor {
def apply(pre: Type, sym: Symbol, args: List[Type]): Type = unique({
if (args.nonEmpty) {
- if (sym.isAliasType) new ArgsTypeRef(pre, sym, args) with AliasTypeRef
- else if (sym.isAbstractType) new ArgsTypeRef(pre, sym, args) with AbstractTypeRef
- else new ArgsTypeRef(pre, sym, args) with ClassTypeRef
+ if (sym.isAliasType) new AliasArgsTypeRef(pre, sym, args)
+ else if (sym.isAbstractType) new AbstractArgsTypeRef(pre, sym, args)
+ else new ClassArgsTypeRef(pre, sym, args)
}
else {
- if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef
- else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef
+ if (sym.isAliasType) new AliasNoArgsTypeRef(pre, sym)
+ else if (sym.isAbstractType) new AbstractNoArgsTypeRef(pre, sym)
else if (sym.isRefinementClass) new RefinementTypeRef(pre, sym)
else if (sym.isPackageClass) new PackageTypeRef(pre, sym)
else if (sym.isModuleClass) new ModuleTypeRef(pre, sym)
- else new NoArgsTypeRef(pre, sym) with ClassTypeRef
+ else new ClassNoArgsTypeRef(pre, sym)
}
})
}
@@ -3752,10 +3760,11 @@ trait Types
if (tp.isTrivial) tp
else if (tp.prefix.typeSymbol isNonBottomSubClass owner) {
val widened = tp match {
- case _: ConstantType => tp // Java enum constants: don't widen to the enum type!
- case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect.
+ case _: ConstantType => tp // Java enum constants: don't widen to the enum type!
+ case _ => tp.widen // C.X.type widens to C.this.X.type, otherwise `tp asSeenFrom (pre, C)` has no effect.
}
- widened asSeenFrom (pre, tp.typeSymbol.owner)
+ val memType = widened asSeenFrom (pre, tp.typeSymbol.owner)
+ if (tp eq widened) memType else memType.narrow
}
else loop(tp.prefix) memberType tp.typeSymbol
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 63b7f73386..d6fca9d186 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -76,6 +76,19 @@ trait Collections {
lb.toList
}
+ final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = {
+ val buf = new ListBuffer[A]
+ val seen = mutable.Set[B]()
+ xs foreach { x =>
+ val y = f(x)
+ if (!seen(y)) {
+ buf += x
+ seen += y
+ }
+ }
+ buf.toList
+ }
+
@tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = {
xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail)
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 2e38caaf5d..e58e89a4b1 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -242,10 +242,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def reflectField(field: TermSymbol): FieldMirror = {
checkMemberOf(field, symbol)
if ((field.isMethod && !field.isAccessor) || field.isModule) ErrorNotField(field)
- val name =
- if (field.isGetter) nme.getterToLocal(field.name)
- else if (field.isSetter) nme.getterToLocal(nme.setterToGetter(field.name))
- else field.name
+ val name = if (field.isAccessor) field.localName else field.name
val field1 = (field.owner.info decl name).asTerm
try fieldToJava(field1)
catch {
@@ -313,7 +310,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
// the "symbol == Any_getClass || symbol == Object_getClass" test doesn't cut it
// because both AnyVal and its primitive descendants define their own getClass methods
- private def isGetClass(meth: MethodSymbol) = meth.name.toString == "getClass" && meth.paramss.flatten.isEmpty
+ private def isGetClass(meth: MethodSymbol) = (meth.name string_== "getClass") && meth.paramss.flatten.isEmpty
private def isStringConcat(meth: MethodSymbol) = meth == String_+ || (meth.owner.isPrimitiveValueClass && meth.returnType =:= StringClass.toType)
lazy val bytecodelessMethodOwners = Set[Symbol](AnyClass, AnyValClass, AnyRefClass, ObjectClass, ArrayClass) ++ ScalaPrimitiveValueClasses
lazy val bytecodefulObjectMethods = Set[Symbol](Object_clone, Object_equals, Object_finalize, Object_hashCode, Object_toString,
@@ -844,9 +841,10 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
* that start with the given name are searched instead.
*/
private def lookup(clazz: Symbol, jname: String): Symbol = {
- def approximateMatch(sym: Symbol, jstr: String): Boolean =
- (sym.name.toString == jstr) ||
- sym.isPrivate && nme.expandedName(sym.name.toTermName, sym.owner).toString == jstr
+ def approximateMatch(sym: Symbol, jstr: String): Boolean = (
+ (sym.name string_== jstr)
+ || sym.isPrivate && (nme.expandedName(sym.name.toTermName, sym.owner) string_== jstr)
+ )
clazz.info.decl(newTermName(jname)) orElse {
(clazz.info.decls.iterator filter (approximateMatch(_, jname))).toList match {
@@ -1008,7 +1006,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
private def typeParamToScala1(jparam: jTypeVariable[_ <: GenericDeclaration]): TypeSymbol = {
val owner = genericDeclarationToScala(jparam.getGenericDeclaration)
owner.info match {
- case PolyType(tparams, _) => tparams.find(_.name.toString == jparam.getName).get.asType
+ case PolyType(tparams, _) => tparams.find(_.name string_== jparam.getName).get.asType
}
}
@@ -1202,7 +1200,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
*/
def fieldToJava(fld: TermSymbol): jField = fieldCache.toJava(fld) {
val jclazz = classToJava(fld.owner.asClass)
- val jname = nme.dropLocalSuffix(fld.name).toString
+ val jname = fld.name.dropLocal.toString
try jclazz getDeclaredField jname
catch {
case ex: NoSuchFieldException => jclazz getDeclaredField expandedName(fld)
@@ -1215,7 +1213,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
def methodToJava(meth: MethodSymbol): jMethod = methodCache.toJava(meth) {
val jclazz = classToJava(meth.owner.asClass)
val paramClasses = transformedType(meth).paramTypes map typeToJavaClass
- val jname = nme.dropLocalSuffix(meth.name).toString
+ val jname = meth.name.dropLocal.toString
try jclazz getDeclaredMethod (jname, paramClasses: _*)
catch {
case ex: NoSuchMethodException =>
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
index a130013398..4d90afcdc3 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala
@@ -14,7 +14,7 @@ class JavaUniverse extends internal.SymbolTable with ReflectSetup with runtime.S
lazy val settings = new Settings
private val isLogging = sys.props contains "scala.debug.reflect"
- def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg)
+ def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg)
type TreeCopier = InternalTreeCopierOps
def newStrictTreeCopier: TreeCopier = new StrictTreeCopier
diff --git a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala
index 2a07547de2..ac5fec80b3 100755
--- a/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/base/comment/Body.scala
@@ -73,16 +73,20 @@ object EntityLink {
def unapply(el: EntityLink): Option[(Inline, LinkTo)] = Some((el.title, el.link))
}
final case class HtmlTag(data: String) extends Inline {
- def canClose(open: HtmlTag) = {
- open.data.stripPrefix("<") == data.stripPrefix("</")
+ private val Pattern = """(?ms)\A<(/?)(.*?)[\s>].*\z""".r
+ private val (isEnd, tagName) = data match {
+ case Pattern(s1, s2) =>
+ (! s1.isEmpty, Some(s2.toLowerCase))
+ case _ =>
+ (false, None)
}
- def close = {
- if (data.indexOf("</") == -1)
- Some(HtmlTag("</" + data.stripPrefix("<")))
- else
- None
+ def canClose(open: HtmlTag) = {
+ isEnd && tagName == open.tagName
}
+
+ private val TagsNotToClose = Set("br", "img")
+ def close = tagName collect { case name if !TagsNotToClose(name) => HtmlTag(s"</$name>") }
}
/** The summary of a comment, usually its first sentence. There must be exactly one summary per body. */
diff --git a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala
index 5781e680dd..348ea97c5b 100644
--- a/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/html/SyntaxHigh.scala
@@ -6,6 +6,7 @@
package scala.tools.nsc.doc.html
import scala.xml.NodeSeq
+import scala.annotation.tailrec
/** Highlight the syntax of Scala code appearing in a `{{{` wiki block
* (see method `HtmlPage.blockToHtml`).
@@ -209,9 +210,9 @@ private[html] object SyntaxHigh {
out.toString
}
- def parse(pre: String, i: Int): Int = {
+ @tailrec def parse(pre: String, i: Int): Unit = {
out append pre
- if (i == buf.length) return i
+ if (i == buf.length) return
buf(i) match {
case '\n' =>
parse("\n", i+1)
@@ -277,7 +278,6 @@ private[html] object SyntaxHigh {
} else
parse(buf(i).toChar.toString, i+1)
}
- i
}
parse("", 0)