Skip to content

Commit

Permalink
Merge pull request #9206 from dwijnand/merge-2.12.x-into-2.13.x
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Sep 18, 2020
2 parents 431994b + ad19d1a commit e11c86b
Show file tree
Hide file tree
Showing 32 changed files with 461 additions and 213 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -1349,7 +1349,8 @@ lazy val root: Project = (project in file("."))
.aggregate(library, reflect, compiler, interactive, repl, replFrontend,
scaladoc, scalap, testkit, partest, junit, scalaDist).settings(
Compile / sources := Seq.empty,
onLoadMessage := """|*** Welcome to the sbt build definition for Scala! ***
onLoadMessage := s"""|*** Welcome to the sbt build definition for Scala! ***
|version=${(Global / version).value} scalaVersion=${(Global / scalaVersion).value}
|Check README.md for more information.""".stripMargin
)

Expand Down
33 changes: 32 additions & 1 deletion project/ScriptCommands.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import java.nio.file.Paths

import sbt._
import Keys._
import sbt.complete.Parsers._

import BuildSettings.autoImport._
import VersionUtil._

/** Custom commands for use by the Jenkins scripts. This keeps the surface area and call syntax small. */
object ScriptCommands {
Expand All @@ -16,7 +18,8 @@ object ScriptCommands {
setupPublishCore,
setupValidateTest,
setupBootstrapStarr, setupBootstrapLocker, setupBootstrapQuick, setupBootstrapPublish,
enableOptimizerCommand
enableOptimizerCommand,
restarr, restarrFull,
)

/** Set up the environment for `validate/publish-core`.
Expand Down Expand Up @@ -110,6 +113,34 @@ object ScriptCommands {

def enableOptimizerCommand = setup("enableOptimizer")(_ => enableOptimizer)

/** For local dev: sets `scalaVersion` to the version in `/buildcharacter.properties` or the given arg.
* Running `reload` will re-read the build files, resetting `scalaVersion`. */
def restarr = Command("restarr")(_ => (Space ~> StringBasic).?) { (state, s) =>
val newVersion = s.getOrElse(readVersionFromPropsFile(state))
val x = Project.extract(state)
val sv = x.get(Global / scalaVersion)
state.log.info(s"Re-STARR'ing: setting scalaVersion from $sv to $newVersion (`reload` to undo)")
x.appendWithSession(Global / scalaVersion := newVersion, state) // don't use version.value or it'll be a wrong, new value
}

/** For local dev: publishes locally (without optimizing) & then sets the new `scalaVersion`.
* Also it generates `/buildcharacter.properties` which is the default used by `restarr`. */
def restarrFull = Command.command("restarrFull") { state =>
setupPublishCoreNonOpt.nameOption.get ::
generateBuildCharacterPropertiesFile.key.label ::
publishLocal.key.label ::
restarr.nameOption.get ::
state
}

private def readVersionFromPropsFile(state: State): String = {
val props = readProps(file("buildcharacter.properties"))
val newVersion = props("maven.version.number")
val fullVersion = props("version.number")
state.log.info(s"Read STARR version from buildcharacter.properties: $newVersion (full version: $fullVersion)")
newVersion
}

private[this] def setup(name: String)(f: Seq[String] => Seq[Setting[_]]) = Command.args(name, name) { case (state, seq) =>
Project.extract(state).appendWithSession(f(seq), state)
}
Expand Down
15 changes: 9 additions & 6 deletions project/VersionUtil.scala
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,17 @@ object VersionUtil {
propFile
}

/** The global versions.properties data */
lazy val versionProps: Map[String, String] = {
private[build] def readProps(f: File): Map[String, String] = {
val props = new Properties()
val in = new FileInputStream(file("versions.properties"))
val in = new FileInputStream(f)
try props.load(in)
finally in.close()
props.asScala.toMap.map {
case (k, v) => (k, sys.props.getOrElse(k, v)) // allow system properties to override versions.properties
}
props.asScala.toMap
}

/** The global versions.properties data */
lazy val versionProps: Map[String, String] = {
val versionProps = readProps(file("versions.properties"))
versionProps.map { case (k, v) => (k, sys.props.getOrElse(k, v)) } // allow sys props to override versions.properties
}
}
14 changes: 8 additions & 6 deletions src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -676,15 +676,16 @@ abstract class BTypes {
}

def innerClassAttributeEntry: Either[NoClassBTypeInfo, Option[InnerClassEntry]] = info.map(i => i.nestedInfo.force map {
case NestedInfo(_, outerName, innerName, isStaticNestedClass) =>
case NestedInfo(_, outerName, innerName, isStaticNestedClass, enteringTyperPrivate) =>
// the static flag in the InnerClass table has a special meaning, see InnerClass comment
def adjustStatic(flags: Int): Int = ( flags & ~Opcodes.ACC_STATIC |
(if (isStaticNestedClass) Opcodes.ACC_STATIC else 0)
) & BCodeHelpers.INNER_CLASSES_FLAGS
InnerClassEntry(
internalName,
outerName.orNull,
innerName.orNull,
// the static flag in the InnerClass table has a special meaning, see InnerClass comment
( i.flags & ~Opcodes.ACC_STATIC |
(if (isStaticNestedClass) Opcodes.ACC_STATIC else 0)
) & BCodeHelpers.INNER_CLASSES_FLAGS
flags = adjustStatic(if (enteringTyperPrivate) (i.flags & ~Opcodes.ACC_PUBLIC) | Opcodes.ACC_PRIVATE else i.flags)
)
})

Expand Down Expand Up @@ -876,7 +877,8 @@ abstract class BTypes {
final case class NestedInfo(enclosingClass: ClassBType,
outerName: Option[String],
innerName: Option[String],
isStaticNestedClass: Boolean)
isStaticNestedClass: Boolean,
enteringTyperPrivate: Boolean)

/**
* This class holds the data for an entry in the InnerClass table. See the InnerClass summary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ abstract class BTypesFromClassfile {
classBTypeFromParsedClassfile(classNode.outerClass)
}
val staticFlag = (innerEntry.access & Opcodes.ACC_STATIC) != 0
NestedInfo(enclosingClass, Option(innerEntry.outerName), Option(innerEntry.innerName), staticFlag)
NestedInfo(enclosingClass, Option(innerEntry.outerName), Option(innerEntry.innerName), staticFlag,
(flags & Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE)
}

val inlineInfo = inlineInfoFromClassfile(classNode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ abstract class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
else Some(s"${innerClassSym.rawname}${innerClassSym.moduleSuffix}") // moduleSuffix for module classes
}

Some(NestedInfo(enclosingClass, outerName, innerName, isStaticNestedClass))
Some(NestedInfo(enclosingClass, outerName, innerName, isStaticNestedClass, enteringTyper(innerClassSym.isPrivate)))
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/backend/jvm/PostProcessor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ abstract class PostProcessor extends PerRunInit {

def setInnerClasses(classNode: ClassNode): Unit = {
classNode.innerClasses.clear()
backendUtils.addInnerClasses(classNode, backendUtils.collectNestedClasses(classNode))
val (declared, referred) = backendUtils.collectNestedClasses(classNode)
backendUtils.addInnerClasses(classNode, declared, referred)
}

def serializeClass(classNode: ClassNode): Array[Byte] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,12 @@ abstract class BackendUtils extends PerRunInit {
}
/**
* Visit the class node and collect all referenced nested classes.
* @return (declaredInnerClasses, referredInnerClasses)
*/
def collectNestedClasses(classNode: ClassNode): List[ClassBType] = {
def collectNestedClasses(classNode: ClassNode): (List[ClassBType], List[ClassBType]) = {
val c = new Collector
c.visit(classNode)
c.innerClasses.toList
(c.declaredInnerClasses.toList, c.referredInnerClasses.toList)
}

/*
Expand All @@ -432,11 +433,13 @@ abstract class BackendUtils extends PerRunInit {
*
* can-multi-thread
*/
final def addInnerClasses(jclass: asm.ClassVisitor, refedInnerClasses: List[ClassBType]): Unit = {
val allNestedClasses = refedInnerClasses.flatMap(_.enclosingNestedClassesChain.get).distinct

final def addInnerClasses(jclass: asm.tree.ClassNode, declaredInnerClasses: List[ClassBType], refedInnerClasses: List[ClassBType]): Unit = {
// sorting ensures nested classes are listed after their enclosing class thus satisfying the Eclipse Java compiler
for (nestedClass <- allNestedClasses.sortBy(_.internalName.toString)) {
val allNestedClasses = new mutable.TreeSet[ClassBType]()(Ordering.by(_.internalName))
allNestedClasses ++= declaredInnerClasses
refedInnerClasses.foreach(_.enclosingNestedClassesChain.get.foreach(allNestedClasses += _))

for (nestedClass <- allNestedClasses) {
// Extract the innerClassEntry - we know it exists, enclosingNestedClassesChain only returns nested classes.
val Some(e) = nestedClass.innerClassAttributeEntry.get
jclass.visitInnerClass(e.name, e.outerName, e.innerName, e.flags)
Expand Down Expand Up @@ -783,15 +786,23 @@ object BackendUtils {
}

abstract class NestedClassesCollector[T](nestedOnly: Boolean) extends GenericSignatureVisitor(nestedOnly) {
val innerClasses = mutable.Set.empty[T]

val declaredInnerClasses = mutable.Set.empty[T]
val referredInnerClasses = mutable.Set.empty[T]

def innerClasses: collection.Set[T] = declaredInnerClasses ++ referredInnerClasses
def clear(): Unit = {
declaredInnerClasses.clear()
referredInnerClasses.clear()
}

def declaredNestedClasses(internalName: InternalName): List[T]

def getClassIfNested(internalName: InternalName): Option[T]

def visit(classNode: ClassNode): Unit = {
visitInternalName(classNode.name)
innerClasses ++= declaredNestedClasses(classNode.name)
declaredInnerClasses ++= declaredNestedClasses(classNode.name)

visitInternalName(classNode.superName)
classNode.interfaces.asScala foreach visitInternalName
Expand Down Expand Up @@ -850,7 +861,8 @@ object BackendUtils {

def visitInternalName(internalName: String, offset: Int, length: Int): Unit = if (internalName != null && containsChar(internalName, offset, length, '$')) {
for (c <- getClassIfNested(internalName.substring(offset, length)))
innerClasses += c
if (!declaredInnerClasses.contains(c))
referredInnerClasses += c
}

// either an internal/Name or [[Linternal/Name; -- there are certain references in classfiles
Expand Down
139 changes: 49 additions & 90 deletions src/compiler/scala/tools/nsc/javac/JavaParsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -383,100 +383,61 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
* ElementValueList ::= ElementValue {`,` ElementValue}
*/
def annotation(): Tree = {
def annArg(): Tree = {
def elementValue(): Tree = {
tryLiteral() match {
case Some(lit) => atPos(in.currentPos)(Literal(lit))
case _ if in.token == AT =>
in.nextToken()
annotation()
case _ if in.token == LBRACE =>
atPos(in.pos) {
in.nextToken()
val ts = new ListBuffer[Tree]
if (in.token == RBRACE)
Apply(ArrayModule_overloadedApply)
else {
var bailout = false
elementValue() match {
case EmptyTree => bailout = true
case t => ts += t
}
while (in.token == COMMA && !bailout) {
in.nextToken()
if (in.token == RBRACE) {
// trailing comma
} else {
elementValue() match {
case EmptyTree => bailout = true
case t => ts += t
}
}
}
if (!bailout && in.token != RBRACE) {
bailout = true
}
if (bailout) {
var braceDepth = 1
while (braceDepth > 0) {
in.nextToken()
in.token match {
case LBRACE => braceDepth += 1
case RBRACE => braceDepth -= 1
case _ =>
}
}
EmptyTree
} else {
accept(RBRACE)
Apply(ArrayModule_overloadedApply, ts.toList: _*)
}
}
}
case _ if in.token == IDENTIFIER =>
qualId(orClassLiteral = true)
case _ =>
in.nextToken()
EmptyTree
}
object LiteralK { def unapply(token: Token) = tryLiteral() }

def elementValue(): Tree = in.token match {
case LiteralK(k) => in.nextToken(); atPos(in.currentPos)(Literal(k))
case IDENTIFIER => qualId(orClassLiteral = true)
case LBRACE => accept(LBRACE); elementArray()
case AT => accept(AT); annotation()
case _ => in.nextToken(); EmptyTree
}

def elementArray(): Tree = atPos(in.pos) {
val ts = new ListBuffer[Tree]
while (in.token != RBRACE) {
ts += elementValue()
if (in.token == COMMA) in.nextToken() // done this way trailing commas are supported
}
val ok = !ts.contains(EmptyTree)
in.token match {
case RBRACE if ok => accept(RBRACE); Apply(ArrayModule_overloadedApply, ts.toList: _*)
case _ => skipTo(RBRACE); EmptyTree
}
}

if (in.token == IDENTIFIER) {
qualId(orClassLiteral = true) match {
case name: Ident if in.token == EQUALS =>
in.nextToken()
/* name = value */
val value = elementValue()
if (value.isEmpty) EmptyTree else gen.mkNamedArg(name, value)
case rhs =>
/* implicit `value` arg with constant value */
gen.mkNamedArg(nme.value, rhs)
// 1) name = value
// 2) implicit `value` arg with constant value
// 3) implicit `value` arg
def annArg(): Tree = {
def mkNamedArg(name: Ident, value: Tree) = if (value.isEmpty) EmptyTree else gen.mkNamedArg(name, value)
in.token match {
case IDENTIFIER => qualId(orClassLiteral = true) match {
case name: Ident if in.token == EQUALS => accept(EQUALS); mkNamedArg(name, elementValue())
case rhs => mkNamedArg(Ident(nme.value), rhs)
}
} else {
/* implicit `value` arg */
val value = elementValue()
if (value.isEmpty) EmptyTree else gen.mkNamedArg(nme.value, value)
case _ => mkNamedArg(Ident(nme.value), elementValue())
}
}

atPos(in.pos) {
val id = convertToTypeId(qualId())
if (in.token == LPAREN) {
val saved = new JavaTokenData {}.copyFrom(in) // prep to bail if non-literals/identifiers
accept(LPAREN)
val args =
if (in.token == RPAREN) Nil
else commaSeparated(atPos(in.pos)(annArg()))
if (in.token == RPAREN) {
accept(RPAREN)
New(id, args :: Nil)
} else {
in.copyFrom(saved)
skipAhead()
accept(RPAREN)
EmptyTree
}
} else New(id, ListOfNil)
in.token match {
case LPAREN =>
// TODO: fix copyFrom+skipAhead; CharArrayReaderData missing
val saved = new JavaTokenData {}.copyFrom(in) // prep to bail if non-literals/identifiers
accept(LPAREN)
val args = in.token match {
case RPAREN => Nil
case _ => commaSeparated(atPos(in.pos)(annArg()))
}
val ok = !args.contains(EmptyTree)
in.token match {
case RPAREN if ok => accept(RPAREN); New(id, List(args))
case _ => in.copyFrom(saved); skipAhead(); accept(RPAREN); EmptyTree
}
case _ => New(id, ListOfNil)
}
}
}

Expand Down Expand Up @@ -720,6 +681,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
def constantTpe(const: Constant): Tree = TypeTree(ConstantType(const))

def forConst(const: Constant): Tree = {
in.nextToken()
if (in.token != SEMI) tpt1
else {
def isStringTyped = tpt1 match {
Expand Down Expand Up @@ -1015,10 +977,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
case _ => null
}
if (l == null) None
else {
in.nextToken()
Some(Constant(l))
}
else Some(Constant(l))
}

/** CompilationUnit ::= [package QualId semi] TopStatSeq
Expand Down

0 comments on commit e11c86b

Please sign in to comment.