Merge pull request #9308 from lrytz/merge-2.12-to-2.13-nov-9
This commit is contained in:
commit
a8d3741fb7
|
@ -365,6 +365,13 @@ val mimaFilterSettings = Seq {
|
|||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.removeElement"),
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.addElement"),
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.macros.Attachments.containsElement"),
|
||||
// https://github.com/scala/scala/pull/7960: these only cause problems if someone is implausibly extending Attachments somehow
|
||||
ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.reflect.macros.Attachments.all"),
|
||||
ProblemFilters.exclude[ReversedAbstractMethodProblem]("scala.reflect.macros.Attachments.all"),
|
||||
ProblemFilters.exclude[DirectAbstractMethodProblem]("scala.reflect.macros.Attachments.isEmpty"),
|
||||
ProblemFilters.exclude[ReversedAbstractMethodProblem]("scala.reflect.macros.Attachments.isEmpty"),
|
||||
ProblemFilters.exclude[MissingClassProblem]("scala.reflect.macros.EmptyAttachments"),
|
||||
ProblemFilters.exclude[MissingClassProblem]("scala.reflect.macros.SingleAttachment"),
|
||||
|
||||
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.Settings.async"),
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import Flags._
|
|||
import scala.annotation.tailrec
|
||||
import scala.collection.mutable
|
||||
import scala.reflect.NameTransformer
|
||||
import scala.reflect.internal.util.ListOfNil
|
||||
|
||||
|
||||
abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
|
||||
|
@ -322,7 +323,11 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis {
|
|||
JUnitAnnotations.exists(annot => annot.exists && member.hasAnnotation(annot))
|
||||
}
|
||||
|
||||
if (existsCompetingMethod(clazz.baseClasses) || generateJUnitForwarder)
|
||||
def generateSerializationForwarder: Boolean = {
|
||||
(member.name == nme.readResolve || member.name == nme.writeReplace) && member.info.paramss == ListOfNil
|
||||
}
|
||||
|
||||
if (existsCompetingMethod(clazz.baseClasses) || generateJUnitForwarder || generateSerializationForwarder)
|
||||
genForwarder(required = true)
|
||||
else if (settings.mixinForwarderChoices.isTruthy)
|
||||
genForwarder(required = false)
|
||||
|
|
|
@ -14,7 +14,7 @@ package scala.tools.nsc.transform.async
|
|||
|
||||
import scala.collection.mutable
|
||||
import scala.tools.nsc.transform.{Transform, TypingTransformers}
|
||||
import scala.reflect.internal.util.SourceFile
|
||||
import scala.reflect.internal.util.{SourceFile, NoSourceFile}
|
||||
|
||||
abstract class AsyncPhase extends Transform with TypingTransformers with AnfTransform with Lifter with LiveVariables {
|
||||
self =>
|
||||
|
@ -75,7 +75,9 @@ abstract class AsyncPhase extends Transform with TypingTransformers with AnfTran
|
|||
|
||||
override def transformUnit(unit: CompilationUnit): Unit = {
|
||||
if (settings.async) {
|
||||
if (sourceFilesToTransform.contains(unit.source)) super.transformUnit(unit)
|
||||
// NoSourceFile can happen for, e.g., toolbox compilation; overestimate by always transforming them. See test/async/jvm/toolbox.scala
|
||||
val shouldTransform = unit.source == NoSourceFile || sourceFilesToTransform.contains(unit.source)
|
||||
if (shouldTransform) super.transformUnit(unit)
|
||||
if (awaits.exists(_.isInitialized)) {
|
||||
unit.body.foreach {
|
||||
case tree: RefTree if tree.symbol != null && awaits.contains(tree.symbol) =>
|
||||
|
|
|
@ -16,7 +16,7 @@ package internal
|
|||
package util
|
||||
|
||||
/** @inheritdoc */
|
||||
class Position extends scala.reflect.api.Position with InternalPositionImpl with DeprecatedPosition {
|
||||
class Position extends macros.EmptyAttachments with api.Position with InternalPositionImpl with DeprecatedPosition {
|
||||
type Pos = Position
|
||||
def pos: Position = this
|
||||
def withPos(newPos: Position): macros.Attachments { type Pos = Position.this.Pos } = newPos
|
||||
|
|
|
@ -14,6 +14,8 @@ package scala
|
|||
package reflect
|
||||
package macros
|
||||
|
||||
import reflect.internal.util.Position
|
||||
|
||||
/**
|
||||
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
|
||||
*
|
||||
|
@ -35,7 +37,7 @@ package macros
|
|||
abstract class Attachments { self =>
|
||||
|
||||
/** The position type of this attachment */
|
||||
type Pos >: Null
|
||||
type Pos >: Null // <: api.Position
|
||||
|
||||
/** The underlying position */
|
||||
def pos: Pos
|
||||
|
@ -44,7 +46,7 @@ abstract class Attachments { self =>
|
|||
def withPos(newPos: Pos): Attachments { type Pos = self.Pos }
|
||||
|
||||
/** The underlying payload with the guarantee that no two elements have the same type. */
|
||||
def all: Set[Any] = Set.empty
|
||||
def all: Set[Any]
|
||||
|
||||
private def matchesTag[T: ClassTag]: (Any => Boolean) = {
|
||||
// OPT: avoid lambda allocation for each call to `remove`, etc.
|
||||
|
@ -78,6 +80,7 @@ abstract class Attachments { self =>
|
|||
else {
|
||||
val newAll = all filterNot matchesTag[T]
|
||||
if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }]
|
||||
else if (newAll.size == 1) new SingleAttachment[Pos](pos, newAll.head)
|
||||
else new NonemptyAttachments[Pos](this.pos, newAll)
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +91,11 @@ abstract class Attachments { self =>
|
|||
else if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }]
|
||||
else new NonemptyAttachments[Pos](this.pos, newAll)
|
||||
}
|
||||
|
||||
/** Creates a copy of this attachment with the given element added. */
|
||||
final def addElement[T](attachment: T): Attachments { type Pos = self.Pos } = {
|
||||
val newAll = all + attachment
|
||||
if (newAll eq all) this
|
||||
if (newAll eq all) this // i.e., this was the same attachment as before
|
||||
else new NonemptyAttachments[Pos](this.pos, newAll)
|
||||
}
|
||||
|
||||
|
@ -100,7 +104,7 @@ abstract class Attachments { self =>
|
|||
all.contains(element)
|
||||
}
|
||||
|
||||
def isEmpty: Boolean = true
|
||||
def isEmpty: Boolean
|
||||
def cloneAttachments: Attachments { type Pos = self.Pos } = this
|
||||
}
|
||||
|
||||
|
@ -110,6 +114,31 @@ private object Attachments {
|
|||
}
|
||||
}
|
||||
|
||||
private[reflect] abstract class EmptyAttachments extends Attachments { self: Position =>
|
||||
final override def all: Set[Any] = Set.empty
|
||||
final override def get[T: ClassTag]: Option[T] = None
|
||||
final override def contains[T: ClassTag]: Boolean = false
|
||||
final override def update[T: ClassTag](newAtt: T): Attachments { type Pos = self.Pos } =
|
||||
new SingleAttachment[Pos](pos, newAtt)
|
||||
final override def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = this
|
||||
final override def isEmpty: Boolean = true
|
||||
}
|
||||
|
||||
private final class SingleAttachment[P >: Null](override val pos: P, val att: Any) extends Attachments {
|
||||
type Pos = P
|
||||
def withPos(newPos: Pos) = new SingleAttachment[Pos](newPos, att)
|
||||
override def isEmpty: Boolean = false
|
||||
override def cloneAttachments: Attachments { type Pos = P } = new SingleAttachment[P](pos, att)
|
||||
override def all = Set.empty[Any] + att
|
||||
override def contains[T](implicit tt: ClassTag[T]) = tt.runtimeClass.isInstance(att)
|
||||
override def get[T](implicit tt: ClassTag[T]) = if (contains(tt)) Some(att.asInstanceOf[T]) else None
|
||||
override def update[T](newAtt: T)(implicit tt: ClassTag[T]) =
|
||||
if (contains(tt)) new SingleAttachment[P](pos, newAtt)
|
||||
else new NonemptyAttachments[P](pos, Set.empty[Any] + att + newAtt)
|
||||
override def remove[T](implicit tt: ClassTag[T]) =
|
||||
if (contains(tt)) pos.asInstanceOf[Attachments { type Pos = P }] else this
|
||||
}
|
||||
|
||||
// scala/bug#7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the
|
||||
// IDE via $outer pointers.
|
||||
private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import scala.tools.reflect._
|
||||
import scala.reflect.runtime._
|
||||
object Test extends App {
|
||||
val box = currentMirror.mkToolBox(options = "-Xasync")
|
||||
|
||||
val code =
|
||||
"""
|
||||
import scala.concurrent._, scala.concurrent.duration._, ExecutionContext.Implicits._
|
||||
import scala.tools.testkit.async._
|
||||
val f1 = Future(1)
|
||||
val f2 = Future(2)
|
||||
val res = Async.async { Async.await(f1) + Async.await(f2) }
|
||||
Await.result(res, 1.second)
|
||||
""".stripMargin
|
||||
assert(box.eval(box.parse(code)) == 3)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// scalac: -Xmixin-force-forwarders:false
|
||||
|
||||
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}
|
||||
|
||||
trait T1 extends Serializable {
|
||||
def writeReplace(): AnyRef = new SerializationProxy(this.asInstanceOf[C].s)
|
||||
}
|
||||
trait T2 {
|
||||
def readResolve: AnyRef = new C(this.asInstanceOf[SerializationProxy].s.toLowerCase)
|
||||
}
|
||||
class C(val s: String) extends T1
|
||||
class SerializationProxy(val s: String) extends T2 with Serializable
|
||||
|
||||
object Test {
|
||||
def serializeDeserialize[T <: AnyRef](obj: T) = {
|
||||
val buffer = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(buffer)
|
||||
out.writeObject(obj)
|
||||
val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray))
|
||||
in.readObject.asInstanceOf[T]
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val c1 = new C("TEXT")
|
||||
val c2 = serializeDeserialize(c1)
|
||||
assert(c2.s == "text")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}
|
||||
|
||||
trait T1 extends Serializable {
|
||||
def writeReplace(): AnyRef = new SerializationProxy(this.asInstanceOf[C].s)
|
||||
}
|
||||
trait T2 {
|
||||
def readResolve: AnyRef = new C(this.asInstanceOf[SerializationProxy].s.toLowerCase)
|
||||
}
|
||||
class C(val s: String) extends T1
|
||||
class SerializationProxy(val s: String) extends T2 with Serializable
|
||||
|
||||
object Test {
|
||||
def serializeDeserialize[T <: AnyRef](obj: T) = {
|
||||
val buffer = new ByteArrayOutputStream
|
||||
val out = new ObjectOutputStream(buffer)
|
||||
out.writeObject(obj)
|
||||
val in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray))
|
||||
in.readObject.asInstanceOf[T]
|
||||
}
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val c1 = new C("TEXT")
|
||||
val c2 = serializeDeserialize(c1)
|
||||
assert(c2.s == "text")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package scala.reflect.macros
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
|
||||
import scala.reflect.internal.util._
|
||||
|
||||
@RunWith(classOf[JUnit4])
|
||||
class AttachmentsTest {
|
||||
def emptyAtt: Attachments = NoPosition
|
||||
|
||||
@Test def testAttachments = {
|
||||
var atts = emptyAtt
|
||||
|
||||
assert(atts.isEmpty)
|
||||
assert(atts.all.isEmpty)
|
||||
|
||||
atts = atts update Foo(0)
|
||||
assert(!atts.isEmpty)
|
||||
assert(atts.all == Set(Foo(0)))
|
||||
assert(atts.contains[Foo])
|
||||
assert(atts.get[Foo] == Some(Foo(0)))
|
||||
|
||||
atts = atts.remove[Bar]
|
||||
assert(!atts.isEmpty)
|
||||
assert(atts.all == Set(Foo(0)))
|
||||
assert(atts.contains[Foo])
|
||||
assert(atts.get[Foo] == Some(Foo(0)))
|
||||
|
||||
object theBar extends Bar
|
||||
atts = atts.update(theBar)
|
||||
assert(!atts.isEmpty)
|
||||
assert(atts.all == Set(Foo(0), theBar))
|
||||
assert(atts.get[Foo] == Some(Foo(0)))
|
||||
assert(atts.get[Bar] == Some(theBar))
|
||||
assert(atts.get[theBar.type] == Some(theBar))
|
||||
|
||||
atts = atts.update(new Baz)
|
||||
assert(!atts.isEmpty)
|
||||
assert(!(atts.all contains Foo(0)))
|
||||
assert(atts.all.exists(_.isInstanceOf[Baz]))
|
||||
assert(atts.get[Baz].isDefined)
|
||||
assert(atts.get[Foo].isEmpty)
|
||||
assert(atts.get[Bar].isDefined)
|
||||
|
||||
atts = atts.update("foo")
|
||||
atts = atts.update(Zzy)
|
||||
assert(!atts.isEmpty)
|
||||
assert(atts.all.size == 4, atts.toString)
|
||||
assert(atts.contains[String])
|
||||
assert(atts.contains[Zzy.type])
|
||||
assert(atts.contains[Baz])
|
||||
assert(atts.contains[theBar.type])
|
||||
|
||||
atts = atts.remove[Zzy.type].remove[String]
|
||||
assert(atts.all.size == 2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case class Foo(i: Int) extends Baz
|
||||
class Bar
|
||||
class Baz
|
||||
object Zzy
|
Loading…
Reference in New Issue