summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.sbt12
-rw-r--r--project/VersionUtil.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala6
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Fields.scala117
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala53
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala11
-rw-r--r--src/library/scala/util/Properties.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala1
-rw-r--r--test/files/pos/sd219.scala11
-rw-r--r--test/files/pos/t9920.scala6
-rw-r--r--test/files/run/delambdafy_t6028.check2
-rw-r--r--test/files/run/t6028.check2
-rw-r--r--test/files/run/t9697.check1
-rw-r--r--test/files/run/t9697.scala204
-rw-r--r--test/files/run/t9920.scala17
-rw-r--r--test/files/run/t9920b.scala17
-rw-r--r--test/files/run/t9920c.scala21
-rw-r--r--test/files/run/t9920d.scala14
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala8
-rwxr-xr-xtools/get-scala-commit-date9
-rwxr-xr-xtools/get-scala-commit-sha14
-rw-r--r--versions.properties2
27 files changed, 463 insertions, 81 deletions
diff --git a/build.sbt b/build.sbt
index 30e3894754..2ae5db9d3d 100644
--- a/build.sbt
+++ b/build.sbt
@@ -160,7 +160,7 @@ lazy val commonSettings = clearSourceAndResourceDirectories ++ publishSettings +
<developers>
<developer>
<id>lamp</id>
- <name>EPFL LAMP</name>
+ <name>LAMP/EPFL</name>
</developer>
<developer>
<id>Lightbend</id>
@@ -406,7 +406,7 @@ lazy val compiler = configureAsSubproject(project)
),
// Generate the ScriptEngineFactory service definition. The Ant build does this when building
// the JAR but sbt has no support for it and it is easier to do as a resource generator:
- generateServiceProviderResources("javax.script.ScriptEngineFactory" -> "scala.tools.nsc.interpreter.IMain$Factory"),
+ generateServiceProviderResources("javax.script.ScriptEngineFactory" -> "scala.tools.nsc.interpreter.Scripted$Factory"),
managedResourceDirectories in Compile := Seq((resourceManaged in Compile).value),
fixPom(
"/project/name" -> <name>Scala Compiler</name>,
@@ -510,8 +510,10 @@ lazy val scalap = configureAsSubproject(project)
)
.dependsOn(compiler)
-lazy val partestExtras = configureAsSubproject(Project("partest-extras", file(".") / "src" / "partest-extras"))
+lazy val partestExtras = Project("partest-extras", file(".") / "src" / "partest-extras")
.dependsOn(replJlineEmbedded)
+ .settings(commonSettings: _*)
+ .settings(generatePropertiesFileSettings: _*)
.settings(clearSourceAndResourceDirectories: _*)
.settings(disableDocs: _*)
.settings(disablePublishing: _*)
@@ -597,8 +599,6 @@ lazy val partestJavaAgent = Project("partest-javaagent", file(".") / "src" / "pa
// Setting name to "scala-partest-javaagent" so that the jar file gets that name, which the Runner relies on
name := "scala-partest-javaagent",
description := "Scala Compiler Testing Tool (compiler-specific java agent)",
- // writing jar file to $buildDirectory/pack/lib because that's where it's expected to be found
- setJarLocation,
// add required manifest entry - previously included from file
packageOptions in (Compile, packageBin) +=
Package.ManifestAttributes( "Premain-Class" -> "scala.tools.partest.javaagent.ProfilingAgent" ),
@@ -829,7 +829,7 @@ lazy val root: Project = (project in file("."))
)
// The following subprojects' binaries are required for building "pack":
-lazy val distDependencies = Seq(replJline, replJlineEmbedded, compiler, library, partestExtras, partestJavaAgent, reflect, scalap, scaladoc)
+lazy val distDependencies = Seq(replJline, replJlineEmbedded, compiler, library, reflect, scalap, scaladoc)
lazy val dist = (project in file("dist"))
.settings(commonSettings)
diff --git a/project/VersionUtil.scala b/project/VersionUtil.scala
index 1c2fff27b7..5613520e27 100644
--- a/project/VersionUtil.scala
+++ b/project/VersionUtil.scala
@@ -18,7 +18,7 @@ object VersionUtil {
)
lazy val generatePropertiesFileSettings = Seq[Setting[_]](
- copyrightString := "Copyright 2002-2016, LAMP/EPFL",
+ copyrightString := "Copyright 2002-2016, LAMP/EPFL and Lightbend, Inc.",
resourceGenerators in Compile += generateVersionPropertiesFile.map(file => Seq(file)).taskValue,
generateVersionPropertiesFile := generateVersionPropertiesFileImpl.value
)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
index 3e53419573..466793010f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
@@ -73,9 +73,11 @@ abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
/* ------ (4) exception-handler version of monitor-exit code.
* Reached upon abrupt termination of (2).
* Protected by whatever protects the whole synchronized expression.
+ * null => "any" exception in bytecode, like we emit for finally.
+ * Important not to use j/l/Throwable which dooms the method to a life of interpretation! (SD-233)
* ------
*/
- protect(startProtected, endProtected, currProgramPoint(), jlThrowableRef)
+ protect(startProtected, endProtected, currProgramPoint(), null)
locals.load(monitor)
emit(asm.Opcodes.MONITOREXIT)
emit(asm.Opcodes.ATHROW)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 09e82de89b..edb75514e8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -114,7 +114,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
if (classSym == NothingClass) srNothingRef
else if (classSym == NullClass) srNullRef
else {
- val internalName = classSym.javaBinaryName.toString
+ val internalName = classSym.javaBinaryNameString
classBTypeFromInternalName.getOrElse(internalName, {
// The new ClassBType is added to the map in its constructor, before we set its info. This
// allows initializing cyclic dependencies, see the comment on variable ClassBType._info.
@@ -625,7 +625,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
*/
def mirrorClassClassBType(moduleClassSym: Symbol): ClassBType = {
assert(isTopLevelModuleClass(moduleClassSym), s"not a top-level module class: $moduleClassSym")
- val internalName = moduleClassSym.javaBinaryName.dropModule.toString
+ val internalName = moduleClassSym.javaBinaryNameString.stripSuffix(nme.MODULE_SUFFIX_STRING)
classBTypeFromInternalName.getOrElse(internalName, {
val c = ClassBType(internalName)
// class info consistent with BCodeHelpers.genMirrorClass
@@ -642,7 +642,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
}
def beanInfoClassClassBType(mainClass: Symbol): ClassBType = {
- val internalName = mainClass.javaBinaryName.toString + "BeanInfo"
+ val internalName = mainClass.javaBinaryNameString + "BeanInfo"
classBTypeFromInternalName.getOrElse(internalName, {
val c = ClassBType(internalName)
c.info = Right(ClassInfo(
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index 0a54767f76..6593d4b725 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -337,7 +337,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
bTypes.initializeCoreBTypes()
bTypes.javaDefinedClasses.clear()
bTypes.javaDefinedClasses ++= currentRun.symSource collect {
- case (sym, _) if sym.isJavaDefined => sym.javaBinaryName.toString
+ case (sym, _) if sym.isJavaDefined => sym.javaBinaryNameString
}
Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart)
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 8d362f13dd..daf645fd20 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -527,7 +527,7 @@ abstract class Constructors extends Statics with Transform with TypingTransforme
super.transform(tree)
else if (canBeSupplanted(tree.symbol))
gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos
- else if (tree.symbol.outerSource == clazz)
+ else if (tree.symbol.outerSource == clazz && !isDelayedInitSubclass)
gen.mkAttributedIdent(parameterNamed(nme.OUTER)) setPos tree.pos
else
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 69240b07a1..cc234eb623 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -258,7 +258,7 @@ abstract class Erasure extends InfoTransform
// Anything which could conceivably be a module (i.e. isn't known to be
// a type parameter or similar) must go through here or the signature is
// likely to end up with Foo<T>.Empty where it needs Foo<T>.Empty$.
- def fullNameInSig(sym: Symbol) = "L" + enteringJVM(sym.javaBinaryName)
+ def fullNameInSig(sym: Symbol) = "L" + enteringJVM(sym.javaBinaryNameString)
def jsig(tp0: Type, existentiallyBound: List[Symbol] = Nil, toplevel: Boolean = false, primitiveOK: Boolean = true): String = {
val tp = tp0.dealias
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index f3d5ceb0f0..7d50c12852 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -8,7 +8,7 @@ package tools.nsc
package transform
import symtab._
-import Flags.{ CASE => _, _ }
+import Flags.{CASE => _, _}
import scala.collection.mutable.ListBuffer
/** This class ...
diff --git a/src/compiler/scala/tools/nsc/transform/Fields.scala b/src/compiler/scala/tools/nsc/transform/Fields.scala
index 894d0a1701..6cf6a5abce 100644
--- a/src/compiler/scala/tools/nsc/transform/Fields.scala
+++ b/src/compiler/scala/tools/nsc/transform/Fields.scala
@@ -207,9 +207,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
moduleVar
}
- private def moduleInit(module: Symbol) = {
+ private def moduleInit(module: Symbol, moduleVar: Symbol) = {
// println(s"moduleInit for $module in ${module.ownerChain} --> ${moduleVarOf.get(module)}")
- val moduleVar = moduleOrLazyVarOf(module)
def moduleVarRef = gen.mkAttributedRef(moduleVar)
// for local modules, we synchronize on the owner of the method that owns the module
@@ -238,7 +237,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
*/
val computeName = nme.newLazyValSlowComputeName(module.name)
val computeMethod = DefDef(NoMods, computeName, Nil, ListOfNil, TypeTree(UnitTpe), gen.mkSynchronized(monitorHolder)(If(needsInit, init, EmptyTree)))
- Block(computeMethod :: If(needsInit, Apply(Ident(computeName), Nil), EmptyTree) :: Nil, moduleVarRef)
+ Block(computeMethod :: If(needsInit, Apply(Ident(computeName), Nil), EmptyTree) :: Nil,
+ gen.mkCast(moduleVarRef, module.info.resultType))
}
// NoSymbol for lazy accessor sym with unit result type
@@ -305,6 +305,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
lazyCallingSuper setInfo tp
}
+ private def classNeedsInfoTransform(cls: Symbol): Boolean = {
+ !(cls.isPackageClass || cls.isJavaDefined) && (currentRun.compiles(cls) || refChecks.isSeparatelyCompiledScalaSuperclass(cls))
+ }
+
def apply(tp0: Type): Type = tp0 match {
// TODO: make less destructive (name changes, decl additions, flag setting --
// none of this is actually undone when travelling back in time using atPhase)
@@ -360,9 +364,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
ClassInfoType(parents, allDecls, clazz)
} else tp
+
+ case tp@ClassInfoType(parents, oldDecls, clazz) if !classNeedsInfoTransform(clazz) => tp
+
// mix in fields & accessors for all mixed in traits
+ case tp@ClassInfoType(parents, oldDecls, clazz) =>
- case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass =>
val site = clazz.thisType
// setter conflicts cannot arise independently from a getter conflict, since a setter without a getter does not a val definition make
@@ -590,62 +597,81 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
}
// synth trees for accessors/fields and trait setters when they are mixed into a class
- def fieldsAndAccessors(clazz: Symbol): List[ValOrDefDef] = {
- def fieldAccess(accessor: Symbol): List[Tree] = {
- val fieldName = accessor.localName
- val field = clazz.info.decl(fieldName)
- // The `None` result denotes an error, but it's refchecks' job to report it (this fallback is for robustness).
- // This is the result of overriding a val with a def, so that no field is found in the subclass.
- if (field.exists) List(Select(This(clazz), field))
- else Nil
- }
-
- def getterBody(getter: Symbol): List[Tree] = {
+ def fieldsAndAccessors(clazz: Symbol): List[Tree] = {
+ // scala/scala-dev#219
+ // Cast to avoid spurious mismatch in paths containing trait vals that have
+ // not been rebound to accessors in the subclass we're in now.
+ // For example, for a lazy val mixed into a class, the lazy var's info
+ // will not refer to symbols created during our info transformer,
+ // so if its type depends on a val that is now implemented after the info transformer,
+ // we'll get a mismatch when assigning `rhs` to `lazyVarOf(getter)`.
+ // TODO: could we rebind more aggressively? consider overriding in type equality?
+ def cast(tree: Tree, pt: Type) = gen.mkAsInstanceOf(tree, pt)
+
+ // Could be NoSymbol, which denotes an error, but it's refchecks' job to report it (this fallback is for robustness).
+ // This is the result of overriding a val with a def, so that no field is found in the subclass.
+ def fieldAccess(accessor: Symbol): Symbol =
+ afterOwnPhase { clazz.info.decl(accessor.localName) }
+
+ def getterBody(getter: Symbol): Tree =
// accessor created by newMatchingModuleAccessor for a static module that does need an accessor
// (because there's a matching member in a super class)
- if (getter.asTerm.referenced.isModule) {
- List(gen.mkAttributedRef(clazz.thisType, getter.asTerm.referenced))
- } else {
+ if (getter.asTerm.referenced.isModule)
+ mkAccessor(getter)(cast(Select(This(clazz), getter.asTerm.referenced), getter.info.resultType))
+ else {
val fieldMemoization = fieldMemoizationIn(getter, clazz)
- if (fieldMemoization.constantTyped) List(gen.mkAttributedQualifier(fieldMemoization.tp)) // TODO: drop when we no longer care about producing identical bytecode
- else fieldAccess(getter)
+ // TODO: drop getter for constant? (when we no longer care about producing identical bytecode?)
+ if (fieldMemoization.constantTyped) mkAccessor(getter)(gen.mkAttributedQualifier(fieldMemoization.tp))
+ else fieldAccess(getter) match {
+ case NoSymbol => EmptyTree
+ case fieldSel => mkAccessor(getter)(cast(Select(This(clazz), fieldSel), getter.info.resultType))
+ }
}
- }
// println(s"accessorsAndFieldsNeedingTrees for $templateSym: $accessorsAndFieldsNeedingTrees")
- def setterBody(setter: Symbol): List[Tree] = {
+ def setterBody(setter: Symbol): Tree =
// trait setter in trait
- if (clazz.isTrait) List(EmptyTree)
+ if (clazz.isTrait) mkAccessor(setter)(EmptyTree)
// trait setter for overridden val in class
- else if (checkAndClearOverriddenTraitSetter(setter)) List(mkTypedUnit(setter.pos))
+ else if (checkAndClearOverriddenTraitSetter(setter)) mkAccessor(setter)(mkTypedUnit(setter.pos))
// trait val/var setter mixed into class
- else fieldAccess(setter) map (fieldSel => Assign(fieldSel, Ident(setter.firstParam)))
- }
+ else fieldAccess(setter) match {
+ case NoSymbol => EmptyTree
+ case fieldSel => afterOwnPhase { // the assign only type checks after our phase (assignment to val)
+ mkAccessor(setter)(Assign(Select(This(clazz), fieldSel), cast(Ident(setter.firstParam), fieldSel.info)))
+ }
+ }
- def moduleAccessorBody(module: Symbol): List[Tree] = List(
+ def moduleAccessorBody(module: Symbol): Tree =
// added during synthFieldsAndAccessors using newModuleAccessor
// a module defined in a trait by definition can't be static (it's a member of the trait and thus gets a new instance for every outer instance)
- if (clazz.isTrait) EmptyTree
+ if (clazz.isTrait) mkAccessor(module)(EmptyTree)
// symbol created by newModuleAccessor for a (non-trait) class
- else moduleInit(module)
- )
+ else {
+ mkAccessor(module)(moduleInit(module, moduleOrLazyVarOf(module)))
+ }
val synthAccessorInClass = new SynthLazyAccessorsIn(clazz)
- def superLazy(getter: Symbol): List[ValOrDefDef] = {
+ def superLazy(getter: Symbol): Tree = {
assert(!clazz.isTrait)
- // this contortion was the only way I can get the super select to be type checked correctly.. TODO: why does SelectSuper not work?
- val rhs = Apply(Select(Super(This(clazz), tpnme.EMPTY), getter.name), Nil)
- explodeThicket(synthAccessorInClass.expandLazyClassMember(lazyVarOf(getter), getter, rhs, Map.empty)).asInstanceOf[List[ValOrDefDef]]
+ // this contortion was the only way I can get the super select to be type checked correctly..
+ // TODO: why does SelectSuper not work?
+ val selectSuper = Select(Super(This(clazz), tpnme.EMPTY), getter.name)
+
+ val lazyVar = lazyVarOf(getter)
+ val rhs = cast(Apply(selectSuper, Nil), lazyVar.info)
+
+ synthAccessorInClass.expandLazyClassMember(lazyVar, getter, rhs, Map.empty)
}
- clazz.info.decls.toList.filter(checkAndClearNeedsTrees) flatMap {
- case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module) map mkAccessor(module)
+ (afterOwnPhase { clazz.info.decls } toList) filter checkAndClearNeedsTrees map {
+ case module if module hasAllFlags (MODULE | METHOD) => moduleAccessorBody(module)
case getter if getter hasAllFlags (LAZY | METHOD) => superLazy(getter)
- case setter if setter.isSetter => setterBody(setter) map mkAccessor(setter)
- case getter if getter.hasFlag(ACCESSOR) => getterBody(getter) map mkAccessor(getter)
- case field if !(field hasFlag METHOD) => Some(mkTypedValDef(field)) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES)
- case _ => None
- }
+ case setter if setter.isSetter => setterBody(setter)
+ case getter if getter.hasFlag(ACCESSOR) => getterBody(getter)
+ case field if !(field hasFlag METHOD) => mkTypedValDef(field) // vals/vars and module vars (cannot have flags PACKAGE | JAVA since those never receive NEEDS_TREES)
+ case _ => EmptyTree
+ } filterNot (_ == EmptyTree) // there will likely be many EmptyTrees, but perhaps no thicket blocks that need expanding
}
def rhsAtOwner(stat: ValOrDefDef, newOwner: Symbol): Tree =
@@ -705,7 +731,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
if (currOwner.isClass) cd
else { // local module -- symbols cannot be generated by info transformer, so do it all here
val moduleVar = newModuleVarSymbol(currOwner, statSym, statSym.info.resultType)
- Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym)) :: Nil)
+ Thicket(cd :: mkTypedValDef(moduleVar) :: mkAccessor(statSym)(moduleInit(statSym, moduleVar)) :: Nil)
}
case tree =>
@@ -724,7 +750,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
val addedStats =
if (!currentOwner.isClass || currentOwner.isPackageClass) Nil
- else afterOwnPhase { fieldsAndAccessors(currentOwner) }
+ else {
+ val thickets = fieldsAndAccessors(currentOwner)
+ if (thickets exists mustExplodeThicket)
+ thickets flatMap explodeThicket
+ else thickets
+ }
val inRealClass = currentOwner.isClass && !(currentOwner.isPackageClass || currentOwner.isTrait)
if (inRealClass)
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 74e6c58388..798cfcd072 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -104,8 +104,31 @@ abstract class LambdaLift extends InfoTransform {
/** Buffers for lifted out classes and methods */
private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]]
+ val delayedInitDummies = new mutable.HashMap[Symbol, Symbol]
+
+ /**
+ * For classes capturing locals, LambdaLift uses `local.logicallyEnclosingMember` to decide
+ * whether an access to the local is re-written to the field or constructor parameter. If the
+ * access is in a constructor statement, the constructor parameter is used.
+ *
+ * For DelayedInit subclasses, constructor statements end up in the synthetic init method
+ * instead of the constructor itself, so the access should go to the field. This method changes
+ * `logicallyEnclosingMember` in this case to return a temprorary symbol corresponding to that
+ * method.
+ */
+ private def logicallyEnclosingMember(sym: Symbol): Symbol = {
+ if (sym.isLocalDummy) {
+ val enclClass = sym.enclClass
+ if (enclClass.isSubClass(DelayedInitClass))
+ delayedInitDummies.getOrElseUpdate(enclClass, enclClass.newMethod(nme.delayedInit))
+ else
+ enclClass.primaryConstructor
+ } else if (sym.isMethod || sym.isClass || sym == NoSymbol) sym
+ else logicallyEnclosingMember(sym.owner)
+ }
+
private def isSameOwnerEnclosure(sym: Symbol) =
- sym.owner.logicallyEnclosingMember == currentOwner.logicallyEnclosingMember
+ logicallyEnclosingMember(sym.owner) == logicallyEnclosingMember(currentOwner)
/** Mark symbol `sym` as being free in `enclosure`, unless `sym`
* is defined in `enclosure` or there is a class between `enclosure`s owner
@@ -139,9 +162,9 @@ abstract class LambdaLift extends InfoTransform {
*/
private def markFree(sym: Symbol, enclosure: Symbol): Boolean = {
// println(s"mark free: ${sym.fullLocationString} marked free in $enclosure")
- (enclosure == sym.owner.logicallyEnclosingMember) || {
- debuglog("%s != %s".format(enclosure, sym.owner.logicallyEnclosingMember))
- if (enclosure.isPackageClass || !markFree(sym, enclosure.skipConstructor.owner.logicallyEnclosingMember)) false
+ (enclosure == logicallyEnclosingMember(sym.owner)) || {
+ debuglog("%s != %s".format(enclosure, logicallyEnclosingMember(sym.owner)))
+ if (enclosure.isPackageClass || !markFree(sym, logicallyEnclosingMember(enclosure.skipConstructor.owner))) false
else {
val ss = symSet(free, enclosure)
if (!ss(sym)) {
@@ -184,14 +207,14 @@ abstract class LambdaLift extends InfoTransform {
if (sym == NoSymbol) {
assert(name == nme.WILDCARD)
} else if (sym.isLocalToBlock) {
- val owner = currentOwner.logicallyEnclosingMember
+ val owner = logicallyEnclosingMember(currentOwner)
if (sym.isTerm && !sym.isMethod) markFree(sym, owner)
else if (sym.isMethod) markCalled(sym, owner)
//symSet(called, owner) += sym
}
case Select(_, _) =>
if (sym.isConstructor && sym.owner.isLocalToBlock)
- markCalled(sym, currentOwner.logicallyEnclosingMember)
+ markCalled(sym, logicallyEnclosingMember(currentOwner))
case _ =>
}
super.traverse(tree)
@@ -283,17 +306,18 @@ abstract class LambdaLift extends InfoTransform {
private def proxy(sym: Symbol) = {
def searchIn(enclosure: Symbol): Symbol = {
- if (enclosure eq NoSymbol) throw new IllegalArgumentException("Could not find proxy for "+ sym.defString +" in "+ sym.ownerChain +" (currentOwner= "+ currentOwner +" )")
- debuglog("searching for " + sym + "(" + sym.owner + ") in " + enclosure + " " + enclosure.logicallyEnclosingMember)
+ if (enclosure eq NoSymbol)
+ throw new IllegalArgumentException("Could not find proxy for "+ sym.defString +" in "+ sym.ownerChain +" (currentOwner= "+ currentOwner +" )")
+ debuglog("searching for " + sym + "(" + sym.owner + ") in " + enclosure + " " + logicallyEnclosingMember(enclosure))
val proxyName = proxyNames.getOrElse(sym, sym.name)
- val ps = (proxies get enclosure.logicallyEnclosingMember).toList.flatten find (_.name == proxyName)
+ val ps = (proxies get logicallyEnclosingMember(enclosure)).toList.flatten find (_.name == proxyName)
ps getOrElse searchIn(enclosure.skipConstructor.owner)
}
debuglog("proxy %s from %s has logical enclosure %s".format(
sym.debugLocationString,
currentOwner.debugLocationString,
- sym.owner.logicallyEnclosingMember.debugLocationString)
+ logicallyEnclosingMember(sym.owner).debugLocationString)
)
if (isSameOwnerEnclosure(sym)) sym
@@ -319,7 +343,14 @@ abstract class LambdaLift extends InfoTransform {
else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
else outerValue match {
case EmptyTree => prematureSelfReference()
- case o => outerPath(o, currentClass.outerClass, clazz)
+ case o =>
+ val path = outerPath(o, currentClass.outerClass, clazz)
+ if (path.tpe <:< clazz.tpeHK) path
+ else {
+ // SI-9920 The outer accessor might have an erased type of the self type of a trait,
+ // rather than the trait itself. Add a cast if necessary.
+ gen.mkAttributedCast(path, clazz.tpeHK)
+ }
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 8034d056d7..106b076eef 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -95,6 +95,15 @@ abstract class RefChecks extends Transform {
)
}
+ private val separatelyCompiledScalaSuperclass = perRunCaches.newAnyRefMap[Symbol, Unit]()
+ final def isSeparatelyCompiledScalaSuperclass(sym: Symbol) = if (globalPhase.refChecked){
+ separatelyCompiledScalaSuperclass.contains(sym)
+ } else {
+ // conservative approximation in case someone in pre-refchecks phase asks for `exitingFields(someClass.info)`
+ // and we haven't run the refchecks tree transform which populates `separatelyCompiledScalaSuperclass`
+ false
+ }
+
class RefCheckTransformer(unit: CompilationUnit) extends Transformer {
var localTyper: analyzer.Typer = typer
@@ -854,6 +863,8 @@ abstract class RefChecks extends Transform {
// println("validate base type "+tp)
val baseClass = tp.typeSymbol
if (baseClass.isClass) {
+ if (!baseClass.isTrait && !baseClass.isJavaDefined && !currentRun.compiles(baseClass) && !separatelyCompiledScalaSuperclass.contains(baseClass))
+ separatelyCompiledScalaSuperclass.update(baseClass, ())
val index = clazz.info.baseTypeIndex(baseClass)
if (index >= 0) {
if (seenTypes(index) forall (tp1 => !(tp1 <:< tp)))
diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala
index a176748cd6..fc2302d148 100644
--- a/src/library/scala/util/Properties.scala
+++ b/src/library/scala/util/Properties.scala
@@ -105,7 +105,7 @@ private[scala] trait PropertiesTrait {
* or "version (unknown)" if it cannot be determined.
*/
val versionString = "version " + scalaPropOrElse("version.number", "(unknown)")
- val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL")
+ val copyrightString = scalaPropOrElse("copyright.string", "Copyright 2002-2016, LAMP/EPFL and Lightbend, Inc.")
/** This is the encoding to use reading in source files, overridden with -encoding.
* Note that it uses "prop" i.e. looks in the scala jar, not the system properties.
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index ac025e50ae..f870ecfc15 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -2166,7 +2166,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def logicallyEnclosingMember: Symbol =
if (isLocalDummy) enclClass.primaryConstructor
else if (isMethod || isClass || this == NoSymbol) this
- else if (this == NoSymbol) { devWarningDumpStack("NoSymbol.logicallyEnclosingMember", 15); this }
else owner.logicallyEnclosingMember
/** The top-level class containing this symbol. */
diff --git a/test/files/pos/sd219.scala b/test/files/pos/sd219.scala
new file mode 100644
index 0000000000..3c3f4962f0
--- /dev/null
+++ b/test/files/pos/sd219.scala
@@ -0,0 +1,11 @@
+class Global { class Name }
+
+trait CommonPrintUtils {
+ val global: Global
+
+ lazy val precedence: global.Name => Int = ???
+}
+
+trait CompilerProvider { val global: Global = ??? }
+
+class AbstractPrinter extends CommonPrintUtils with CompilerProvider \ No newline at end of file
diff --git a/test/files/pos/t9920.scala b/test/files/pos/t9920.scala
new file mode 100644
index 0000000000..8612618cc4
--- /dev/null
+++ b/test/files/pos/t9920.scala
@@ -0,0 +1,6 @@
+object Test {
+ def o = {
+ def i: Int = { i; 0 }
+ i
+ }
+}
diff --git a/test/files/run/delambdafy_t6028.check b/test/files/run/delambdafy_t6028.check
index 6a15b3b003..7b319c92dd 100644
--- a/test/files/run/delambdafy_t6028.check
+++ b/test/files/run/delambdafy_t6028.check
@@ -47,7 +47,7 @@ package <empty> {
final <stable> private[this] def MethodLocalObject$1(barParam$1: String, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = {
if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null))
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1);
- MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]()
+ (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type)
};
final <artifact> private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try {
tryyLocal$1.elem = tryyParam$1
diff --git a/test/files/run/t6028.check b/test/files/run/t6028.check
index 80f8698ecf..903ea3b753 100644
--- a/test/files/run/t6028.check
+++ b/test/files/run/t6028.check
@@ -59,7 +59,7 @@ package <empty> {
final <stable> private[this] def MethodLocalObject$1(barParam$1: Int, MethodLocalObject$module$1: runtime.VolatileObjectRef): T#MethodLocalObject$2.type = {
if (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]().eq(null))
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1);
- MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]()
+ (MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type](): T#MethodLocalObject$2.type)
};
@SerialVersionUID(value = 0) final <synthetic> class $anonfun$tryy$1 extends scala.runtime.AbstractFunction0$mcV$sp with Serializable {
def <init>($outer: T, tryyParam$1: Int, tryyLocal$1: runtime.IntRef): <$anon: Function0> = {
diff --git a/test/files/run/t9697.check b/test/files/run/t9697.check
new file mode 100644
index 0000000000..2a4f01c14f
--- /dev/null
+++ b/test/files/run/t9697.check
@@ -0,0 +1 @@
+warning: there were 9 deprecation warnings (since 2.11.0); re-run with -deprecation for details
diff --git a/test/files/run/t9697.scala b/test/files/run/t9697.scala
new file mode 100644
index 0000000000..eb8e44f8fc
--- /dev/null
+++ b/test/files/run/t9697.scala
@@ -0,0 +1,204 @@
+object log {
+ val b = new collection.mutable.StringBuilder
+ def apply(s: Any): Unit = b.append(s)
+ def check(s: String) = {
+ val bs = b.toString
+ assert(s == bs, bs)
+ b.clear()
+ }
+}
+
+package t9697 {
+ abstract class WA extends DelayedInit {
+ override def delayedInit(x: => Unit): Unit = x
+ val waField = "4"
+ }
+
+ class C {
+ def b(s: String) = log(s)
+ val cField = "1"
+
+ {
+ val dummyLocal = "2"
+ new WA {
+ val anonField = "3"
+ b(cField)
+ b(dummyLocal)
+ b(anonField)
+ b(waField)
+ }
+ }
+ }
+}
+
+package sd229 {
+ class Broken {
+ def is(ee: AnyRef) = {
+ new Delayed {
+ log(ee)
+ }
+ }
+ }
+
+ class Delayed extends DelayedInit {
+ def delayedInit(x: => Unit): Unit = x
+ }
+}
+
+
+// already fixed in 2.11.8, crashes in 2.10.6
+package t4683a {
+ class A { log("a") }
+ class B { log("b") }
+ class Bug extends DelayedInit {
+ log("bug")
+ def foo(a: A): B = new B
+ def delayedInit(init: => Unit): Unit = init
+ }
+}
+
+// already fixed in 2.12.0-RC1, crashes in 2.11.8
+package t4683b {
+ class Entity extends DelayedInit {
+ def delayedInit(x: => Unit): Unit = x
+
+ class Field
+
+ protected def EntityField[T <: Entity: reflect.ClassTag] = new Field
+
+ def find[T <: Entity: reflect.ClassTag] {
+ Nil.map(dbo => {
+ class EntityHolder extends Entity {
+ val entity = EntityField[T]
+ }
+ })
+ log("find")
+ }
+ }
+}
+
+package t4683c {
+ trait T extends DelayedInit {
+ def delayedInit(body: => Unit) = {
+ log("init")
+ body
+ }
+ }
+}
+
+package t4683d {
+ class C extends DelayedInit {
+ def delayedInit(body: => Unit): Unit = body
+ }
+ class Injector {
+ def test: Object = {
+ val name = "k"
+ class crash extends C {
+ log(name)
+ }
+ new crash()
+ }
+ }
+}
+
+package t4683e {
+ class DelayedInitTest {
+ def a = log("uh")
+ class B extends DelayedInit {
+ a
+ def delayedInit(body: => Unit): Unit = body
+ }
+ }
+}
+
+package t4683f {
+ class Foo extends DelayedInit {
+ log("fooInit")
+ def delayedInit(newBody: => Unit): Unit = {
+ log("delayedInit")
+ inits = {
+ val f = () => newBody
+ if (inits == null) {
+ log("initsNull")
+ List(f)
+ } else
+ f :: inits
+ }
+ }
+ def foo = log("foo")
+ var inits: List[() => Unit] = Nil
+ }
+
+ class Bar extends Foo {
+ log("barInit")
+ def bar = foo
+ def newBaz: Foo = new Baz
+ private class Baz extends Foo {
+ log("bazInit")
+ bar
+ }
+ }
+}
+
+package t4683g {
+ trait MatExpWorld { self =>
+ class T extends Runner { val expWorld: self.type = self }
+ }
+
+ trait Runner extends DelayedInit {
+ def delayedInit(init: => Unit): Unit = init
+ val expWorld: MatExpWorld
+ }
+}
+
+
+object Test extends App {
+ new t9697.C()
+ log.check("1234")
+
+ new sd229.Broken().is("hi")
+ log.check("hi")
+
+ val a: t4683a.A = new t4683a.A
+ var b: t4683a.B = null
+ new t4683a.Bug {
+ val b = foo(a)
+ }
+ log.check("abugb")
+
+ new t4683b.Entity().find[t4683b.Entity]
+ log.check("find")
+
+ val f = (p1: Int) => new t4683c.T { log(p1) }
+ f(5)
+ log.check("init5")
+
+ new t4683d.Injector().test
+ log.check("k")
+
+ val dit = new t4683e.DelayedInitTest()
+ new dit.B()
+ log.check("uh")
+
+ val fuu = new t4683f.Foo
+ log.check("delayedInitinitsNull")
+ fuu.inits.foreach(_.apply())
+ log.check("fooInit")
+ assert(fuu.inits == Nil) // the (delayed) initializer of Foo sets the inits field to Nil
+
+ val brr = new t4683f.Bar
+ log.check("delayedInitinitsNulldelayedInit") // delayedInit is called once for each constructor
+ brr.inits.foreach(_.apply())
+ log.check("barInitfooInit")
+ assert(brr.inits == Nil)
+
+ val bzz = brr.newBaz
+ log.check("delayedInitinitsNulldelayedInit")
+ bzz.inits.foreach(_.apply())
+ log.check("bazInitfoofooInit")
+ assert(bzz.inits == Nil)
+
+ val mew = new t4683g.MatExpWorld { }
+ val mt = new mew.T
+ assert(mt.expWorld == mew)
+}
diff --git a/test/files/run/t9920.scala b/test/files/run/t9920.scala
new file mode 100644
index 0000000000..5dc32e99b7
--- /dev/null
+++ b/test/files/run/t9920.scala
@@ -0,0 +1,17 @@
+class C0
+trait T { self: C0 =>
+ def test = {
+ object Local
+
+ class C1 {
+ Local
+ }
+ new C1()
+ }
+}
+
+object Test extends C0 with T {
+ def main(args: Array[String]): Unit = {
+ test
+ }
+}
diff --git a/test/files/run/t9920b.scala b/test/files/run/t9920b.scala
new file mode 100644
index 0000000000..fab196b669
--- /dev/null
+++ b/test/files/run/t9920b.scala
@@ -0,0 +1,17 @@
+class C0
+trait T {
+ def test = {
+ object Local
+
+ class C1 {
+ Local
+ }
+ new C1()
+ }
+}
+
+object Test extends C0 with T {
+ def main(args: Array[String]): Unit = {
+ test
+ }
+}
diff --git a/test/files/run/t9920c.scala b/test/files/run/t9920c.scala
new file mode 100644
index 0000000000..9541dc650a
--- /dev/null
+++ b/test/files/run/t9920c.scala
@@ -0,0 +1,21 @@
+class C0
+trait T { self: C0 =>
+ def test = {
+ object Local
+
+ class C2 {
+ class C1 {
+ Local
+ }
+ T.this.toString
+ new C1
+ }
+ new C2()
+ }
+}
+
+object Test extends C0 with T {
+ def main(args: Array[String]): Unit = {
+ test
+ }
+}
diff --git a/test/files/run/t9920d.scala b/test/files/run/t9920d.scala
new file mode 100644
index 0000000000..debc99e199
--- /dev/null
+++ b/test/files/run/t9920d.scala
@@ -0,0 +1,14 @@
+class C { object O }
+trait T { _: C =>
+ def foo {
+ class D { O }
+ new D
+ }
+}
+
+
+object Test extends C with T {
+ def main(args: Array[String]): Unit = {
+ foo
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
index b09a41969e..00b6d1cc42 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala
@@ -187,4 +187,12 @@ class BytecodeTest extends BytecodeTesting {
List(Label(0), LineNumber(2, Label(0)), VarOp(ALOAD, 0), Invoke(INVOKESPECIAL, "T", "t", "()V", true), Op(RETURN), Label(4))
)
}
+
+ @Test
+ def sd233(): Unit = {
+ val code = "def f = { println(1); synchronized(println(2)) }"
+ val m = compileMethod(code)
+ val List(ExceptionHandler(_, _, _, desc)) = m.handlers
+ assert(desc == None, desc)
+ }
}
diff --git a/tools/get-scala-commit-date b/tools/get-scala-commit-date
index b2e4e10770..6511ed98ca 100755
--- a/tools/get-scala-commit-date
+++ b/tools/get-scala-commit-date
@@ -10,8 +10,13 @@
[[ $# -eq 0 ]] || cd "$1"
-lastcommitdate=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 1)
-lastcommithours=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 2)
+if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
+ lastcommitdate=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 1)
+ lastcommithours=$(git log --format="%ci" HEAD | head -n 1 | cut -d ' ' -f 2)
+else
+ lastcommitdate=$(date +%Y-%m-%d)
+ lastcommithours=$(date +%H:%M:%S)
+fi
# 20120324
echo "${lastcommitdate//-/}-${lastcommithours//:/}"
diff --git a/tools/get-scala-commit-sha b/tools/get-scala-commit-sha
index eab90a4215..18289c7ca8 100755
--- a/tools/get-scala-commit-sha
+++ b/tools/get-scala-commit-sha
@@ -10,9 +10,13 @@
[[ $# -eq 0 ]] || cd "$1"
-# printf %016s is not portable for 0-padding, has to be a digit.
-# so we're stuck disassembling it.
-hash=$(git log -1 --format="%H" HEAD)
-hash=${hash#g}
-hash=${hash:0:10}
+if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
+ # printf %016s is not portable for 0-padding, has to be a digit.
+ # so we're stuck disassembling it.
+ hash=$(git log -1 --format="%H" HEAD)
+ hash=${hash#g}
+ hash=${hash:0:10}
+else
+ hash="unknown"
+fi
echo "$hash"
diff --git a/versions.properties b/versions.properties
index 773999c485..7c357f7fa7 100644
--- a/versions.properties
+++ b/versions.properties
@@ -8,7 +8,7 @@
# The scala version used for bootstrapping. This has no impact on the final classfiles:
# there are two stages (locker and quick), so compiler and library are always built
# with themselves. Stability is ensured by building a third stage (strap).
-starr.version=2.12.0-RC1-be43eb5
+starr.version=2.12.0-RC1-ceaf419
# These are the versions of the modules that go with this release.
# These properties are used during PR validation and in dbuild builds.