summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala9
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala5
-rw-r--r--src/reflect/scala/reflect/internal/tpe/TypeMaps.scala4
-rw-r--r--src/reflect/scala/reflect/internal/transform/UnCurry.scala69
-rw-r--r--src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala28
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala2
8 files changed, 103 insertions, 19 deletions
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index 78f360409d..fd8f51cfb1 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -78,4 +78,7 @@ trait StdAttachments {
case object OuterArgCanBeElided extends PlainAttachment
case object UseInvokeSpecial extends PlainAttachment
+
+ /** An attachment carrying information between uncurry and erasure */
+ case class TypeParamVarargsAttachment(val typeParamRef: Type)
}
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 56b6dc078d..5077169525 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -34,9 +34,13 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def recursionTable = _recursionTable
def recursionTable_=(value: immutable.Map[Symbol, Int]) = _recursionTable = value
+ @deprecated("Global existential IDs no longer used", "2.12.1")
private var existentialIds = 0
+ @deprecated("Global existential IDs no longer used", "2.12.1")
protected def nextExistentialId() = { existentialIds += 1; existentialIds }
- protected def freshExistentialName(suffix: String) = newTypeName("_" + nextExistentialId() + suffix)
+ @deprecated("Use overload that accepts an id", "2.12.1")
+ protected def freshExistentialName(suffix: String): TypeName = freshExistentialName(suffix, nextExistentialId())
+ protected def freshExistentialName(suffix: String, id: Int): TypeName = newTypeName("_" + id + suffix)
// Set the fields which point companions at one another. Returns the module.
def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = {
@@ -440,8 +444,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newGADTSkolem(name: TypeName, origin: Symbol, info: Type): TypeSkolem =
newTypeSkolemSymbol(name, origin, origin.pos, origin.flags & ~(EXISTENTIAL | PARAM) | GADT_SKOLEM_FLAGS) setInfo info
+ @deprecated("Use overload that accepts an id", "2.12.1")
final def freshExistential(suffix: String): TypeSymbol =
newExistential(freshExistentialName(suffix), pos)
+ final def freshExistential(suffix: String, id: Int): TypeSymbol =
+ newExistential(freshExistentialName(suffix, id), pos)
/** Type skolems are type parameters ''seen from the inside''
* Assuming a polymorphic method m[T], its type is a PolyType which has a TypeParameter
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index f8679616d1..5e1bf37b80 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -4487,6 +4487,7 @@ trait Types
debuglog(s"transposed irregular matrix!? tps=$tps argss=$argss")
NoType
case Some(argsst) =>
+ var capturedParamIds = 0
val args = map2(sym.typeParams, argsst) { (tparam, as0) =>
val as = as0.distinct
if (as.size == 1) as.head
@@ -4508,8 +4509,10 @@ trait Types
else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
// just err on the conservative side, i.e. with a bound that is too high.
// if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251
+ capturedParamIds += 1
+ val capturedParamId = capturedParamIds
- val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
+ val qvar = commonOwner(as).freshExistential("", capturedParamId) setInfo TypeBounds(g, l)
capturedParams += qvar
qvar.tpe
}
diff --git a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
index ba4f2bec4b..08219c0634 100644
--- a/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
+++ b/src/reflect/scala/reflect/internal/tpe/TypeMaps.scala
@@ -512,6 +512,8 @@ private[internal] trait TypeMaps {
&& isBaseClassOfEnclosingClass(sym.owner)
)
+ private var capturedThisIds= 0
+ private def nextCapturedThisId() = { capturedThisIds += 1; capturedThisIds }
/** Creates an existential representing a type parameter which appears
* in the prefix of a ThisType.
*/
@@ -519,7 +521,7 @@ private[internal] trait TypeMaps {
capturedParams find (_.owner == clazz) match {
case Some(p) => p.tpe
case _ =>
- val qvar = clazz freshExistential nme.SINGLETON_SUFFIX setInfo singletonBounds(pre)
+ val qvar = clazz.freshExistential(nme.SINGLETON_SUFFIX, nextCapturedThisId()) setInfo singletonBounds(pre)
_capturedParams ::= qvar
debuglog(s"Captured This(${clazz.fullNameString}) seen from $seenFromPrefix: ${qvar.defString}")
qvar.tpe
diff --git a/src/reflect/scala/reflect/internal/transform/UnCurry.scala b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
index a50084f40d..3918723b5c 100644
--- a/src/reflect/scala/reflect/internal/transform/UnCurry.scala
+++ b/src/reflect/scala/reflect/internal/transform/UnCurry.scala
@@ -4,6 +4,7 @@ package internal
package transform
import Flags._
+import scala.collection.mutable
trait UnCurry {
@@ -11,6 +12,12 @@ trait UnCurry {
import global._
import definitions._
+ /**
+ * The synthetic Java vararg method symbol corresponding to a Scala vararg method
+ * annotated with @varargs.
+ */
+ case class VarargsSymbolAttachment(varargMethod: Symbol)
+
/** Note: changing tp.normalize to tp.dealias in this method leads to a single
* test failure: run/t5688.scala, where instead of the expected output
* Vector(ta, tb, tab)
@@ -65,18 +72,74 @@ trait UnCurry {
def apply(tp0: Type): Type = {
val tp = expandAlias(tp0)
tp match {
- case ClassInfoType(parents, decls, clazz) =>
+ case ClassInfoType(parents, decls, clazz) if !clazz.isJavaDefined =>
val parents1 = parents mapConserve uncurry
- if (parents1 eq parents) tp
- else ClassInfoType(parents1, decls, clazz) // @MAT normalize in decls??
+ val varargOverloads = mutable.ListBuffer.empty[Symbol]
+
+ // Not using `hasAnnotation` here because of dreaded cyclic reference errors:
+ // it may happen that VarargsClass has not been initialized yet and we get here
+ // while processing one of its superclasses (such as java.lang.Object). Since we
+ // don't need the more precise `matches` semantics, we only check the symbol, which
+ // is anyway faster and safer
+ for (decl <- decls if decl.annotations.exists(_.symbol == VarargsClass)) {
+ if (mexists(decl.paramss)(sym => definitions.isRepeatedParamType(sym.tpe))) {
+ varargOverloads += varargForwarderSym(clazz, decl, exitingPhase(phase)(decl.info))
+ }
+ }
+ if ((parents1 eq parents) && varargOverloads.isEmpty) tp
+ else {
+ val newDecls = decls.cloneScope
+ varargOverloads.foreach(newDecls.enter)
+ ClassInfoType(parents1, newDecls, clazz)
+ } // @MAT normalize in decls??
+
case PolyType(_, _) =>
mapOver(tp)
+
case _ =>
tp
}
}
}
+ private def varargForwarderSym(currentClass: Symbol, origSym: Symbol, newInfo: Type): Symbol = {
+ val forwSym = origSym.cloneSymbol(currentClass, VARARGS | SYNTHETIC | origSym.flags & ~DEFERRED, origSym.name.toTermName).withoutAnnotations
+
+ // we are using `origSym.info`, which contains the type *before* the transformation
+ // so we still see repeated parameter types (uncurry replaces them with Seq)
+ val isRepeated = origSym.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe))
+ val oldPs = newInfo.paramss.head
+ def toArrayType(tp: Type, newParam: Symbol): Type = {
+ val arg = elementType(SeqClass, tp)
+ val elem = if (arg.typeSymbol.isTypeParameterOrSkolem && !(arg <:< AnyRefTpe)) {
+ // To prevent generation of an `Object` parameter from `Array[T]` parameter later
+ // as this would crash the Java compiler which expects an `Object[]` array for varargs
+ // e.g. def foo[T](a: Int, b: T*)
+ // becomes def foo[T](a: Int, b: Array[Object])
+ // instead of def foo[T](a: Int, b: Array[T]) ===> def foo[T](a: Int, b: Object)
+ //
+ // In order for the forwarder method to type check we need to insert a cast:
+ // def foo'[T'](a: Int, b: Array[Object]) = foo[T'](a, wrapRefArray(b).asInstanceOf[Seq[T']])
+ // The target element type for that cast (T') is stored in the TypeParamVarargsAttachment
+// val originalArg = arg.substSym(oldTps, tps)
+ // Store the type parameter that was replaced by Object to emit the correct generic signature
+ newParam.updateAttachment(new TypeParamVarargsAttachment(arg))
+ ObjectTpe
+ } else
+ arg
+ arrayType(elem)
+ }
+
+ foreach2(forwSym.paramss.flatten, isRepeated)((p, isRep) =>
+ if (isRep) {
+ p.setInfo(toArrayType(p.info, p))
+ }
+ )
+
+ origSym.updateAttachment(VarargsSymbolAttachment(forwSym))
+ forwSym
+ }
+
/** - return symbol's transformed type,
* - if symbol is a def parameter with transformed type T, return () => T
*
diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
index b5030460b8..3cede1b3c5 100644
--- a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
+++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala
@@ -12,6 +12,20 @@ import java.security.cert.Certificate
import java.security.{ ProtectionDomain, CodeSource }
import java.util.{ Collections => JCollections, Enumeration => JEnumeration }
+object AbstractFileClassLoader {
+ // should be a method on AbstractFile, but adding in `internal.util._` for now as we're in a minor release
+ private[scala] final def lookupPath(base: AbstractFile)(pathParts: Seq[String], directory: Boolean): AbstractFile = {
+ var file: AbstractFile = base
+ for (dirPart <- pathParts.init) {
+ file = file.lookupName(dirPart, directory = true)
+ if (file == null)
+ return null
+ }
+
+ file.lookupName(pathParts.last, directory = directory)
+ }
+}
+
/** A class loader that loads files from a [[scala.reflect.io.AbstractFile]].
*
* @author Lex Spoon
@@ -25,19 +39,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader)
else s"${name.replace('.', '/')}.class"
protected def findAbstractFile(name: String): AbstractFile = {
- var file: AbstractFile = root
- val pathParts = name split '/'
-
- for (dirPart <- pathParts.init) {
- file = file.lookupName(dirPart, directory = true)
- if (file == null)
- return null
- }
-
- file.lookupName(pathParts.last, directory = false) match {
- case null => null
- case file => file
- }
+ AbstractFileClassLoader.lookupPath(root)(name split '/', directory = false)
}
protected def dirNameToPath(name: String): String =
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index b74ccb9177..dbafbfc6ba 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -47,6 +47,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.InlineCallsiteAttachment
this.OuterArgCanBeElided
this.UseInvokeSpecial
+ this.TypeParamVarargsAttachment
this.noPrint
this.typeDebug
this.Range
@@ -458,6 +459,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.ScalaValueClassesNoUnit
definitions.ScalaValueClasses
+ uncurry.VarargsSymbolAttachment
uncurry.DesugaredParameterType
erasure.GenericArray
erasure.scalaErasure
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
index 237afa082b..4e7ddda54e 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala
@@ -10,7 +10,9 @@ private[reflect] trait SynchronizedSymbols extends internal.Symbols { self: Symb
private lazy val atomicIds = new java.util.concurrent.atomic.AtomicInteger(0)
override protected def nextId() = atomicIds.incrementAndGet()
+ @deprecated("Global existential IDs no longer used", "2.12.1")
private lazy val atomicExistentialIds = new java.util.concurrent.atomic.AtomicInteger(0)
+ @deprecated("Global existential IDs no longer used", "2.12.1")
override protected def nextExistentialId() = atomicExistentialIds.incrementAndGet()
private lazy val _recursionTable = mkThreadLocalStorage(immutable.Map.empty[Symbol, Int])