diff options
Diffstat (limited to 'src')
209 files changed, 2148 insertions, 1788 deletions
diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml index fe99e956d9..2e490163e0 100644 --- a/src/build/maven/maven-deploy.xml +++ b/src/build/maven/maven-deploy.xml @@ -129,7 +129,7 @@ <artifact:pom refid="@{name}.pom" /> <artifact:remoteRepository url="@{repository}" id="${repository.credentials.id}" /> <artifact:attach type="jar" file="@{name}/@{name}-src.jar" classifier="sources" /> - <artifact:attach type="jar" file="@{name}/@{name}-doc.jar" classifier="javadoc" /> + <artifact:attach type="jar" file="@{name}/@{name}-docs.jar" classifier="javadoc" /> <extra-attachments /> </artifact:deploy> </sequential> diff --git a/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala b/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala index 9e5c93753f..3753a45133 100644 --- a/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala +++ b/src/compiler/scala/reflect/internal/BaseTypeSeqs.scala @@ -29,12 +29,12 @@ trait BaseTypeSeqs { this: SymbolTable => import definitions._ - protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = + protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = new BaseTypeSeq(parents, elems) /** Note: constructor is protected to force everyone to use the factory method newBaseTypeSeq instead. - * This is necessary because when run from reflection every base type sequence needs to have a - * SynchronizedBaseTypeSeq as mixin. + * This is necessary because when run from reflection every base type sequence needs to have a + * SynchronizedBaseTypeSeq as mixin. */ class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) { self => @@ -242,7 +242,7 @@ trait BaseTypeSeqs { // Console.println("computed baseTypeSeq of " + tsym.tpe + " " + parents + ": "+elems.toString)//DEBUG newBaseTypeSeq(parents, elems) } - + class MappedBaseTypeSeq(orig: BaseTypeSeq, f: Type => Type) extends BaseTypeSeq(orig.parents map f, orig.elems) { override def apply(i: Int) = f(orig.apply(i)) override def rawElem(i: Int) = f(orig.rawElem(i)) @@ -254,7 +254,7 @@ trait BaseTypeSeqs { override def exists(p: Type => Boolean) = elems exists (x => p(f(x))) override protected def maxDepthOfElems: Int = elems map (x => maxDpth(f(x))) max override def toString = elems.mkString("MBTS(", ",", ")") - } - + } + val CyclicInheritance = new Throwable } diff --git a/src/compiler/scala/reflect/internal/ClassfileConstants.scala b/src/compiler/scala/reflect/internal/ClassfileConstants.scala index 1c4c007de0..eec72d082d 100644 --- a/src/compiler/scala/reflect/internal/ClassfileConstants.scala +++ b/src/compiler/scala/reflect/internal/ClassfileConstants.scala @@ -360,7 +360,7 @@ object ClassfileConstants { res |= translateFlag(jflags & JAVA_ACC_INTERFACE) res } - + def classFlags(jflags: Int): Long = { initFields(jflags) isClass = true @@ -376,11 +376,11 @@ object ClassfileConstants { } } object FlagTranslation extends FlagTranslation { } - + def toScalaMethodFlags(flags: Int): Long = FlagTranslation methodFlags flags def toScalaClassFlags(flags: Int): Long = FlagTranslation classFlags flags def toScalaFieldFlags(flags: Int): Long = FlagTranslation fieldFlags flags - + @deprecated("Use another method in this object", "2.10.0") def toScalaFlags(flags: Int, isClass: Boolean = false, isField: Boolean = false): Long = ( if (isClass) toScalaClassFlags(flags) diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 7ed3e977db..ec171c5f2c 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -21,7 +21,7 @@ trait Definitions extends reflect.api.StandardDefinitions { * methods. */ private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type) - + private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { val clazz = owner.newClassSymbol(name, NoPosition, flags) clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) @@ -164,7 +164,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass - + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists @@ -176,10 +176,10 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor - + // Java types def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) - + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { case java.lang.Void.TYPE => UnitClass case java.lang.Byte.TYPE => ByteClass @@ -213,7 +213,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Note: this is not the type alias AnyRef, it's a companion-like // object used by the @specialize annotation. lazy val AnyRefModule = getMember(ScalaPackageClass, nme.AnyRef) - @deprecated("Use AnyRefModule", "2.10.0") + @deprecated("Use AnyRefModule", "2.10.0") def Predef_AnyRef = AnyRefModule // bottom types @@ -269,13 +269,13 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val PredefModule: Symbol = getRequiredModule("scala.Predef") lazy val PredefModuleClass = PredefModule.moduleClass - + def Predef_classOf = getMember(PredefModule, nme.classOf) def Predef_identity = getMember(PredefModule, nme.identity) def Predef_conforms = getMember(PredefModule, nme.conforms) def Predef_wrapRefArray = getMember(PredefModule, nme.wrapRefArray) def Predef_??? = getMember(PredefModule, nme.???) - + /** Is `sym` a member of Predef with the given name? * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` * which does a member lookup (it can't be a lazy val because we might reload Predef @@ -284,7 +284,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def isPredefMemberNamed(sym: Symbol, name: Name) = ( (sym.name == name) && (sym.owner == PredefModule.moduleClass) ) - + /** Specialization. */ lazy val SpecializableModule = getRequiredModule("scala.Specializable") @@ -429,7 +429,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case m: ClassManifest[_] => val sym = manifestToSymbol(m) val args = m.typeArguments - + if ((sym eq NoSymbol) || args.isEmpty) sym.tpe else appliedType(sym.typeConstructor, args map manifestToType) case _ => @@ -439,7 +439,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def manifestToSymbol(m: ClassManifest[_]): Symbol = m match { case x: scala.reflect.AnyValManifest[_] => getMember(ScalaPackageClass, newTypeName("" + x)) - case _ => + case _ => val name = m.erasure.getName if (name endsWith nme.MODULE_SUFFIX_STRING) getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING) @@ -499,7 +499,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case DoubleClass => nme.wrapDoubleArray case BooleanClass => nme.wrapBooleanArray case UnitClass => nme.wrapUnitArray - case _ => + case _ => if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray else nme.genericWrapArray } @@ -605,7 +605,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def ClassType(arg: Type) = if (phase.erasedTypes || forMSIL) ClassClass.tpe else appliedType(ClassClass.typeConstructor, List(arg)) - + def vmClassType(arg: Type): Type = ClassType(arg) def vmSignature(sym: Symbol, info: Type): String = signature(info) // !!! @@ -658,7 +658,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => false }) } - + // members of class scala.Any lazy val Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) lazy val Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) @@ -688,7 +688,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) - lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => + lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) ) lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) @@ -796,10 +796,10 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } - + def getRequiredModule(fullname: String): Symbol = getModule(newTermNameCached(fullname)) - def getRequiredClass(fullname: String): Symbol = + def getRequiredClass(fullname: String): Symbol = getClass(newTypeNameCached(fullname)) def getClassIfDefined(fullname: String): Symbol = @@ -851,15 +851,15 @@ trait Definitions extends reflect.api.StandardDefinitions { private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = owner.newAliasType(name) setInfoAndEnter alias - + private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): Symbol = { val clazz = newClass(ScalaPackageClass, name, Nil) val tparam = clazz.newSyntheticTypeParam("T0", flags) val parents = List(AnyRefClass.tpe, parentFn(tparam)) - + clazz setInfo polyType(List(tparam), ClassInfoType(parents, newScope, clazz)) } - + def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): Symbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val tparams = msym.newSyntheticTypeParams(typeParamCount) @@ -870,7 +870,7 @@ trait Definitions extends reflect.api.StandardDefinitions { msym setInfoAndEnter polyType(tparams, mtpe) } - + /** T1 means one type parameter. */ def newT1NullaryMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): Symbol = { @@ -977,7 +977,7 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage - + val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 RepeatedParamClass, diff --git a/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala b/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala index 47f794681c..f1fe4fc118 100644 --- a/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala +++ b/src/compiler/scala/reflect/internal/ExistentialsAndSkolems.scala @@ -14,7 +14,7 @@ import util._ */ trait ExistentialsAndSkolems { self: SymbolTable => - + /** Map a list of type parameter symbols to skolemized symbols, which * can be deskolemized to the original type parameter. (A skolem is a * representation of a bound variable when viewed inside its scope.) diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala index aa696bc6e8..270491d078 100644 --- a/src/compiler/scala/reflect/internal/Flags.scala +++ b/src/compiler/scala/reflect/internal/Flags.scala @@ -165,6 +165,7 @@ class Flags extends ModifierFlags { final val TRIEDCOOKING = 0x100000000000L // ``Cooking'' has been tried on this symbol // A Java method's type is ``cooked'' by transforming raw types to existentials + final val SYNCHRONIZED = 0x200000000000L // symbol is a method which should be marked ACC_SYNCHRONIZED // ------- shift definitions ------------------------------------------------------- final val InitialFlags = 0x0001FFFFFFFFFFFFL // flags that are enabled from phase 1. @@ -222,7 +223,7 @@ class Flags extends ModifierFlags { /** These modifiers appear in TreePrinter output. */ final val PrintableFlags: Long = ExplicitFlags | LOCAL | SYNTHETIC | STABLE | CASEACCESSOR | MACRO | - ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC | VBRIDGE | SPECIALIZED + ACCESSOR | SUPERACCESSOR | PARAMACCESSOR | BRIDGE | STATIC | VBRIDGE | SPECIALIZED | SYNCHRONIZED /** The two bridge flags */ final val BridgeFlags = BRIDGE | VBRIDGE @@ -384,7 +385,7 @@ class Flags extends ModifierFlags { case VBRIDGE => "<vbridge>" // (1L << 42) case VARARGS => "<varargs>" // (1L << 43) case TRIEDCOOKING => "<triedcooking>" // (1L << 44) - case 0x200000000000L => "" // (1L << 45) + case SYNCHRONIZED => "<synchronized>" // (1L << 45) case 0x400000000000L => "" // (1L << 46) case 0x800000000000L => "" // (1L << 47) case 0x1000000000000L => "" // (1L << 48) diff --git a/src/compiler/scala/reflect/internal/HasFlags.scala b/src/compiler/scala/reflect/internal/HasFlags.scala index ec4e919bdc..8affd66cd5 100644 --- a/src/compiler/scala/reflect/internal/HasFlags.scala +++ b/src/compiler/scala/reflect/internal/HasFlags.scala @@ -136,7 +136,7 @@ trait HasFlags { /** Whether this entity has NONE of the flags in the given mask. */ def hasNoFlags(mask: Long): Boolean = !hasFlag(mask) - + protected def isSetting(f: Long, mask: Long) = !hasFlag(f) && ((mask & f) != 0L) protected def isClearing(f: Long, mask: Long) = hasFlag(f) && ((mask & f) != 0L) diff --git a/src/compiler/scala/reflect/internal/Kinds.scala b/src/compiler/scala/reflect/internal/Kinds.scala index e675be43dc..23bff950b8 100644 --- a/src/compiler/scala/reflect/internal/Kinds.scala +++ b/src/compiler/scala/reflect/internal/Kinds.scala @@ -128,7 +128,7 @@ trait Kinds { // @M sometimes hkargs != arg.typeParams, the symbol and the type may // have very different type parameters val hkparams = param.typeParams - + def kindCheck(cond: Boolean, f: KindErrors => KindErrors) { if (!cond) kindErrors = f(kindErrors) diff --git a/src/compiler/scala/reflect/internal/NameManglers.scala b/src/compiler/scala/reflect/internal/NameManglers.scala index e43a0906a8..12f56976c9 100644 --- a/src/compiler/scala/reflect/internal/NameManglers.scala +++ b/src/compiler/scala/reflect/internal/NameManglers.scala @@ -22,10 +22,10 @@ trait NameManglers { val MODULE_SUFFIX_STRING = NameTransformer.MODULE_SUFFIX_STRING val NAME_JOIN_STRING = NameTransformer.NAME_JOIN_STRING - + val MODULE_SUFFIX_NAME: TermName = newTermName(MODULE_SUFFIX_STRING) val NAME_JOIN_NAME: TermName = newTermName(NAME_JOIN_STRING) - + def flattenedName(segments: Name*): NameType = compactedString(segments mkString NAME_JOIN_STRING) /** @@ -79,7 +79,7 @@ trait NameManglers { val SUPER_PREFIX_STRING = "super$" val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" val SETTER_SUFFIX: TermName = encode("_=") - + @deprecated("2.10.0", "Use SPECIALIZED_SUFFIX") def SPECIALIZED_SUFFIX_STRING = SPECIALIZED_SUFFIX.toString @deprecated("2.10.0", "Use SPECIALIZED_SUFFIX") @@ -121,13 +121,13 @@ trait NameManglers { name.subName(i, name.length) } else name } - + def unspecializedName(name: Name): Name = ( if (name endsWith SPECIALIZED_SUFFIX) name.subName(0, name.lastIndexOf('m') - 1) else name ) - + def macroMethodName(name: Name) = { val base = if (name.isTypeName) nme.TYPEkw else nme.DEFkw base append nme.MACRO append name @@ -158,7 +158,7 @@ trait NameManglers { 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 = { diff --git a/src/compiler/scala/reflect/internal/Names.scala b/src/compiler/scala/reflect/internal/Names.scala index e6ca4c49ba..5f38374f20 100644 --- a/src/compiler/scala/reflect/internal/Names.scala +++ b/src/compiler/scala/reflect/internal/Names.scala @@ -73,7 +73,7 @@ trait Names extends api.Names { /** Create a term name from the characters in cs[offset..offset+len-1]. */ def newTermName(cs: Array[Char], offset: Int, len: Int): TermName = newTermName(cs, offset, len, cachedString = null) - + def newTermName(cs: Array[Char]): TermName = newTermName(cs, 0, cs.length) def newTypeName(cs: Array[Char]): TypeName = newTypeName(cs, 0, cs.length) @@ -87,7 +87,7 @@ trait Names extends api.Names { var n = termHashtable(h) while ((n ne null) && (n.length != len || !equals(n.start, cs, offset, len))) n = n.next - + if (n ne null) n else { // The logic order here is future-proofing against the possibility @@ -135,7 +135,7 @@ trait Names extends api.Names { /** The name class. * TODO - resolve schizophrenia regarding whether to treat Names as Strings - * or Strings as Names. Give names the key functions the absence of which + * or Strings as Names. Give names the key functions the absence of which * make people want Strings all the time. */ sealed abstract class Name(protected val index: Int, protected val len: Int) extends AbsName with Function1[Int, Char] { @@ -166,7 +166,7 @@ trait Names extends api.Names { /** Return a new name of the same variety. */ def newName(str: String): ThisNameType - + /** Return a new name based on string transformation. */ def mapName(f: String => String): ThisNameType = newName(f(toString)) @@ -357,7 +357,7 @@ trait Names extends api.Names { def dropRight(n: Int) = subName(0, len - n) def drop(n: Int) = subName(n, len) - + def indexOf(ch: Char) = { val idx = pos(ch) if (idx == length) -1 else idx @@ -382,7 +382,7 @@ trait Names extends api.Names { } newTermName(cs, 0, len) } - + /** TODO - reconcile/fix that encode returns a Name but * decode returns a String. */ @@ -393,7 +393,7 @@ trait Names extends api.Names { def encoded: String = "" + encode // def decodedName: ThisNameType = newName(decoded) def encodedName: ThisNameType = encode - + /** Replace operator symbols by corresponding $op_name. */ def encode: ThisNameType = { val str = toString @@ -425,7 +425,7 @@ trait Names extends api.Names { def longString: String = nameKind + " " + decode def debugString = { val s = decode ; if (isTypeName) s + "!" else s } } - + /** A name that contains no operator chars nor dollar signs. * TODO - see if it's any faster to do something along these lines. */ @@ -461,7 +461,7 @@ trait Names extends api.Names { sealed abstract class TermName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { type ThisNameType = TermName protected[this] def thisName: TermName = this - + var next: TermName = termHashtable(hash) termHashtable(hash) = this def isTermName: Boolean = true @@ -488,7 +488,7 @@ trait Names extends api.Names { sealed abstract class TypeName(index0: Int, len0: Int, hash: Int) extends Name(index0, len0) { type ThisNameType = TypeName protected[this] def thisName: TypeName = this - + var next: TypeName = typeHashtable(hash) typeHashtable(hash) = this def isTermName: Boolean = false diff --git a/src/compiler/scala/reflect/internal/Phase.scala b/src/compiler/scala/reflect/internal/Phase.scala index acd3360c4f..89d643aacf 100644 --- a/src/compiler/scala/reflect/internal/Phase.scala +++ b/src/compiler/scala/reflect/internal/Phase.scala @@ -26,6 +26,8 @@ abstract class Phase(val prev: Phase) { if ((prev ne null) && (prev ne NoPhase)) prev.nx = this def next: Phase = nx + def hasNext = next != this + def iterator = Iterator.iterate(this)(_.next) takeWhile (p => p.next != p) def name: String def description: String = name @@ -37,7 +39,7 @@ abstract class Phase(val prev: Phase) { def refChecked: Boolean = false /** This is used only in unsafeTypeParams, and at this writing is - * overridden to false in namer, typer, and erasure. (And NoPhase.) + * overridden to false in parser, namer, typer, and erasure. (And NoPhase.) */ def keepsTypeParams = true def run(): Unit diff --git a/src/compiler/scala/reflect/internal/Scopes.scala b/src/compiler/scala/reflect/internal/Scopes.scala index 37464ebf29..ef48d6102f 100644 --- a/src/compiler/scala/reflect/internal/Scopes.scala +++ b/src/compiler/scala/reflect/internal/Scopes.scala @@ -38,11 +38,11 @@ trait Scopes extends api.Scopes { self: SymbolTable => } /** Note: constructor is protected to force everyone to use the factory methods newScope or newNestedScope instead. - * This is necessary because when run from reflection every scope needs to have a - * SynchronizedScope as mixin. + * This is necessary because when run from reflection every scope needs to have a + * SynchronizedScope as mixin. */ class Scope protected[Scopes] (initElems: ScopeEntry = null) extends Iterable[Symbol] { - + protected[Scopes] def this(base: Scope) = { this(base.elems) nestinglevel = base.nestinglevel + 1 @@ -319,7 +319,7 @@ trait Scopes extends api.Scopes { self: SymbolTable => /** Create a new scope */ def newScope: Scope = new Scope() - + /** Create a new scope nested in another one with which it shares its elements */ def newNestedScope(outer: Scope): Scope = new Scope(outer) diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 3c181e39c6..ef2114b608 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -246,7 +246,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val x_7 : NameType = "x$7" val x_8 : NameType = "x$8" val x_9 : NameType = "x$9" - + @switch def syntheticParamName(i: Int): TermName = i match { case 0 => nme.x_0 case 1 => nme.x_1 @@ -260,9 +260,9 @@ trait StdNames extends NameManglers { self: SymbolTable => case 9 => nme.x_9 case _ => newTermName("x$" + i) } - + val ??? = encode("???") - + val wrapRefArray: NameType = "wrapRefArray" val wrapByteArray: NameType = "wrapByteArray" val wrapShortArray: NameType = "wrapShortArray" @@ -347,6 +347,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val isInstanceOf_ : NameType = "isInstanceOf" val isInstanceOf_Ob : NameType = "$isInstanceOf" val java: NameType = "java" + val key: NameType = "key" val lang: NameType = "lang" val length: NameType = "length" val lengthCompare: NameType = "lengthCompare" @@ -617,7 +618,7 @@ trait StdNames extends NameManglers { self: SymbolTable => val testLessOrEqualThan: NameType = "testLessOrEqualThan" val testLessThan: NameType = "testLessThan" val testNotEqual: NameType = "testNotEqual" - + val isBoxedNumberOrBoolean: NameType = "isBoxedNumberOrBoolean" val isBoxedNumber: NameType = "isBoxedNumber" @@ -669,7 +670,7 @@ trait StdNames extends NameManglers { self: SymbolTable => case `toDouble` => toDouble case _ => NO_NAME } - + val reflPolyCacheName: NameType = "reflPoly$Cache" val reflClassCacheName: NameType = "reflClass$Cache" val reflParamsCacheName: NameType = "reflParams$Cache" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index 4bcf522a8f..ce54c32273 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -8,6 +8,7 @@ package internal import scala.collection.{ mutable, immutable } import util._ +import scala.tools.nsc.util.WeakHashSet abstract class SymbolTable extends api.Universe with Collections @@ -42,7 +43,7 @@ abstract class SymbolTable extends api.Universe /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) - + /** Overridden when we know more about what was happening during a failure. */ def supplementErrorMessage(msg: String): String = msg @@ -78,7 +79,8 @@ abstract class SymbolTable extends api.Universe type RunId = Int final val NoRunId = 0 - private var phStack: List[Phase] = Nil + // sigh, this has to be public or atPhase doesn't inline. + var phStack: List[Phase] = Nil private var ph: Phase = NoPhase private var per = NoPeriod @@ -91,6 +93,16 @@ abstract class SymbolTable extends api.Universe ph = p per = period(currentRunId, p.id) } + final def pushPhase(ph: Phase): Phase = { + val current = phase + phase = ph + phStack ::= ph + current + } + final def popPhase(ph: Phase) { + phStack = phStack.tail + phase = ph + } /** The current compiler run identifier. */ def currentRunId: RunId @@ -118,20 +130,19 @@ abstract class SymbolTable extends api.Universe /** Perform given operation at given phase. */ @inline final def atPhase[T](ph: Phase)(op: => T): T = { - val current = phase - phase = ph - phStack ::= ph + val saved = pushPhase(ph) try op - finally { - phase = current - phStack = phStack.tail - } + finally popPhase(saved) } + + /** Since when it is to be "at" a phase is inherently ambiguous, * a couple unambiguously named methods. */ @inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op) @inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op) + @inline final def afterCurrentPhase[T](op: => T): T = atPhase(phase.next)(op) + @inline final def beforePrevPhase[T](op: => T): T = atPhase(phase.prev)(op) @inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T = if (target != NoPhase && phase.id > target.id) atPhase(target)(op) else op @@ -266,9 +277,10 @@ abstract class SymbolTable extends api.Universe } } - def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]()) - def newMap[K, V]() = recordCache(mutable.HashMap[K, V]()) - def newSet[K]() = recordCache(mutable.HashSet[K]()) + def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]()) + def newMap[K, V]() = recordCache(mutable.HashMap[K, V]()) + def newSet[K]() = recordCache(mutable.HashSet[K]()) + def newWeakSet[K <: AnyRef]() = recordCache(new WeakHashSet[K]()) } /** Break into repl debugger if assertion is true. */ @@ -285,7 +297,7 @@ abstract class SymbolTable extends api.Universe /** The phase which has given index as identifier. */ val phaseWithId: Array[Phase] - + /** Is this symbol table part of reflexive mirror? In this case * operations need to be made thread safe. */ diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index ce85d65050..62b0206c28 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -17,7 +17,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ protected var ids = 0 - + val emptySymbolArray = new Array[Symbol](0) def symbolCount = ids // statistics @@ -38,14 +38,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => nextexid += 1 newTypeName("_" + nextexid + suffix) } - + // Set the fields which point companions at one another. Returns the module. def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = { moduleClass.sourceModule = m m setModuleClass moduleClass m } - + /** Create a new free variable. Its owner is NoSymbol. */ def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar = @@ -67,7 +67,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def selfType: Type = typeOfThis def typeSignature: Type = info def typeSignatureIn(site: Type): Type = site memberInfo this - + def asType: Type = tpe def asTypeIn(site: Type): Type = site.memberType(this) def asTypeConstructor: Type = typeConstructor @@ -89,19 +89,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api private[this] var _rawname = initName private[this] var _rawflags = 0L - + def rawowner = _rawowner def rawname = _rawname def rawflags = _rawflags - + protected def rawflags_=(x: FlagsType) { _rawflags = x } - + private var rawpos = initPos - + val id = nextId() // identity displayed when -uniqid private[this] var _validTo: Period = NoPeriod - + def validTo = _validTo def validTo_=(x: Period) { _validTo = x} @@ -179,10 +179,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = new TermSymbol(this, pos, name) initFlags newFlags - + def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol = new AbstractTypeSymbol(this, pos, name) initFlags newFlags - + def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol = new AliasTypeSymbol(this, pos, name) initFlags newFlags @@ -194,10 +194,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = new ClassSymbol(this, pos, name) initFlags newFlags - + def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = new ModuleClassSymbol(this, pos, name) initFlags newFlags - + /** Derive whether it is an abstract type from the flags; after creation * the DEFERRED flag will be ignored. */ @@ -206,7 +206,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => newAliasTypeSymbol(name, pos, newFlags) else newAbstractTypeSymbol(name, pos, newFlags) - + def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem = if ((newFlags & DEFERRED) == 0L) new TypeSkolem(this, pos, name, origin) initFlags newFlags @@ -243,7 +243,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = newAliasTypeSymbol(name, pos, newFlags) - + /** Symbol of an abstract type type T >: ... <: ... */ final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = @@ -261,7 +261,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def freshName() = { cnt += 1; nme.syntheticParamName(cnt) } mmap(argtypess)(tp => newValueParameter(freshName(), focusPos(owner.pos), SYNTHETIC) setInfo tp) } - + def newSyntheticTypeParam(): Symbol = newSyntheticTypeParam("T0", 0L) def newSyntheticTypeParam(name: String, newFlags: Long): Symbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty def newSyntheticTypeParams(num: Int): List[Symbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L)) @@ -302,7 +302,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) = newClassSymbol(name, pos, newFlags) - + /** A new class with its info set to a ClassInfoType with given scope and parents. */ def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L) = { val clazz = newClass(name, pos, newFlags) @@ -354,9 +354,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos) @deprecated("Use the other signature", "2.10.0") def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos) // ----- locking and unlocking ------------------------------------------------------ @@ -838,7 +838,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def addModuleSuffix(n: Name): Name = if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n - + def moduleSuffix: String = ( if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING else "" @@ -846,7 +846,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform. */ def needsModuleSuffix = ( - hasModuleFlag + hasModuleFlag && !isMethod && !isImplClass && !isJavaDefined @@ -873,7 +873,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (owner.isEffectiveRoot) name else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name ) - + def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) /** The encoded full path name of this symbol, where outer names and inner names @@ -1028,7 +1028,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else modifyInfo(_.substSym(syms0, syms1)) def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this) - + /** Set the info and enter this symbol into the owner's scope. */ def setInfoAndEnter(info: Type): this.type = { setInfo(info) @@ -1166,7 +1166,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => abort("typeConstructor inapplicable for " + this) /** The logic approximately boils down to finding the most recent phase - * which immediately follows any of namer, typer, or erasure. + * which immediately follows any of parser, namer, typer, or erasure. + * In effect that means this will return one of: + * + * - packageobjects (follows namer) + * - superaccessors (follows typer) + * - lazyvals (follows erasure) + * - null */ private def unsafeTypeParamPhase = { var ph = phase @@ -1337,7 +1343,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def isNestedIn(that: Symbol): Boolean = owner == that || owner != NoSymbol && (owner isNestedIn that) - + /** Is this class symbol a subclass of that symbol, * and is this class symbol also different from Null or Nothing? */ def isNonBottomSubClass(that: Symbol): Boolean = false @@ -1398,10 +1404,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => clone.typeOfThis = (clone.typeOfThis cloneInfo clone) if (newName != nme.NO_NAME) clone.name = newName - + clone } - + /** Internal method to clone a symbol's implementation with the given flags and no info. */ def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol def cloneSymbolImpl(owner: Symbol): Symbol = cloneSymbolImpl(owner, 0L) @@ -1594,7 +1600,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Kept for source compatibility with 2.9. Scala IDE for Eclipse relies on this. */ @deprecated("Use enclosingTopLevelClass") def toplevelClass: Symbol = enclosingTopLevelClass - + /** The top-level class containing this symbol. */ def enclosingTopLevelClass: Symbol = if (owner.isPackageClass) { @@ -1870,7 +1876,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Remove any access boundary and clear flags PROTECTED | PRIVATE. */ def makePublic = this setPrivateWithin NoSymbol resetFlag AccessFlags - + /** The first parameter to the first argument list of this method, * or NoSymbol if inapplicable. */ @@ -2154,7 +2160,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def referenced: Symbol = _referenced def referenced_=(x: Symbol) { _referenced = x } - + def existentialBound = singletonBounds(this.tpe) def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = @@ -2248,7 +2254,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (!isMethod && needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname) - + flatname } else rawname.toTermName @@ -2284,7 +2290,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => res } } - + class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { // Temporary programmatic help tracking down who might do such a thing @@ -2299,13 +2305,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol = owner.newAliasTypeSymbol(name, pos, newFlags) } - + class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin { override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol = owner.newAbstractTypeSymbol(name, pos, newFlags) } - + /** Might be mixed into TypeSymbol or TypeSkolem. */ trait AbstractTypeMixin extends TypeSymbol { @@ -2503,7 +2509,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final override def isNonClassType = false final override def isAbstractType = false final override def isAliasType = false - + override def existentialBound = polyType(this.typeParams, TypeBounds.upper(this.classBound)) override def sourceFile = @@ -2531,19 +2537,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => } thisTypeCache } - + override def owner: Symbol = if (needsFlatClasses) rawowner.owner else rawowner override def name: TypeName = ( if (needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname).toTypeName - + flatname } else rawname.toTypeName ) - + /** A symbol carrying the self type of the class as its type */ override def thisSym: Symbol = thissym @@ -2728,7 +2734,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => val syms1 = cloneSymbolsAtOwner(syms, owner) creator(syms1, tpe.substSym(syms, syms1)) } - + /** A deep map on a symbol's paramss. */ def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f) @@ -2752,5 +2758,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => assert(validFrom != NoPeriod) override def toString() = "TypeHistory(" + phaseOf(validFrom)+":"+runId(validFrom) + "," + info + "," + prev + ")" + + def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList ) } } diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index e3ee39d2a0..3252b970d1 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -146,7 +146,7 @@ abstract class TreeInfo { true } - + /** * Selects the correct parameter list when there are nested applications. * Given Apply(fn, args), args might correspond to any of fn.symbol's parameter @@ -175,7 +175,7 @@ abstract class TreeInfo { } def foreachMethodParamAndArg(t: Tree)(f: (Symbol, Tree) => Unit): Unit = t match { case Apply(fn, args) => foreachMethodParamAndArg(applyMethodParameters(fn), args)(f) - case _ => + case _ => } /** Is symbol potentially a getter of a variable? diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 610c6dc493..54cc53aaac 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -121,7 +121,7 @@ trait Trees extends api.Trees { self: SymbolTable => new ChangeOwnerTraverser(oldOwner, newOwner) apply t } } - + def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = { val list = pairs.toList val subst = new TreeSymSubstituter(list map (_._1), list map (_._2)) @@ -230,17 +230,18 @@ trait Trees extends api.Trees { self: SymbolTable => def Bind(sym: Symbol, body: Tree): Bind = Bind(sym.name, body) setSymbol sym - /** 0-1 argument list new, based on a symbol or type. - */ - def New(sym: Symbol, args: Tree*): Tree = - New(sym.tpe, args: _*) + def Try(body: Tree, cases: (Tree, Tree)*): Try = + Try(body, cases.toList map { case (pat, rhs) => CaseDef(pat, EmptyTree, rhs) }, EmptyTree) - def New(tpe: Type, args: Tree*): Tree = - New(TypeTree(tpe), List(args.toList)) + def Throw(tpe: Type, args: Tree*): Throw = + Throw(New(tpe, args: _*)) def Apply(sym: Symbol, args: Tree*): Tree = Apply(Ident(sym), args.toList) + def New(sym: Symbol, args: Tree*): Tree = + New(sym.tpe, args: _*) + def Super(sym: Symbol, mix: TypeName): Tree = Super(This(sym), mix) /** Block factory that flattens directly nested blocks. diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index fd75e42b61..64edbdb8bd 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -110,13 +110,13 @@ trait Types extends api.Types { self: SymbolTable => * to undo constraints in the case of isSubType/isSameType failure. */ lazy val undoLog = newUndoLog - + protected def newUndoLog = new UndoLog - + class UndoLog { private type UndoPairs = List[(TypeVar, TypeConstraint)] private var log: UndoPairs = List() - + // register with the auto-clearing cache manager perRunCaches.recordCache(this) @@ -136,7 +136,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] def record(tv: TypeVar) = { log ::= ((tv, tv.constr.cloneInternal)) } - + private[scala] def clear() { if (settings.debug.value) self.log("Clearing " + log.size + " entries from the undoLog.") @@ -428,7 +428,7 @@ trait Types extends api.Types { self: SymbolTable => /** For a typeref, its arguments. The empty list for all other types */ def typeArgs: List[Type] = List() - + /** A list of placeholder types derived from the type parameters. * Used by RefinedType and TypeRef. */ @@ -525,7 +525,7 @@ trait Types extends api.Types { self: SymbolTable => * Alternatives of overloaded symbol appear in the order they are declared. */ def decl(name: Name): Symbol = findDecl(name, 0) - + /** A list of all non-private members defined or declared in this type. */ def nonPrivateDecls: List[Symbol] = decls filter (x => !x.isPrivate) toList @@ -566,7 +566,7 @@ trait Types extends api.Types { self: SymbolTable => */ def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) - + /** All members with the given flags, excluding bridges. */ def membersWithFlags(requiredFlags: Long): List[Symbol] = @@ -591,7 +591,7 @@ trait Types extends api.Types { self: SymbolTable => * an OverloadedSymbol if several exist, NoSymbol if none exist */ def nonLocalMember(name: Name): Symbol = memberBasedOnName(name, BridgeFlags | LOCAL) - + /** Members excluding and requiring the given flags. * Note: unfortunately it doesn't work to exclude DEFERRED this way. */ @@ -893,7 +893,7 @@ trait Types extends api.Types { self: SymbolTable => def toLongString = { val str = toString if (str == "type") widen.toString - else if (str endsWith ".type") str + " (with underlying type " + widen + ")" + else if ((str endsWith ".type") && !typeSymbol.isModuleClass) str + " (with underlying type " + widen + ")" else str } @@ -1118,7 +1118,14 @@ trait Types extends api.Types { self: SymbolTable => underlying.baseTypeSeq prepend this } override def isHigherKinded = false // singleton type classifies objects, thus must be kind * - override def safeToString: String = prefixString + "type" + override def safeToString: String = { + // Avoiding printing Predef.type and scala.package.type as "type", + // since in all other cases we omit those prefixes. + val pre = underlying.typeSymbol.skipPackageObject + if (pre.isOmittablePrefix) pre.fullName + ".type" + else prefixString + "type" + } + /* override def typeOfThis: Type = typeSymbol.typeOfThis override def bounds: TypeBounds = TypeBounds(this, this) @@ -1237,7 +1244,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var underlyingPeriod = NoPeriod override def underlying: Type = { val cache = underlyingCache - if (underlyingPeriod == currentPeriod && cache != null) cache + if (underlyingPeriod == currentPeriod && cache != null) cache else { defineUnderlyingOfSingleType(this) underlyingCache @@ -1280,7 +1287,7 @@ trait Types extends api.Types { self: SymbolTable => unique(new UniqueSingleType(pre, sym)) } } - + protected def defineUnderlyingOfSingleType(tpe: SingleType) = { val period = tpe.underlyingPeriod if (period != currentPeriod) { @@ -1350,13 +1357,13 @@ trait Types extends api.Types { self: SymbolTable => override def baseTypeSeq: BaseTypeSeq = { val cached = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) cached else { defineBaseTypeSeqOfCompoundType(this) if (baseTypeSeqCache eq undetBaseTypeSeq) throw new RecoverableCyclicReference(typeSymbol) - + baseTypeSeqCache } } @@ -1370,7 +1377,7 @@ trait Types extends api.Types { self: SymbolTable => defineBaseClassesOfCompoundType(this) if (baseClassesCache eq null) throw new RecoverableCyclicReference(typeSymbol) - + baseClassesCache } } @@ -1410,13 +1417,13 @@ trait Types extends api.Types { self: SymbolTable => // override def isNullable: Boolean = // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType); - + override def safeToString: String = parents.mkString(" with ") + (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) decls.mkString("{", "; ", "}") else "") } - + protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { val period = tpe.baseTypeSeqPeriod; if (period != currentPeriod) { @@ -1469,7 +1476,7 @@ trait Types extends api.Types { self: SymbolTable => if (tpe.baseTypeSeqCache eq undetBaseTypeSeq) throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol) } - + protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = { def computeBaseClasses: List[Symbol] = if (tpe.parents.isEmpty) List(tpe.typeSymbol) @@ -1751,7 +1758,7 @@ trait Types extends api.Types { self: SymbolTable => // override def isNonNull: Boolean = symbol == NonNullClass || super.isNonNull; override def kind = "ClassInfoType" - + override def safeToString = if (settings.debug.value || decls.size > 1) formattedToString @@ -1801,13 +1808,13 @@ trait Types extends api.Types { self: SymbolTable => } } - /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected + /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected * with synchronized, because they are accessed only from isVolatile, which is called only from * Typer. */ private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] - + class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType { require(args0.nonEmpty, this) @@ -1825,7 +1832,7 @@ trait Types extends api.Types { self: SymbolTable => asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) } - + // note: does not go through typeRef. There's no need to because // neither `pre` nor `sym` changes. And there's a performance // advantage to call TypeRef directly. @@ -1840,7 +1847,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = typeParams.nonEmpty override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) - + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = if (isHigherKinded) { if (sameLength(formals intersect typeParams, typeParams)) @@ -1860,9 +1867,9 @@ trait Types extends api.Types { self: SymbolTable => res } - override def transformInfo(tp: Type): Type = + override def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), dummyArgs) - + override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) else super.narrow @@ -1870,14 +1877,14 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = this // eta-expand, subtyping relies on eta-expansion of higher-kinded types - override protected def normalizeImpl: Type = + override protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalizeImpl } - + trait ClassTypeRef extends TypeRef { // !!! There are scaladoc-created symbols arriving which violate this require. // require(sym.isClass, sym) - + override protected def normalizeImpl: Type = if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers else super.normalizeImpl @@ -1886,7 +1893,7 @@ trait Types extends api.Types { self: SymbolTable => if (sym == clazz) this else transform(sym.info.baseType(clazz)) } - + trait NonClassTypeRef extends TypeRef { require(sym.isNonClassType, sym) @@ -1905,11 +1912,11 @@ trait Types extends api.Types { self: SymbolTable => } relativeInfoCache } - + override def baseType(clazz: Symbol): Type = if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz) } - + protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try { basetypeRecursions += 1 if (basetypeRecursions < LogPendingBaseTypesThreshold) @@ -1926,7 +1933,7 @@ trait Types extends api.Types { self: SymbolTable => } finally { basetypeRecursions -= 1 } - + trait AliasTypeRef extends NonClassTypeRef { require(sym.isAliasType, sym) @@ -1944,7 +1951,7 @@ trait Types extends api.Types { self: SymbolTable => if (typeParamsMatchArgs) betaReduce.normalize else if (isHigherKinded) super.normalizeImpl else ErrorType - + // isHKSubType0 introduces synthetic type params so that // betaReduce can first apply sym.info to typeArgs before calling // asSeenFrom. asSeenFrom then skips synthetic type params, which @@ -1954,7 +1961,7 @@ trait Types extends api.Types { self: SymbolTable => // this crashes pos/depmet_implicit_tpbetareduce.scala // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) def betaReduce = transform(sym.info.resultType) - + // #3731: return sym1 for which holds: pre bound sym.name to sym and // pre1 now binds sym.name to sym1, conceptually exactly the same // symbol as sym. The selection of sym on pre must be updated to the @@ -1968,12 +1975,12 @@ trait Types extends api.Types { self: SymbolTable => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? case _ => sym } - + } trait AbstractTypeRef extends NonClassTypeRef { require(sym.isAbstractType, sym) - + /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment */ private var symInfoCache: Type = _ @@ -2002,7 +2009,7 @@ trait Types extends api.Types { self: SymbolTable => volatileRecursions -= 1 } } - + override def thisInfo = { val symInfo = sym.info if (thisInfoCache == null || (symInfo ne symInfoCache)) { @@ -2035,7 +2042,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var parentsPeriod = NoPeriod private[reflect] var baseTypeSeqCache: BaseTypeSeq = _ private[reflect] var baseTypeSeqPeriod = NoPeriod - private var normalized: Type = _ + private var normalized: Type = _ // @M: propagate actual type params (args) to `tp`, by replacing // formal type parameters with actual ones. If tp is higher kinded, @@ -2057,7 +2064,7 @@ trait Types extends api.Types { self: SymbolTable => normalized } } - + def etaExpand: Type = { // must initialise symbol, see test/files/pos/ticket0137.scala val tpars = initializedTypeParams @@ -2111,12 +2118,12 @@ trait Types extends api.Types { self: SymbolTable => } thisInfo.decls } - + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) cache else { defineBaseTypeSeqOfTypeRef(this) @@ -2210,7 +2217,7 @@ trait Types extends api.Types { self: SymbolTable => } }) } - + protected def defineParentsOfTypeRef(tpe: TypeRef) = { val period = tpe.parentsPeriod if (period != currentPeriod) { @@ -2222,7 +2229,7 @@ trait Types extends api.Types { self: SymbolTable => } } } - + protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = { val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { @@ -2382,7 +2389,7 @@ trait Types extends api.Types { self: SymbolTable => } object PolyType extends PolyTypeExtractor - + /** A creator for existential types which flattens nested existentials. */ def newExistentialType(quantified: List[Symbol], underlying: Type): Type = @@ -2436,7 +2443,7 @@ trait Types extends api.Types { self: SymbolTable => /** An existential can only be printed with wildcards if: * - the underlying type is a typeref * - where there is a 1-to-1 correspondence between underlying's typeargs and quantified - * - and none of the existential parameters is referenced from anywhere else in the type + * - and none of the existential parameters is referenced from anywhere else in the type * - and none of the existential parameters are singleton types */ private def isRepresentableWithWildcards = !settings.debug.value && { @@ -2597,7 +2604,7 @@ trait Types extends api.Types { self: SymbolTable => else if (args.isEmpty) new HKTypeVar(origin, constr, params) else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params))) ) - + trace("create", "In " + tv.originLocation)(tv) } } @@ -2638,7 +2645,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = true override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) } - + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) */ class AppliedTypeVar( @@ -2646,17 +2653,17 @@ trait Types extends api.Types { self: SymbolTable => _constr: TypeConstraint, zippedArgs: List[(Symbol, Type)] ) extends TypeVar(_origin, _constr) { - + require(zippedArgs.nonEmpty, this) override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) - + override protected def typeVarString = ( zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") ) } - + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). @@ -2674,7 +2681,7 @@ trait Types extends api.Types { self: SymbolTable => override def typeArgs: List[Type] = Nil override def isHigherKinded = false - /** The constraint associated with the variable + /** The constraint associated with the variable * Syncnote: Type variables are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of `constr` @@ -2685,7 +2692,7 @@ trait Types extends api.Types { self: SymbolTable => /** The variable's skolemization level */ val level = skolemizationLevel - + /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. * @@ -2716,7 +2723,7 @@ trait Types extends api.Types { self: SymbolTable => // inference may generate several TypeVar's for a single type parameter that must be inferred, // only one of them is in the set of tvars that need to be solved, but // they share the same TypeConstraint instance - + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2940,7 +2947,7 @@ trait Types extends api.Types { self: SymbolTable => def originLocation = { val sym = origin.typeSymbolDirect val encl = sym.owner.logicallyEnclosingMember - + // This should display somewhere between one and three // things which enclose the origin: at most, a class, a // a method, and a term. At least, a class. @@ -3272,7 +3279,7 @@ trait Types extends api.Types { self: SymbolTable => case WildcardType => tycon // needed for neg/t0226 case _ => abort(debugString(tycon)) } - + /** A creator for existential types where the type arguments, * rather than being applied directly, are interpreted as the * upper bounds of unknown types. For instance if the type argument @@ -3283,7 +3290,7 @@ trait Types extends api.Types { self: SymbolTable => tycon match { case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) => val eparams = typeParamsToExistentials(sym) - val bounds = args map (TypeBounds upper _) + val bounds = args map (TypeBounds upper _) (eparams, bounds).zipped foreach (_ setInfo _) newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe))) @@ -3387,7 +3394,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Type with all top-level occurrences of abstract types replaced by their bounds */ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) case TypeRef(_, sym, _) if sym.isAbstractType => @@ -3497,7 +3504,7 @@ trait Types extends api.Types { self: SymbolTable => def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi)) def this() = this(List(), List()) - + /* Syncnote: Type constraints are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of any @@ -3571,7 +3578,7 @@ trait Types extends api.Types { self: SymbolTable => val hi = hiBounds filterNot (_.typeSymbolDirect eq AnyClass) val lostr = if (lo.isEmpty) Nil else List(lo.mkString(" >: (", ", ", ")")) val histr = if (hi.isEmpty) Nil else List(hi.mkString(" <: (", ", ", ")")) - + lostr ++ histr mkString ("[", " | ", "]") } if (inst eq NoType) boundsStr @@ -3597,7 +3604,7 @@ trait Types extends api.Types { self: SymbolTable => override def variance = _variance def variance_=(x: Int) = _variance = x - + override protected def noChangeToSymbols(origSyms: List[Symbol]) = { origSyms forall { sym => val v = variance @@ -3763,7 +3770,7 @@ trait Types extends api.Types { self: SymbolTable => protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = args mapConserve this - + /** Called by mapOver to determine whether the original symbols can * be returned, or whether they must be cloned. Overridden in VariantTypeMap. */ @@ -3777,7 +3784,7 @@ trait Types extends api.Types { self: SymbolTable => if (elems1 eq elems) scope else newScopeWith(elems1: _*) } - + /** Map this function over given list of symbols */ def mapOver(origSyms: List[Symbol]): List[Symbol] = { // fast path in case nothing changes due to map @@ -3840,7 +3847,7 @@ trait Types extends api.Types { self: SymbolTable => def traverse(tp: Type): Unit def apply(tp: Type): Type = { traverse(tp); tp } } - + abstract class TypeTraverserWithResult[T] extends TypeTraverser { def result: T def clear(): Unit @@ -3860,13 +3867,13 @@ trait Types extends api.Types { self: SymbolTable => */ // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap { // variance = v - // + // // def traverse(tp: Type) = tp match { // case ExistentialType(_, _) if (variance == v) => result = true // case _ => mapOver(tp) // } // } - // + // // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) @@ -3917,7 +3924,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Used by existentialAbstraction. */ class ExistentialExtrapolation(tparams: List[Symbol]) extends VariantTypeMap { @@ -3935,10 +3942,10 @@ trait Types extends api.Types { self: SymbolTable => countOccs(tpe) for (tparam <- tparams) countOccs(tparam.info) - + apply(tpe) } - + def apply(tp: Type): Type = { val tp1 = mapOver(tp) if (variance == 0) tp1 @@ -4331,7 +4338,7 @@ trait Types extends api.Types { self: SymbolTable => def apply(tp: Type): Type = mapOver(tp) match { // unsound to replace args by unstable actual #3873 case SingleType(NoPrefix, StableArg(arg)) => arg - // (soundly) expand type alias selections on implicit arguments, + // (soundly) expand type alias selections on implicit arguments, // see depmet_implicit_oopsla* test cases -- typically, `param.isImplicit` case tp1 @ TypeRef(SingleType(NoPrefix, Arg(pid)), sym, targs) => val arg = actuals(pid) @@ -4360,7 +4367,7 @@ trait Types extends api.Types { self: SymbolTable => override def mapOver(arg: Tree, giveup: ()=>Nothing): Tree = { // TODO: this should be simplified; in the stable case, one can // probably just use an Ident to the tree.symbol. - // + // // @PP: That leads to failure here, where stuff no longer has type // 'String @Annot("stuff")' but 'String @Annot(x)'. // @@ -4517,12 +4524,12 @@ trait Types extends api.Types { self: SymbolTable => result } } - + protected def commonOwnerMap: CommonOwnerMap = commonOwnerMapObj - + protected class CommonOwnerMap extends TypeTraverserWithResult[Symbol] { var result: Symbol = _ - + def clear() { result = null } private def register(sym: Symbol) { @@ -4540,7 +4547,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => mapOver(tp) } } - + private lazy val commonOwnerMapObj = new CommonOwnerMap class MissingAliasControl extends ControlThrowable @@ -4548,7 +4555,7 @@ trait Types extends api.Types { self: SymbolTable => class MissingTypeControl extends ControlThrowable object adaptToNewRunMap extends TypeMap { - + private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { if (phase.flatClasses) { sym @@ -4715,7 +4722,7 @@ trait Types extends api.Types { self: SymbolTable => case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG if (tparam.variance == 0) arg1 =:= arg2 else if (arg1.isInstanceOf[TypeVar]) @@ -5738,8 +5745,8 @@ trait Types extends api.Types { self: SymbolTable => val formatted = tableDef.table(transposed) println("** Depth is " + depth + "\n" + formatted) } - - /** From a list of types, find any which take type parameters + + /** From a list of types, find any which take type parameters * where the type parameter bounds contain references to other * any types in the list (including itself.) * @@ -5839,7 +5846,7 @@ trait Types extends api.Types { self: SymbolTable => } } - val initialBTSes = ts map (_.baseTypeSeq.toList filter (_.typeSymbol.isPublic)) + val initialBTSes = ts map (_.baseTypeSeq.toList) if (printLubs) printLubMatrix(ts zip initialBTSes toMap, depth) @@ -6258,13 +6265,13 @@ trait Types extends api.Types { self: SymbolTable => if (ts exists (_.isNotNull)) res.notNull else res } - + /** A list of the typevars in a type. */ def typeVarsInType(tp: Type): List[TypeVar] = { var tvs: List[TypeVar] = Nil tp foreach { case t: TypeVar => tvs ::= t - case _ => + case _ => } tvs.reverse } @@ -6276,7 +6283,7 @@ trait Types extends api.Types { self: SymbolTable => // !!! Is it somehow guaranteed that this will not break under nesting? // In general one has to save and restore the contents of the field... tvs foreach (_.suspended = true) - tvs + tvs } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list @@ -6504,5 +6511,5 @@ trait Types extends api.Types { self: SymbolTable => } finally { tostringRecursions -= 1 } - + } diff --git a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala index 9f93108420..34163d54f8 100644 --- a/src/compiler/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/compiler/scala/reflect/internal/pickling/UnPickler.scala @@ -846,10 +846,11 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ { private val p = phase override def complete(sym: Symbol) : Unit = try { val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` - if (p != phase) atPhase(p) (sym setInfo tp) - else sym setInfo tp - if (currentRunId != definedAtRunId) sym.setInfo(adaptToNewRunMap(tp)) - } catch { + atPhase(p) (sym setInfo tp) + if (currentRunId != definedAtRunId) + sym.setInfo(adaptToNewRunMap(tp)) + } + catch { case e: MissingRequirementError => throw toTypeError(e) } override def load(sym: Symbol) { complete(sym) } diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala index e3fb1a9cad..d26a1abadb 100644 --- a/src/compiler/scala/reflect/internal/util/Collections.scala +++ b/src/compiler/scala/reflect/internal/util/Collections.scala @@ -64,7 +64,7 @@ trait Collections { } lb.toList } - + final def foreachWithIndex[A, B](xs: List[A])(f: (A, Int) => Unit) { var index = 0 var ys = xs @@ -74,6 +74,10 @@ trait Collections { index += 1 } } + + @inline final def findOrElse[A](xs: TraversableOnce[A])(p: A => Boolean)(orElse: => A): A = { + xs find p getOrElse orElse + } final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = { val lb = new ListBuffer[B] @@ -98,7 +102,7 @@ trait Collections { val x2 = ys2.head if (p(x1, x2)) buf += ((x1, x2)) - + ys1 = ys1.tail ys2 = ys2.tail } @@ -130,7 +134,7 @@ trait Collections { while (!ys1.isEmpty && !ys2.isEmpty) { if (f(ys1.head, ys2.head)) return true - + ys1 = ys1.tail ys2 = ys2.tail } @@ -142,7 +146,7 @@ trait Collections { while (!ys1.isEmpty && !ys2.isEmpty) { if (!f(ys1.head, ys2.head)) return false - + ys1 = ys1.tail ys2 = ys2.tail } @@ -155,7 +159,7 @@ trait Collections { while (!ys1.isEmpty && !ys2.isEmpty && !ys3.isEmpty) { if (!f(ys1.head, ys2.head, ys3.head)) return false - + ys1 = ys1.tail ys2 = ys2.tail ys3 = ys3.tail diff --git a/src/compiler/scala/reflect/runtime/ConversionUtil.scala b/src/compiler/scala/reflect/runtime/ConversionUtil.scala index e75fd78590..8c32026e37 100644 --- a/src/compiler/scala/reflect/runtime/ConversionUtil.scala +++ b/src/compiler/scala/reflect/runtime/ConversionUtil.scala @@ -23,7 +23,7 @@ trait ConversionUtil { self: SymbolTable => toJavaMap(s) = j } - def toScala(key: J)(body: => S): S = synchronized { + def toScala(key: J)(body: => S): S = synchronized { toScalaMap get key match { case Some(v) => v @@ -34,7 +34,7 @@ trait ConversionUtil { self: SymbolTable => } } - def toJava(key: S)(body: => J): J = synchronized { + def toJava(key: S)(body: => J): J = synchronized { toJavaMap get key match { case Some(v) => v diff --git a/src/compiler/scala/reflect/runtime/Mirror.scala b/src/compiler/scala/reflect/runtime/Mirror.scala index 028a660a35..d3e4dd7619 100644 --- a/src/compiler/scala/reflect/runtime/Mirror.scala +++ b/src/compiler/scala/reflect/runtime/Mirror.scala @@ -16,12 +16,12 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe val clazz = javaClass(name, defaultReflectiveClassLoader()) classToScala(clazz) } - + def companionInstance(clazz: Symbol): AnyRef = { val singleton = ReflectionUtils.singletonInstance(clazz.fullName, defaultReflectiveClassLoader()) singleton } - + def symbolOfInstance(obj: Any): Symbol = classToScala(obj.getClass) def typeOfInstance(obj: Any): Type = typeToScala(obj.getClass) // to do add getClass/getType for instances of primitive types, probably like this: @@ -41,8 +41,8 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe case nme.update => return Array.set(receiver, args(0).asInstanceOf[Int], args(1)) } } - - val jmeth = methodToJava(meth) + + val jmeth = methodToJava(meth) jmeth.invoke(receiver, args.asInstanceOf[Seq[AnyRef]]: _*) } @@ -51,7 +51,7 @@ class Mirror extends Universe with RuntimeTypes with TreeBuildUtil with ToolBoxe override def typeToClass(tpe: Type): java.lang.Class[_] = typeToJavaClass(tpe) override def symbolToClass(sym: Symbol): java.lang.Class[_] = classToJava(sym) - + override def inReflexiveMirror = true } diff --git a/src/compiler/scala/reflect/runtime/SynchronizedOps.scala b/src/compiler/scala/reflect/runtime/SynchronizedOps.scala index 72adbd4004..dd806beb2a 100644 --- a/src/compiler/scala/reflect/runtime/SynchronizedOps.scala +++ b/src/compiler/scala/reflect/runtime/SynchronizedOps.scala @@ -1,22 +1,22 @@ package scala.reflect package runtime -trait SynchronizedOps extends internal.SymbolTable +trait SynchronizedOps extends internal.SymbolTable with SynchronizedSymbols with SynchronizedTypes { self: SymbolTable => - + // Names - + private lazy val nameLock = new Object - + override def newTermName(s: String): TermName = nameLock.synchronized { super.newTermName(s) } override def newTypeName(s: String): TypeName = nameLock.synchronized { super.newTypeName(s) } - + // BaseTypeSeqs - - override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = + + override protected def newBaseTypeSeq(parents: List[Type], elems: Array[Type]) = new BaseTypeSeq(parents, elems) with SynchronizedBaseTypeSeq - + trait SynchronizedBaseTypeSeq extends BaseTypeSeq { override def apply(i: Int): Type = synchronized { super.apply(i) } override def rawElem(i: Int) = synchronized { super.rawElem(i) } @@ -30,9 +30,9 @@ trait SynchronizedOps extends internal.SymbolTable override def lateMap(f: Type => Type): BaseTypeSeq = new MappedBaseTypeSeq(this, f) with SynchronizedBaseTypeSeq } - + // Scopes - + override def newScope = new Scope() with SynchronizedScope override def newNestedScope(outer: Scope): Scope = new Scope(outer) with SynchronizedScope diff --git a/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala index 9baf94f71d..3f2fa30be2 100644 --- a/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/compiler/scala/reflect/runtime/SynchronizedSymbols.scala @@ -6,61 +6,61 @@ import internal.Flags.DEFERRED trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => override protected def nextId() = synchronized { super.nextId() } - - override protected def freshExistentialName(suffix: String) = + + override protected def freshExistentialName(suffix: String) = synchronized { super.freshExistentialName(suffix) } // Set the fields which point companions at one another. Returns the module. override def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = synchronized { super.connectModuleToClass(m, moduleClass) } - + override def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar = new FreeVar(name, value) with SynchronizedTermSymbol initFlags newFlags setInfo tpe override protected def makeNoSymbol = new NoSymbol with SynchronizedSymbol - + trait SynchronizedSymbol extends Symbol { - + override def rawowner = synchronized { super.rawowner } override def rawname = synchronized { super.rawname } override def rawflags = synchronized { super.rawflags } - + override def rawflags_=(x: FlagsType) = synchronized { super.rawflags_=(x) } override def name_=(x: Name) = synchronized { super.name_=(x) } override def owner_=(owner: Symbol) = synchronized { super.owner_=(owner) } - + override def validTo = synchronized { super.validTo } override def validTo_=(x: Period) = synchronized { super.validTo_=(x) } - + override def pos = synchronized { super.pos } override def setPos(pos: Position): this.type = { synchronized { super.setPos(pos) }; this } override def privateWithin = synchronized { super.privateWithin } - override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) } + override def privateWithin_=(sym: Symbol) = synchronized { super.privateWithin_=(sym) } - override def info = synchronized { super.info } + override def info = synchronized { super.info } override def info_=(info: Type) = synchronized { super.info_=(info) } - override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) } + override def updateInfo(info: Type): Symbol = synchronized { super.updateInfo(info) } override def rawInfo: Type = synchronized { super.rawInfo } override def typeParams: List[Symbol] = synchronized { super.typeParams } - override def reset(completer: Type) = synchronized { super.reset(completer) } + override def reset(completer: Type) = synchronized { super.reset(completer) } - override def infosString: String = synchronized { super.infosString } + override def infosString: String = synchronized { super.infosString } override def annotations: List[AnnotationInfo] = synchronized { super.annotations } - override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this } + override def setAnnotations(annots: List[AnnotationInfo]): this.type = { synchronized { super.setAnnotations(annots) }; this } // ------ creators ------------------------------------------------------------------- override def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = new TermSymbol(this, pos, name) with SynchronizedTermSymbol initFlags newFlags - + override def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol = new AbstractTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags - + override def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol = new AliasTypeSymbol(this, pos, name) with SynchronizedTypeSymbol initFlags newFlags @@ -72,10 +72,10 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => override def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = new ClassSymbol(this, pos, name) with SynchronizedClassSymbol initFlags newFlags - + override def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = new ModuleClassSymbol(this, pos, name) with SynchronizedModuleClassSymbol initFlags newFlags - + override def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem = if ((newFlags & DEFERRED) == 0L) new TypeSkolem(this, pos, name, origin) with SynchronizedTypeSymbol initFlags newFlags @@ -116,4 +116,4 @@ trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => override def implicitMembers: List[Symbol] = synchronized { super.implicitMembers } } } - + diff --git a/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala b/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala index c842d3dd01..e5a508f802 100644 --- a/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala +++ b/src/compiler/scala/reflect/runtime/SynchronizedTypes.scala @@ -2,86 +2,86 @@ package scala.reflect package runtime /** This trait overrides methods in reflect.internal, bracketing - * them in synchronized { ... } to make them thread-safe + * them in synchronized { ... } to make them thread-safe */ trait SynchronizedTypes extends internal.Types { self: SymbolTable => - + // No sharing of map objects: override protected def commonOwnerMap = new CommonOwnerMap - + private val uniqueLock = new Object override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) } - + class SynchronizedUndoLog extends UndoLog { - - override def clear() = + + override def clear() = synchronized { super.clear() } - + override def undo[T](block: => T): T = synchronized { super.undo(block) } - + override def undoUnless(block: => Boolean): Boolean = synchronized { super.undoUnless(block) } } - + override protected def newUndoLog = new SynchronizedUndoLog - - override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = + + override protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = synchronized { super.baseTypeOfNonClassTypeRef(tpe, clazz) } - - private val subsametypeLock = new Object - + + private val subsametypeLock = new Object + override def isSameType(tp1: Type, tp2: Type): Boolean = subsametypeLock.synchronized { super.isSameType(tp1, tp2) } - + override def isDifferentType(tp1: Type, tp2: Type): Boolean = subsametypeLock.synchronized { super.isDifferentType(tp1, tp2) } - + override def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = subsametypeLock.synchronized { super.isSubType(tp1, tp2, depth) } - + private val lubglbLock = new Object - + override def glb(ts: List[Type]): Type = lubglbLock.synchronized { super.glb(ts) } - + override def lub(ts: List[Type]): Type = lubglbLock.synchronized { super.lub(ts) } - + private val indentLock = new Object - + override protected def explain[T](op: String, p: (Type, T) => Boolean, tp1: Type, arg2: T): Boolean = { indentLock.synchronized { super.explain(op, p, tp1, arg2) } } - + private val toStringLock = new Object override protected def typeToString(tpe: Type): String = toStringLock.synchronized(super.typeToString(tpe)) - - /* The idea of caches is as follows. + + /* The idea of caches is as follows. * When in reflexive mode, a cache is either null, or one sentinal * value representing undefined or the final defined * value. Hence, we can ask in non-synchronized ode whether the cache field - * is non null and different from the sentinel (if a sentinel exists). + * is non null and different from the sentinel (if a sentinel exists). * If that's true, the cache value is current. * Otherwise we arrive in one of the defined... methods listed below * which go through all steps in synchronized mode. */ - + override protected def defineUnderlyingOfSingleType(tpe: SingleType) = tpe.synchronized { super.defineUnderlyingOfSingleType(tpe) } - - override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = + + override protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = tpe.synchronized { super.defineBaseTypeSeqOfCompoundType(tpe) } - override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = + override protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = tpe.synchronized { super.defineBaseClassesOfCompoundType(tpe) } - - override protected def defineParentsOfTypeRef(tpe: TypeRef) = + + override protected def defineParentsOfTypeRef(tpe: TypeRef) = tpe.synchronized { super.defineParentsOfTypeRef(tpe) } - - override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = + + override protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = tpe.synchronized { super.defineBaseTypeSeqOfTypeRef(tpe) } }
\ No newline at end of file diff --git a/src/compiler/scala/tools/ant/Scaladoc.scala b/src/compiler/scala/tools/ant/Scaladoc.scala index 92d6e6320c..c92474b33e 100644 --- a/src/compiler/scala/tools/ant/Scaladoc.scala +++ b/src/compiler/scala/tools/ant/Scaladoc.scala @@ -123,10 +123,10 @@ class Scaladoc extends ScalaMatchingTask { /** Instruct the compiler to generate unchecked information. */ private var unchecked: Boolean = false - + /** Instruct the ant task not to fail in the event of errors */ private var nofail: Boolean = false - + /*============================================================================*\ ** Properties setters ** \*============================================================================*/ @@ -356,7 +356,7 @@ class Scaladoc extends ScalaMatchingTask { def setDocUncompilable(input: String) { docUncompilable = Some(input) } - + /** Set the `nofail` info attribute. * * @param input One of the flags `yes/no` or `on/off`. Default if no/off. @@ -569,7 +569,7 @@ class Scaladoc extends ScalaMatchingTask { } def safeBuildError(message: String): Unit = if (nofail) log(message) else buildError(message) - + /** Performs the compilation. */ override def execute() = { val Pair(docSettings, sourceFiles) = initialize diff --git a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl index 7e51930fa4..599936f6f8 100644 --- a/src/compiler/scala/tools/ant/templates/tool-unix.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-unix.tmpl @@ -128,9 +128,11 @@ if [[ -z "$cygwin$mingw" ]]; then usebootcp="true" fi +# If using the boot classpath, also pass an empty classpath +# to java to suppress "." from materializing. classpathArgs () { if [[ -n $usebootcp ]]; then - echo "-Xbootclasspath/a:$TOOL_CLASSPATH" + echo "-Xbootclasspath/a:$TOOL_CLASSPATH -classpath \"\"" else echo "-classpath $TOOL_CLASSPATH" fi diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala index 940d115b2f..d6f57801e7 100644 --- a/src/compiler/scala/tools/nsc/CompilationUnits.scala +++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala @@ -74,7 +74,7 @@ trait CompilationUnits { self: Global => * It is empty up to phase 'icode'. */ val icode: LinkedHashSet[icodes.IClass] = new LinkedHashSet - + def echo(pos: Position, msg: String) = reporter.echo(pos, msg) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index ff8d86873c..552479bc0b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -59,7 +59,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb type AbstractFileType = scala.tools.nsc.io.AbstractFile def mkAttributedQualifier(tpe: Type, termSym: Symbol): Tree = gen.mkAttributedQualifier(tpe, termSym) - + def picklerPhase: Phase = if (currentRun.isDefined) currentRun.picklerPhase else NoPhase // platform specific elements @@ -154,7 +154,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Register top level class (called on entering the class) */ def registerTopLevelSym(sym: Symbol) {} - + // ------------------ Reporting ------------------------------------- // not deprecated yet, but a method called "error" imported into @@ -210,22 +210,23 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def logError(msg: String, t: Throwable): Unit = () - private def atPhaseStackMessage = atPhaseStack match { - case Nil => "" - case ps => ps.reverseMap("->" + _).mkString("(", " ", ")") + def logAfterEveryPhase[T](msg: String)(op: => T) { + log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) } - private def shouldLogAtThisPhase = ( + + def shouldLogAtThisPhase = ( (settings.log.isSetByUser) && ((settings.log containsPhase globalPhase) || (settings.log containsPhase phase)) ) - - def logAfterEveryPhase[T](msg: String)(op: => T) { - log("Running operation '%s' after every phase.\n".format(msg) + describeAfterEveryPhase(op)) + def atPhaseStackMessage = atPhaseStack match { + case Nil => "" + case ps => ps.reverseMap("->" + _).mkString("(", " ", ")") } // Over 200 closure objects are eliminated by inlining this. - @inline final def log(msg: => AnyRef): Unit = + @inline final def log(msg: => AnyRef) { if (shouldLogAtThisPhase) inform("[log %s%s] %s".format(globalPhase, atPhaseStackMessage, msg)) + } @inline final override def debuglog(msg: => String) { if (settings.debug.value) @@ -710,18 +711,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb private lazy val unitTimings = mutable.HashMap[CompilationUnit, Long]() withDefaultValue 0L // tracking time spent per unit private def unitTimingsFormatted(): String = { def toMillis(nanos: Long) = "%.3f" format nanos / 1000000d - + val formatter = new util.TableDef[(String, String)] { >> ("ms" -> (_._1)) >+ " " << ("path" -> (_._2)) } "" + ( - new formatter.Table(unitTimings.toList sortBy (-_._2) map { + new formatter.Table(unitTimings.toList sortBy (-_._2) map { case (unit, nanos) => (toMillis(nanos), unit.source.path) }) ) } - + protected def addToPhasesSet(sub: SubComponent, descr: String) { phasesSet += sub phasesDescMap(sub) = descr @@ -772,7 +773,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb * where the value compares unequal to the previous phase's value. */ def afterEachPhase[T](op: => T): List[(Phase, T)] = { - phaseDescriptors.map(_.ownPhase).foldLeft(List[(Phase, T)]()) { (res, ph) => + phaseDescriptors.map(_.ownPhase).filterNot(_ eq NoPhase).foldLeft(List[(Phase, T)]()) { (res, ph) => val value = afterPhase(ph)(op) if (res.nonEmpty && res.head._2 == value) res else ((ph, value)) :: res @@ -866,28 +867,28 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def currentRun: Run = curRun def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile - + // TODO - trim these to the absolute minimum. - @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) - @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) - @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) - @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) - @inline final def afterMixin[T](op: => T): T = afterPhase(currentRun.mixinPhase)(op) - @inline final def afterPickler[T](op: => T): T = afterPhase(currentRun.picklerPhase)(op) - @inline final def afterRefchecks[T](op: => T): T = afterPhase(currentRun.refchecksPhase)(op) - @inline final def afterSpecialize[T](op: => T): T = afterPhase(currentRun.specializePhase)(op) - @inline final def afterTyper[T](op: => T): T = afterPhase(currentRun.typerPhase)(op) - @inline final def afterUncurry[T](op: => T): T = afterPhase(currentRun.uncurryPhase)(op) - @inline final def beforeErasure[T](op: => T): T = beforePhase(currentRun.erasurePhase)(op) + @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) + @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) + @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) + @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) + @inline final def afterMixin[T](op: => T): T = afterPhase(currentRun.mixinPhase)(op) + @inline final def afterPickler[T](op: => T): T = afterPhase(currentRun.picklerPhase)(op) + @inline final def afterRefchecks[T](op: => T): T = afterPhase(currentRun.refchecksPhase)(op) + @inline final def afterSpecialize[T](op: => T): T = afterPhase(currentRun.specializePhase)(op) + @inline final def afterTyper[T](op: => T): T = afterPhase(currentRun.typerPhase)(op) + @inline final def afterUncurry[T](op: => T): T = afterPhase(currentRun.uncurryPhase)(op) + @inline final def beforeErasure[T](op: => T): T = beforePhase(currentRun.erasurePhase)(op) @inline final def beforeExplicitOuter[T](op: => T): T = beforePhase(currentRun.explicitouterPhase)(op) - @inline final def beforeFlatten[T](op: => T): T = beforePhase(currentRun.flattenPhase)(op) - @inline final def beforeIcode[T](op: => T): T = beforePhase(currentRun.icodePhase)(op) - @inline final def beforeMixin[T](op: => T): T = beforePhase(currentRun.mixinPhase)(op) - @inline final def beforePickler[T](op: => T): T = beforePhase(currentRun.picklerPhase)(op) - @inline final def beforeRefchecks[T](op: => T): T = beforePhase(currentRun.refchecksPhase)(op) - @inline final def beforeSpecialize[T](op: => T): T = beforePhase(currentRun.specializePhase)(op) - @inline final def beforeTyper[T](op: => T): T = beforePhase(currentRun.typerPhase)(op) - @inline final def beforeUncurry[T](op: => T): T = beforePhase(currentRun.uncurryPhase)(op) + @inline final def beforeFlatten[T](op: => T): T = beforePhase(currentRun.flattenPhase)(op) + @inline final def beforeIcode[T](op: => T): T = beforePhase(currentRun.icodePhase)(op) + @inline final def beforeMixin[T](op: => T): T = beforePhase(currentRun.mixinPhase)(op) + @inline final def beforePickler[T](op: => T): T = beforePhase(currentRun.picklerPhase)(op) + @inline final def beforeRefchecks[T](op: => T): T = beforePhase(currentRun.refchecksPhase)(op) + @inline final def beforeSpecialize[T](op: => T): T = beforePhase(currentRun.specializePhase)(op) + @inline final def beforeTyper[T](op: => T): T = beforePhase(currentRun.typerPhase)(op) + @inline final def beforeUncurry[T](op: => T): T = beforePhase(currentRun.uncurryPhase)(op) /** Don't want to introduce new errors trying to report errors, * so swallow exceptions. @@ -935,7 +936,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Counts for certain classes of warnings during this run. */ var deprecationWarnings: List[(Position, String)] = Nil var uncheckedWarnings: List[(Position, String)] = Nil - + /** A flag whether macro expansions failed */ var macroExpansionFailed = false @@ -996,16 +997,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb // Each subcomponent supplies a phase, which are chained together. // If -Ystop:phase is given, neither that phase nor any beyond it is added. // If -Yskip:phase is given, that phase will be skipped. - val lastPhase = phaseDescriptors.tail . - takeWhile (pd => !stopPhase(pd.phaseName)) . - filterNot (pd => skipPhase(pd.phaseName)) . - foldLeft (parserPhase) ((chain, ph) => ph newPhase chain) - - // Ensure there is a terminal phase at the end, since -Ystop may have limited the phases. - terminalPhase = - if (lastPhase.name == "terminal") lastPhase - else terminal newPhase lastPhase - + val phaseLinks = { + val phs = ( + phaseDescriptors.tail + takeWhile (pd => !stopPhase(pd.phaseName)) + filterNot (pd => skipPhase(pd.phaseName)) + ) + // Ensure there is a terminal phase at the end, since -Ystop may have limited the phases. + if (phs.isEmpty || (phs.last ne terminal)) phs :+ terminal + else phs + } + // Link them together. + phaseLinks.foldLeft(parserPhase)((chain, ph) => ph newPhase chain) parserPhase } @@ -1082,39 +1085,45 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } def cancel() { reporter.cancelled = true } - + private def currentProgress = (phasec * size) + unitc private def totalProgress = (phaseDescriptors.size - 1) * size // -1: drops terminal phase private def refreshProgress() = if (size > 0) progress(currentProgress, totalProgress) // ----- finding phases -------------------------------------------- - def phaseNamed(name: String): Phase = { - var p: Phase = firstPhase - while (p.next != p && p.name != name) p = p.next - if (p.name != name) NoPhase else p - } - - val parserPhase = phaseNamed("parser") - val namerPhase = phaseNamed("namer") - // packageobjects - val typerPhase = phaseNamed("typer") - // superaccessors - val picklerPhase = phaseNamed("pickler") - val refchecksPhase = phaseNamed("refchecks") - val uncurryPhase = phaseNamed("uncurry") - // tailcalls, specialize - val specializePhase = phaseNamed("specialize") - val explicitouterPhase = phaseNamed("explicitouter") - val erasurePhase = phaseNamed("erasure") - // lazyvals, lambdalift, constructors - val lambdaLiftPhase = phaseNamed("lambdalift") - val flattenPhase = phaseNamed("flatten") - val mixinPhase = phaseNamed("mixin") - val cleanupPhase = phaseNamed("cleanup") - val icodePhase = phaseNamed("icode") - // inliner, closelim, dce - val jvmPhase = phaseNamed("jvm") + def phaseNamed(name: String): Phase = + findOrElse(firstPhase.iterator)(_.name == name)(NoPhase) + + /** All phases as of 3/2012 here for handiness; the ones in + * active use uncommented. + */ + val parserPhase = phaseNamed("parser") + val namerPhase = phaseNamed("namer") + // val packageobjectsPhase = phaseNamed("packageobjects") + val typerPhase = phaseNamed("typer") + // val superaccessorsPhase = phaseNamed("superaccessors") + val picklerPhase = phaseNamed("pickler") + val refchecksPhase = phaseNamed("refchecks") + // val selectiveanfPhase = phaseNamed("selectiveanf") + // val selectivecpsPhase = phaseNamed("selectivecps") + val uncurryPhase = phaseNamed("uncurry") + // val tailcallsPhase = phaseNamed("tailcalls") + val specializePhase = phaseNamed("specialize") + val explicitouterPhase = phaseNamed("explicitouter") + val erasurePhase = phaseNamed("erasure") + // val lazyvalsPhase = phaseNamed("lazyvals") + val lambdaliftPhase = phaseNamed("lambdalift") + // val constructorsPhase = phaseNamed("constructors") + val flattenPhase = phaseNamed("flatten") + val mixinPhase = phaseNamed("mixin") + val cleanupPhase = phaseNamed("cleanup") + val icodePhase = phaseNamed("icode") + // val inlinerPhase = phaseNamed("inliner") + // val inlineExceptionHandlersPhase = phaseNamed("inlineExceptionHandlers") + // val closelimPhase = phaseNamed("closelim") + // val dcePhase = phaseNamed("dce") + val jvmPhase = phaseNamed("jvm") def runIsAt(ph: Phase) = globalPhase.id == ph.id def runIsPast(ph: Phase) = globalPhase.id > ph.id @@ -1250,12 +1259,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb */ def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) - catch { case ex => + catch { case ex => globalError(supplementErrorMessage("uncaught exception during compilation: " + ex.getClass.getName)) throw ex } } - + private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) { units foreach addUnit if (opt.profileAll) { @@ -1268,7 +1277,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb checkDeprecatedSettings(unitbuf.head) globalPhase = fromPhase - while (globalPhase != terminalPhase && !reporter.hasErrors) { + while (globalPhase.hasNext && !reporter.hasErrors) { val startTime = currentTime phase = globalPhase @@ -1389,19 +1398,13 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Compile abstract file until `globalPhase`, but at least to phase "namer". */ def compileLate(unit: CompilationUnit) { - def stop(ph: Phase) = ph == null || ph.id >= (globalPhase.id max typerPhase.id) - def loop(ph: Phase) { - if (stop(ph)) refreshProgress - else { - atPhase(ph)(ph.asInstanceOf[GlobalPhase] applyPhase unit) - loop(ph.next match { - case `ph` => null // ph == ph.next implies terminal, and null ends processing - case x => x - }) - } - } + val maxId = math.max(globalPhase.id, typerPhase.id) addUnit(unit) - loop(firstPhase) + + firstPhase.iterator takeWhile (_.id < maxId) foreach (ph => + atPhase(ph)(ph.asInstanceOf[GlobalPhase] applyPhase unit) + ) + refreshProgress } /** diff --git a/src/compiler/scala/tools/nsc/MacroContext.scala b/src/compiler/scala/tools/nsc/MacroContext.scala index 72662291f8..9ea1f87125 100644 --- a/src/compiler/scala/tools/nsc/MacroContext.scala +++ b/src/compiler/scala/tools/nsc/MacroContext.scala @@ -3,8 +3,8 @@ package scala.tools.nsc import symtab.Flags._ trait MacroContext extends reflect.macro.Context { self: Global => - + def captureVariable(vble: Symbol): Unit = vble setFlag CAPTURED - + def referenceCapturedVariable(id: Ident): Tree = ReferenceToBoxed(id) } diff --git a/src/compiler/scala/tools/nsc/SubComponent.scala b/src/compiler/scala/tools/nsc/SubComponent.scala index 7e832a56b0..a3e451f32f 100644 --- a/src/compiler/scala/tools/nsc/SubComponent.scala +++ b/src/compiler/scala/tools/nsc/SubComponent.scala @@ -46,9 +46,9 @@ abstract class SubComponent { private var ownPhaseCache: WeakReference[Phase] = new WeakReference(null) private var ownPhaseRunId = global.NoRunId - - @inline final def atOwnPhase[T](op: => T) = global.atPhase(ownPhase)(op) - @inline final def afterOwnPhase[T](op: => T) = global.afterPhase(ownPhase)(op) + + @inline final def beforeOwnPhase[T](op: => T) = global.beforePhase(ownPhase)(op) + @inline final def afterOwnPhase[T](op: => T) = global.afterPhase(ownPhase)(op) /** The phase corresponding to this subcomponent in the current compiler run */ def ownPhase: Phase = { diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala index f361d45018..0d19b781e2 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala @@ -253,13 +253,11 @@ trait TreeDSL { } /** Top level accessible. */ - def MATCHERROR(arg: Tree) = Throw(New(MatchErrorClass, arg)) - /** !!! should generalize null guard from match error here. */ - def THROW(sym: Symbol): Throw = Throw(New(sym)) - def THROW(sym: Symbol, msg: Tree): Throw = Throw(New(sym, msg.TOSTRING())) + def MATCHERROR(arg: Tree) = Throw(MatchErrorClass.tpe, arg) + def THROW(sym: Symbol, msg: Tree): Throw = Throw(sym.tpe, msg.TOSTRING()) def NEW(tpt: Tree, args: Tree*): Tree = New(tpt, List(args.toList)) - def NEW(sym: Symbol, args: Tree*): Tree = New(sym, args: _*) + def NEW(sym: Symbol, args: Tree*): Tree = New(sym.tpe, args: _*) def DEF(name: Name, tp: Type): DefTreeStart = DEF(name) withType tp def DEF(name: Name): DefTreeStart = new DefTreeStart(name) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index c7414bf34b..d7159c5fa8 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -30,7 +30,7 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { else tree } - + /** Builds a fully attributed wildcard import node. */ def mkWildcardImport(pkg: Symbol): Import = { @@ -51,9 +51,8 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { } // wrap the given expression in a SoftReference so it can be gc-ed - def mkSoftRef(expr: Tree): Tree = atPos(expr.pos) { - New(SoftReferenceClass, expr) - } + def mkSoftRef(expr: Tree): Tree = atPos(expr.pos)(New(SoftReferenceClass.tpe, expr)) + // annotate the expression with @unchecked def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { // This can't be "Annotated(New(UncheckedClass), expr)" because annotations @@ -161,7 +160,7 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { def mkModuleVarDef(accessor: Symbol) = { val inClass = accessor.owner.isClass val extraFlags = if (inClass) PrivateLocal | SYNTHETIC else 0 - + val mval = ( accessor.owner.newVariable(nme.moduleVarName(accessor.name), accessor.pos.focus, MODULEVAR | extraFlags) setInfo accessor.tpe.finalResultType @@ -220,6 +219,18 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { def mkSynchronized(monitor: Tree, body: Tree): Tree = Apply(Select(monitor, Object_synchronized), List(body)) + def mkAppliedTypeForCase(clazz: Symbol): Tree = { + val numParams = clazz.typeParams.size + if (clazz.typeParams.isEmpty) Ident(clazz) + else AppliedTypeTree(Ident(clazz), 1 to numParams map (_ => Bind(tpnme.WILDCARD, EmptyTree)) toList) + } + def mkBindForCase(patVar: Symbol, clazz: Symbol, targs: List[Type]): Tree = { + Bind(patVar, Typed(Ident(nme.WILDCARD), + if (targs.isEmpty) mkAppliedTypeForCase(clazz) + else AppliedTypeTree(Ident(clazz), targs map TypeTree) + )) + } + def wildcardStar(tree: Tree) = atPos(tree.pos) { Typed(tree, Ident(tpnme.WILDCARD_STAR)) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 8e445a62db..077f0f9c0e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -38,7 +38,7 @@ trait ParsersCommon extends ScannersCommon { def freshTypeName(prefix: String): TypeName def deprecationWarning(off: Int, msg: String): Unit def accept(token: Int): Int - + /** Methods inParensOrError and similar take a second argument which, should * the next token not be the expected opener (e.g. LPAREN) will be returned * instead of the contents of the groupers. However in all cases accept(LPAREN) @@ -658,7 +658,8 @@ self => DocDef(doc, t) setPos { if (t.pos.isDefined) { val pos = doc.pos.withEnd(t.pos.endOrPoint) - if (t.pos.isOpaqueRange) pos else pos.makeTransparent + // always make the position transparent + pos.makeTransparent } else { t.pos } @@ -1141,7 +1142,7 @@ self => private def interpolatedString(): Tree = atPos(in.offset) { val start = in.offset val interpolator = in.name - + val partsBuf = new ListBuffer[Tree] val exprBuf = new ListBuffer[Tree] in.nextToken() @@ -1153,7 +1154,7 @@ self => } } if (in.token == STRINGLIT) partsBuf += literal() - + val t1 = atPos(o2p(start)) { Ident(nme.StringContext) } val t2 = atPos(start) { Apply(t1, partsBuf.toList) } t2 setPos t2.pos.makeTransparent diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index f712c7411f..2895d02dfe 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -84,7 +84,7 @@ trait Scanners extends ScannersCommon { abstract class Scanner extends CharArrayReader with TokenData with ScannerCommon { private def isDigit(c: Char) = java.lang.Character isDigit c - + def isAtEnd = charOffset >= buf.length def flush = { charOffset = offset; nextChar(); this } @@ -164,7 +164,7 @@ trait Scanners extends ScannersCommon { * RBRACE if region starts with '{' * ARROW if region starts with `case' * STRINGLIT if region is a string interpolation expression starting with '${' - * (the STRINGLIT appears twice in succession on the stack iff the + * (the STRINGLIT appears twice in succession on the stack iff the * expression is a multiline string literal). */ var sepRegions: List[Int] = List() @@ -173,15 +173,15 @@ trait Scanners extends ScannersCommon { /** Are we directly in a string interpolation expression? */ - @inline private def inStringInterpolation = + @inline private def inStringInterpolation = sepRegions.nonEmpty && sepRegions.head == STRINGLIT - + /** Are we directly in a multiline string interpolation expression? * @pre: inStringInterpolation */ - @inline private def inMultiLineInterpolation = + @inline private def inMultiLineInterpolation = inStringInterpolation && sepRegions.tail.nonEmpty && sepRegions.tail.head == STRINGPART - + /** read next token and return last offset */ def skipToken(): Offset = { @@ -205,7 +205,7 @@ trait Scanners extends ScannersCommon { case CASE => sepRegions = ARROW :: sepRegions case RBRACE => - while (!sepRegions.isEmpty && sepRegions.head != RBRACE) + while (!sepRegions.isEmpty && sepRegions.head != RBRACE) sepRegions = sepRegions.tail if (!sepRegions.isEmpty) sepRegions = sepRegions.tail docBuffer = null @@ -223,7 +223,7 @@ trait Scanners extends ScannersCommon { sepRegions = sepRegions.tail case _ => } - + // Read a token or copy it from `next` tokenData if (next.token == EMPTY) { lastOffset = charOffset - 1 @@ -327,8 +327,8 @@ trait Scanners extends ScannersCommon { 'z' => putChar(ch) nextChar() - getIdentRest() - if (ch == '"' && token == IDENTIFIER && settings.Xexperimental.value) + getIdentRest() + if (ch == '"' && token == IDENTIFIER && settings.Xexperimental.value) token = INTERPOLATIONID case '<' => // is XMLSTART? val last = if (charOffset >= 2) buf(charOffset - 2) else ' ' @@ -409,7 +409,7 @@ trait Scanners extends ScannersCommon { token = STRINGLIT strVal = "" } - } else { + } else { getStringLit() } } @@ -632,8 +632,8 @@ trait Scanners extends ScannersCommon { else finishNamed() } } - - + + // Literals ----------------------------------------------------------------- private def getStringLit() = { @@ -661,21 +661,27 @@ trait Scanners extends ScannersCommon { getRawStringLit() } } - + @annotation.tailrec private def getStringPart(multiLine: Boolean): Unit = { def finishStringPart() = { setStrVal() token = STRINGPART next.lastOffset = charOffset - 1 next.offset = charOffset - 1 - } + } if (ch == '"') { - nextRawChar() - if (!multiLine || isTripleQuote()) { + if (multiLine) { + nextRawChar() + if (isTripleQuote()) { + setStrVal() + token = STRINGLIT + } else + getStringPart(multiLine) + } else { + nextChar() setStrVal() token = STRINGLIT - } else - getStringPart(multiLine) + } } else if (ch == '$') { nextRawChar() if (ch == '$') { @@ -698,20 +704,23 @@ trait Scanners extends ScannersCommon { } else { syntaxError("invalid string interpolation") } - } else if ((ch == CR || ch == LF || ch == SU) && !isUnicodeEscape) { - syntaxError("unclosed string literal") } else { - putChar(ch) - nextRawChar() - getStringPart(multiLine) + val isUnclosedLiteral = !isUnicodeEscape && (ch == SU || (!multiLine && (ch == CR || ch == LF))) + if (isUnclosedLiteral) { + syntaxError(if (!multiLine) "unclosed string literal" else "unclosed multi-line string literal") + } else { + putChar(ch) + nextRawChar() + getStringPart(multiLine) + } } } - + private def fetchStringPart() = { offset = charOffset - 1 getStringPart(multiLine = inMultiLineInterpolation) } - + private def isTripleQuote(): Boolean = if (ch == '"') { nextRawChar() @@ -732,7 +741,7 @@ trait Scanners extends ScannersCommon { false } - /** copy current character into cbuf, interpreting any escape sequences, + /** copy current character into cbuf, interpreting any escape sequences, * and advance to next character. */ protected def getLitChar(): Unit = diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 091f333c27..fb4daefd57 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -58,7 +58,7 @@ object Tokens extends Tokens { final val BACKQUOTED_IDENT = 11 def isIdentifier(code: Int) = code >= IDENTIFIER && code <= BACKQUOTED_IDENT - + @switch def canBeginExpression(code: Int) = code match { case IDENTIFIER|BACKQUOTED_IDENT|USCORE => true case LBRACE|LPAREN|LBRACKET|COMMENT => true diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala index 4ab0eb0129..68c4ac03f6 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala @@ -18,7 +18,7 @@ trait BasicBlocks { import opcodes._ import global.{ ifDebug, settings, log, nme } import nme.isExceptionResultName - + object NoBasicBlock extends BasicBlock(-1, null) /** This class represents a basic block. Each @@ -182,7 +182,7 @@ trait BasicBlocks { final def foreach[U](f: Instruction => U) = { if (!closed) dumpMethodAndAbort(method, this) else instrs foreach f - + // !!! If I replace "instrs foreach f" with the following: // var i = 0 // val len = instrs.length diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala index 44a58e75b4..36651541b2 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala @@ -21,7 +21,7 @@ trait Members { self: ICodes => import global._ - + object NoCode extends Code(null, "NoCode") { override def blocksList: List[BasicBlock] = Nil } @@ -138,7 +138,7 @@ trait Members { /** Represent a field in ICode */ class IField(val symbol: Symbol) extends IMember { } - + object NoIMethod extends IMethod(NoSymbol) { } /** @@ -183,12 +183,7 @@ trait Members { this } - def addLocal(l: Local): Local = - locals find (_ == l) getOrElse { - locals ::= l - l - } - + def addLocal(l: Local): Local = findOrElse(locals)(_ == l) { locals ::= l ; l } def addParam(p: Local): Unit = if (params contains p) () @@ -212,7 +207,7 @@ trait Members { def isStatic: Boolean = symbol.isStaticMember override def toString() = symbol.fullName - + def matchesSignature(other: IMethod) = { (symbol.name == other.symbol.name) && (params corresponds other.params)(_.kind == _.kind) && diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala index ba4b250303..8a2ec9a191 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeStacks.scala @@ -21,7 +21,7 @@ trait TypeStacks { * stack of the ICode. */ type Rep = List[TypeKind] - + object NoTypeStack extends TypeStack(Nil) { } class TypeStack(var types: Rep) { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 32177c309a..c217869a48 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -83,7 +83,7 @@ trait BytecodeWriters { emitJavap(bytes, javapFile) } } - + trait ClassBytecodeWriter extends BytecodeWriter { def writeClass(label: String, jclass: JClass, sym: Symbol) { val outfile = getFile(sym, jclass, ".class") @@ -94,18 +94,18 @@ trait BytecodeWriters { informProgress("wrote '" + label + "' to " + outfile) } } - + trait DumpBytecodeWriter extends BytecodeWriter { val baseDir = Directory(settings.Ydumpclasses.value).createDirectory() - + abstract override def writeClass(label: String, jclass: JClass, sym: Symbol) { super.writeClass(label, jclass, sym) - + val pathName = jclass.getName() var dumpFile = pathName.split("[./]").foldLeft(baseDir: Path) (_ / _) changeExtension "class" toFile; dumpFile.parent.createDirectory() val outstream = new DataOutputStream(new FileOutputStream(dumpFile.path)) - + try jclass writeTo outstream finally outstream.close() } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index a838c7d54d..387b7fb3d7 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -152,7 +152,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (settings.Ygenjavap.isDefault) { if(settings.Ydumpclasses.isDefault) new ClassBytecodeWriter { } - else + else new ClassBytecodeWriter with DumpBytecodeWriter { } } else new ClassBytecodeWriter with JavapBytecodeWriter { } @@ -207,7 +207,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val BeanInfoSkipAttr = definitions.getRequiredClass("scala.beans.BeanInfoSkip") val BeanDisplayNameAttr = definitions.getRequiredClass("scala.beans.BeanDisplayName") val BeanDescriptionAttr = definitions.getRequiredClass("scala.beans.BeanDescription") - + final val ExcludedForwarderFlags = { import Flags._ // Should include DEFERRED but this breaks findMember. @@ -1914,7 +1914,8 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (sym.isStaticMember) ACC_STATIC else 0, if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0, if (sym.isClass && !sym.isInterface) ACC_SUPER else 0, - if (sym.isVarargsMethod) ACC_VARARGS else 0 + if (sym.isVarargsMethod) ACC_VARARGS else 0, + if (sym.hasFlag(Flags.SYNCHRONIZED)) JAVA_ACC_SYNCHRONIZED else 0 ) } def javaFieldFlags(sym: Symbol) = { diff --git a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala index e8abee7d06..ff45bb8fd1 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/ClosureElimination.scala @@ -108,7 +108,7 @@ abstract class ClosureElimination extends SubComponent { case LOAD_LOCAL(l) if info.bindings isDefinedAt LocalVar(l) => val t = info.getBinding(l) t match { - case Deref(LocalVar(_)) | Deref(This) | Const(_) => + case Deref(This) | Const(_) => bb.replaceInstruction(i, valueToInstruction(t)); log("replaced " + i + " with " + t) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index d017cf94b3..a734b2b92b 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -707,7 +707,8 @@ abstract class Inliners extends SubComponent { } def isStampedForInlining(stackLength: Int) = - !sameSymbols && inc.m.hasCode && shouldInline && isSafeToInline(stackLength) + !sameSymbols && inc.m.hasCode && shouldInline && + isSafeToInline(stackLength) // `isSafeToInline()` must be invoked last in this AND expr bc it mutates the `knownSafe` and `knownUnsafe` maps for good. def logFailure(stackLength: Int) = log( """|inline failed for %s: @@ -724,6 +725,7 @@ abstract class Inliners extends SubComponent { def failureReason(stackLength: Int) = if (!inc.m.hasCode) "bytecode was unavailable" + else if (inc.m.symbol.hasFlag(Flags.SYNCHRONIZED)) "method is synchronized" else if (!isSafeToInline(stackLength)) "it is unsafe (target may reference private fields)" else "of a bug (run with -Ylog:inline -Ydebug for more information)" @@ -764,8 +766,8 @@ abstract class Inliners extends SubComponent { true } - if (!inc.m.hasCode || inc.isRecursive) - return false + if (!inc.m.hasCode || inc.isRecursive) { return false } + if (inc.m.symbol.hasFlag(Flags.SYNCHRONIZED)) { return false } val accessNeeded = usesNonPublics.getOrElseUpdate(inc.m, { // Avoiding crashing the compiler if there are open blocks. diff --git a/src/compiler/scala/tools/nsc/dependencies/Changes.scala b/src/compiler/scala/tools/nsc/dependencies/Changes.scala index 089ef9cf35..176c00c025 100644 --- a/src/compiler/scala/tools/nsc/dependencies/Changes.scala +++ b/src/compiler/scala/tools/nsc/dependencies/Changes.scala @@ -18,7 +18,7 @@ abstract class Changes { abstract class Change - private lazy val annotationsChecked = + private lazy val annotationsChecked = List(definitions.SpecializedClass) // Any others that should be checked? private val flagsToCheck = IMPLICIT | FINAL | PRIVATE | PROTECTED | SEALED | diff --git a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala index 395757237b..02be916f59 100644 --- a/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala +++ b/src/compiler/scala/tools/nsc/dependencies/DependencyAnalysis.scala @@ -146,7 +146,7 @@ trait DependencyAnalysis extends SubComponent with Files { d.symbol match { case s : ModuleClassSymbol => val isTopLevelModule = afterPickler { !s.isImplClass && !s.isNestedClass } - + if (isTopLevelModule && (s.companionModule != NoSymbol)) { dependencies.emits(source, nameToFile(unit.source.file, name)) } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 7eb8c393f3..127faf8ed9 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -104,7 +104,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { case mb: NonTemplateMemberEntity if (mb.useCaseOf.isDefined) => mb.useCaseOf.get.inDefinitionTemplates case _ => - if (inTpl == null) + if (inTpl == null) makeRootPackage.toList else makeTemplate(sym.owner) :: (sym.allOverriddenSymbols map { inhSym => makeTemplate(inhSym.owner) }) @@ -123,14 +123,14 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { else Public() } } - def flags = { + def flags = { val fgs = mutable.ListBuffer.empty[Paragraph] if (sym.isImplicit) fgs += Paragraph(Text("implicit")) if (sym.isSealed) fgs += Paragraph(Text("sealed")) if (!sym.isTrait && (sym hasFlag Flags.ABSTRACT)) fgs += Paragraph(Text("abstract")) if (!sym.isTrait && (sym hasFlag Flags.DEFERRED)) fgs += Paragraph(Text("abstract")) if (!sym.isModule && (sym hasFlag Flags.FINAL)) fgs += Paragraph(Text("final")) - fgs.toList + fgs.toList } def deprecation = if (sym.isDeprecated) diff --git a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala index f2d59206e0..1b91b06942 100644 --- a/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala +++ b/src/compiler/scala/tools/nsc/interactive/CompilerControl.scala @@ -10,6 +10,8 @@ import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.{SourceFile, Position, WorkScheduler} import scala.tools.nsc.symtab._ import scala.tools.nsc.ast._ +import scala.tools.nsc.util.FailedInterrupt +import scala.tools.nsc.util.EmptyAction /** Interface of interactive compiler to a client such as an IDE * The model the presentation compiler consists of the following parts: @@ -48,7 +50,7 @@ trait CompilerControl { self: Global => /** The scheduler by which client and compiler communicate * Must be initialized before starting compilerRunner */ - protected[interactive] val scheduler = new WorkScheduler + @volatile protected[interactive] var scheduler = new WorkScheduler /** Return the compilation unit attached to a source file, or None * if source is not loaded. @@ -374,6 +376,25 @@ trait CompilerControl { self: Global => response raise new MissingResponse } + /** A do-nothing work scheduler that responds immediately with MissingResponse. + * + * Used during compiler shutdown. + */ + class NoWorkScheduler extends WorkScheduler { + + override def postWorkItem(action: Action) = synchronized { + action match { + case w: WorkItem => w.raiseMissing() + case e: EmptyAction => // do nothing + case _ => println("don't know what to do with this " + action.getClass) + } + } + + override def doQuickly[A](op: () => A): A = { + throw new FailedInterrupt(new Exception("Posted a work item to a compiler that's shutting down")) + } + } + } // ---------------- Interpreted exceptions ------------------- diff --git a/src/compiler/scala/tools/nsc/interactive/Global.scala b/src/compiler/scala/tools/nsc/interactive/Global.scala index 0f28407f5a..166b38f503 100644 --- a/src/compiler/scala/tools/nsc/interactive/Global.scala +++ b/src/compiler/scala/tools/nsc/interactive/Global.scala @@ -357,6 +357,7 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") checkNoResponsesOutstanding() log.flush(); + scheduler = new NoWorkScheduler throw ShutdownReq } @@ -609,6 +610,15 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") } response raise ex throw ex + + case ex @ ShutdownReq => + if (debugIDE) { + println("ShutdownReq thrown during response") + ex.printStackTrace() + } + response raise ex + throw ex + case ex => if (debugIDE) { println("exception thrown during response: "+ex) @@ -1052,7 +1062,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "") def newTyperRun() { currentTyperRun = new TyperRun - perRunCaches.clearAll() } class TyperResult(val tree: Tree) extends ControlThrowable diff --git a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala index 39a1a406ba..68c8f2fdb8 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ExprTyper.scala @@ -92,7 +92,7 @@ trait ExprTyper { case _ => NoType } } - + def evaluate(): Type = { typeOfExpressionDepth += 1 try typeOfTerm(expr) orElse asModule orElse asExpr orElse asQualifiedImport diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 16085c07d6..e1ea69842f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -382,7 +382,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private def findToolsJar() = { val jdkPath = Directory(jdkHome) val jar = jdkPath / "lib" / "tools.jar" toFile; - + if (jar isFile) Some(jar) else if (jdkPath.isDirectory) diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala index 073501912a..d579e0369e 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Imports.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala @@ -61,7 +61,7 @@ trait Imports { def importedTypeSymbols = importedSymbols collect { case x: TypeSymbol => x } def implicitSymbols = importedSymbols filter (_.isImplicit) - def importedTermNamed(name: String): Symbol = + def importedTermNamed(name: String): Symbol = importedTermSymbols find (_.name.toString == name) getOrElse NoSymbol /** Tuples of (source, imported symbols) in the order they were imported. diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala index 0e2c34efbf..f9c1907696 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineCompletion.scala @@ -61,7 +61,7 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput def packageNames = packages map tos def aliasNames = aliases map tos } - + object NoTypeCompletion extends TypeMemberCompletion(NoType) { override def memberNamed(s: String) = NoSymbol override def members = Nil @@ -165,11 +165,11 @@ class JLineCompletion(val intp: IMain) extends Completion with CompletionOutput override def follow(id: String): Option[CompletionAware] = { if (!completions(0).contains(id)) return None - + val tpe = intp typeOfExpression id if (tpe == NoType) return None - + def default = Some(TypeMemberCompletion(tpe)) // only rebinding vals in power mode for now. diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index ef84876b94..14876425f4 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -155,7 +155,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl ( rutil.info[ReplValsImpl].membersDeclared filter (m => m.isPublic && !m.hasModuleFlag && !m.isConstructor) - sortBy (_.decodedName) + sortBy (_.decodedName) map to_str mkString ("Name and type of values imported into the repl in power mode.\n\n", "\n", "") ) @@ -165,7 +165,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None) } object InternalInfo extends LowPriorityInternalInfo { } - + /** Now dealing with the problem of acidentally calling a method on Type * when you're holding a Symbol and seeing the Symbol converted to the * type of Symbol rather than the type of the thing represented by the @@ -176,7 +176,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl implicit def apply[T: Manifest] : InternalInfoWrapper[T] = new InternalInfoWrapper[T](None) } object InternalInfoWrapper extends LowPriorityInternalInfoWrapper { - + } class InternalInfoWrapper[T: Manifest](value: Option[T] = None) { def ? : InternalInfo[T] = new InternalInfo[T](value) @@ -190,7 +190,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl private def newInfo[U: Manifest](value: U): InternalInfo[U] = new InternalInfo[U](Some(value)) private def isSpecialized(s: Symbol) = s.name.toString contains "$mc" private def isImplClass(s: Symbol) = s.name.toString endsWith "$class" - + /** Standard noise reduction filter. */ def excludeMember(s: Symbol) = ( isSpecialized(s) @@ -218,7 +218,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl def membersInherited = members filterNot (membersDeclared contains _) def memberTypes = members filter (_.name.isTypeName) def memberMethods = members filter (_.isMethod) - + def pkg = symbol.enclosingPackage def pkgName = pkg.fullName def pkgClass = symbol.enclosingPackageClass @@ -343,12 +343,12 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl def sigs = syms map (_.defString) def infos = syms map (_.info) } - + trait Implicits1 { // fallback implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) = new SinglePrettifierClass[T](x) - + implicit def liftToTypeName(s: String): TypeName = newTypeName(s) } trait Implicits2 extends Implicits1 { @@ -375,7 +375,7 @@ class Power[ReplValsImpl <: ReplVals : Manifest](val intp: IMain, replVals: Repl implicit def replInputStream(in: InputStream)(implicit codec: Codec) = new RichInputStream(in) implicit def replEnhancedURLs(url: URL)(implicit codec: Codec): RichReplURL = new RichReplURL(url)(codec) - + implicit def liftToTermName(s: String): TermName = newTermName(s) implicit def replListOfSymbols(xs: List[Symbol]) = new RichSymbolList(xs) } diff --git a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala index b20017c1d3..a68392f0fb 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ReplVals.scala @@ -50,7 +50,7 @@ object ReplVals { def mkManifestToType[T <: Global](global: T) = { import global._ import definitions._ - + /** We can't use definitions.manifestToType directly because we're passing * it to map and the compiler refuses to perform eta expansion on a method * with a dependent return type. (Can this be relaxed?) To get around this @@ -59,7 +59,7 @@ object ReplVals { */ def manifestToType(m: OptManifest[_]): Global#Type = definitions.manifestToType(m) - + class AppliedTypeFromManifests(sym: Symbol) { def apply[M](implicit m1: Manifest[M]): Type = if (sym eq NoSymbol) NoType @@ -69,7 +69,7 @@ object ReplVals { if (sym eq NoSymbol) NoType else appliedType(sym.typeConstructor, List(m1, m2) map (x => manifestToType(x).asInstanceOf[Type])) } - + (sym: Symbol) => new AppliedTypeFromManifests(sym) } } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 4d94ed68fc..06b06c50a6 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -393,7 +393,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { // assumed true unless we see public/private/protected var isPackageAccess = true var annots: List[Tree] = Nil - def addAnnot(sym: Symbol) = annots :+= New(sym) + def addAnnot(sym: Symbol) = annots :+= New(sym.tpe) while (true) { in.token match { diff --git a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala index 5e46960d04..371f4bc4d8 100644 --- a/src/compiler/scala/tools/nsc/matching/MatchSupport.scala +++ b/src/compiler/scala/tools/nsc/matching/MatchSupport.scala @@ -115,6 +115,10 @@ trait MatchSupport extends ast.TreeDSL { self: ParallelMatching => println(fmt.format(xs: _*) + " == " + x) x } + private[nsc] def debugging[T](fmt: String, xs: Any*)(x: T): T = { + if (settings.debug.value) printing(fmt, xs: _*)(x) + else x + } def indent(s: Any) = s.toString() split "\n" map (" " + _) mkString "\n" def indentAll(s: Seq[Any]) = s map (" " + _.toString() + "\n") mkString diff --git a/src/compiler/scala/tools/nsc/matching/Matrix.scala b/src/compiler/scala/tools/nsc/matching/Matrix.scala index d81f05cd51..e1ff88557e 100644 --- a/src/compiler/scala/tools/nsc/matching/Matrix.scala +++ b/src/compiler/scala/tools/nsc/matching/Matrix.scala @@ -198,6 +198,10 @@ trait Matrix extends MatrixAdditions { class PatternVar(val lhs: Symbol, val rhs: Tree, val checked: Boolean) { def sym = lhs def tpe = lhs.tpe + if (checked) + lhs resetFlag NO_EXHAUSTIVE + else + lhs setFlag NO_EXHAUSTIVE // See #1427 for an example of a crash which occurs unless we retype: // in that instance there is an existential in the pattern. @@ -207,11 +211,6 @@ trait Matrix extends MatrixAdditions { override def toString() = "%s: %s = %s".format(lhs, tpe, rhs) } - /** Sets the rhs to EmptyTree, which makes the valDef ignored in Scrutinee. - */ - def specialVar(lhs: Symbol, checked: Boolean) = - new PatternVar(lhs, EmptyTree, checked) - /** Given a tree, creates a new synthetic variable of the same type * and assigns the tree to it. */ diff --git a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala index 24d3c38e74..e72a0007a0 100644 --- a/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala +++ b/src/compiler/scala/tools/nsc/matching/MatrixAdditions.scala @@ -131,23 +131,11 @@ trait MatrixAdditions extends ast.TreeDSL { import Flags.{ MUTABLE, ABSTRACT, SEALED } - private case class Combo(index: Int, sym: Symbol) { - val isBaseClass = sym.tpe.baseClasses.toSet - - // is this combination covered by the given pattern? - def isCovered(p: Pattern) = { - def coversSym = isBaseClass(decodedEqualsType(p.tpe).typeSymbol) - - cond(p.tree) { - case _: UnApply | _: ArrayValue => true - case x => p.isDefault || coversSym - } - } - } + private case class Combo(index: Int, sym: Symbol) { } /* True if the patterns in 'row' cover the given type symbol combination, and has no guard. */ private def rowCoversCombo(row: Row, combos: List[Combo]) = - row.guard.isEmpty && (combos forall (c => c isCovered row.pats(c.index))) + row.guard.isEmpty && combos.forall(c => row.pats(c.index) covers c.sym) private def requiresExhaustive(sym: Symbol) = { (sym.isMutable) && // indicates that have not yet checked exhaustivity diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index 9d4c9b4411..1285e29d4a 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -745,7 +745,7 @@ trait ParallelMatching extends ast.TreeDSL (others.head :: _column.tail, make(_tvars, _rows)) def mix() = { - val newScrut = new Scrutinee(specialVar(_pv.sym, _pv.checked)) + val newScrut = new Scrutinee(new PatternVar(_pv.sym, EmptyTree, _pv.checked)) PatternMatch(newScrut, _ncol) mkRule _nrep } } diff --git a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala index 5dd7d8f3ee..56297f0195 100644 --- a/src/compiler/scala/tools/nsc/matching/PatternBindings.scala +++ b/src/compiler/scala/tools/nsc/matching/PatternBindings.scala @@ -19,9 +19,10 @@ trait PatternBindings extends ast.TreeDSL import Debug._ /** EqualsPattern **/ - def isEquals(tpe: Type) = cond(tpe) { case TypeRef(_, EqualsPatternClass, _) => true } + def isEquals(tpe: Type) = tpe.typeSymbol == EqualsPatternClass def mkEqualsRef(tpe: Type) = typeRef(NoPrefix, EqualsPatternClass, List(tpe)) - def decodedEqualsType(tpe: Type) = condOpt(tpe) { case TypeRef(_, EqualsPatternClass, List(arg)) => arg } getOrElse (tpe) + def decodedEqualsType(tpe: Type) = + if (tpe.typeSymbol == EqualsPatternClass) tpe.typeArgs.head else tpe // A subtype test which creates fresh existentials for type // parameters on the right hand side. diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 18409cfffe..8bdf83fda4 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -26,19 +26,6 @@ trait Patterns extends ast.TreeDSL { type PatternMatch = MatchMatrix#PatternMatch private type PatternVar = MatrixContext#PatternVar - // private def unapplyArgs(x: Any) = x match { - // case UnApply(Apply(TypeApply(_, targs), args), _) => (targs map (_.symbol), args map (_.symbol)) - // case _ => (Nil, Nil) - // } - // - // private def unapplyCall(x: Any) = x match { - // case UnApply(t, _) => treeInfo.methPart(t).symbol - // case _ => NoSymbol - // } - - private lazy val dummyMethod = - NoSymbol.newTermSymbol(newTermName("matching$dummy")) - // Fresh patterns def emptyPatterns(i: Int): List[Pattern] = List.fill(i)(NoPattern) def emptyTrees(i: Int): List[Tree] = List.fill(i)(EmptyTree) @@ -56,13 +43,14 @@ trait Patterns extends ast.TreeDSL { case class VariablePattern(tree: Ident) extends NamePattern { lazy val Ident(name) = tree require(isVarPattern(tree) && name != nme.WILDCARD) - + override def covers(sym: Symbol) = true override def description = "%s".format(name) } // 8.1.1 (b) case class WildcardPattern() extends Pattern { def tree = EmptyTree + override def covers(sym: Symbol) = true override def isDefault = true override def description = "_" } @@ -71,6 +59,8 @@ trait Patterns extends ast.TreeDSL { case class TypedPattern(tree: Typed) extends Pattern { lazy val Typed(expr, tpt) = tree + override def covers(sym: Symbol) = newMatchesPattern(sym, tpt.tpe) + override def sufficientType = tpt.tpe override def subpatternsForVars: List[Pattern] = List(Pattern(expr)) override def simplify(pv: PatternVar) = Pattern(expr) match { case ExtractorPattern(ua) if pv.sym.tpe <:< tpt.tpe => this rebindTo expr @@ -115,6 +105,7 @@ trait Patterns extends ast.TreeDSL { } } + override def covers(sym: Symbol) = newMatchesPattern(sym, sufficientType) override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = backticked match { case Some(s) => "this." + s @@ -133,13 +124,15 @@ trait Patterns extends ast.TreeDSL { case class ObjectPattern(tree: Apply) extends ApplyPattern { // NamePattern? require(!fn.isType && isModule) + override def covers(sym: Symbol) = newMatchesPattern(sym, sufficientType) override def sufficientType = tpe.narrow override def simplify(pv: PatternVar) = this.rebindToObjectCheck() override def description = "Obj(%s)".format(fn) } // 8.1.4 (e) case class SimpleIdPattern(tree: Ident) extends NamePattern { - lazy val Ident(name) = tree + val Ident(name) = tree + override def covers(sym: Symbol) = newMatchesPattern(sym, tpe.narrow) override def description = "Id(%s)".format(name) } @@ -163,6 +156,11 @@ trait Patterns extends ast.TreeDSL { if (args.isEmpty) this rebindToEmpty tree.tpe else this + override def covers(sym: Symbol) = { + debugging("[constructor] Does " + this + " cover " + sym + " ? ") { + sym.tpe.typeSymbol == this.tpe.typeSymbol + } + } override def description = { if (isColonColon) "%s :: %s".format(Pattern(args(0)), Pattern(args(1))) else "%s(%s)".format(name, toPats(args).mkString(", ")) @@ -175,17 +173,12 @@ trait Patterns extends ast.TreeDSL { // 8.1.7 / 8.1.8 (unapply and unapplySeq calls) case class ExtractorPattern(tree: UnApply) extends UnapplyPattern { - override def simplify(pv: PatternVar) = { - if (pv.sym hasFlag NO_EXHAUSTIVE) () - else { - TRACE("Setting NO_EXHAUSTIVE on " + pv.sym + " due to extractor " + tree) - pv.sym setFlag NO_EXHAUSTIVE - } + private def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe + override def simplify(pv: PatternVar) = { if (pv.tpe <:< arg.tpe) this else this rebindTo uaTyped } - override def description = "Unapply(%s => %s)".format(necessaryType, resTypesString) } @@ -208,6 +201,7 @@ trait Patterns extends ast.TreeDSL { private def listFolder(hd: Tree, tl: Tree): Tree = unbind(hd) match { case t @ Star(_) => moveBindings(hd, WILD(t.tpe)) case _ => + val dummyMethod = NoSymbol.newTermSymbol(newTermName("matching$dummy")) val consType = MethodType(dummyMethod newSyntheticValueParams List(packedType, listRef), consRef) Apply(TypeTree(consType), List(hd, tl)) setType consRef @@ -376,7 +370,7 @@ trait Patterns extends ast.TreeDSL { case _: This if isVariableName(name) => Some("`%s`".format(name)) case _ => None } - + override def covers(sym: Symbol) = newMatchesPattern(sym, tree.tpe) protected def getPathSegments(t: Tree): List[Name] = t match { case Select(q, name) => name :: getPathSegments(q) case Apply(f, Nil) => getPathSegments(f) @@ -395,7 +389,13 @@ trait Patterns extends ast.TreeDSL { lazy val UnApply(unfn, args) = tree lazy val Apply(fn, _) = unfn lazy val MethodType(List(arg, _*), _) = fn.tpe - protected def uaTyped = Typed(tree, TypeTree(arg.tpe)) setType arg.tpe + + // Covers if the symbol matches the unapply method's argument type, + // and the return type of the unapply is Some. + override def covers(sym: Symbol) = newMatchesPattern(sym, arg.tpe) + + // TODO: for alwaysCovers: + // fn.tpe.finalResultType.typeSymbol == SomeClass override def necessaryType = arg.tpe override def subpatternsForVars = args match { @@ -419,6 +419,7 @@ trait Patterns extends ast.TreeDSL { else emptyPatterns(sufficientType.typeSymbol.caseFieldAccessors.size) def isConstructorPattern = fn.isType + override def covers(sym: Symbol) = newMatchesPattern(sym, fn.tpe) } sealed abstract class Pattern extends PatternBindingLogic { @@ -443,6 +444,15 @@ trait Patterns extends ast.TreeDSL { // the subpatterns for this pattern (at the moment, that means constructor arguments) def subpatterns(pm: MatchMatrix#PatternMatch): List[Pattern] = pm.dummies + // if this pattern should be considered to cover the given symbol + def covers(sym: Symbol): Boolean = newMatchesPattern(sym, sufficientType) + def newMatchesPattern(sym: Symbol, pattp: Type) = { + debugging("[" + kindString + "] Does " + pattp + " cover " + sym + " ? ") { + (sym.isModuleClass && (sym.tpe.typeSymbol eq pattp.typeSymbol)) || + (sym.tpe.baseTypeSeq exists (_ matchesPattern pattp)) + } + } + def sym = tree.symbol def tpe = tree.tpe def isEmpty = tree.isEmpty @@ -475,6 +485,7 @@ trait Patterns extends ast.TreeDSL { final override def toString = description def toTypeString() = "%s <: x <: %s".format(necessaryType, sufficientType) + def kindString = "" } /*** Extractors ***/ diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index f19a285d7c..309fc5733f 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -56,10 +56,10 @@ abstract class Reporter { */ def echo(msg: String): Unit = info(NoPosition, msg, true) def echo(pos: Position, msg: String): Unit = info(pos, msg, true) - + /** Informational messages, suppressed unless -verbose or force=true. */ def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) - + /** Warnings and errors. */ def warning(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, WARNING, false)) def error(pos: Position, msg: String): Unit = withoutTruncating(info0(pos, msg, ERROR, false)) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala index a47bfda8c1..fb85ebeeb0 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala @@ -9,4 +9,4 @@ package symtab import ast.{Trees, TreePrinters, DocComments} import util._ -abstract class SymbolTable extends reflect.internal.SymbolTable
\ No newline at end of file +abstract class SymbolTable extends reflect.internal.SymbolTable
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index a7ddfae819..07d132f7dd 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -368,7 +368,7 @@ abstract class ClassfileParser { case arr: Type => Constant(arr) } } - + private def getSubArray(bytes: Array[Byte]): Array[Byte] = { val decodedLength = ByteCodecs.decode(bytes) val arr = new Array[Byte](decodedLength) @@ -424,7 +424,7 @@ abstract class ClassfileParser { def forceMangledName(name: Name, module: Boolean): Symbol = { val parts = name.decode.toString.split(Array('.', '$')) var sym: Symbol = definitions.RootClass - + // was "at flatten.prev" beforeFlatten { for (part0 <- parts; if !(part0 == ""); part = newTermName(part0)) { @@ -432,7 +432,7 @@ abstract class ClassfileParser { sym.linkedClassOfClass.info sym.info.decl(part.encode) }//.suchThat(module == _.isModule) - + sym = ( if (sym1 ne NoSymbol) sym1 else sym.info.decl(part.encode.toTypeName) @@ -721,7 +721,7 @@ abstract class ClassfileParser { index += 1 val bounds = variance match { case '+' => TypeBounds.upper(objToAny(sig2type(tparams, skiptvs))) - case '-' => + case '-' => val tp = sig2type(tparams, skiptvs) // sig2type seems to return AnyClass regardless of the situation: // we don't want Any as a LOWER bound. @@ -1211,7 +1211,7 @@ abstract class ClassfileParser { else getMember(sym, innerName.toTypeName) - assert(s ne NoSymbol, + assert(s ne NoSymbol, "" + ((externalName, outerName, innerName, sym.fullLocationString)) + " / " + " while parsing " + ((in.file, busy)) + sym + "." + innerName + " linkedModule: " + sym.companionModule + sym.companionModule.info.members diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 25ae6f33d2..758f870d6b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -77,7 +77,7 @@ abstract class Pickler extends SubComponent { private var entries = new Array[AnyRef](256) private var ep = 0 private val index = new LinkedHashMap[AnyRef, Int] - private lazy val nonClassRoot = root.ownersIterator.find(! _.isClass) getOrElse NoSymbol + private lazy val nonClassRoot = findOrElse(root.ownersIterator)(!_.isClass)(NoSymbol) private def isRootSym(sym: Symbol) = sym.name.toTermName == rootName && sym.owner == rootOwner diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 2c024fe6fa..d04c6115ca 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -33,14 +33,14 @@ abstract class CleanUp extends Transform with ast.TreeDSL { private def savingStatics[T](body: => T): T = { val savedNewStaticMembers : mutable.Buffer[Tree] = newStaticMembers.clone() val savedNewStaticInits : mutable.Buffer[Tree] = newStaticInits.clone() - val savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = symbolsStoredAsStatic.clone() + val savedSymbolsStoredAsStatic : mutable.Map[String, Symbol] = symbolsStoredAsStatic.clone() val result = body clearStatics() newStaticMembers ++= savedNewStaticMembers newStaticInits ++= savedNewStaticInits symbolsStoredAsStatic ++= savedSymbolsStoredAsStatic - + result } private def transformTemplate(tree: Tree) = { @@ -85,6 +85,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case "poly-cache" => POLY_CACHE } + def shouldRewriteTry(tree: Try) = { + val sym = tree.tpe.typeSymbol + forMSIL && (sym != UnitClass) && (sym != NothingClass) + } + private def typedWithPos(pos: Position)(tree: Tree) = localTyper.typedPos(pos)(tree) @@ -97,7 +102,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { /** The boxed type if it's a primitive; identity otherwise. */ def toBoxedType(tp: Type) = if (isJavaValueType(tp)) boxedClass(tp.typeSymbol).tpe else tp - + override def transform(tree: Tree): Tree = tree match { /* Transforms dynamic calls (i.e. calls to methods that are undefined @@ -134,7 +139,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { case ad@ApplyDynamic(qual0, params) => if (settings.logReflectiveCalls.value) unit.echo(ad.pos, "method invocation uses reflection") - + val typedPos = typedWithPos(ad.pos) _ assert(ad.symbol.isPublic) @@ -146,7 +151,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { val flags = PRIVATE | STATIC | SYNTHETIC | ( if (isFinal) FINAL else 0 ) - + val varSym = currentClass.newVariable(mkTerm("" + forName), ad.pos, flags) setInfoAndEnter forType if (!isFinal) varSym.addAnnotation(VolatileAttr) @@ -488,7 +493,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { val t: Tree = ad.symbol.tpe match { case MethodType(mparams, resType) => assert(params.length == mparams.length, mparams) - + typedPos { val sym = currentOwner.newValue(mkTerm("qual"), ad.pos) setInfo qual0.tpe qual = safeREF(sym) @@ -560,8 +565,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL { * Hence, we here rewrite all try blocks with a result != {Unit, All} such that they * store their result in a local variable. The catch blocks are adjusted as well. * The try tree is subsituted by a block whose result expression is read of that variable. */ - case theTry @ Try(block, catches, finalizer) - if theTry.tpe.typeSymbol != definitions.UnitClass && theTry.tpe.typeSymbol != definitions.NothingClass => + case theTry @ Try(block, catches, finalizer) if shouldRewriteTry(theTry) => val tpe = theTry.tpe.widen val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe) def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs))) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 804c15a350..d8f19f85c0 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -126,7 +126,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { if (from.name != nme.OUTER) result else localTyper.typedPos(to.pos) { - IF (from OBJ_EQ NULL) THEN THROW(NullPointerExceptionClass) ELSE result + IF (from OBJ_EQ NULL) THEN Throw(NullPointerExceptionClass.tpe) ELSE result } } @@ -515,7 +515,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { } def delayedInitCall(closure: Tree) = localTyper.typedPos(impl.pos) { - gen.mkMethodCall(This(clazz), delayedInitMethod, Nil, List(New(closure.symbol, This(clazz)))) + gen.mkMethodCall(This(clazz), delayedInitMethod, Nil, List(New(closure.symbol.tpe, This(clazz)))) } /** Return a pair consisting of (all statements up to and including superclass and trait constr calls, rest) */ diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index c15da6e9a9..595c1486b6 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -68,7 +68,7 @@ abstract class ExplicitOuter extends InfoTransform result } - + private val innerClassConstructorParamName: TermName = newTermName("arg" + nme.OUTER) class RemoveBindingsTransformer(toRemove: Set[Symbol]) extends Transformer { @@ -89,13 +89,13 @@ abstract class ExplicitOuter extends InfoTransform def outerAccessor(clazz: Symbol): Symbol = { val firstTry = clazz.info.decl(nme.expandedName(nme.OUTER, clazz)) if (firstTry != NoSymbol && firstTry.outerSource == clazz) firstTry - else clazz.info.decls find (_.outerSource == clazz) getOrElse NoSymbol - } + else findOrElse(clazz.info.decls)(_.outerSource == clazz)(NoSymbol) + } def newOuterAccessor(clazz: Symbol) = { val accFlags = SYNTHETIC | METHOD | STABLE | ( if (clazz.isTrait) DEFERRED else 0 ) val sym = clazz.newMethodSymbol(nme.OUTER, clazz.pos, accFlags) val restpe = if (clazz.isTrait) clazz.outerClass.tpe else clazz.outerClass.thisType - + sym expandName clazz sym.referenced = clazz sym setInfo MethodType(Nil, restpe) @@ -163,7 +163,7 @@ abstract class ExplicitOuter extends InfoTransform decls1 = decls.cloneScope val outerAcc = clazz.newMethod(nme.OUTER, clazz.pos) // 3 outerAcc expandName clazz - + decls1 enter newOuterAccessor(clazz) if (hasOuterField(clazz)) //2 decls1 enter newOuterField(clazz) @@ -468,7 +468,7 @@ abstract class ExplicitOuter extends InfoTransform } } super.transform( - deriveTemplate(tree)(decls => + deriveTemplate(tree)(decls => if (newDefs.isEmpty) decls else decls ::: newDefs.toList ) diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index f2c3402d21..570eaba3a9 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -18,7 +18,7 @@ abstract class LambdaLift extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "lambdalift" - + /** Converts types of captured variables to *Ref types. */ def boxIfCaptured(sym: Symbol, tpe: Type, erasedTypes: Boolean) = @@ -75,10 +75,10 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] - + /** True if we are transforming under a ReferenceToBoxed node */ private var isBoxedRef = false - + private type SymSet = TreeSet[Symbol] private def newSymSet = new TreeSet[Symbol](_ isLess _) @@ -221,7 +221,7 @@ abstract class LambdaLift extends InfoTransform { for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs) markFree(fv, caller) } while (changedFreeVars) - + def renameSym(sym: Symbol) { val originalName = sym.name val base = sym.name + nme.NAME_JOIN_STRING + ( @@ -245,7 +245,7 @@ abstract class LambdaLift extends InfoTransform { debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name)) } - + for (sym <- renamable) { // If we renamed a trait from Foo to Foo$1, we must rename the implementation // class from Foo$class to Foo$1$class. (Without special consideration it would @@ -324,7 +324,7 @@ abstract class LambdaLift extends InfoTransform { val addParams = cloneSymbols(ps).map(_.setFlag(PARAM)) sym.updateInfo( lifted(MethodType(sym.info.params ::: addParams, sym.info.resultType))) - + copyDefDef(tree)(vparamss = List(vparams ++ freeParams)) case ClassDef(_, _, _, _) => // Disabled attempt to to add getters to freeParams @@ -419,10 +419,10 @@ abstract class LambdaLift extends InfoTransform { def refConstr(expr: Tree): Tree = expr match { case Try(block, catches, finalizer) => Try(refConstr(block), catches map refConstrCase, finalizer) - case _ => - New(sym, expr) + case _ => + New(sym.tpe, expr) } - def refConstrCase(cdef: CaseDef): CaseDef = + def refConstrCase(cdef: CaseDef): CaseDef = CaseDef(cdef.pat, cdef.guard, refConstr(cdef.body)) treeCopy.ValDef(tree, mods, name, tpt1, typer.typedPos(rhs.pos) { refConstr(constructorArg) @@ -467,7 +467,7 @@ abstract class LambdaLift extends InfoTransform { tree } } - + private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe) override def transform(tree: Tree): Tree = tree match { @@ -476,7 +476,7 @@ abstract class LambdaLift extends InfoTransform { case _ => postTransform(preTransform(tree)) } - + /** Transform statements and add lifted definitions to them. */ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala index 75d3e443d4..85ba539993 100644 --- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala +++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala @@ -125,7 +125,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD } case ValDef(_, _, _, _) if !sym.owner.isModule && !sym.owner.isClass => - deriveValDef(tree) { rhs0 => + deriveValDef(tree) { rhs0 => val rhs = super.transform(rhs0) if (LocalLazyValFinder.find(rhs)) typed(addBitmapDefs(sym, rhs)) else rhs } @@ -133,7 +133,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD case l@LabelDef(name0, params0, ifp0@If(_, _, _)) if name0.startsWith(nme.WHILE_PREFIX) => val ifp1 = super.transform(ifp0) val If(cond0, thenp0, elsep0) = ifp1 - + if (LocalLazyValFinder.find(thenp0)) deriveLabelDef(l)(_ => treeCopy.If(ifp1, cond0, typed(addBitmapDefs(sym.owner, thenp0)), elsep0)) else diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 3a2482e816..c9794cc20f 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -147,7 +147,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { member.hasAccessorFlag && (!member.isDeferred || (member hasFlag lateDEFERRED)) /** Is member overridden (either directly or via a bridge) in base class sequence `bcs`? */ - def isOverriddenAccessor(member: Symbol, bcs: List[Symbol]): Boolean = atOwnPhase { + def isOverriddenAccessor(member: Symbol, bcs: List[Symbol]): Boolean = beforeOwnPhase { def hasOverridingAccessor(clazz: Symbol) = { clazz.info.nonPrivateDecl(member.name).alternatives.exists( sym => @@ -203,7 +203,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { setter setInfo MethodType(setter.newSyntheticValueParams(List(field.info)), UnitClass.tpe) if (needsExpandedSetterName(field)) setter.name = nme.expandedSetterName(setter.name, clazz) - + setter } @@ -350,7 +350,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { setAnnotations accessed.annotations) } } - } + } else if (member.isSuperAccessor) { // mixin super accessors val member1 = addMember(clazz, member.cloneSymbol(clazz)) setPos clazz.pos assert(member1.alias != NoSymbol, member1) @@ -533,7 +533,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { self = sym.newValueParameter(nme.SELF, sym.pos) setInfo toInterface(currentOwner.typeOfThis) val selfdef = ValDef(self) setType NoType copyDefDef(tree)(vparamss = List(selfdef :: vparams)) - } + } else EmptyTree } else { @@ -1160,7 +1160,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { def implSym = implClass(sym.owner).info.member(sym.name) assert(target ne NoSymbol, List(sym + ":", sym.tpe, sym.owner, implClass(sym.owner), implSym, - atPhase(phase.prev)(implSym.tpe), phase) mkString " " + beforePrevPhase(implSym.tpe), phase) mkString " " ) typedPos(tree.pos)(Apply(staticRef(target), transformSuper(qual) :: args)) } @@ -1185,7 +1185,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL { val sym1 = sym.overridingSymbol(currentOwner.enclClass) typedPos(tree.pos)((transformSuper(qual) DOT sym1)()) } else { - staticCall(atPhase(phase.prev)(sym.overridingSymbol(implClass(sym.owner)))) + staticCall(beforePrevPhase(sym.overridingSymbol(implClass(sym.owner)))) } } else { assert(!currentOwner.enclClass.isImplClass, currentOwner.enclClass) diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index e49f8d7c0b..d8c18c2d50 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -50,7 +50,7 @@ abstract class OverridingPairs { val result = sym1.isType || (self.memberType(sym1) matches self.memberType(sym2)) debuglog("overriding-pairs? %s matches %s (%s vs. %s) == %s".format( sym1.fullLocationString, sym2.fullLocationString, tp_s(sym1), tp_s(sym2), result)) - + result } diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index e5d1e348d6..88ad458748 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -97,7 +97,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { private val wasSpecializedForTypeVars = perRunCaches.newMap[Symbol, Set[Symbol]]() withDefaultValue Set() /** Concrete methods that use a specialized type, or override such methods. */ - private val concreteSpecMethods = perRunCaches.newSet[Symbol]() + private val concreteSpecMethods = perRunCaches.newWeakSet[Symbol]() private def isSpecialized(sym: Symbol) = sym hasAnnotation SpecializedClass private def hasSpecializedFlag(sym: Symbol) = sym hasFlag SPECIALIZED @@ -110,7 +110,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { tp baseType GroupOfSpecializable match { case TypeRef(_, GroupOfSpecializable, arg :: Nil) => arg.typeArgs map (_.typeSymbol) - case _ => + case _ => List(tp.typeSymbol) } } @@ -511,11 +511,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * was both already used for a map and mucho long. So "sClass" is the * specialized subclass of "clazz" throughout this file. */ - val sClass = clazz.owner.newClass(specializedName(clazz, env0).toTypeName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) + + // SI-5545: Eliminate classes with the same name loaded from the bytecode already present - all we need to do is + // to force .info on them, as their lazy type will be evaluated and the symbols will be eliminated. Unfortunately + // evaluating the info after creating the specialized class will mess the specialized class signature, so we'd + // better evaluate it before creating the new class symbol + val clazzName = specializedName(clazz, env0).toTypeName + val bytecodeClazz = clazz.owner.info.decl(clazzName) + debuglog("Specializing " + clazz + " found " + bytecodeClazz + " already there") + bytecodeClazz.info + + val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) = member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED)) - + sClass.sourceFile = clazz.sourceFile currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin @@ -1226,7 +1236,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else NoSymbol def illegalSpecializedInheritance(clazz: Symbol): Boolean = ( - hasSpecializedFlag(clazz) + hasSpecializedFlag(clazz) && originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait) ) @@ -1291,7 +1301,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val specMember = specCandidates suchThat { s => doesConform(symbol, tree.tpe, qual.tpe.memberType(s), env) } - + debuglog("[specSym] found: " + specCandidates.tpe + ", instantiated as: " + tree.tpe) debuglog("[specSym] found specMember: " + specMember) if (specMember ne NoSymbol) @@ -1405,7 +1415,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { (new CollectMethodBodies)(tree) val parents1 = map2(currentOwner.info.parents, parents)((tpe, parent) => TypeTree(tpe) setPos parent.pos) - + treeCopy.Template(tree, parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ , self, @@ -1419,7 +1429,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val superRef: Tree = Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) forwardCtorCall(tree.pos, superRef, vparamss, symbol.owner) } - if (symbol.isPrimaryConstructor) + if (symbol.isPrimaryConstructor) localTyper.typedPos(symbol.pos)(deriveDefDef(tree)(_ => Block(List(t), Literal(Constant())))) else // duplicate the original constructor duplicateBody(ddef, info(symbol).target) @@ -1505,10 +1515,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { deriveValDef(newValDef)(transform) case Apply(sel @ Select(sup @ Super(qual, name), name1), args) - if (sup.symbol.info.parents != atPhase(phase.prev)(sup.symbol.info.parents)) => + if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) => def parents = sup.symbol.info.parents - debuglog(tree + " parents changed from: " + atPhase(phase.prev)(parents) + " to: " + parents) + debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents) val res = localTyper.typed( Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 23697a4730..848d6be47b 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -228,7 +228,7 @@ abstract class TailCalls extends Transform { debuglog("Considering " + dd.name + " for tailcalls") val newRHS = transform(rhs0, newCtx) - deriveDefDef(tree)(rhs => + deriveDefDef(tree)(rhs => if (newCtx.isTransformed) { /** We have rewritten the tree, but there may be nested recursive calls remaining. * If @tailrec is given we need to fail those now. diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index f49c340bec..ee565530b7 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -144,13 +144,13 @@ abstract class UnCurry extends InfoTransform * todo: maybe clone a pre-existing exception instead? * (but what to do about exceptions that miss their targets?) */ - private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = - localTyper.typed { - Throw( - New( - TypeTree(nonLocalReturnExceptionType(expr.tpe)), - List(List(Ident(nonLocalReturnKey(meth)), expr)))) - } + private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = localTyper typed { + Throw( + nonLocalReturnExceptionType(expr.tpe.widen), + Ident(nonLocalReturnKey(meth)), + expr + ) + } /** Transform (body, key) to: * @@ -166,31 +166,18 @@ abstract class UnCurry extends InfoTransform * } */ private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { - localTyper.typed { - val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) - val ex = meth.newValue(nme.ex, body.pos) setInfo extpe - val pat = Bind(ex, - Typed(Ident(nme.WILDCARD), - AppliedTypeTree(Ident(NonLocalReturnControlClass), - List(Bind(tpnme.WILDCARD, - EmptyTree))))) - val rhs = - If( - Apply( - Select( - Apply(Select(Ident(ex), "key"), List()), - Object_eq), - List(Ident(key))), - Apply( - TypeApply( - Select( - Apply(Select(Ident(ex), "value"), List()), - Any_asInstanceOf), - List(TypeTree(meth.tpe.finalResultType))), - List()), - Throw(Ident(ex))) - val keyDef = ValDef(key, New(ObjectClass)) - val tryCatch = Try(body, List(CaseDef(pat, EmptyTree, rhs)), EmptyTree) + localTyper typed { + val extpe = nonLocalReturnExceptionType(meth.tpe.finalResultType) + val ex = meth.newValue(body.pos, nme.ex) setInfo extpe + val pat = gen.mkBindForCase(ex, NonLocalReturnControlClass, List(meth.tpe.finalResultType)) + val rhs = ( + IF ((ex DOT nme.key)() OBJ_EQ Ident(key)) + THEN ((ex DOT nme.value)()) + ELSE (Throw(Ident(ex))) + ) + val keyDef = ValDef(key, New(ObjectClass.tpe)) + val tryCatch = Try(body, pat -> rhs) + Block(List(keyDef), tryCatch) } } @@ -260,7 +247,7 @@ abstract class UnCurry extends InfoTransform else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) anonClass setInfo ClassInfoType(parents, newScope, anonClass) - val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL) + val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL) applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe) anonClass addAnnotation serialVersionUIDAnnotation @@ -357,7 +344,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), - Typed(New(anonClass), TypeTree(fun.tpe))) + Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } } } @@ -465,6 +452,25 @@ abstract class UnCurry extends InfoTransform } } + private def isSelfSynchronized(ddef: DefDef) = ddef.rhs match { + case Apply(fn @ TypeApply(Select(sel, _), _), _) => + fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait + case _ => false + } + + /** If an eligible method is entirely wrapped in a call to synchronized + * locked on the same instance, remove the synchronized scaffolding and + * mark the method symbol SYNCHRONIZED for bytecode generation. + */ + private def translateSynchronized(tree: Tree) = tree match { + case dd @ DefDef(_, _, _, _, _, Apply(fn, body :: Nil)) if isSelfSynchronized(dd) => + log("Translating " + dd.symbol.defString + " into synchronized method") + dd.symbol setFlag SYNCHRONIZED + deriveDefDef(dd)(_ => body) + case _ => tree + } + def isNonLocalReturn(ret: Return) = ret.symbol != currentOwner.enclMethod || currentOwner.isLazy + // ------ The tree transformers -------------------------------------------------------- def mainTransform(tree: Tree): Tree = { @@ -508,9 +514,10 @@ abstract class UnCurry extends InfoTransform // breakage until a reasonable interface is settled upon. if ((sym ne null) && (sym.elisionLevel.exists (_ < settings.elidebelow.value || settings.noassertions.value))) replaceElidableTree(tree) - else tree match { + else translateSynchronized(tree) match { case dd @ DefDef(mods, name, tparams, vparamss, tpt, rhs) => if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd) + withNeedLift(false) { if (dd.symbol.isClassConstructor) { atOwner(sym) { @@ -525,11 +532,11 @@ abstract class UnCurry extends InfoTransform treeCopy.Block(rhs, presupers ::: supercalls ::: others, transform(expr)) } treeCopy.DefDef( - tree, mods, name, transformTypeDefs(tparams), + dd, mods, name, transformTypeDefs(tparams), transformValDefss(vparamss), transform(tpt), rhs1) } } else { - super.transform(tree) + super.transform(dd) } } case ValDef(_, _, _, rhs) => @@ -564,6 +571,9 @@ abstract class UnCurry extends InfoTransform case Assign(lhs, _) if lhs.symbol.owner != currentMethod || lhs.symbol.hasFlag(LAZY | ACCESSOR) => withNeedLift(true) { super.transform(tree) } + case ret @ Return(_) if (isNonLocalReturn(ret)) => + withNeedLift(true) { super.transform(ret) } + case Try(block, catches, finalizer) => if (needTryLift || shouldBeLiftedAnyway(tree)) transform(liftTree(tree)) else super.transform(tree) @@ -669,9 +679,9 @@ abstract class UnCurry extends InfoTransform applyUnary() case Select(_, _) | TypeApply(_, _) => applyUnary() - case Return(expr) if (tree.symbol != currentOwner.enclMethod || currentOwner.isLazy) => - debuglog("non local return in "+tree.symbol+" from "+currentOwner.enclMethod) - atPos(tree.pos)(nonLocalReturnThrow(expr, tree.symbol)) + case ret @ Return(expr) if (isNonLocalReturn(ret)) => + debuglog("non local return in "+ret.symbol+" from "+currentOwner.enclMethod) + atPos(ret.pos)(nonLocalReturnThrow(expr, ret.symbol)) case TypeTree() => tree case _ => @@ -775,7 +785,7 @@ abstract class UnCurry extends InfoTransform // add the method to `newMembers` newMembers += forwtree } - + flatdd } } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index e290a5193c..d7b4171c65 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -31,14 +31,14 @@ trait ContextErrors { case class NormalTypeError(underlyingTree: Tree, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos:Position = underlyingTree.pos override def toString() = "[Type error at:" + underlyingTree.pos + "] " + errMsg } case class SymbolTypeError(underlyingSym: Symbol, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos = underlyingSym.pos } @@ -76,7 +76,7 @@ trait ContextErrors { } def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) } - + def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = { def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" "type mismatch" + foundReqMsg(found, req) + missingArgsMsg @@ -143,12 +143,12 @@ trait ContextErrors { found } assert(!found.isErroneous && !req.isErroneous, (found, req)) - + issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req))) ) if (settings.explaintypes.value) explainTypes(found, req) } - + def WithFilterError(tree: Tree, ex: AbsTypeError) = { issueTypeError(ex) setError(tree) @@ -177,13 +177,13 @@ trait ContextErrors { val calcSimilar = ( name.length > 2 && ( startingIdentCx.reportErrors - || startingIdentCx.enclClassOrMethod.reportErrors + || startingIdentCx.enclClassOrMethod.reportErrors ) ) - // avoid calculating if we're in "silent" mode. - // name length check to limit unhelpful suggestions for e.g. "x" and "b1" + // avoid calculating if we're in "silent" mode. + // name length check to limit unhelpful suggestions for e.g. "x" and "b1" val similar = { - if (!calcSimilar) "" + if (!calcSimilar) "" else { val allowed = ( startingIdentCx.enclosingContextChain @@ -624,11 +624,21 @@ trait ContextErrors { setError(tree) } - // checkNoDoubleDefs... - def DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) = - issueSymbolTypeError(sym0, sym1+" is defined twice"+ - {if(!settings.debug.value) "" else " in "+context0.unit}+ - {if (sym0.isMacro && sym1.isMacro) " \n(note that macros cannot be overloaded)" else ""}) + // checkNoDoubleDefs... + // @PP: I hacked the filename in (context0.unit) to work around SI-4893. It would be + // much better if every symbol could offer some idea of where it came from, else + // the obviously untrue claim that something has been defined twice can only frustrate. + // There's no direct test because partest doesn't work, but to reproduce, separately + // compile the next two lines: + // package object foo { val x: Class[_] = null } + // package foo + def DefDefinedTwiceError(sym0: Symbol, sym1: Symbol) = { + val isBug = sym0.isAbstractType && sym1.isAbstractType && (sym0.name startsWith "_$") + issueSymbolTypeError(sym0, sym1+" is defined twice in " + context0.unit + + ( if (sym0.isMacro && sym1.isMacro) "\n(note that macros cannot be overloaded)" else "" ) + + ( if (isBug) "\n(this error is likely due to a bug in the scala compiler involving wildcards in package objects)" else "" ) + ) + } // cyclic errors def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) = @@ -662,7 +672,7 @@ trait ContextErrors { type ErrorType = Value val WrongNumber, NoParams, ArgsDoNotConform = Value } - + private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) = if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) { val methodName = nme.defaultGetterToMethod(sym1.name) @@ -708,11 +718,11 @@ trait ContextErrors { "constructor cannot be instantiated to expected type" + foundReqMsg(restpe, pt)) setError(tree) } - + def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type) = { issueNormalTypeError(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) - // since inferMethodAlternative modifies the state of the tree + // since inferMethodAlternative modifies the state of the tree // we have to set the type of tree to ErrorType only in the very last // fallback action that is done in the inference (tracking it manually is error prone). // This avoids entering infinite loop in doTypeApply. @@ -833,14 +843,14 @@ trait ContextErrors { object NamerErrorGen { implicit val context0 = context - + object SymValidateErrors extends Enumeration { val ImplicitConstr, ImplicitNotTerm, ImplicitTopObject, OverrideClass, SealedNonClass, AbstractNonClass, OverrideConstr, AbstractOverride, LazyAndEarlyInit, ByNameParameter, AbstractVar = Value } - + object DuplicatesErrorKinds extends Enumeration { val RenamedTwice, AppearsTwice = Value } @@ -848,7 +858,7 @@ trait ContextErrors { import SymValidateErrors._ import DuplicatesErrorKinds._ import symtab.Flags - + def TypeSigError(tree: Tree, ex: TypeError) = { ex match { case CyclicReference(sym, info: TypeCompleter) => @@ -857,7 +867,7 @@ trait ContextErrors { context0.issue(TypeErrorWithUnderlyingTree(tree, ex)) } } - + def GetterDefinedTwiceError(getter: Symbol) = issueSymbolTypeError(getter, getter+" is defined twice") @@ -900,37 +910,37 @@ trait ContextErrors { val msg = errKind match { case ImplicitConstr => "`implicit' modifier not allowed for constructors" - + case ImplicitNotTerm => "`implicit' modifier can be used only for values, variables and methods" - + case ImplicitTopObject => "`implicit' modifier cannot be used for top-level objects" - + case OverrideClass => "`override' modifier not allowed for classes" - + case SealedNonClass => "`sealed' modifier can be used only for classes" - + case AbstractNonClass => "`abstract' modifier can be used only for classes; it should be omitted for abstract members" - + case OverrideConstr => "`override' modifier not allowed for constructors" - + case AbstractOverride => "`abstract override' modifier only allowed for members of traits" - + case LazyAndEarlyInit => "`lazy' definitions may not be initialized early" - + case ByNameParameter => "pass-by-name arguments not allowed for case class parameters" - + case AbstractVar => "only classes can have declared but undefined members" + abstractVarMessage(sym) - + } issueSymbolTypeError(sym, msg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 51f84b4260..261cc18d26 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -21,7 +21,7 @@ trait Contexts { self: Analyzer => outer = this enclClass = this enclMethod = this - + override def nextEnclosing(p: Context => Boolean): Context = this override def enclosingContextChain: List[Context] = Nil override def implicitss: List[List[ImplicitInfo]] = Nil @@ -128,7 +128,7 @@ trait Contexts { self: Analyzer => var typingIndentLevel: Int = 0 def typingIndent = " " * typingIndentLevel - + var buffer: Set[AbsTypeError] = _ def enclClassOrMethod: Context = @@ -179,7 +179,7 @@ trait Contexts { self: Analyzer => buffer.clear() current } - + def logError(err: AbsTypeError) = buffer += err def withImplicitsDisabled[T](op: => T): T = { @@ -240,7 +240,7 @@ trait Contexts { self: Analyzer => c.implicitsEnabled = true c } - + def makeNewImport(sym: Symbol): Context = makeNewImport(gen.mkWildcardImport(sym)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 3d2f86d54d..0ddacf7d36 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -215,7 +215,7 @@ trait Implicits { object HasMethodMatching { val dummyMethod = NoSymbol.newTermSymbol(newTermName("typer$dummy")) def templateArgType(argtpe: Type) = new BoundedWildcardType(TypeBounds.lower(argtpe)) - + def apply(name: Name, argtpes: List[Type], restpe: Type): Type = { val mtpe = MethodType(dummyMethod.newSyntheticValueParams(argtpes map templateArgType), restpe) memberWildcardType(name, mtpe) @@ -571,7 +571,7 @@ trait Implicits { else { val tvars = undetParams map freshVar def ptInstantiated = pt.instantiateTypeParams(undetParams, tvars) - + printInference("[search] considering %s (pt contains %s) trying %s against pt=%s".format( if (undetParams.isEmpty) "no tparams" else undetParams.map(_.name).mkString(", "), typeVarsInType(ptInstantiated) filterNot (_.isGround) match { case Nil => "no tvars" ; case tvs => tvs.mkString(", ") }, @@ -594,7 +594,7 @@ trait Implicits { // we must be conservative in leaving type params in undetparams // prototype == WildcardType: want to remove all inferred Nothings val AdjustedTypeArgs(okParams, okArgs) = adjustTypeArgs(undetParams, tvars, targs) - + val subst: TreeTypeSubstituter = if (okParams.isEmpty) EmptyTreeTypeSubstituter else { @@ -621,7 +621,7 @@ trait Implicits { case Apply(TypeApply(fun, args), _) => typedTypeApply(itree2, EXPRmode, fun, args) // t2421c case t => t } - + if (context.hasErrors) fail("typing TypeApply reported errors for the implicit tree") else { @@ -780,13 +780,13 @@ trait Implicits { val newPending = undoLog undo { is filterNot (alt => alt == i || { try improves(i, alt) - catch { - case e: CyclicReference => + catch { + case e: CyclicReference => if (printInfers) { println(i+" discarded because cyclic reference occurred") e.printStackTrace() } - true + true } }) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 4fa6ae8b33..cea5858915 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -210,9 +210,9 @@ trait Infer { def getContext = context def issue(err: AbsTypeError): Unit = context.issue(err) - - def isPossiblyMissingArgs(found: Type, req: Type) = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req) - + + def isPossiblyMissingArgs(found: Type, req: Type) = (found.resultApprox ne found) && isWeaklyCompatible(found.resultApprox, req) + def explainTypes(tp1: Type, tp2: Type) = withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2)) @@ -465,7 +465,7 @@ trait Infer { */ def adjustTypeArgs(tparams: List[Symbol], tvars: List[TypeVar], targs: List[Type], restpe: Type = WildcardType): AdjustedTypeArgs.Result = { val buf = AdjustedTypeArgs.Result.newBuilder[Symbol, Option[Type]] - + foreach3(tparams, tvars, targs) { (tparam, tvar, targ) => val retract = ( targ.typeSymbol == NothingClass // only retract Nothings @@ -1385,9 +1385,10 @@ trait Infer { case _ => } } + // todo: missing test case NoBestExprAlternativeError(tree, pt) } else if (!competing.isEmpty) { - if (secondTry) NoBestExprAlternativeError(tree, pt) + if (secondTry) { NoBestExprAlternativeError(tree, pt); setError(tree) } else if (!pt.isErroneous) AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt) } else { // val applicable = alts1 filter (alt => diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala index 3ba8cefca8..088a56cd7b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala +++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala @@ -18,7 +18,7 @@ trait MethodSynthesis { import global._ import definitions._ import CODE._ - + object synthesisUtil { type M[T] = Manifest[T] type CM[T] = ClassManifest[T] @@ -39,7 +39,7 @@ trait MethodSynthesis { typeRef(container.typeConstructor.prefix, container, args map (_.tpe)) } - + def companionType[T](implicit m: M[T]) = getRequiredModule(m.erasure.getName).tpe @@ -71,7 +71,7 @@ trait MethodSynthesis { class ClassMethodSynthesis(val clazz: Symbol, localTyper: Typer) { private def isOverride(name: TermName) = clazzMember(name).alternatives exists (sym => !sym.isDeferred && (sym.owner != clazz)) - + def newMethodFlags(name: TermName) = { val overrideFlag = if (isOverride(name)) OVERRIDE else 0L overrideFlag | SYNTHETIC @@ -344,7 +344,7 @@ trait MethodSynthesis { if (mods.isDeferred) tpt setOriginal tree.tpt - // TODO - reconcile this with the DefDef creator in Trees (which + // TODO - reconcile this with the DefDef creator in Trees (which // at this writing presented no way to pass a tree in for tpt.) atPos(derivedSym.pos) { DefDef( diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index eb7ea51d2b..82bcb93965 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -113,7 +113,7 @@ trait Namers extends MethodSynthesis { private def contextFile = context.unit.source.file private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = { case ex: TypeError => - // H@ need to ensure that we handle only cyclic references + // H@ need to ensure that we handle only cyclic references TypeSigError(tree, ex) alt } @@ -284,7 +284,7 @@ trait Namers extends MethodSynthesis { private def logAssignSymbol(tree: Tree, sym: Symbol): Symbol = { sym.name.toTermName match { case nme.IMPORT | nme.OUTER | nme.ANON_CLASS_NAME | nme.ANON_FUN_NAME | nme.CONSTRUCTOR => () - case _ => + case _ => log("[+symbol] " + sym.debugLocationString) } tree.symbol = sym @@ -300,7 +300,7 @@ trait Namers extends MethodSynthesis { val pos = tree.pos val isParameter = tree.mods.isParameter val flags = tree.mods.flags & mask - + tree match { case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 44a3abf1b2..e8d3b7a7de 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -428,11 +428,11 @@ trait NamesDefaults { self: Analyzer => } } else NoSymbol } - + private def savingUndeterminedTParams[T](context: Context)(fn: List[Symbol] => T): T = { val savedParams = context.extractUndetparams() val savedReporting = context.ambiguousErrors - + context.setAmbiguousErrors(false) try fn(savedParams) finally { @@ -451,7 +451,7 @@ trait NamesDefaults { self: Analyzer => || (ctx.owner.rawInfo.member(name) != NoSymbol) ) ) - + /** A full type check is very expensive; let's make sure there's a name * somewhere which could potentially be ambiguous before we go that route. */ @@ -519,7 +519,7 @@ trait NamesDefaults { self: Analyzer => def matchesName(param: Symbol) = !param.isSynthetic && ( (param.name == name) || (param.deprecatedParamName match { case Some(`name`) => - context0.unit.deprecationWarning(arg.pos, + context0.unit.deprecationWarning(arg.pos, "the parameter name "+ name +" has been deprecated. Use "+ param.name +" instead.") true case _ => false diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala index 8bf5fc3557..b060fd7121 100644 --- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala +++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala @@ -1160,7 +1160,7 @@ class Foo(x: Other) { x._1 } // no error in this order def _match(n: Name): SelectStart = matchStrategy DOT n private lazy val oneSig: Type = - typer.typed(_match(vpmName.one), EXPRmode | POLYmode | TAPPmode | FUNmode, WildcardType).tpe // TODO: error message + typer.typed(_match(vpmName.one), EXPRmode | POLYmode | TAPPmode | FUNmode, WildcardType).tpe // TODO: error message } trait PureCodegen extends CodegenCore with PureMatchMonadInterface { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4a92458403..507ffd55d7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -150,7 +150,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } // Override checking ------------------------------------------------------------ - + def isJavaVarargsAncestor(clazz: Symbol) = ( clazz.isClass && clazz.isJavaDefined @@ -167,14 +167,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R log("Found java varargs ancestor in " + clazz.fullLocationString + ".") val self = clazz.thisType val bridges = new ListBuffer[Tree] - + def varargBridge(member: Symbol, bridgetpe: Type): Tree = { log("Generating varargs bridge for " + member.fullLocationString + " of type " + bridgetpe) - + val bridge = member.cloneSymbolImpl(clazz, member.flags | VBRIDGE) setPos clazz.pos bridge.setInfo(bridgetpe.cloneInfo(bridge)) clazz.info.decls enter bridge - + val params = bridge.paramss.head val elemtp = params.last.tpe.typeArgs.head val idents = params map Ident @@ -183,7 +183,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R localTyper typed DefDef(bridge, body) } - + // For all concrete non-private members that have a (Scala) repeated parameter: // compute the corresponding method type `jtpe` with a Java repeated parameter // if a method with type `jtpe` exists and that method is not a varargs bridge @@ -203,7 +203,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } } } - + bridges.toList } else Nil @@ -277,7 +277,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R */ def checkOverride(member: Symbol, other: Symbol) { debuglog("Checking validity of %s overriding %s".format(member.fullLocationString, other.fullLocationString)) - + def memberTp = self.memberType(member) def otherTp = self.memberType(other) def noErrorType = other.tpe != ErrorType && member.tpe != ErrorType @@ -337,7 +337,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R def deferredCheck = member.isDeferred || !other.isDeferred def subOther(s: Symbol) = s isSubClass other.owner def subMember(s: Symbol) = s isSubClass member.owner - + if (subOther(member.owner) && deferredCheck) { //Console.println(infoString(member) + " shadows1 " + infoString(other) " in " + clazz);//DEBUG return @@ -430,12 +430,12 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if( !(sameLength(member.typeParams, other.typeParams) && (memberTp.substSym(member.typeParams, other.typeParams) =:= otherTp)) ) // (1.6) overrideTypeError(); - } + } else if (other.isAbstractType) { //if (!member.typeParams.isEmpty) // (1.7) @MAT // overrideError("may not be parameterized"); val otherTp = self.memberInfo(other) - + if (!(otherTp.bounds containsType memberTp)) { // (1.7.1) overrideTypeError(); // todo: do an explaintypes with bounds here explainTypes(_.bounds containsType _, otherTp, memberTp) diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 64f1662a22..243e685b13 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -24,7 +24,7 @@ import symtab.Flags._ */ abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers { import global._ - import definitions.{ UnitClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf } + import definitions.{ UnitClass, ObjectClass, isRepeatedParamType, isByNameParamType, Any_asInstanceOf } import analyzer.{ restrictionError } /** the following two members override abstract members in Transform */ @@ -34,6 +34,12 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT new SuperAccTransformer(unit) class SuperAccTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { + /** validCurrentOwner arrives undocumented, but I reverse engineer it to be + * a flag for needsProtectedAccessor which is false while transforming either + * a by-name argument block or a closure. This excludes them from being + * considered able to access protected members via subclassing (why?) which in turn + * increases the frequency with which needsProtectedAccessor will be true. + */ private var validCurrentOwner = true private val accDefs = mutable.Map[Symbol, ListBuffer[Tree]]() @@ -41,6 +47,25 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz)) buf += typers(clazz) typed tree } + private def ensureAccessor(sel: Select) = { + val Select(qual, name) = sel + val sym = sel.symbol + val clazz = qual.symbol + val supername = nme.superName(name) + val superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) orElse { + debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug + val acc = clazz.newMethod(supername, sel.pos, SUPERACCESSOR | PRIVATE) setAlias sym + val tpe = clazz.thisType memberType sym match { + case t if sym.isModule && !sym.isMethod => NullaryMethodType(t) + case t => t + } + acc setInfoAndEnter (tpe cloneInfo acc) + storeAccessorDefinition(clazz, DefDef(acc, EmptyTree)) + acc + } + + atPos(sel.pos)(Select(gen.mkAttributedThis(clazz), superAcc) setType sel.tpe) + } private def transformArgs(params: List[Symbol], args: List[Tree]) = { treeInfo.mapMethodParamsAndArgs(params, args) { (param, arg) => @@ -88,42 +113,21 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } } - private def transformSuperSelect(tree: Tree): Tree = tree match { - case Select(sup @ Super(_, mix), name) => - val sym = tree.symbol - val clazz = sup.symbol - - if (sym.isDeferred) { - val member = sym.overridingSymbol(clazz); - if (mix != tpnme.EMPTY || member == NoSymbol || - !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) - unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+ - "unless it is overridden by a member declared `abstract' and `override'"); - } - if (tree.isTerm && mix == tpnme.EMPTY && - (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) { - val supername = nme.superName(sym.name) - var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym) - if (superAcc == NoSymbol) { - debuglog("add super acc " + sym + sym.locationString + " to `" + clazz);//debug - superAcc = clazz.newMethod(supername, tree.pos, SUPERACCESSOR | PRIVATE) setAlias sym - var superAccTpe = clazz.thisType.memberType(sym) - if (sym.isModule && !sym.isMethod) { - // the super accessor always needs to be a method. See #231 - superAccTpe = NullaryMethodType(superAccTpe) - } - superAcc setInfoAndEnter (superAccTpe cloneInfo superAcc) - storeAccessorDefinition(clazz, DefDef(superAcc, EmptyTree)) - } - atPos(sup.pos) { - Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe; - } - } else { - tree - } - case _ => - assert(tree.tpe.isError, tree) - tree + private def transformSuperSelect(sel: Select): Tree = { + val Select(sup @ Super(_, mix), name) = sel + val sym = sel.symbol + val clazz = sup.symbol + + if (sym.isDeferred) { + val member = sym.overridingSymbol(clazz); + if (mix != tpnme.EMPTY || member == NoSymbol || + !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) + unit.error(sel.pos, ""+sym.fullLocationString+" is accessed from super. It may not be abstract "+ + "unless it is overridden by a member declared `abstract' and `override'"); + } + if (name.isTermName && mix == tpnme.EMPTY && (clazz.isTrait || clazz != currentClass || !validCurrentOwner)) + ensureAccessor(sel) + else sel } // Disallow some super.XX calls targeting Any methods which would @@ -156,9 +160,11 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT for (s <- decls) { if (s.privateWithin.isClass && !s.isProtected && !s.privateWithin.isModuleClass && !s.hasFlag(EXPANDEDNAME) && !s.isConstructor) { + val savedName = s.name decls.unlink(s) s.expandName(s.privateWithin) decls.enter(s) + log("Expanded '%s' to '%s' in %s".format(savedName, s.name, sym)) } } if (settings.verbose.value && forScaladoc && !sym.isAnonymousClass) { @@ -218,24 +224,47 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT // direct calls to aliases of param accessors to the superclass in order to avoid // duplicating fields. if (sym.isParamAccessor && sym.alias != NoSymbol) { - val result = localTyper.typed { - Select( - Super(qual, tpnme.EMPTY/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos, - sym.alias) setPos tree.pos - } + val result = (localTyper.typedPos(tree.pos) { + Select(Super(qual, tpnme.EMPTY) setPos qual.pos, sym.alias) + }).asInstanceOf[Select] debuglog("alias replacement: " + tree + " ==> " + result);//debug localTyper.typed(gen.maybeMkAsInstanceOf(transformSuperSelect(result), sym.tpe, sym.alias.tpe, true)) } - else mayNeedProtectedAccessor(sel, List(EmptyTree), false) + else { + /** A trait which extends a class and accesses a protected member + * of that class cannot implement the necessary accessor method + * because its implementation is in an implementation class (e.g. + * Foo$class) which inherits nothing, and jvm access restrictions + * require the call site to be in an actual subclass. So non-trait + * classes inspect their ancestors for any such situations and + * generate the accessors. See SI-2296. + */ + // FIXME - this should be unified with needsProtectedAccessor, but some + // subtlety which presently eludes me is foiling my attempts. + val shouldEnsureAccessor = ( + currentClass.isTrait + && sym.isProtected + && sym.enclClass != currentClass + && !sym.owner.isTrait + && (sym.owner.enclosingPackageClass != currentPackage) + && (qual.symbol.info.member(sym.name) ne NoSymbol) + ) + if (shouldEnsureAccessor) { + log("Ensuring accessor for call to protected " + sym.fullLocationString + " from " + currentClass) + ensureAccessor(sel) + } + else + mayNeedProtectedAccessor(sel, List(EmptyTree), false) + } - case Select(Super(_, mix), name) => + case sel @ Select(Super(_, mix), name) => if (sym.isValue && !sym.isMethod || sym.hasAccessorFlag) { unit.error(tree.pos, "super may be not be used on "+ sym.accessedOrSelf) } else if (isDisallowed(sym)) { unit.error(tree.pos, "super not allowed here: use this." + name.decode + " instead") } - transformSuperSelect(tree) + transformSuperSelect(sel) case TypeApply(sel @ Select(qual, name), args) => mayNeedProtectedAccessor(sel, args, true) @@ -280,11 +309,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } private def withInvalidOwner[A](trans: => A): A = { - val prevValidCurrentOwner = validCurrentOwner + val saved = validCurrentOwner validCurrentOwner = false - val result = trans - validCurrentOwner = prevValidCurrentOwner - result + try trans + finally validCurrentOwner = saved } /** Add a protected accessor, if needed, and return a tree that calls @@ -294,7 +322,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT private def makeAccessor(tree: Select, targs: List[Tree]): Tree = { val Select(qual, name) = tree val sym = tree.symbol - val clazz = hostForAccessorOf(sym, currentOwner.enclClass) + val clazz = hostForAccessorOf(sym, currentClass) assert(clazz != NoSymbol, sym) debuglog("Decided for host class: " + clazz) @@ -334,7 +362,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT } val selection = Select(This(clazz), protAcc) def mkApply(fn: Tree) = Apply(fn, qual :: Nil) - val res = atPos(tree.pos) { + val res = atPos(tree.pos) { targs.head match { case EmptyTree => mkApply(selection) case _ => mkApply(TypeApply(selection, targs)) @@ -373,27 +401,27 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT */ private def makeSetter(tree: Select): Tree = { val field = tree.symbol - val clazz = hostForAccessorOf(field, currentOwner.enclClass) + val clazz = hostForAccessorOf(field, currentClass) assert(clazz != NoSymbol, field) debuglog("Decided for host class: " + clazz) - + val accName = nme.protSetterName(field.originalName) val protectedAccessor = clazz.info decl accName orElse { val protAcc = clazz.newMethod(accName, field.pos) val paramTypes = List(clazz.typeOfThis, field.tpe) val params = protAcc newSyntheticValueParams paramTypes val accessorType = MethodType(params, UnitClass.tpe) - + protAcc setInfoAndEnter accessorType val obj :: value :: Nil = params storeAccessorDefinition(clazz, DefDef(protAcc, Assign(Select(Ident(obj), field.name), Ident(value)))) - + protAcc } atPos(tree.pos)(Select(This(clazz), protectedAccessor)) } - /** Does `sym` need an accessor when accessed from `currentOwner`? + /** Does `sym` need an accessor when accessed from `currentClass`? * A special case arises for classes with explicit self-types. If the * self type is a Java class, and a protected accessor is needed, we issue * an error. If the self type is a Scala class, we don't add an accessor. @@ -407,23 +435,20 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT * classes, this has to be signaled as error. */ private def needsProtectedAccessor(sym: Symbol, pos: Position): Boolean = { - val clazz = currentOwner.enclClass + val clazz = currentClass def accessibleThroughSubclassing = validCurrentOwner && clazz.thisSym.isSubClass(sym.owner) && !clazz.isTrait - def packageAccessBoundry(sym: Symbol) = { - val b = sym.accessBoundary(sym.owner) - if (b.isPackageClass) b - else b.enclosingPackageClass - } + def packageAccessBoundry(sym: Symbol) = + sym.accessBoundary(sym.enclosingPackageClass) val isCandidate = ( sym.isProtected && sym.isJavaDefined && !sym.isDefinedInPackage && !accessibleThroughSubclassing - && (sym.owner.enclosingPackageClass != currentOwner.enclosingPackageClass) - && (sym.owner.enclosingPackageClass == packageAccessBoundry(sym)) + && (sym.enclosingPackageClass != currentPackage) + && (sym.enclosingPackageClass == sym.accessBoundary(sym.enclosingPackageClass)) ) val host = hostForAccessorOf(sym, clazz) def isSelfType = !(host.tpe <:< host.typeOfThis) && { @@ -433,15 +458,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT ) true } - def isJavaProtected = host.isTrait && sym.isJavaDefined && { - restrictionError(pos, unit, - """|%s accesses protected %s inside a concrete trait method. - |Add an accessor in a class extending %s as a workaround.""".stripMargin.format( - clazz, sym, sym.enclClass) - ) - true - } - isCandidate && !host.isPackageClass && !isSelfType && !isJavaProtected + isCandidate && !host.isPackageClass && !isSelfType } /** Return the innermost enclosing class C of referencingClass for which either diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index c53b92c5be..7559b78db3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -115,7 +115,7 @@ trait SyntheticMethods extends ast.TreeDSL { * def canEqual(that: Any) = that.isInstanceOf[This] */ def canEqualMethod: Tree = ( - createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m => + createMethod(nme.canEqual_, List(AnyClass.tpe), BooleanClass.tpe)(m => Ident(m.firstParam) IS_OBJ classExistentialType(clazz)) ) @@ -248,7 +248,7 @@ trait SyntheticMethods extends ast.TreeDSL { } if (phase.id > currentRun.typerPhase.id) templ - else deriveTemplate(templ)(body => + else deriveTemplate(templ)(body => if (clazz.isCase) caseTemplateBody() else synthesize() match { case Nil => body // avoiding unnecessary copy diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala index 4f4087a953..1434002121 100644 --- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala +++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala @@ -415,7 +415,7 @@ trait TypeDiagnostics { "\nIf applicable, you may wish to try moving some members into another object." ) } - + /** Report a type error. * * @param pos0 The position where to report the error diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ea8112f1a4..5cb722a90f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -156,7 +156,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ErrorType => fun } - + def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = inferView(tree, from, to, reportAmbiguous, true) @@ -276,7 +276,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } tp match { case TypeRef(pre, sym, args) => - checkNotLocked(sym) && + checkNotLocked(sym) && ((!sym.isNonClassType) || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)) // @M! info for a type ref to a type parameter now returns a polytype // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) @@ -604,6 +604,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { * 1. Check that non-function pattern expressions are stable * 2. Check that packages and static modules are not used as values * 3. Turn tree type into stable type if possible and required by context. + * 4. Give getClass calls a more precise type based on the type of the target of the call. */ private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = { if (tree.symbol.isOverloaded && !inFunMode(mode)) @@ -614,7 +615,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (tree.isErrorTyped) tree else if ((mode & (PATTERNmode | FUNmode)) == PATTERNmode && tree.isTerm) { // (1) - if (sym.isValue) checkStable(tree) + if (sym.isValue) { + val tree1 = checkStable(tree) + // A module reference in a pattern has type Foo.type, not "object Foo" + if (sym.isModule && !sym.isMethod) tree1 setType singleType(pre, sym) + else tree1 + } else fail() } else if ((mode & (EXPRmode | QUALmode)) == EXPRmode && !sym.isValue && !phase.erasedTypes) { // (2) fail() @@ -622,7 +628,18 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (sym.isStable && pre.isStable && !isByNameParamType(tree.tpe) && (isStableContext(tree, mode, pt) || sym.isModule && !sym.isMethod)) tree.setType(singleType(pre, sym)) - else tree + // To fully benefit from special casing the return type of + // getClass, we have to catch it immediately so expressions + // like x.getClass().newInstance() are typed with the type of x. + else if ( tree.symbol.name == nme.getClass_ + && tree.tpe.params.isEmpty + // TODO: If the type of the qualifier is inaccessible, we can cause private types + // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this + // so for now it requires the type symbol be public. + && pre.typeSymbol.isPublic) + tree setType MethodType(Nil, erasure.getClassReturnType(pre)) + else + tree } } @@ -1092,7 +1109,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // Note: implicit arguments are still inferred (this kind of "chaining" is allowed) ) } - + def adaptToMember(qual: Tree, searchTemplate: Type): Tree = adaptToMember(qual, searchTemplate, true, true) def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree = @@ -1107,12 +1124,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match { case EmptyTree => qual - case coercion => + case coercion => if (settings.logImplicitConv.value) unit.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) - + typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) } } @@ -2175,9 +2192,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasDefaultFlag && !e.sym.hasAnnotation(BridgeClass) && !e1.sym.hasAnnotation(BridgeClass)) { log("Double definition detected:\n " + - ((e.sym.getClass, e.sym.info, e.sym.ownerChain)) + "\n " + + ((e.sym.getClass, e.sym.info, e.sym.ownerChain)) + "\n " + ((e1.sym.getClass, e1.sym.info, e1.sym.ownerChain))) - + DefDefinedTwiceError(e.sym, e1.sym) scope.unlink(e1) // need to unlink to avoid later problems with lub; see #2779 } @@ -2862,7 +2879,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type? sym.isTypeParameter && sym.owner.isJavaDefined - + /** If we map a set of hidden symbols to their existential bounds, we * have a problem: the bounds may themselves contain references to the * hidden symbols. So this recursively calls existentialBound until @@ -2889,7 +2906,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { }) }).toMap } - + /** Given a set `rawSyms` of term- and type-symbols, and a type * `tp`, produce a set of fresh type parameters and a type so that * it can be abstracted to an existential type. Every type symbol @@ -2933,10 +2950,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) - + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = - ctx.owner.isTerm && - (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || { var ctx1 = ctx.outer while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer @@ -3797,7 +3814,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (settings.warnSelectNullable.value && isPotentialNullDeference && unit != null) unit.warning(tree.pos, "potential null pointer dereference: "+tree) - val selection = result match { + result match { // could checkAccessible (called by makeAccessible) potentially have skipped checking a type application in qual? case SelectFromTypeTree(qual@TypeTree(), name) if qual.tpe.typeArgs nonEmpty => // TODO: somehow the new qual is not checked in refchecks treeCopy.SelectFromTypeTree( @@ -3819,22 +3836,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case _ => result } - // To fully benefit from special casing the return type of - // getClass, we have to catch it immediately so expressions - // like x.getClass().newInstance() are typed with the type of x. - val isRefinableGetClass = ( - !selection.isErrorTyped - && selection.symbol.name == nme.getClass_ - && selection.tpe.params.isEmpty - // TODO: If the type of the qualifier is inaccessible, we can cause private types - // to escape scope here, e.g. pos/t1107. I'm not sure how to properly handle this - // so for now it requires the type symbol be public. - && qual.tpe.typeSymbol.isPublic - ) - if (isRefinableGetClass) - selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) - else - selection } } @@ -3888,7 +3889,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { reallyExists(sym) && ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.hasFlag(ACCESSOR)) } - + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -4384,7 +4385,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ReferenceToBoxed(idt @ Ident(_)) => val id1 = typed1(idt, mode, pt) match { case id: Ident => id } - treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe case Literal(value) => tree setType ( diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 19b8632ed7..312958feca 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -22,7 +22,7 @@ trait Unapplies extends ast.TreeDSL import treeInfo.{ isRepeatedParamType, isByNameParamType } private val unapplyParamName = nme.x_0 - + /** returns type list for return type of the extraction */ def unapplyTypeList(ufn: Symbol, ufntpe: Type) = { assert(ufn.isMethod, ufn) diff --git a/src/compiler/scala/tools/nsc/util/DocStrings.scala b/src/compiler/scala/tools/nsc/util/DocStrings.scala index 24c9926ad8..fbe92e5d84 100755 --- a/src/compiler/scala/tools/nsc/util/DocStrings.scala +++ b/src/compiler/scala/tools/nsc/util/DocStrings.scala @@ -71,10 +71,10 @@ object DocStrings { * Every section starts with a `@` and extends to the next `@`, or * to the end of the comment string, but excluding the final two * characters which terminate the comment. - * - * Also take usecases into account - they need to expand until the next - * usecase or the end of the string, as they might include other sections - * of their own + * + * Also take usecases into account - they need to expand until the next + * usecase or the end of the string, as they might include other sections + * of their own */ def tagIndex(str: String, p: Int => Boolean = (idx => true)): List[(Int, Int)] = findAll(str, 0) (idx => str(idx) == '@' && p(idx)) match { @@ -84,10 +84,10 @@ object DocStrings { idxs2 zip (idxs2.tail ::: List(str.length - 2)) } } - + /** - * Merge sections following an usecase into the usecase comment, so they - * can override the parent symbol's sections + * Merge sections following an usecase into the usecase comment, so they + * can override the parent symbol's sections */ def mergeUsecaseSections(str: String, idxs: List[Int]): List[Int] = { idxs.find(str.substring(_).startsWith("@usecase")) match { @@ -99,7 +99,7 @@ object DocStrings { idxs } } - + /** Does interval `iv` start with given `tag`? */ def startsWithTag(str: String, section: (Int, Int), tag: String): Boolean = diff --git a/src/compiler/scala/tools/nsc/util/Statistics.scala b/src/compiler/scala/tools/nsc/util/Statistics.scala index f7c27dceb5..d1cdd30dd8 100644 --- a/src/compiler/scala/tools/nsc/util/Statistics.scala +++ b/src/compiler/scala/tools/nsc/util/Statistics.scala @@ -20,7 +20,7 @@ class Statistics extends scala.reflect.internal.util.Statistics { val typedSelectCount = new Counter val typerNanos = new Timer val classReadNanos = new Timer - + val failedApplyNanos = new Timer val failedOpEqNanos = new Timer val failedSilentNanos = new Timer diff --git a/src/compiler/scala/tools/nsc/util/WeakHashSet.scala b/src/compiler/scala/tools/nsc/util/WeakHashSet.scala new file mode 100644 index 0000000000..6a10422b00 --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/WeakHashSet.scala @@ -0,0 +1,60 @@ +package scala.tools.nsc.util + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer +import scala.collection.mutable.Builder +import scala.collection.mutable.SetBuilder +import scala.runtime.AbstractFunction1 + +/** A bare-bones implementation of a mutable `Set` that uses weak references + * to hold the elements. + * + * This implementation offers only add/remove/test operations, + * therefore it does not fulfill the contract of Scala collection sets. + */ +class WeakHashSet[T <: AnyRef] extends AbstractFunction1[T, Boolean] { + private val underlying = mutable.HashSet[WeakReferenceWithEquals[T]]() + + /** Add the given element to this set. */ + def +=(elem: T): this.type = { + underlying += new WeakReferenceWithEquals(elem) + this + } + + /** Remove the given element from this set. */ + def -=(elem: T): this.type = { + underlying -= new WeakReferenceWithEquals(elem) + this + } + + /** Does the given element belong to this set? */ + def contains(elem: T): Boolean = + underlying.contains(new WeakReferenceWithEquals(elem)) + + /** Does the given element belong to this set? */ + def apply(elem: T): Boolean = contains(elem) + + /** Return the number of elements in this set, including reclaimed elements. */ + def size = underlying.size + + /** Remove all elements in this set. */ + def clear() = underlying.clear() +} + +/** A WeakReference implementation that implements equals and hashCode by + * delegating to the referent. + */ +class WeakReferenceWithEquals[T <: AnyRef](ref: T) { + def get(): T = underlying.get() + + override val hashCode = ref.hashCode + + override def equals(other: Any): Boolean = other match { + case wf: WeakReferenceWithEquals[_] => + underlying.get() == wf.get() + case _ => + false + } + + private val underlying = new java.lang.ref.WeakReference(ref) +} diff --git a/src/compiler/scala/tools/util/EditDistance.scala b/src/compiler/scala/tools/util/EditDistance.scala index 5f152ecabb..0af34020a8 100644 --- a/src/compiler/scala/tools/util/EditDistance.scala +++ b/src/compiler/scala/tools/util/EditDistance.scala @@ -8,7 +8,7 @@ package util object EditDistance { import java.lang.Character.{ toLowerCase => lower } - + def similarString(name: String, allowed: TraversableOnce[String]): String = { val suggested = suggestions(name, allowed.toSeq, maxDistance = 1, maxSuggestions = 2) if (suggested.isEmpty) "" diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala index 9930f28229..af0d768607 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSAnnotationChecker.scala @@ -53,23 +53,23 @@ abstract class CPSAnnotationChecker extends CPSUtils { if ((annots1 corresponds annots2)(_.atp <:< _.atp)) return true - // Need to handle uninstantiated type vars specially: - + // Need to handle uninstantiated type vars specially: + // g map (x => x) with expected type List[Int] @cps // results in comparison ?That <:< List[Int] @cps - + // Instantiating ?That to an annotated type would fail during // transformation. - + // Instead we force-compare tpe1 <:< tpe2.withoutAnnotations // to trigger instantiation of the TypeVar to the base type - + // This is a bit unorthodox (we're only supposed to look at // annotations here) but seems to work. - + if (!annots2.isEmpty && !tpe1.isGround) return tpe1 <:< tpe2.withoutAnnotations - + false } @@ -336,29 +336,31 @@ abstract class CPSAnnotationChecker extends CPSUtils { def single(xs: List[AnnotationInfo]) = xs match { case List(x) => x case _ => - global.globalError("not a single cps annotation: " + xs)// FIXME: error message + global.globalError("not a single cps annotation: " + xs) xs(0) } + + def emptyOrSingleList(xs: List[AnnotationInfo]) = if (xs.isEmpty) Nil else List(single(xs)) def transChildrenInOrder(tree: Tree, tpe: Type, childTrees: List[Tree], byName: List[Tree]) = { def inspect(t: Tree): List[AnnotationInfo] = { if (t.tpe eq null) Nil else { val extra: List[AnnotationInfo] = t.tpe match { case _: MethodType | _: PolyType | _: OverloadedType => - // method types, poly types and overloaded types do not obtain cps annotions by propagat - // need to reconstruct transitively from their children. - t match { - case Select(qual, name) => inspect(qual) - case Apply(fun, args) => (fun::args) flatMap inspect - case TypeApply(fun, args) => (fun::args) flatMap inspect - case _ => Nil - } + // method types, poly types and overloaded types do not obtain cps annotions by propagation + // need to reconstruct transitively from their children. + t match { + case Select(qual, name) => inspect(qual) + case Apply(fun, args) => (fun::(transArgList(fun,args).flatten)) flatMap inspect + case TypeApply(fun, args) => (fun::(transArgList(fun,args).flatten)) flatMap inspect + case _ => Nil + } case _ => Nil } - + val types = cpsParamAnnotation(t.tpe) // TODO: check that it has been adapted and if so correctly - extra ++ (if (types.isEmpty) Nil else List(single(types))) + extra ++ emptyOrSingleList(types) } } val children = childTrees flatMap inspect diff --git a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala index 8bbda5dd05..075009ce5e 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/CPSUtils.scala @@ -12,7 +12,7 @@ trait CPSUtils { var cpsEnabled = true val verbose: Boolean = System.getProperty("cpsVerbose", "false") == "true" def vprintln(x: =>Any): Unit = if (verbose) println(x) - + object cpsNames { val catches = newTermName("$catches") val ex = newTermName("$ex") diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala index d98169f21a..1189cc2e38 100644 --- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala +++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala @@ -97,13 +97,17 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with case vd @ ValDef(mods, name, tpt, rhs) => // object-level valdefs debuglog("transforming valdef " + vd.symbol) - atOwner(vd.symbol) { + if (getExternalAnswerTypeAnn(tpt.tpe).isEmpty) { + + atOwner(vd.symbol) { - assert(getExternalAnswerTypeAnn(tpt.tpe) == None) + val rhs1 = transExpr(rhs, None, None) - val rhs1 = transExpr(rhs, None, None) - - treeCopy.ValDef(vd, mods, name, transform(tpt), rhs1) + treeCopy.ValDef(vd, mods, name, transform(tpt), rhs1) + } + } else { + unit.error(tree.pos, "cps annotations not allowed on by-value parameters or value definitions") + super.transform(tree) } case TypeTree() => diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index 3d85f2f52f..80571943e5 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -55,7 +55,7 @@ abstract class Enumeration (initial: Int) extends Serializable { thisenum => def this() = this(0) - + @deprecated("Names should be specified individually or discovered via reflection", "2.10.0") def this(initial: Int, names: String*) = { this(initial) @@ -201,7 +201,7 @@ abstract class Enumeration (initial: Int) extends Serializable { case _ => false } override def hashCode: Int = id.## - + /** Create a ValueSet which contains this value and another one */ def + (v: Value) = ValueSet(this, v) } @@ -266,7 +266,7 @@ abstract class Enumeration (initial: Int) extends Serializable { * new array of longs */ def toBitMask: Array[Long] = nnIds.toBitMask } - + /** A factory object for value sets */ object ValueSet { import generic.CanBuildFrom diff --git a/src/library/scala/Function0.scala b/src/library/scala/Function0.scala index 508ef25e81..dceed26439 100644 --- a/src/library/scala/Function0.scala +++ b/src/library/scala/Function0.scala @@ -12,12 +12,12 @@ package scala /** A function of 0 parameters. - * + * * In the following example, the definition of javaVersion is a * shorthand for the anonymous class definition anonfun0: * * {{{ - * object Main extends App { + * object Main extends App { * val javaVersion = () => sys.props("java.version") * * val anonfun0 = new Function0[String] { @@ -31,13 +31,13 @@ package scala * be suggested by the existence of [[scala.PartialFunction]]. The only * distinction between `Function1` and `PartialFunction` is that the * latter can specify inputs which it will not handle. - + */ trait Function0[@specialized +R] extends AnyRef { self => /** Apply the body of this function to the arguments. * @return the result of function application. */ def apply(): R - + override def toString() = "<function0>" } diff --git a/src/library/scala/Function1.scala b/src/library/scala/Function1.scala index 06936e54cb..8995ef912b 100644 --- a/src/library/scala/Function1.scala +++ b/src/library/scala/Function1.scala @@ -11,12 +11,12 @@ package scala /** A function of 1 parameter. - * + * * In the following example, the definition of succ is a * shorthand for the anonymous class definition anonfun1: * * {{{ - * object Main extends App { + * object Main extends App { * val succ = (x: Int) => x + 1 * val anonfun1 = new Function1[Int, Int] { * def apply(x: Int): Int = x + 1 @@ -29,7 +29,7 @@ package scala * be suggested by the existence of [[scala.PartialFunction]]. The only * distinction between `Function1` and `PartialFunction` is that the * latter can specify inputs which it will not handle. - + */ @annotation.implicitNotFound(msg = "No implicit view available from ${T1} => ${R}.") trait Function1[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends AnyRef { self => @@ -37,7 +37,7 @@ trait Function1[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, s * @return the result of function application. */ def apply(v1: T1): R - + /** Composes two instances of Function1 in a new Function1, with this function applied last. * * @tparam A the type to which function `g` can be applied diff --git a/src/library/scala/Function2.scala b/src/library/scala/Function2.scala index 1812f042e0..cacb96ef5d 100644 --- a/src/library/scala/Function2.scala +++ b/src/library/scala/Function2.scala @@ -11,12 +11,12 @@ package scala /** A function of 2 parameters. - * + * * In the following example, the definition of max is a * shorthand for the anonymous class definition anonfun2: * * {{{ - * object Main extends App { + * object Main extends App { * val max = (x: Int, y: Int) => if (x < y) y else x * * val anonfun2 = new Function2[Int, Int, Int] { @@ -30,7 +30,7 @@ package scala * be suggested by the existence of [[scala.PartialFunction]]. The only * distinction between `Function1` and `PartialFunction` is that the * latter can specify inputs which it will not handle. - + */ trait Function2[@specialized(scala.Int, scala.Long, scala.Double) -T1, @specialized(scala.Int, scala.Long, scala.Double) -T2, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double) +R] extends AnyRef { self => /** Apply the body of this function to the arguments. diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index 70caff0221..3c5d6d0d23 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -26,18 +26,18 @@ package scala * * {{{ * val sample = 1 to 10 - * val isEven: PartialFunction[Int, String] = { - * case x if x % 2 == 0 => x+" is even" + * val isEven: PartialFunction[Int, String] = { + * case x if x % 2 == 0 => x+" is even" * } * * // the method collect can use isDefinedAt to select which members to collect * val evenNumbers = sample collect isEven * - * val isOdd: PartialFunction[Int, String] = { - * case x if x % 2 == 1 => x+" is odd" + * val isOdd: PartialFunction[Int, String] = { + * case x if x % 2 == 1 => x+" is odd" * } * - * // the method orElse allows chaining another partial function to handle + * // the method orElse allows chaining another partial function to handle * // input outside the declared domain * val numbers = sample map (isEven orElse isOdd) * }}} diff --git a/src/library/scala/Product1.scala b/src/library/scala/Product1.scala index 0106ad34ee..ab8b0a4505 100644 --- a/src/library/scala/Product1.scala +++ b/src/library/scala/Product1.scala @@ -23,7 +23,7 @@ trait Product1[@specialized(Int, Long, Double) +T1] extends Product { */ override def productArity = 1 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product1[@specialized(Int, Long, Double) +T1] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case _ => throw new IndexOutOfBoundsException(n.toString()) } diff --git a/src/library/scala/Product10.scala b/src/library/scala/Product10.scala index ca53b580c0..536fb2fed9 100644 --- a/src/library/scala/Product10.scala +++ b/src/library/scala/Product10.scala @@ -23,7 +23,7 @@ trait Product10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10] extends Produ */ override def productArity = 10 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10] extends Produ */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product11.scala b/src/library/scala/Product11.scala index 3d5942f3fa..7d49eccc5e 100644 --- a/src/library/scala/Product11.scala +++ b/src/library/scala/Product11.scala @@ -23,7 +23,7 @@ trait Product11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11] extends */ override def productArity = 11 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11] extends */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product12.scala b/src/library/scala/Product12.scala index 803193793c..0e9c4a01a2 100644 --- a/src/library/scala/Product12.scala +++ b/src/library/scala/Product12.scala @@ -23,7 +23,7 @@ trait Product12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12] e */ override def productArity = 12 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12] e */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product13.scala b/src/library/scala/Product13.scala index 0c1d889624..a0629201d0 100644 --- a/src/library/scala/Product13.scala +++ b/src/library/scala/Product13.scala @@ -23,7 +23,7 @@ trait Product13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 13 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product14.scala b/src/library/scala/Product14.scala index 0222309a0a..32dda81c3e 100644 --- a/src/library/scala/Product14.scala +++ b/src/library/scala/Product14.scala @@ -23,7 +23,7 @@ trait Product14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 14 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product15.scala b/src/library/scala/Product15.scala index 41be7ec504..57851f9870 100644 --- a/src/library/scala/Product15.scala +++ b/src/library/scala/Product15.scala @@ -23,7 +23,7 @@ trait Product15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 15 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product16.scala b/src/library/scala/Product16.scala index accee3f965..75076f3b3c 100644 --- a/src/library/scala/Product16.scala +++ b/src/library/scala/Product16.scala @@ -23,7 +23,7 @@ trait Product16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 16 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product17.scala b/src/library/scala/Product17.scala index da80ae9a6b..9ee6072ffe 100644 --- a/src/library/scala/Product17.scala +++ b/src/library/scala/Product17.scala @@ -23,7 +23,7 @@ trait Product17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 17 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product18.scala b/src/library/scala/Product18.scala index ea25647762..25d0839af1 100644 --- a/src/library/scala/Product18.scala +++ b/src/library/scala/Product18.scala @@ -23,7 +23,7 @@ trait Product18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 18 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product19.scala b/src/library/scala/Product19.scala index 5d4347c1a8..5464de7264 100644 --- a/src/library/scala/Product19.scala +++ b/src/library/scala/Product19.scala @@ -23,7 +23,7 @@ trait Product19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 19 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product2.scala b/src/library/scala/Product2.scala index 4e6c70f463..8097245926 100644 --- a/src/library/scala/Product2.scala +++ b/src/library/scala/Product2.scala @@ -23,7 +23,7 @@ trait Product2[@specialized(Int, Long, Double) +T1, @specialized(Int, Long, Doub */ override def productArity = 2 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product2[@specialized(Int, Long, Double) +T1, @specialized(Int, Long, Doub */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case _ => throw new IndexOutOfBoundsException(n.toString()) diff --git a/src/library/scala/Product20.scala b/src/library/scala/Product20.scala index f23a0dee3a..b094e09aca 100644 --- a/src/library/scala/Product20.scala +++ b/src/library/scala/Product20.scala @@ -23,7 +23,7 @@ trait Product20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 20 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product21.scala b/src/library/scala/Product21.scala index 4a4fe0697f..fa06cfb438 100644 --- a/src/library/scala/Product21.scala +++ b/src/library/scala/Product21.scala @@ -23,7 +23,7 @@ trait Product21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 21 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product22.scala b/src/library/scala/Product22.scala index 7ee01b85ae..46038bf1a2 100644 --- a/src/library/scala/Product22.scala +++ b/src/library/scala/Product22.scala @@ -23,7 +23,7 @@ trait Product22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ override def productArity = 22 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, + */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product3.scala b/src/library/scala/Product3.scala index 23563c9e23..3a4cd8fc5e 100644 --- a/src/library/scala/Product3.scala +++ b/src/library/scala/Product3.scala @@ -23,7 +23,7 @@ trait Product3[+T1, +T2, +T3] extends Product { */ override def productArity = 3 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product3[+T1, +T2, +T3] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product4.scala b/src/library/scala/Product4.scala index 4abaa9051b..a4d47457fa 100644 --- a/src/library/scala/Product4.scala +++ b/src/library/scala/Product4.scala @@ -23,7 +23,7 @@ trait Product4[+T1, +T2, +T3, +T4] extends Product { */ override def productArity = 4 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product4[+T1, +T2, +T3, +T4] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product5.scala b/src/library/scala/Product5.scala index 9aa4af58b7..9f25e70af0 100644 --- a/src/library/scala/Product5.scala +++ b/src/library/scala/Product5.scala @@ -23,7 +23,7 @@ trait Product5[+T1, +T2, +T3, +T4, +T5] extends Product { */ override def productArity = 5 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product5[+T1, +T2, +T3, +T4, +T5] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product6.scala b/src/library/scala/Product6.scala index 2ca1d7c31e..87fd318c68 100644 --- a/src/library/scala/Product6.scala +++ b/src/library/scala/Product6.scala @@ -23,7 +23,7 @@ trait Product6[+T1, +T2, +T3, +T4, +T5, +T6] extends Product { */ override def productArity = 6 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product6[+T1, +T2, +T3, +T4, +T5, +T6] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product7.scala b/src/library/scala/Product7.scala index b7af2d3e32..d074503315 100644 --- a/src/library/scala/Product7.scala +++ b/src/library/scala/Product7.scala @@ -23,7 +23,7 @@ trait Product7[+T1, +T2, +T3, +T4, +T5, +T6, +T7] extends Product { */ override def productArity = 7 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product7[+T1, +T2, +T3, +T4, +T5, +T6, +T7] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product8.scala b/src/library/scala/Product8.scala index 17b5e48512..bd6150c235 100644 --- a/src/library/scala/Product8.scala +++ b/src/library/scala/Product8.scala @@ -23,7 +23,7 @@ trait Product8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8] extends Product { */ override def productArity = 8 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Product9.scala b/src/library/scala/Product9.scala index 784e9a7029..1f042944cc 100644 --- a/src/library/scala/Product9.scala +++ b/src/library/scala/Product9.scala @@ -23,7 +23,7 @@ trait Product9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9] extends Product { */ override def productArity = 9 - + /** Returns the n-th projection of this product if 0 < n <= productArity, * otherwise throws an `IndexOutOfBoundsException`. * @@ -33,7 +33,7 @@ trait Product9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9] extends Product { */ @throws(classOf[IndexOutOfBoundsException]) - override def productElement(n: Int) = n match { + override def productElement(n: Int) = n match { case 0 => _1 case 1 => _2 case 2 => _3 diff --git a/src/library/scala/Specializable.scala b/src/library/scala/Specializable.scala index 811a735110..67126b3069 100644 --- a/src/library/scala/Specializable.scala +++ b/src/library/scala/Specializable.scala @@ -16,7 +16,7 @@ trait Specializable extends SpecializableCompanion object Specializable { // No type parameter in @specialized annotation. trait SpecializedGroup { } - + // Smuggle a list of types by way of a tuple upon which Group is parameterized. class Group[T >: Null](value: T) extends SpecializedGroup { } diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala index 6116547aa2..1b01355108 100644 --- a/src/library/scala/StringContext.scala +++ b/src/library/scala/StringContext.scala @@ -13,7 +13,7 @@ import collection.mutable.ArrayBuffer /** A class to support string interpolation. * This class supports string interpolation as outlined in Scala SIP-11. * It needs to be fully documented once the SIP is accepted. - * + * * @param parts The parts that make up the interpolated string, * without the expressions that get inserted by interpolation. */ @@ -26,13 +26,13 @@ case class StringContext(parts: String*) { * @param `args` The arguments to be checked. * @throws An `IllegalArgumentException` if this is not the case. */ - def checkLengths(args: Any*): Unit = + def checkLengths(args: Any*): Unit = if (parts.length != args.length + 1) throw new IllegalArgumentException("wrong number of arguments for interpolated string") /** The simple string interpolator. - * + * * It inserts its arguments between corresponding parts of the string context. * It also treats standard escape sequences as defined in the Scala specification. * @param `args` The arguments to be inserted into the resulting string. @@ -46,30 +46,30 @@ case class StringContext(parts: String*) { checkLengths(args: _*) val pi = parts.iterator val ai = args.iterator - val bldr = new java.lang.StringBuilder(treatEscapes(pi.next)) + val bldr = new java.lang.StringBuilder(treatEscapes(pi.next())) while (ai.hasNext) { bldr append ai.next - bldr append treatEscapes(pi.next) + bldr append treatEscapes(pi.next()) } bldr.toString } /** The formatted string interpolator. - * + * * It inserts its arguments between corresponding parts of the string context. * It also treats standard escape sequences as defined in the Scala specification. * Finally, if an interpolated expression is followed by a `parts` string * that starts with a formatting specifier, the expression is formatted according to that * specifier. All specifiers allowed in Java format strings are handled, and in the same * way they are treated in Java. - * + * * @param `args` The arguments to be inserted into the resulting string. * @throws An `IllegalArgumentException` * if the number of `parts` in the enclosing `StringContext` does not exceed * the number of arguments `arg` by exactly 1. * @throws A `StringContext.InvalidEscapeException` if a `parts` string contains a backslash (`\`) character * that does not start a valid escape sequence. - * + * * Note: The `f` method works by assembling a format string from all the `parts` strings and using * `java.lang.String.format` to format all arguments with that format string. The format string is * obtained by concatenating all `parts` strings, and performing two transformations: @@ -89,11 +89,12 @@ case class StringContext(parts: String*) { val bldr = new java.lang.StringBuilder val args1 = new ArrayBuffer[Any] def copyString(first: Boolean): Unit = { - val str = treatEscapes(pi.next) + val str = treatEscapes(pi.next()) + val strIsEmpty = str.length == 0 var start = 0 var idx = 0 if (!first) { - if ((str charAt 0) != '%') + if (strIsEmpty || (str charAt 0) != '%') bldr append "%s" idx = 1 } @@ -106,11 +107,11 @@ case class StringContext(parts: String*) { } idx += 1 } - bldr append (str substring (start, idx)) + if (!strIsEmpty) bldr append (str substring (start, idx)) } copyString(first = true) while (pi.hasNext) { - args1 += ai.next + args1 += ai.next() copyString(first = false) } bldr.toString format (args1: _*) @@ -125,14 +126,14 @@ object StringContext { * @param idx The index of the offending backslash character in `str`. */ class InvalidEscapeException(str: String, idx: Int) - extends IllegalArgumentException("invalid escape character at index "+idx+" in \""+str+"\"") + extends IllegalArgumentException("invalid escape character at index "+idx+" in \""+str+"\"") /** Expands standard Scala escape sequences in a string. * Escape sequences are: * control: `\b`, `\t`, `\n`, `\f`, `\r` * escape: `\\`, `\"`, `\'` * octal: `\d` `\dd` `\ddd` where `d` is an octal digit between `0` and `7`. - * + * * @param A string that may contain escape sequences * @return The string with all escape sequences expanded. */ diff --git a/src/library/scala/Tuple1.scala b/src/library/scala/Tuple1.scala index 02fdd0cba5..6d31d35e51 100644 --- a/src/library/scala/Tuple1.scala +++ b/src/library/scala/Tuple1.scala @@ -19,5 +19,5 @@ case class Tuple1[@specialized(Int, Long, Double) +T1](_1: T1) extends Product1[T1] { override def toString() = "(" + _1 + ")" - + } diff --git a/src/library/scala/Tuple10.scala b/src/library/scala/Tuple10.scala index ba2a02a8b2..10d554d467 100644 --- a/src/library/scala/Tuple10.scala +++ b/src/library/scala/Tuple10.scala @@ -28,5 +28,5 @@ case class Tuple10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10](_1: T1, _2 extends Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + ")" - + } diff --git a/src/library/scala/Tuple11.scala b/src/library/scala/Tuple11.scala index 7f51d172d4..2065e4f017 100644 --- a/src/library/scala/Tuple11.scala +++ b/src/library/scala/Tuple11.scala @@ -29,5 +29,5 @@ case class Tuple11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11](_1: extends Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + ")" - + } diff --git a/src/library/scala/Tuple12.scala b/src/library/scala/Tuple12.scala index 4bbc6a0eab..a463986752 100644 --- a/src/library/scala/Tuple12.scala +++ b/src/library/scala/Tuple12.scala @@ -31,5 +31,5 @@ case class Tuple12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + ")" - + } diff --git a/src/library/scala/Tuple13.scala b/src/library/scala/Tuple13.scala index 77bd59bf2e..2bee0d69ad 100644 --- a/src/library/scala/Tuple13.scala +++ b/src/library/scala/Tuple13.scala @@ -32,5 +32,5 @@ case class Tuple13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + ")" - + } diff --git a/src/library/scala/Tuple14.scala b/src/library/scala/Tuple14.scala index bf7a4ce016..60f7c51e64 100644 --- a/src/library/scala/Tuple14.scala +++ b/src/library/scala/Tuple14.scala @@ -33,5 +33,5 @@ case class Tuple14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + ")" - + } diff --git a/src/library/scala/Tuple15.scala b/src/library/scala/Tuple15.scala index 582c359bc6..fc8e30580b 100644 --- a/src/library/scala/Tuple15.scala +++ b/src/library/scala/Tuple15.scala @@ -34,5 +34,5 @@ case class Tuple15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + ")" - + } diff --git a/src/library/scala/Tuple16.scala b/src/library/scala/Tuple16.scala index a1e9a790ff..80181f6648 100644 --- a/src/library/scala/Tuple16.scala +++ b/src/library/scala/Tuple16.scala @@ -35,5 +35,5 @@ case class Tuple16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + ")" - + } diff --git a/src/library/scala/Tuple17.scala b/src/library/scala/Tuple17.scala index f531766c18..6236122be2 100644 --- a/src/library/scala/Tuple17.scala +++ b/src/library/scala/Tuple17.scala @@ -36,5 +36,5 @@ case class Tuple17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + ")" - + } diff --git a/src/library/scala/Tuple18.scala b/src/library/scala/Tuple18.scala index a96db25e4b..dd6a819ac5 100644 --- a/src/library/scala/Tuple18.scala +++ b/src/library/scala/Tuple18.scala @@ -37,5 +37,5 @@ case class Tuple18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + ")" - + } diff --git a/src/library/scala/Tuple19.scala b/src/library/scala/Tuple19.scala index 718280d68a..65f0fd22cf 100644 --- a/src/library/scala/Tuple19.scala +++ b/src/library/scala/Tuple19.scala @@ -38,5 +38,5 @@ case class Tuple19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + ")" - + } diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala index b1befca4fa..684d2266e8 100644 --- a/src/library/scala/Tuple2.scala +++ b/src/library/scala/Tuple2.scala @@ -23,7 +23,7 @@ case class Tuple2[@specialized(Int, Long, Double, Char, Boolean, AnyRef) +T1, @s extends Product2[T1, T2] { override def toString() = "(" + _1 + "," + _2 + ")" - + /** Swaps the elements of this `Tuple`. * @return a new Tuple where the first element is the second element of this Tuple and the * second element is the first element of this Tuple. diff --git a/src/library/scala/Tuple20.scala b/src/library/scala/Tuple20.scala index 4a44c0bb89..cf3626909d 100644 --- a/src/library/scala/Tuple20.scala +++ b/src/library/scala/Tuple20.scala @@ -39,5 +39,5 @@ case class Tuple20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + ")" - + } diff --git a/src/library/scala/Tuple21.scala b/src/library/scala/Tuple21.scala index 580a169e39..78b9c585c6 100644 --- a/src/library/scala/Tuple21.scala +++ b/src/library/scala/Tuple21.scala @@ -40,5 +40,5 @@ case class Tuple21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + "," + _21 + ")" - + } diff --git a/src/library/scala/Tuple22.scala b/src/library/scala/Tuple22.scala index fd3392ddea..0993dfbbc3 100644 --- a/src/library/scala/Tuple22.scala +++ b/src/library/scala/Tuple22.scala @@ -41,5 +41,5 @@ case class Tuple22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12 { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + "," + _21 + "," + _22 + ")" - + } diff --git a/src/library/scala/Tuple3.scala b/src/library/scala/Tuple3.scala index 0d5399308b..dfa0c962a2 100644 --- a/src/library/scala/Tuple3.scala +++ b/src/library/scala/Tuple3.scala @@ -24,7 +24,7 @@ case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3) extends Product3[T1, T2, T3] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + ")" - + @deprecated("Use `zipped` instead.", "2.9.0") def zip[Repr1, El1, El2, El3, To](implicit w1: T1 => TLike[El1, Repr1], diff --git a/src/library/scala/Tuple4.scala b/src/library/scala/Tuple4.scala index a859078bcf..a919072c88 100644 --- a/src/library/scala/Tuple4.scala +++ b/src/library/scala/Tuple4.scala @@ -22,5 +22,5 @@ case class Tuple4[+T1, +T2, +T3, +T4](_1: T1, _2: T2, _3: T3, _4: T4) extends Product4[T1, T2, T3, T4] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + ")" - + } diff --git a/src/library/scala/Tuple5.scala b/src/library/scala/Tuple5.scala index 1edfb673ee..6a94f48ab4 100644 --- a/src/library/scala/Tuple5.scala +++ b/src/library/scala/Tuple5.scala @@ -23,5 +23,5 @@ case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T extends Product5[T1, T2, T3, T4, T5] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + ")" - + } diff --git a/src/library/scala/Tuple6.scala b/src/library/scala/Tuple6.scala index 5b74937e58..34f8224627 100644 --- a/src/library/scala/Tuple6.scala +++ b/src/library/scala/Tuple6.scala @@ -24,5 +24,5 @@ case class Tuple6[+T1, +T2, +T3, +T4, +T5, +T6](_1: T1, _2: T2, _3: T3, _4: T4, extends Product6[T1, T2, T3, T4, T5, T6] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + ")" - + } diff --git a/src/library/scala/Tuple7.scala b/src/library/scala/Tuple7.scala index a7f572e9f0..6fc3477ba2 100644 --- a/src/library/scala/Tuple7.scala +++ b/src/library/scala/Tuple7.scala @@ -25,5 +25,5 @@ case class Tuple7[+T1, +T2, +T3, +T4, +T5, +T6, +T7](_1: T1, _2: T2, _3: T3, _4: extends Product7[T1, T2, T3, T4, T5, T6, T7] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + ")" - + } diff --git a/src/library/scala/Tuple8.scala b/src/library/scala/Tuple8.scala index 9bb427d689..1e21b684fc 100644 --- a/src/library/scala/Tuple8.scala +++ b/src/library/scala/Tuple8.scala @@ -26,5 +26,5 @@ case class Tuple8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8](_1: T1, _2: T2, _3: T3 extends Product8[T1, T2, T3, T4, T5, T6, T7, T8] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + ")" - + } diff --git a/src/library/scala/Tuple9.scala b/src/library/scala/Tuple9.scala index 4d50539e0c..453cea31a1 100644 --- a/src/library/scala/Tuple9.scala +++ b/src/library/scala/Tuple9.scala @@ -27,5 +27,5 @@ case class Tuple9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9](_1: T1, _2: T2, _ extends Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + ")" - + } diff --git a/src/library/scala/annotation/elidable.scala b/src/library/scala/annotation/elidable.scala index 053cdba220..880b645daa 100644 --- a/src/library/scala/annotation/elidable.scala +++ b/src/library/scala/annotation/elidable.scala @@ -52,8 +52,8 @@ import java.util.logging.Level // INFO lies between WARNING and FINE % scalac -Xelide-below INFO example.scala && scala Test Warning! Danger! Warning! - I computed a value: 0 - }}} + I computed a value: 0 + }}} * * @author Paul Phillips * @since 2.8 diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 02298ef096..b51a37cf9e 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -151,7 +151,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] with GenSeqLike[A, Repr] def next(): Repr = { if (!hasNext) Iterator.empty.next - + val forcedElms = new mutable.ArrayBuffer[A](elms.size) ++= elms val result = (self.newBuilder ++= forcedElms).result var i = idxs.length - 2 diff --git a/src/library/scala/collection/generic/MutableSortedSetFactory.scala b/src/library/scala/collection/generic/MutableSortedSetFactory.scala index b235379575..cbbedc0231 100644 --- a/src/library/scala/collection/generic/MutableSortedSetFactory.scala +++ b/src/library/scala/collection/generic/MutableSortedSetFactory.scala @@ -11,12 +11,12 @@ package generic import scala.collection.mutable.{ Builder, GrowingBuilder } -/** +/** * @define Coll mutable.SortedSet * @define coll mutable sorted * * @author Lucien Pereira - * + * */ abstract class MutableSortedSetFactory[CC[A] <: mutable.SortedSet[A] with SortedSetLike[A, CC[A]] with mutable.Set[A] with mutable.SetLike[A, CC[A]]] extends SortedSetFactory[CC] { @@ -26,7 +26,7 @@ abstract class MutableSortedSetFactory[CC[A] <: mutable.SortedSet[A] with Sorted * is evaluated elems is cloned (which is O(n)). * * Fortunately GrowingBuilder comes to rescue. - * + * */ override def newBuilder[A](implicit ord: Ordering[A]): Builder[A, CC[A]] = new GrowingBuilder[A, CC[A]](empty) diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala index abccd91f9c..870d5534dc 100644 --- a/src/library/scala/collection/immutable/BitSet.scala +++ b/src/library/scala/collection/immutable/BitSet.scala @@ -131,7 +131,7 @@ object BitSet extends BitSetFactory[BitSet] { * the capacity of two long values). The constructor wraps an existing * bit mask without copying, thus exposing a mutable part of the internal * implementation. Care needs to be taken not to modify the exposed - * array. + * array. */ class BitSetN(val elems: Array[Long]) extends BitSet { protected def nwords = elems.length diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index e2a4a09938..381fcf3117 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -326,13 +326,13 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend override def head : B = hd override def tail : List[B] = tl override def isEmpty: Boolean = false - + private def writeObject(out: ObjectOutputStream) { out.writeObject(ListSerializeStart) // needed to differentiate with the legacy `::` serialization out.writeObject(this.hd) out.writeObject(this.tl) } - + private def readObject(in: ObjectInputStream) { val obj = in.readObject() if (obj == ListSerializeStart) { @@ -340,7 +340,7 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend this.tl = in.readObject().asInstanceOf[List[B]] } else oldReadObject(in, obj) } - + /* The oldReadObject method exists here for compatibility reasons. * :: objects used to be serialized by serializing all the elements to * the output stream directly, but this was broken (see SI-5374). @@ -359,13 +359,13 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend current = list } } - + private def oldWriteObject(out: ObjectOutputStream) { var xs: List[B] = this while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } out.writeObject(ListSerializeEnd) } - + } /** $factoryInfo diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 7537558f0b..b72d83f896 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -77,9 +77,9 @@ extends collection.AbstractSeq[Int] } final val lastElement = start + (numRangeElements - 1) * step final val terminalElement = start + numRangeElements * step - + override def last = if (isEmpty) Nil.last else lastElement - + protected def copy(start: Int, end: Int, step: Int): Range = new Range(start, end, step) /** Create a new range with the `start` and `end` values of this range and @@ -93,14 +93,14 @@ extends collection.AbstractSeq[Int] override def size = length override def length = if (numRangeElements < 0) fail() else numRangeElements - + private def description = "%d %s %d by %s".format(start, if (isInclusive) "to" else "until", end, step) private def fail() = throw new IllegalArgumentException(description + ": seqs cannot contain more than Int.MaxValue elements.") private def validateMaxLength() { if (numRangeElements < 0) fail() } - + def validateRangeBoundaries(f: Int => Any): Boolean = { validateMaxLength() @@ -121,7 +121,7 @@ extends collection.AbstractSeq[Int] if (idx < 0 || idx >= numRangeElements) throw new IndexOutOfBoundsException(idx.toString) else start + (step * idx) } - + @inline final override def foreach[@specialized(Unit) U](f: Int => U) { if (validateRangeBoundaries(f)) { var i = start @@ -309,7 +309,7 @@ object Range { // number of full-sized jumps. val hasStub = isInclusive || (gap % step != 0) val result: Long = jumps + ( if (hasStub) 1 else 0 ) - + if (result > scala.Int.MaxValue) -1 else result.toInt } @@ -405,4 +405,3 @@ object Range { // super.foreach(f) } } -
\ No newline at end of file diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala index ba2af8f120..9aea25f330 100644 --- a/src/library/scala/collection/mutable/AVLTree.scala +++ b/src/library/scala/collection/mutable/AVLTree.scala @@ -12,9 +12,9 @@ package mutable /** * An immutable AVL Tree implementation used by mutable.TreeSet - * + * * @author Lucien Pereira - * + * */ private[mutable] sealed trait AVLTree[+A] extends Serializable { def balance: Int @@ -28,28 +28,28 @@ private[mutable] sealed trait AVLTree[+A] extends Serializable { /** * Returns a new tree containing the given element. * Thows an IllegalArgumentException if element is already present. - * + * */ def insert[B >: A](value: B, ordering: Ordering[B]): AVLTree[B] = Node(value, Leaf, Leaf) /** * Return a new tree which not contains given element. - * + * */ def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = throw new NoSuchElementException(String.valueOf(value)) - + /** * Return a tuple containing the smallest element of the provided tree * and a new tree from which this element has been extracted. - * + * */ def removeMin[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") - + /** * Return a tuple containing the biggest element of the provided tree * and a new tree from which this element has been extracted. - * + * */ def removeMax[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") @@ -90,7 +90,7 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree /** * Returns a new tree containing the given element. * Thows an IllegalArgumentException if element is already present. - * + * */ override def insert[B >: A](value: B, ordering: Ordering[B]) = { val ord = ordering.compare(value, data) @@ -104,7 +104,7 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree /** * Return a new tree which not contains given element. - * + * */ override def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = { val ord = ordering.compare(value, data) @@ -130,7 +130,7 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree /** * Return a tuple containing the smallest element of the provided tree * and a new tree from which this element has been extracted. - * + * */ override def removeMin[B >: A]: (B, AVLTree[B]) = { if (Leaf == left) @@ -144,7 +144,7 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree /** * Return a tuple containing the biggest element of the provided tree * and a new tree from which this element has been extracted. - * + * */ override def removeMax[B >: A]: (B, AVLTree[B]) = { if (Leaf == right) @@ -154,7 +154,7 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree (max, Node(data, left, newRight).rebalance) } } - + override def rebalance[B >: A] = { if (-2 == balance) { if (1 == left.balance) diff --git a/src/library/scala/collection/mutable/Ctrie.scala b/src/library/scala/collection/mutable/Ctrie.scala index 699b96b87c..cbec118aa9 100644 --- a/src/library/scala/collection/mutable/Ctrie.scala +++ b/src/library/scala/collection/mutable/Ctrie.scala @@ -22,29 +22,29 @@ import annotation.switch private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends INodeBase[K, V](g) { import INodeBase._ - + WRITE(bn) - + def this(g: Gen) = this(null, g) - + @inline final def WRITE(nval: MainNode[K, V]) = INodeBase.updater.set(this, nval) - + @inline final def CAS(old: MainNode[K, V], n: MainNode[K, V]) = INodeBase.updater.compareAndSet(this, old, n) - + final def gcasRead(ct: Ctrie[K, V]): MainNode[K, V] = GCAS_READ(ct) - + @inline final def GCAS_READ(ct: Ctrie[K, V]): MainNode[K, V] = { val m = /*READ*/mainnode val prevval = /*READ*/m.prev if (prevval eq null) m else GCAS_Complete(m, ct) } - + @tailrec private def GCAS_Complete(m: MainNode[K, V], ct: Ctrie[K, V]): MainNode[K, V] = if (m eq null) null else { // complete the GCAS val prev = /*READ*/m.prev val ctr = ct.readRoot(true) - + prev match { case null => m @@ -71,7 +71,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends } } } - + @inline final def GCAS(old: MainNode[K, V], n: MainNode[K, V], ct: Ctrie[K, V]): Boolean = { n.WRITE_PREV(old) if (CAS(old, n)) { @@ -79,27 +79,27 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends /*READ*/n.prev eq null } else false } - + @inline private def inode(cn: MainNode[K, V]) = { val nin = new INode[K, V](gen) nin.WRITE(cn) nin } - + final def copyToGen(ngen: Gen, ct: Ctrie[K, V]) = { val nin = new INode[K, V](ngen) val main = GCAS_READ(ct) nin.WRITE(main) nin } - + /** Inserts a key value pair, overwriting the old pair if the keys match. - * + * * @return true if successful, false otherwise */ @tailrec final def rec_insert(k: K, v: V, hc: Int, lev: Int, parent: INode[K, V], startgen: Gen, ct: Ctrie[K, V]): Boolean = { val m = GCAS_READ(ct) // use -Yinline! - + m match { case cn: CNode[K, V] => // 1) a multiway node val idx = (hc >>> lev) & 0x1f @@ -137,7 +137,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends GCAS(ln, nn, ct) } } - + /** Inserts a new key value pair, given that a specific condition is met. * * @param cond null - don't care if the key was there; KEY_ABSENT - key wasn't there; KEY_PRESENT - key was there; other value `v` - key must be bound to `v` @@ -145,7 +145,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends */ @tailrec final def rec_insertif(k: K, v: V, hc: Int, cond: AnyRef, lev: Int, parent: INode[K, V], startgen: Gen, ct: Ctrie[K, V]): Option[V] = { val m = GCAS_READ(ct) // use -Yinline! - + m match { case cn: CNode[K, V] => // 1) a multiway node val idx = (hc >>> lev) & 0x1f @@ -228,14 +228,14 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends } } } - + /** Looks up the value associated with the key. - * + * * @return null if no value has been found, RESTART if the operation wasn't successful, or any other value otherwise */ @tailrec final def rec_lookup(k: K, hc: Int, lev: Int, parent: INode[K, V], startgen: Gen, ct: Ctrie[K, V]): AnyRef = { val m = GCAS_READ(ct) // use -Yinline! - + m match { case cn: CNode[K, V] => // 1) a multinode val idx = (hc >>> lev) & 0x1f @@ -270,15 +270,15 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends ln.get(k).asInstanceOf[Option[AnyRef]].orNull } } - + /** Removes the key associated with the given value. - * + * * @param v if null, will remove the key irregardless of the value; otherwise removes only if binding contains that exact key and value * @return null if not successful, an Option[V] indicating the previous value otherwise */ final def rec_remove(k: K, v: V, hc: Int, lev: Int, parent: INode[K, V], startgen: Gen, ct: Ctrie[K, V]): Option[V] = { val m = GCAS_READ(ct) // use -Yinline! - + m match { case cn: CNode[K, V] => val idx = (hc >>> lev) & 0x1f @@ -289,7 +289,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends val pos = Integer.bitCount(bmp & (flag - 1)) val sub = cn.array(pos) val res = sub match { - case in: INode[K, V] => + case in: INode[K, V] => if (startgen eq in.gen) in.rec_remove(k, v, hc, lev + 5, this, startgen, ct) else { if (GCAS(cn, cn.renewed(startgen, ct), ct)) rec_remove(k, v, hc, lev, parent, startgen, ct) @@ -301,7 +301,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends if (GCAS(cn, ncn, ct)) Some(sn.v) else null } else None } - + if (res == None || (res eq null)) res else { @tailrec def cleanParent(nonlive: AnyRef) { @@ -325,13 +325,13 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends case _ => // parent is no longer a cnode, we're done } } - + if (parent ne null) { // never tomb at root val n = GCAS_READ(ct) if (n.isInstanceOf[TNode[_, _]]) cleanParent(n) } - + res } } @@ -351,7 +351,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends } } } - + private def clean(nd: INode[K, V], ct: Ctrie[K, V], lev: Int) { val m = nd.GCAS_READ(ct) m match { @@ -359,14 +359,14 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends case _ => } } - + final def isNullInode(ct: Ctrie[K, V]) = GCAS_READ(ct) eq null - + final def cachedSize(ct: Ctrie[K, V]): Int = { val m = GCAS_READ(ct) m.cachedSize(ct) } - + /* this is a quiescent method! */ def string(lev: Int) = "%sINode -> %s".format(" " * lev, mainnode match { case null => "<null>" @@ -375,14 +375,14 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends case ln: LNode[_, _] => ln.string(lev) case x => "<elem: %s>".format(x) }) - + } private[mutable] object INode { val KEY_PRESENT = new AnyRef val KEY_ABSENT = new AnyRef - + def newRootNode[K, V] = { val gen = new Gen val cn = new CNode[K, V](0, new Array(0), gen) @@ -393,11 +393,11 @@ private[mutable] object INode { private[mutable] final class FailedNode[K, V](p: MainNode[K, V]) extends MainNode[K, V] { WRITE_PREV(p) - + def string(lev: Int) = throw new UnsupportedOperationException - + def cachedSize(ct: AnyRef): Int = throw new UnsupportedOperationException - + override def toString = "FailedNode(%s)".format(p) } @@ -449,7 +449,7 @@ extends MainNode[K, V] { private[collection] final class CNode[K, V](final val bitmap: Int, final val array: Array[BasicNode], final val gen: Gen) extends CNodeBase[K, V] { - + // this should only be called from within read-only snapshots final def cachedSize(ct: AnyRef) = { val currsz = READ_SIZE() @@ -460,7 +460,7 @@ extends CNodeBase[K, V] { READ_SIZE() } } - + // lends itself towards being parallelizable by choosing // a random starting offset in the array // => if there are concurrent size computations, they start @@ -480,7 +480,7 @@ extends CNodeBase[K, V] { } sz } - + final def updatedAt(pos: Int, nn: BasicNode, gen: Gen) = { val len = array.length val narr = new Array[BasicNode](len) @@ -488,7 +488,7 @@ extends CNodeBase[K, V] { narr(pos) = nn new CNode[K, V](bitmap, narr, gen) } - + final def removedAt(pos: Int, flag: Int, gen: Gen) = { val arr = array val len = arr.length @@ -497,7 +497,7 @@ extends CNodeBase[K, V] { Array.copy(arr, pos + 1, narr, pos, len - pos - 1) new CNode[K, V](bitmap ^ flag, narr, gen) } - + final def insertedAt(pos: Int, flag: Int, nn: BasicNode, gen: Gen) = { val len = array.length val bmp = bitmap @@ -507,7 +507,7 @@ extends CNodeBase[K, V] { Array.copy(array, pos, narr, pos + 1, len - pos) new CNode[K, V](bmp | flag, narr, gen) } - + /** Returns a copy of this cnode such that all the i-nodes below it are copied * to the specified generation `ngen`. */ @@ -525,17 +525,17 @@ extends CNodeBase[K, V] { } new CNode[K, V](bitmap, narr, ngen) } - + private def resurrect(inode: INode[K, V], inodemain: AnyRef): BasicNode = inodemain match { case tn: TNode[_, _] => tn.copyUntombed case _ => inode } - + final def toContracted(lev: Int): MainNode[K, V] = if (array.length == 1 && lev > 0) array(0) match { case sn: SNode[K, V] => sn.copyTombed case _ => this } else this - + // - if the branching factor is 1 for this CNode, and the child // is a tombed SNode, returns its tombed version // - otherwise, if there is at least one non-null node below, @@ -559,12 +559,12 @@ extends CNodeBase[K, V] { } i += 1 } - + new CNode[K, V](bmp, tmparray, gen).toContracted(lev) } - + private[mutable] def string(lev: Int): String = "CNode %x\n%s".format(bitmap, array.map(_.string(lev + 1)).mkString("\n")) - + /* quiescently consistent - don't call concurrently to anything involving a GCAS!! */ protected def collectElems: Seq[(K, V)] = array flatMap { case sn: SNode[K, V] => Some(sn.kvPair) @@ -574,12 +574,12 @@ extends CNodeBase[K, V] { case cn: CNode[K, V] => cn.collectElems } } - + protected def collectLocalElems: Seq[String] = array flatMap { case sn: SNode[K, V] => Some(sn.kvPair._2.toString) case in: INode[K, V] => Some(in.toString.drop(14) + "(" + in.gen + ")") } - + override def toString = { val elems = collectLocalElems "CNode(sz: %d; %s)".format(elems.size, elems.sorted.mkString(", ")) @@ -588,7 +588,7 @@ extends CNodeBase[K, V] { private[mutable] object CNode { - + def dual[K, V](x: SNode[K, V], xhc: Int, y: SNode[K, V], yhc: Int, lev: Int, gen: Gen): MainNode[K, V] = if (lev < 35) { val xidx = (xhc >>> lev) & 0x1f val yidx = (yhc >>> lev) & 0x1f @@ -604,7 +604,7 @@ private[mutable] object CNode { } else { new LNode(x.k, x.v, y.k, y.v) } - + } @@ -620,9 +620,9 @@ private[mutable] case class RDCSS_Descriptor[K, V](old: INode[K, V], expectedmai * lock-free snapshots which are used to implement linearizable lock-free size, * iterator and clear operations. The cost of evaluating the (lazy) snapshot is * distributed across subsequent updates, thus making snapshot evaluation horizontally scalable. - * + * * For details, see: http://lampwww.epfl.ch/~prokopec/ctries-snapshot.pdf - * + * * @author Aleksandar Prokopec * @since 2.10 */ @@ -634,17 +634,17 @@ extends ConcurrentMap[K, V] with Serializable { import Ctrie.computeHash - + private var rootupdater = rtupd @volatile var root = r - + def this() = this( INode.newRootNode, AtomicReferenceFieldUpdater.newUpdater(classOf[Ctrie[K, V]], classOf[AnyRef], "root") ) - + /* internal methods */ - + private def writeObject(out: java.io.ObjectOutputStream) { val it = iterator while (it.hasNext) { @@ -654,11 +654,11 @@ extends ConcurrentMap[K, V] } out.writeObject(CtrieSerializationEnd) } - + private def readObject(in: java.io.ObjectInputStream) { root = INode.newRootNode rootupdater = AtomicReferenceFieldUpdater.newUpdater(classOf[Ctrie[K, V]], classOf[AnyRef], "root") - + var obj: AnyRef = null do { obj = in.readObject() @@ -669,11 +669,11 @@ extends ConcurrentMap[K, V] } } while (obj != CtrieSerializationEnd) } - + @inline final def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv) - + final def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort) - + @inline final def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = { val r = /*READ*/root r match { @@ -681,7 +681,7 @@ extends ConcurrentMap[K, V] case desc: RDCSS_Descriptor[K, V] => RDCSS_Complete(abort) } } - + @tailrec private def RDCSS_Complete(abort: Boolean): INode[K, V] = { val v = /*READ*/root v match { @@ -705,7 +705,7 @@ extends ConcurrentMap[K, V] } } } - + private def RDCSS_ROOT(ov: INode[K, V], expectedmain: MainNode[K, V], nv: INode[K, V]): Boolean = { val desc = RDCSS_Descriptor(ov, expectedmain, nv) if (CAS_ROOT(ov, desc)) { @@ -713,27 +713,27 @@ extends ConcurrentMap[K, V] /*READ*/desc.committed } else false } - + @tailrec private def inserthc(k: K, hc: Int, v: V) { val r = RDCSS_READ_ROOT() if (!r.rec_insert(k, v, hc, 0, null, r.gen, this)) inserthc(k, hc, v) } - + @tailrec private def insertifhc(k: K, hc: Int, v: V, cond: AnyRef): Option[V] = { val r = RDCSS_READ_ROOT() - + val ret = r.rec_insertif(k, v, hc, cond, 0, null, r.gen, this) if (ret eq null) insertifhc(k, hc, v, cond) else ret } - + @tailrec private def lookuphc(k: K, hc: Int): AnyRef = { val r = RDCSS_READ_ROOT() val res = r.rec_lookup(k, hc, 0, null, r.gen, this) if (res eq INodeBase.RESTART) lookuphc(k, hc) else res } - + /* slower: //@tailrec private def lookuphc(k: K, hc: Int): AnyRef = { @@ -746,31 +746,31 @@ extends ConcurrentMap[K, V] } } */ - + @tailrec private def removehc(k: K, v: V, hc: Int): Option[V] = { val r = RDCSS_READ_ROOT() val res = r.rec_remove(k, v, hc, 0, null, r.gen, this) if (res ne null) res else removehc(k, v, hc) } - + def string = RDCSS_READ_ROOT().string(0) - + /* public methods */ - + override def seq = this - + override def par = new ParCtrie(this) - + override def empty: Ctrie[K, V] = new Ctrie[K, V] - + final def isReadOnly = rootupdater eq null - + final def nonReadOnly = rootupdater ne null - + /** Returns a snapshot of this Ctrie. * This operation is lock-free and linearizable. - * + * * The snapshot is lazily updated - the first time some branch * in the snapshot or this Ctrie are accessed, they are rewritten. * This means that the work of rebuilding both the snapshot and this @@ -783,17 +783,17 @@ extends ConcurrentMap[K, V] if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen, this))) new Ctrie(r.copyToGen(new Gen, this), rootupdater) else snapshot() } - + /** Returns a read-only snapshot of this Ctrie. * This operation is lock-free and linearizable. - * + * * The snapshot is lazily updated - the first time some branch * of this Ctrie are accessed, it is rewritten. The work of creating * the snapshot is thus distributed across subsequent updates * and accesses on this Ctrie by all threads. * Note that the snapshot itself is never rewritten unlike when calling * the `snapshot` method, but the obtained snapshot cannot be modified. - * + * * This method is used by other methods such as `size` and `iterator`. */ @tailrec final def readOnlySnapshot(): collection.Map[K, V] = { @@ -802,106 +802,106 @@ extends ConcurrentMap[K, V] if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen, this))) new Ctrie(r, null) else readOnlySnapshot() } - + @tailrec final override def clear() { val r = RDCSS_READ_ROOT() if (!RDCSS_ROOT(r, r.gcasRead(this), INode.newRootNode[K, V])) clear() } - + final def lookup(k: K): V = { val hc = computeHash(k) lookuphc(k, hc).asInstanceOf[V] } - + final override def apply(k: K): V = { val hc = computeHash(k) val res = lookuphc(k, hc) if (res eq null) throw new NoSuchElementException else res.asInstanceOf[V] } - + final def get(k: K): Option[V] = { val hc = computeHash(k) Option(lookuphc(k, hc)).asInstanceOf[Option[V]] } - + override def put(key: K, value: V): Option[V] = { val hc = computeHash(key) insertifhc(key, hc, value, null) } - + final override def update(k: K, v: V) { val hc = computeHash(k) inserthc(k, hc, v) } - + final def +=(kv: (K, V)) = { update(kv._1, kv._2) this } - + final override def remove(k: K): Option[V] = { val hc = computeHash(k) removehc(k, null.asInstanceOf[V], hc) } - + final def -=(k: K) = { remove(k) this } - + def putIfAbsent(k: K, v: V): Option[V] = { val hc = computeHash(k) insertifhc(k, hc, v, INode.KEY_ABSENT) } - + def remove(k: K, v: V): Boolean = { val hc = computeHash(k) removehc(k, v, hc).nonEmpty } - + def replace(k: K, oldvalue: V, newvalue: V): Boolean = { val hc = computeHash(k) insertifhc(k, hc, newvalue, oldvalue.asInstanceOf[AnyRef]).nonEmpty } - + def replace(k: K, v: V): Option[V] = { val hc = computeHash(k) insertifhc(k, hc, v, INode.KEY_PRESENT) } - + def iterator: Iterator[(K, V)] = if (nonReadOnly) readOnlySnapshot().iterator else new CtrieIterator(0, this) - + private def cachedSize() = { val r = RDCSS_READ_ROOT() r.cachedSize(this) } - + override def size: Int = if (nonReadOnly) readOnlySnapshot().size else cachedSize() - + override def stringPrefix = "Ctrie" - + } object Ctrie extends MutableMapFactory[Ctrie] { val inodeupdater = AtomicReferenceFieldUpdater.newUpdater(classOf[INodeBase[_, _]], classOf[MainNode[_, _]], "mainnode") - + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Ctrie[K, V]] = new MapCanBuildFrom[K, V] - + def empty[K, V]: Ctrie[K, V] = new Ctrie[K, V] - + @inline final def computeHash[K](k: K): Int = { var hcode = k.hashCode hcode = hcode * 0x9e3775cd hcode = java.lang.Integer.reverseBytes(hcode) hcode * 0x9e3775cd } - + } @@ -911,11 +911,11 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct var depth = -1 var subiter: Iterator[(K, V)] = null var current: KVNode[K, V] = null - + if (mustInit) initialize() - + def hasNext = (current ne null) || (subiter ne null) - + def next() = if (hasNext) { var r: (K, V) = null if (subiter ne null) { @@ -927,7 +927,7 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct } r } else Iterator.empty.next() - + private def readin(in: INode[K, V]) = in.gcasRead(ct) match { case cn: CNode[K, V] => depth += 1 @@ -942,19 +942,19 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct case null => current = null } - + @inline private def checkSubiter() = if (!subiter.hasNext) { subiter = null advance() } - + @inline private def initialize() { assert(ct.isReadOnly) - + val r = ct.RDCSS_READ_ROOT() readin(r) } - + def advance(): Unit = if (depth >= 0) { val npos = stackpos(depth) + 1 if (npos < stack(depth).length) { @@ -970,19 +970,19 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct advance() } } else current = null - + protected def newIterator(_lev: Int, _ct: Ctrie[K, V], _mustInit: Boolean) = new CtrieIterator[K, V](_lev, _ct, _mustInit) - + protected def dupTo(it: CtrieIterator[K, V]) = { it.level = this.level it.ct = this.ct it.depth = this.depth it.current = this.current - + // these need a deep copy Array.copy(this.stack, 0, it.stack, 0, 7) Array.copy(this.stackpos, 0, it.stackpos, 0, 7) - + // this one needs to be evaluated if (this.subiter == null) it.subiter = null else { @@ -991,7 +991,7 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct it.subiter = lst.iterator } } - + /** Returns a sequence of iterators over subsets of this iterator. * It's used to ease the implementation of splitters for a parallel version of the Ctrie. */ @@ -1026,7 +1026,7 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct this.level += 1 Seq(this) } - + def printDebug { println("ctrie iterator") println(stackpos.mkString(",")) @@ -1034,7 +1034,7 @@ private[collection] class CtrieIterator[K, V](var level: Int, private var ct: Ct println("curr.: " + current) println(stack.mkString("\n")) } - + } @@ -1048,20 +1048,20 @@ private[mutable] case object CtrieSerializationEnd private[mutable] object Debug { import collection._ - + lazy val logbuffer = new java.util.concurrent.ConcurrentLinkedQueue[AnyRef] - + def log(s: AnyRef) = logbuffer.add(s) - + def flush() { for (s <- JavaConversions.asScalaIterator(logbuffer.iterator())) Console.out.println(s.toString) logbuffer.clear() } - + def clear() { logbuffer.clear() } - + } diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index f3fb6738eb..ee6d4d1d22 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -43,19 +43,19 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { /** The array keeping track of number of elements in 32 element blocks. */ @transient protected var sizemap: Array[Int] = null - + @transient var seedvalue: Int = tableSizeSeed - + import HashTable.powerOfTwo - + protected def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) - + private def initialCapacity = capacity(initialSize) - + protected def randomSeed = seedGenerator.get.nextInt() - + protected def tableSizeSeed = Integer.bitCount(table.length - 1) - + /** * Initializes the collection from the input stream. `f` will be called for each element * read from the input stream in the order determined by the stream. This is useful for @@ -65,22 +65,22 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { */ private[collection] def init(in: java.io.ObjectInputStream, f: A => Unit) { in.defaultReadObject - + _loadFactor = in.readInt() assert(_loadFactor > 0) - + val size = in.readInt() tableSize = 0 assert(size >= 0) - + table = new Array(capacity(sizeForThreshold(size, _loadFactor))) threshold = newThreshold(_loadFactor, table.size) - + seedvalue = in.readInt() - + val smDefined = in.readBoolean() if (smDefined) sizeMapInit(table.length) else sizemap = null - + var index = 0 while (index < size) { val elem = in.readObject().asInstanceOf[A] @@ -295,12 +295,12 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { protected final def index(hcode: Int) = { // version 1 (no longer used - did not work with parallel hash tables) // improve(hcode) & (table.length - 1) - + // version 2 (allows for parallel hash table construction) val improved = improve(hcode, seedvalue) val ones = table.length - 1 (improved >>> (32 - java.lang.Integer.bitCount(ones))) & ones - + // version 3 (solves SI-5293 in most cases, but such a case would still arise for parallel hash tables) // val hc = improve(hcode) // val bbp = blockbitpos @@ -345,17 +345,17 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { private[collection] object FlatHashTable { - + /** Creates a specific seed to improve hashcode of a hash table instance * and ensure that iteration order vulnerabilities are not 'felt' in other * hash tables. - * + * * See SI-5293. */ final def seedGenerator = new ThreadLocal[util.Random] { override def initialValue = new util.Random } - + /** The load factor for the hash table; must be < 500 (0.5) */ def defaultLoadFactor: Int = 450 @@ -396,11 +396,11 @@ private[collection] object FlatHashTable { //h = h ^ (h >>> 14) //h = h + (h << 4) //h ^ (h >>> 10) - + var i = hcode * 0x9e3775cd i = java.lang.Integer.reverseBytes(i) val improved = i * 0x9e3775cd - + // for the remainder, see SI-5293 // to ensure that different bits are used for different hash tables, we have to rotate based on the seed val rotation = seed % 32 diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 5b3e07b826..cc0aed6963 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -53,9 +53,9 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU @transient protected var sizemap: Array[Int] = null @transient var seedvalue: Int = tableSizeSeed - + protected def tableSizeSeed = Integer.bitCount(table.length - 1) - + protected def initialSize: Int = HashTable.initialSize private def lastPopulatedIndex = { @@ -80,9 +80,9 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU val size = in.readInt() tableSize = 0 assert(size >= 0) - + seedvalue = in.readInt() - + val smDefined = in.readBoolean() table = new Array(capacity(sizeForThreshold(_loadFactor, size))) @@ -429,7 +429,7 @@ private[collection] object HashTable { // h = h ^ (h >>> 14) // h = h + (h << 4) // h ^ (h >>> 10) - + // the rest of the computation is due to SI-5293 val rotation = seed % 32 val rotated = (i >>> rotation) | (i << (32 - rotation)) diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index 53c876ec08..037f3b2939 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -62,22 +62,22 @@ final class ListBuffer[A] private var len = 0 protected def underlying: immutable.Seq[A] = start - + private def writeObject(out: ObjectOutputStream) { // write start var xs: List[A] = start while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail } out.writeObject(ListSerializeEnd) - + // no need to write last0 - + // write if exported out.writeBoolean(exported) - + // write the length out.writeInt(len) } - + private def readObject(in: ObjectInputStream) { // read start, set last0 appropriately var elem: A = in.readObject.asInstanceOf[A] @@ -97,14 +97,14 @@ final class ListBuffer[A] last0 = current start } - + // read if exported exported = in.readBoolean() - + // read the length len = in.readInt() } - + /** The current length of the buffer. * * This operation takes constant time. diff --git a/src/library/scala/collection/mutable/SortedSet.scala b/src/library/scala/collection/mutable/SortedSet.scala index d87fc0b4a2..f41a51d3ef 100644 --- a/src/library/scala/collection/mutable/SortedSet.scala +++ b/src/library/scala/collection/mutable/SortedSet.scala @@ -13,12 +13,12 @@ import generic._ /** * Base trait for mutable sorted set. - * + * * @define Coll mutable.SortedSet * @define coll mutable sorted set * * @author Lucien Pereira - * + * */ trait SortedSet[A] extends collection.SortedSet[A] with collection.SortedSetLike[A,SortedSet[A]] with mutable.Set[A] with mutable.SetLike[A, SortedSet[A]] { @@ -39,11 +39,11 @@ trait SortedSet[A] extends collection.SortedSet[A] with collection.SortedSetLike * Standard `CanBuildFrom` instance for sorted sets. * * @author Lucien Pereira - * + * */ object SortedSet extends MutableSortedSetFactory[SortedSet] { implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A] - + def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A] - + } diff --git a/src/library/scala/collection/mutable/TreeSet.scala b/src/library/scala/collection/mutable/TreeSet.scala index e0f1c3adfe..02ee811193 100644 --- a/src/library/scala/collection/mutable/TreeSet.scala +++ b/src/library/scala/collection/mutable/TreeSet.scala @@ -11,14 +11,14 @@ package mutable import generic._ -/** +/** * @define Coll mutable.TreeSet * @define coll mutable tree set * @factoryInfo * Companion object of TreeSet providing factory related utilities. - * + * * @author Lucien Pereira - * + * */ object TreeSet extends MutableSortedSetFactory[TreeSet] { /** @@ -32,7 +32,7 @@ object TreeSet extends MutableSortedSetFactory[TreeSet] { * A mutable SortedSet using an immutable AVL Tree as underlying data structure. * * @author Lucien Pereira - * + * */ class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with SetLike[A, TreeSet[A]] with SortedSetLike[A, TreeSet[A]] with Set[A] with Serializable { @@ -67,7 +67,7 @@ class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with S * Cardinality store the set size, unfortunately a * set view (given by rangeImpl) * cannot take advantage of this optimisation - * + * */ override def size: Int = base.map(_ => super.size).getOrElse(cardinality) @@ -101,7 +101,7 @@ class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with S * Thanks to the immutable nature of the * underlying AVL Tree, we can share it with * the clone. So clone complexity in time is O(1). - * + * */ override def clone: TreeSet[A] = { val clone = new TreeSet[A](base, from, until) @@ -119,5 +119,5 @@ class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with S override def iterator: Iterator[A] = resolve.avl.iterator .dropWhile(e => !isLeftAcceptable(from, ordering)(e)) .takeWhile(e => isRightAcceptable(until, ordering)(e)) - + } diff --git a/src/library/scala/collection/parallel/Combiner.scala b/src/library/scala/collection/parallel/Combiner.scala index e304be92ae..6afe901258 100644 --- a/src/library/scala/collection/parallel/Combiner.scala +++ b/src/library/scala/collection/parallel/Combiner.scala @@ -33,8 +33,21 @@ import scala.collection.generic.Sizing * @since 2.9 */ trait Combiner[-Elem, +To] extends Builder[Elem, To] with Sizing with Parallel { -//self: EnvironmentPassingCombiner[Elem, To] => - + + @transient + @volatile + var _combinerTaskSupport = defaultTaskSupport + + def combinerTaskSupport = { + val cts = _combinerTaskSupport + if (cts eq null) { + _combinerTaskSupport = defaultTaskSupport + defaultTaskSupport + } else cts + } + + def combinerTaskSupport_=(cts: TaskSupport) = _combinerTaskSupport = cts + /** Combines the contents of the receiver builder and the `other` builder, * producing a new builder containing both their elements. * @@ -61,14 +74,22 @@ trait Combiner[-Elem, +To] extends Builder[Elem, To] with Sizing with Parallel { * @return the parallel builder containing both the elements of this and the `other` builder */ def combine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]): Combiner[N, NewTo] - + /** Returns `true` if this combiner has a thread-safe `+=` and is meant to be shared * across several threads constructing the collection. - * + * * By default, this method returns `false`. */ def canBeShared: Boolean = false + /** Constructs the result and sets the appropriate tasksupport object to the resulting collection + * if this is applicable. + */ + def resultWithTaskSupport: To = { + val res = result + setTaskSupport(res, combinerTaskSupport) + } + } diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 7c5a835e56..5e6bf8c1a3 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -28,7 +28,7 @@ import immutable.HashMapCombiner import java.util.concurrent.atomic.AtomicBoolean import annotation.unchecked.uncheckedVariance - +import annotation.unchecked.uncheckedStable /** A template trait for parallel collections of type `ParIterable[T]`. @@ -155,7 +155,19 @@ extends GenIterableLike[T, Repr] { self: ParIterableLike[T, Repr, Sequential] => - import tasksupport._ + @transient + @volatile + private var _tasksupport = defaultTaskSupport + + def tasksupport = { + val ts = _tasksupport + if (ts eq null) { + _tasksupport = defaultTaskSupport + defaultTaskSupport + } else ts + } + + def tasksupport_=(ts: TaskSupport) = _tasksupport = ts def seq: Sequential @@ -164,7 +176,7 @@ self: ParIterableLike[T, Repr, Sequential] => def hasDefiniteSize = true def nonEmpty = size != 0 - + /** Creates a new parallel iterator used to traverse the elements of this parallel collection. * This iterator is more specific than the iterator of the returned by `iterator`, and augmented * with additional accessor and transformer methods. @@ -234,7 +246,7 @@ self: ParIterableLike[T, Repr, Sequential] => trait SignallingOps[PI <: DelegatedSignalling] { def assign(cntx: Signalling): PI } - + /* convenience task operations wrapper */ protected implicit def task2ops[R, Tp](tsk: SSCTask[R, Tp]) = new TaskOps[R, Tp] { def mapResult[R1](mapping: R => R1): ResultMapping[R, Tp, R1] = new ResultMapping[R, Tp, R1](tsk) { @@ -262,7 +274,7 @@ self: ParIterableLike[T, Repr, Sequential] => it } } - + protected implicit def builder2ops[Elem, To](cb: Builder[Elem, To]) = new BuilderOps[Elem, To] { def ifIs[Cmb](isbody: Cmb => Unit) = new Otherwise[Cmb] { def otherwise(notbody: => Unit)(implicit m: ClassManifest[Cmb]) { @@ -272,12 +284,12 @@ self: ParIterableLike[T, Repr, Sequential] => def isCombiner = cb.isInstanceOf[Combiner[_, _]] def asCombiner = cb.asInstanceOf[Combiner[Elem, To]] } - + protected[this] def bf2seq[S, That](bf: CanBuildFrom[Repr, S, That]) = new CanBuildFrom[Sequential, S, That] { def apply(from: Sequential) = bf.apply(from.par.asInstanceOf[Repr]) // !!! we only use this on `this.seq`, and know that `this.seq.par.getClass == this.getClass` def apply() = bf.apply() } - + protected[this] def sequentially[S, That <: Parallel](b: Sequential => Parallelizable[S, That]) = b(seq).par.asInstanceOf[Repr] def mkString(start: String, sep: String, end: String): String = seq.mkString(start, sep, end) @@ -287,7 +299,7 @@ self: ParIterableLike[T, Repr, Sequential] => def mkString: String = seq.mkString("") override def toString = seq.mkString(stringPrefix + "(", ", ", ")") - + def canEqual(other: Any) = true /** Reduces the elements of this sequence using the specified associative binary operator. @@ -306,7 +318,7 @@ self: ParIterableLike[T, Repr, Sequential] => * if this $coll is empty. */ def reduce[U >: T](op: (U, U) => U): U = { - executeAndWaitResult(new Reduce(op, splitter) mapResult { _.get }) + tasksupport.executeAndWaitResult(new Reduce(op, splitter) mapResult { _.get }) } /** Optionally reduces the elements of this sequence using the specified associative binary operator. @@ -324,7 +336,7 @@ self: ParIterableLike[T, Repr, Sequential] => * the elements if the collection is nonempty, and `None` otherwise. */ def reduceOption[U >: T](op: (U, U) => U): Option[U] = if (isEmpty) None else Some(reduce(op)) - + /** Folds the elements of this sequence using the specified associative binary operator. * The order in which the elements are reduced is unspecified and may be nondeterministic. * @@ -341,7 +353,7 @@ self: ParIterableLike[T, Repr, Sequential] => * @return the result of applying fold operator `op` between all the elements and `z` */ def fold[U >: T](z: U)(op: (U, U) => U): U = { - executeAndWaitResult(new Fold(z, op, splitter)) + tasksupport.executeAndWaitResult(new Fold(z, op, splitter)) } /** Aggregates the results of applying an operator to subsequent elements. @@ -373,13 +385,13 @@ self: ParIterableLike[T, Repr, Sequential] => * @param combop an associative operator used to combine results from different partitions */ def aggregate[S](z: S)(seqop: (S, T) => S, combop: (S, S) => S): S = { - executeAndWaitResult(new Aggregate(z, seqop, combop, splitter)) + tasksupport.executeAndWaitResult(new Aggregate(z, seqop, combop, splitter)) } - + def foldLeft[S](z: S)(op: (S, T) => S): S = seq.foldLeft(z)(op) - + def foldRight[S](z: S)(op: (T, S) => S): S = seq.foldRight(z)(op) - + def reduceLeft[U >: T](op: (U, T) => U): U = seq.reduceLeft(op) def reduceRight[U >: T](op: (T, U) => U): U = seq.reduceRight(op) @@ -394,27 +406,27 @@ self: ParIterableLike[T, Repr, Sequential] => * @param f function applied to each element */ def foreach[U](f: T => U) = { - executeAndWaitResult(new Foreach(f, splitter)) + tasksupport.executeAndWaitResult(new Foreach(f, splitter)) } def count(p: T => Boolean): Int = { - executeAndWaitResult(new Count(p, splitter)) + tasksupport.executeAndWaitResult(new Count(p, splitter)) } def sum[U >: T](implicit num: Numeric[U]): U = { - executeAndWaitResult(new Sum[U](num, splitter)) + tasksupport.executeAndWaitResult(new Sum[U](num, splitter)) } def product[U >: T](implicit num: Numeric[U]): U = { - executeAndWaitResult(new Product[U](num, splitter)) + tasksupport.executeAndWaitResult(new Product[U](num, splitter)) } def min[U >: T](implicit ord: Ordering[U]): T = { - executeAndWaitResult(new Min(ord, splitter) mapResult { _.get }).asInstanceOf[T] + tasksupport.executeAndWaitResult(new Min(ord, splitter) mapResult { _.get }).asInstanceOf[T] } def max[U >: T](implicit ord: Ordering[U]): T = { - executeAndWaitResult(new Max(ord, splitter) mapResult { _.get }).asInstanceOf[T] + tasksupport.executeAndWaitResult(new Max(ord, splitter) mapResult { _.get }).asInstanceOf[T] } def maxBy[S](f: T => S)(implicit cmp: Ordering[S]): T = { @@ -428,26 +440,26 @@ self: ParIterableLike[T, Repr, Sequential] => reduce((x, y) => if (cmp.lteq(f(x), f(y))) x else y) } - + def map[S, That](f: T => S)(implicit bf: CanBuildFrom[Repr, S, That]): That = if (bf(repr).isCombiner) { - executeAndWaitResult(new Map[S, That](f, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.result }) - } else seq.map(f)(bf2seq(bf)) + tasksupport.executeAndWaitResult(new Map[S, That](f, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.resultWithTaskSupport }) + } else setTaskSupport(seq.map(f)(bf2seq(bf)), tasksupport) /*bf ifParallel { pbf => - executeAndWaitResult(new Map[S, That](f, pbf, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Map[S, That](f, pbf, splitter) mapResult { _.result }) } otherwise seq.map(f)(bf2seq(bf))*/ def collect[S, That](pf: PartialFunction[T, S])(implicit bf: CanBuildFrom[Repr, S, That]): That = if (bf(repr).isCombiner) { - executeAndWaitResult(new Collect[S, That](pf, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.result }) - } else seq.collect(pf)(bf2seq(bf)) + tasksupport.executeAndWaitResult(new Collect[S, That](pf, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.resultWithTaskSupport }) + } else setTaskSupport(seq.collect(pf)(bf2seq(bf)), tasksupport) /*bf ifParallel { pbf => - executeAndWaitResult(new Collect[S, That](pf, pbf, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Collect[S, That](pf, pbf, splitter) mapResult { _.result }) } otherwise seq.collect(pf)(bf2seq(bf))*/ def flatMap[S, That](f: T => GenTraversableOnce[S])(implicit bf: CanBuildFrom[Repr, S, That]): That = if (bf(repr).isCombiner) { - executeAndWaitResult(new FlatMap[S, That](f, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.result }) - } else seq.flatMap(f)(bf2seq(bf)) + tasksupport.executeAndWaitResult(new FlatMap[S, That](f, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { _.resultWithTaskSupport }) + } else setTaskSupport(seq.flatMap(f)(bf2seq(bf)), tasksupport) /*bf ifParallel { pbf => - executeAndWaitResult(new FlatMap[S, That](f, pbf, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new FlatMap[S, That](f, pbf, splitter) mapResult { _.result }) } otherwise seq.flatMap(f)(bf2seq(bf))*/ /** Tests whether a predicate holds for all elements of this $coll. @@ -458,7 +470,7 @@ self: ParIterableLike[T, Repr, Sequential] => * @return true if `p` holds for all elements, false otherwise */ def forall(pred: T => Boolean): Boolean = { - executeAndWaitResult(new Forall(pred, splitter assign new DefaultSignalling with VolatileAbort)) + tasksupport.executeAndWaitResult(new Forall(pred, splitter assign new DefaultSignalling with VolatileAbort)) } /** Tests whether a predicate holds for some element of this $coll. @@ -469,7 +481,7 @@ self: ParIterableLike[T, Repr, Sequential] => * @return true if `p` holds for some element, false otherwise */ def exists(pred: T => Boolean): Boolean = { - executeAndWaitResult(new Exists(pred, splitter assign new DefaultSignalling with VolatileAbort)) + tasksupport.executeAndWaitResult(new Exists(pred, splitter assign new DefaultSignalling with VolatileAbort)) } /** Finds some element in the collection for which the predicate holds, if such @@ -484,13 +496,13 @@ self: ParIterableLike[T, Repr, Sequential] => * @return an option value with the element if such an element exists, or `None` otherwise */ def find(pred: T => Boolean): Option[T] = { - executeAndWaitResult(new Find(pred, splitter assign new DefaultSignalling with VolatileAbort)) + tasksupport.executeAndWaitResult(new Find(pred, splitter assign new DefaultSignalling with VolatileAbort)) } - + /** Creates a combiner factory. Each combiner factory instance is used * once per invocation of a parallel transformer method for a single * collection. - * + * * The default combiner factory creates a new combiner every time it * is requested, unless the combiner is thread-safe as indicated by its * `canBeShared` method. In this case, the method returns a factory which @@ -500,6 +512,7 @@ self: ParIterableLike[T, Repr, Sequential] => */ protected[this] def combinerFactory = { val combiner = newCombiner + combiner.combinerTaskSupport = tasksupport if (combiner.canBeShared) new CombinerFactory[T, Repr] { val shared = combiner def apply() = shared @@ -509,9 +522,10 @@ self: ParIterableLike[T, Repr, Sequential] => def doesShareCombiners = false } } - + protected[this] def combinerFactory[S, That](cbf: () => Combiner[S, That]) = { val combiner = cbf() + combiner.combinerTaskSupport = tasksupport if (combiner.canBeShared) new CombinerFactory[S, That] { val shared = combiner def apply() = shared @@ -521,13 +535,13 @@ self: ParIterableLike[T, Repr, Sequential] => def doesShareCombiners = false } } - + def filter(pred: T => Boolean): Repr = { - executeAndWaitResult(new Filter(pred, combinerFactory, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Filter(pred, combinerFactory, splitter) mapResult { _.resultWithTaskSupport }) } def filterNot(pred: T => Boolean): Repr = { - executeAndWaitResult(new FilterNot(pred, combinerFactory, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new FilterNot(pred, combinerFactory, splitter) mapResult { _.resultWithTaskSupport }) } def ++[U >: T, That](that: GenTraversableOnce[U])(implicit bf: CanBuildFrom[Repr, U, That]): That = { @@ -542,43 +556,47 @@ self: ParIterableLike[T, Repr, Sequential] => tasksupport.executeAndWaitResult(othtask) } val task = (copythis parallel copythat) { _ combine _ } mapResult { - _.result + _.resultWithTaskSupport } - executeAndWaitResult(task) - } else if (bf.isParallel) { + tasksupport.executeAndWaitResult(task) + } else if (bf(repr).isCombiner) { // println("case parallel builder, `that` not parallel") - val pbf = bf.asParallel - val copythis = new Copy(combinerFactory(() => pbf(repr)), splitter) + val copythis = new Copy(combinerFactory(() => bf(repr).asCombiner), splitter) val copythat = wrap { - val cb = pbf(repr) + val cb = bf(repr).asCombiner for (elem <- that.seq) cb += elem cb } - executeAndWaitResult((copythis parallel copythat) { _ combine _ } mapResult { _.result }) + tasksupport.executeAndWaitResult((copythis parallel copythat) { _ combine _ } mapResult { _.resultWithTaskSupport }) } else { // println("case not a parallel builder") val b = bf(repr) this.splitter.copy2builder[U, That, Builder[U, That]](b) for (elem <- that.seq) b += elem - b.result + setTaskSupport(b.result, tasksupport) } } def partition(pred: T => Boolean): (Repr, Repr) = { - executeAndWaitResult(new Partition(pred, combinerFactory, combinerFactory, splitter) mapResult { p => (p._1.result, p._2.result) }) + tasksupport.executeAndWaitResult( + new Partition(pred, combinerFactory, combinerFactory, splitter) mapResult { + p => (p._1.resultWithTaskSupport, p._2.resultWithTaskSupport) + } + ) } def groupBy[K](f: T => K): immutable.ParMap[K, Repr] = { - executeAndWaitResult(new GroupBy(f, () => HashMapCombiner[K, T], splitter) mapResult { + val r = tasksupport.executeAndWaitResult(new GroupBy(f, () => HashMapCombiner[K, T], splitter) mapResult { rcb => rcb.groupByKey(() => combinerFactory()) }) + setTaskSupport(r, tasksupport) } def take(n: Int): Repr = { val actualn = if (size > n) n else size if (actualn < MIN_FOR_COPY) take_sequential(actualn) - else executeAndWaitResult(new Take(actualn, combinerFactory, splitter) mapResult { - _.result + else tasksupport.executeAndWaitResult(new Take(actualn, combinerFactory, splitter) mapResult { + _.resultWithTaskSupport }) } @@ -591,13 +609,13 @@ self: ParIterableLike[T, Repr, Sequential] => cb += it.next left -= 1 } - cb.result + cb.resultWithTaskSupport } def drop(n: Int): Repr = { val actualn = if (size > n) n else size if ((size - actualn) < MIN_FOR_COPY) drop_sequential(actualn) - else executeAndWaitResult(new Drop(actualn, combinerFactory, splitter) mapResult { _.result }) + else tasksupport.executeAndWaitResult(new Drop(actualn, combinerFactory, splitter) mapResult { _.resultWithTaskSupport }) } private def drop_sequential(n: Int) = { @@ -605,14 +623,14 @@ self: ParIterableLike[T, Repr, Sequential] => val cb = newCombiner cb.sizeHint(size - n) while (it.hasNext) cb += it.next - cb.result + cb.resultWithTaskSupport } override def slice(unc_from: Int, unc_until: Int): Repr = { val from = unc_from min size max 0 val until = unc_until min size max from if ((until - from) <= MIN_FOR_COPY) slice_sequential(from, until) - else executeAndWaitResult(new Slice(from, until, combinerFactory, splitter) mapResult { _.result }) + else tasksupport.executeAndWaitResult(new Slice(from, until, combinerFactory, splitter) mapResult { _.resultWithTaskSupport }) } private def slice_sequential(from: Int, until: Int): Repr = { @@ -623,11 +641,15 @@ self: ParIterableLike[T, Repr, Sequential] => cb += it.next left -= 1 } - cb.result + cb.resultWithTaskSupport } def splitAt(n: Int): (Repr, Repr) = { - executeAndWaitResult(new SplitAt(n, combinerFactory, combinerFactory, splitter) mapResult { p => (p._1.result, p._2.result) }) + tasksupport.executeAndWaitResult( + new SplitAt(n, combinerFactory, combinerFactory, splitter) mapResult { + p => (p._1.resultWithTaskSupport, p._2.resultWithTaskSupport) + } + ) } /** Computes a prefix scan of the elements of the collection. @@ -645,20 +667,19 @@ self: ParIterableLike[T, Repr, Sequential] => * * @return a new $coll containing the prefix scan of the elements in this $coll */ - def scan[U >: T, That](z: U)(op: (U, U) => U)(implicit bf: CanBuildFrom[Repr, U, That]): That = if (bf.isParallel) { - val cbf = bf.asParallel - if (parallelismLevel > 1) { - if (size > 0) executeAndWaitResult(new CreateScanTree(0, size, z, op, splitter) mapResult { - tree => executeAndWaitResult(new FromScanTree(tree, z, op, combinerFactory(() => cbf(repr))) mapResult { - cb => cb.result + def scan[U >: T, That](z: U)(op: (U, U) => U)(implicit bf: CanBuildFrom[Repr, U, That]): That = if (bf(repr).isCombiner) { + if (tasksupport.parallelismLevel > 1) { + if (size > 0) tasksupport.executeAndWaitResult(new CreateScanTree(0, size, z, op, splitter) mapResult { + tree => tasksupport.executeAndWaitResult(new FromScanTree(tree, z, op, combinerFactory(() => bf(repr).asCombiner)) mapResult { + cb => cb.resultWithTaskSupport }) - }) else (cbf(self.repr) += z).result - } else seq.scan(z)(op)(bf2seq(bf)) - } else seq.scan(z)(op)(bf2seq(bf)) + }) else setTaskSupport((bf(repr) += z).result, tasksupport) + } else setTaskSupport(seq.scan(z)(op)(bf2seq(bf)), tasksupport) + } else setTaskSupport(seq.scan(z)(op)(bf2seq(bf)), tasksupport) - def scanLeft[S, That](z: S)(op: (S, T) => S)(implicit bf: CanBuildFrom[Repr, S, That]) = seq.scanLeft(z)(op)(bf2seq(bf)) + def scanLeft[S, That](z: S)(op: (S, T) => S)(implicit bf: CanBuildFrom[Repr, S, That]) = setTaskSupport(seq.scanLeft(z)(op)(bf2seq(bf)), tasksupport) - def scanRight[S, That](z: S)(op: (T, S) => S)(implicit bf: CanBuildFrom[Repr, S, That]) = seq.scanRight(z)(op)(bf2seq(bf)) + def scanRight[S, That](z: S)(op: (T, S) => S)(implicit bf: CanBuildFrom[Repr, S, That]) = setTaskSupport(seq.scanRight(z)(op)(bf2seq(bf)), tasksupport) /** Takes the longest prefix of elements that satisfy the predicate. * @@ -672,11 +693,15 @@ self: ParIterableLike[T, Repr, Sequential] => val cbf = combinerFactory if (cbf.doesShareCombiners) { val parseqspan = toSeq.takeWhile(pred) - executeAndWaitResult(new Copy(combinerFactory, parseqspan.splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Copy(combinerFactory, parseqspan.splitter) mapResult { + _.resultWithTaskSupport + }) } else { val cntx = new DefaultSignalling with AtomicIndexFlag cntx.setIndexFlag(Int.MaxValue) - executeAndWaitResult(new TakeWhile(0, pred, combinerFactory, splitter assign cntx) mapResult { _._1.result }) + tasksupport.executeAndWaitResult(new TakeWhile(0, pred, combinerFactory, splitter assign cntx) mapResult { + _._1.resultWithTaskSupport + }) } } @@ -693,17 +718,17 @@ self: ParIterableLike[T, Repr, Sequential] => val cbf = combinerFactory if (cbf.doesShareCombiners) { val (xs, ys) = toSeq.span(pred) - val copyxs = new Copy(combinerFactory, xs.splitter) mapResult { _.result } - val copyys = new Copy(combinerFactory, ys.splitter) mapResult { _.result } + val copyxs = new Copy(combinerFactory, xs.splitter) mapResult { _.resultWithTaskSupport } + val copyys = new Copy(combinerFactory, ys.splitter) mapResult { _.resultWithTaskSupport } val copyall = (copyxs parallel copyys) { (xr, yr) => (xr, yr) } - executeAndWaitResult(copyall) + tasksupport.executeAndWaitResult(copyall) } else { val cntx = new DefaultSignalling with AtomicIndexFlag cntx.setIndexFlag(Int.MaxValue) - executeAndWaitResult(new Span(0, pred, combinerFactory, combinerFactory, splitter assign cntx) mapResult { - p => (p._1.result, p._2.result) + tasksupport.executeAndWaitResult(new Span(0, pred, combinerFactory, combinerFactory, splitter assign cntx) mapResult { + p => (p._1.resultWithTaskSupport, p._2.resultWithTaskSupport) }) } } @@ -721,7 +746,11 @@ self: ParIterableLike[T, Repr, Sequential] => def dropWhile(pred: T => Boolean): Repr = { val cntx = new DefaultSignalling with AtomicIndexFlag cntx.setIndexFlag(Int.MaxValue) - executeAndWaitResult(new Span(0, pred, combinerFactory, combinerFactory, splitter assign cntx) mapResult { _._2.result }) + tasksupport.executeAndWaitResult( + new Span(0, pred, combinerFactory, combinerFactory, splitter assign cntx) mapResult { + _._2.resultWithTaskSupport + } + ) } def copyToArray[U >: T](xs: Array[U]) = copyToArray(xs, 0) @@ -729,31 +758,33 @@ self: ParIterableLike[T, Repr, Sequential] => def copyToArray[U >: T](xs: Array[U], start: Int) = copyToArray(xs, start, xs.length - start) def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) = if (len > 0) { - executeAndWaitResult(new CopyToArray(start, len, xs, splitter)) + tasksupport.executeAndWaitResult(new CopyToArray(start, len, xs, splitter)) } def sameElements[U >: T](that: GenIterable[U]) = seq.sameElements(that) - def zip[U >: T, S, That](that: GenIterable[S])(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf.isParallel && that.isParSeq) { - val pbf = bf.asParallel + def zip[U >: T, S, That](that: GenIterable[S])(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf(repr).isCombiner && that.isParSeq) { val thatseq = that.asParSeq - executeAndWaitResult(new Zip(combinerFactory(() => pbf(repr)), splitter, thatseq.splitter) mapResult { _.result }); - } else seq.zip(that)(bf2seq(bf)) + tasksupport.executeAndWaitResult(new Zip(combinerFactory(() => bf(repr).asCombiner), splitter, thatseq.splitter) mapResult { _.resultWithTaskSupport }); + } else setTaskSupport(seq.zip(that)(bf2seq(bf)), tasksupport) def zipWithIndex[U >: T, That](implicit bf: CanBuildFrom[Repr, (U, Int), That]): That = this zip immutable.ParRange(0, size, 1, false) - def zipAll[S, U >: T, That](that: GenIterable[S], thisElem: U, thatElem: S)(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf.isParallel && that.isParSeq) { - val pbf = bf.asParallel + def zipAll[S, U >: T, That](that: GenIterable[S], thisElem: U, thatElem: S)(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf(repr).isCombiner && that.isParSeq) { val thatseq = that.asParSeq - executeAndWaitResult(new ZipAll(size max thatseq.length, thisElem, thatElem, combinerFactory(() => pbf(repr)), splitter, thatseq.splitter) mapResult { _.result }); - } else seq.zipAll(that, thisElem, thatElem)(bf2seq(bf)) + tasksupport.executeAndWaitResult( + new ZipAll(size max thatseq.length, thisElem, thatElem, combinerFactory(() => bf(repr).asCombiner), splitter, thatseq.splitter) mapResult { + _.resultWithTaskSupport + } + ); + } else setTaskSupport(seq.zipAll(that, thisElem, thatElem)(bf2seq(bf)), tasksupport) protected def toParCollection[U >: T, That](cbf: () => Combiner[U, That]): That = { - executeAndWaitResult(new ToParCollection(combinerFactory(cbf), splitter) mapResult { _.result }); + tasksupport.executeAndWaitResult(new ToParCollection(combinerFactory(cbf), splitter) mapResult { _.resultWithTaskSupport }); } protected def toParMap[K, V, That](cbf: () => Combiner[(K, V), That])(implicit ev: T <:< (K, V)): That = { - executeAndWaitResult(new ToParMap(combinerFactory(cbf), splitter)(ev) mapResult { _.result }) + tasksupport.executeAndWaitResult(new ToParMap(combinerFactory(cbf), splitter)(ev) mapResult { _.resultWithTaskSupport }) } def view = new ParIterableView[T, Repr, Sequential] { @@ -810,7 +841,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends StrictSplitterCheckTask[R, Tp] { protected[this] val pit: IterableSplitter[T] protected[this] def newSubtask(p: IterableSplitter[T]): Accessor[R, Tp] - def shouldSplitFurther = pit.shouldSplitFurther(self.repr, parallelismLevel) + def shouldSplitFurther = pit.shouldSplitFurther(self.repr, tasksupport.parallelismLevel) def split = pit.splitWithSignalling.map(newSubtask(_)) // default split procedure private[parallel] override def signalAbort = pit.abort override def toString = this.getClass.getSimpleName + "(" + pit.toString + ")(" + result + ")(supername: " + super.toString + ")" @@ -844,8 +875,8 @@ self: ParIterableLike[T, Repr, Sequential] => (f: First, s: Second) extends Composite[FR, SR, R, First, Second](f, s) { def leaf(prevr: Option[R]) = { - executeAndWaitResult(ft) - executeAndWaitResult(st) + tasksupport.executeAndWaitResult(ft) + tasksupport.executeAndWaitResult(st) mergeSubtasks } } @@ -855,8 +886,8 @@ self: ParIterableLike[T, Repr, Sequential] => (f: First, s: Second) extends Composite[FR, SR, R, First, Second](f, s) { def leaf(prevr: Option[R]) = { - val ftfuture = execute(ft) - executeAndWaitResult(st) + val ftfuture = tasksupport.execute(ft) + tasksupport.executeAndWaitResult(st) ftfuture() mergeSubtasks } @@ -867,7 +898,7 @@ self: ParIterableLike[T, Repr, Sequential] => @volatile var result: R1 = null.asInstanceOf[R1] def map(r: R): R1 def leaf(prevr: Option[R1]) = { - val initialResult = executeAndWaitResult(inner) + val initialResult = tasksupport.executeAndWaitResult(inner) result = map(initialResult) } private[parallel] override def signalAbort() { @@ -875,9 +906,9 @@ self: ParIterableLike[T, Repr, Sequential] => } override def requiresStrictSplitters = inner.requiresStrictSplitters } - + protected trait Transformer[R, Tp] extends Accessor[R, Tp] - + protected[this] class Foreach[S](op: T => S, protected[this] val pit: IterableSplitter[T]) extends Accessor[Unit, Foreach[S]] { @volatile var result: Unit = () @@ -894,7 +925,7 @@ self: ParIterableLike[T, Repr, Sequential] => override def merge(that: Count) = result = result + that.result // override def toString = "CountTask(" + pittxt + ")" } - + protected[this] class Reduce[U >: T](op: (U, U) => U, protected[this] val pit: IterableSplitter[T]) extends Accessor[Option[U], Reduce[U]] { @volatile var result: Option[U] = None @@ -1303,7 +1334,7 @@ self: ParIterableLike[T, Repr, Sequential] => } else result = that.result override def requiresStrictSplitters = true } - + protected[this] class FromScanTree[U >: T, That] (tree: ScanTree[U], z: U, op: (U, U) => U, cbf: CombinerFactory[U, That]) extends StrictSplitterCheckTask[Combiner[U, That], FromScanTree[U, That]] { @@ -1339,7 +1370,7 @@ self: ParIterableLike[T, Repr, Sequential] => /* scan tree */ - protected[this] def scanBlockSize = (thresholdFromSize(size, parallelismLevel) / 2) max 1 + protected[this] def scanBlockSize = (thresholdFromSize(size, tasksupport.parallelismLevel) / 2) max 1 protected[this] trait ScanTree[U >: T] { def beginsAt: Int @@ -1379,13 +1410,13 @@ self: ParIterableLike[T, Repr, Sequential] => def rightmost = this def print(depth: Int) = println((" " * depth) + this) } - + /* alias methods */ - + def /:[S](z: S)(op: (S, T) => S): S = foldLeft(z)(op); - + def :\[S](z: S)(op: (T, S) => S): S = foldRight(z)(op); - + /* debug information */ private[parallel] def debugInformation = "Parallel collection: " + this.getClass diff --git a/src/library/scala/collection/parallel/ParIterableViewLike.scala b/src/library/scala/collection/parallel/ParIterableViewLike.scala index 1d7659922c..536139c812 100644 --- a/src/library/scala/collection/parallel/ParIterableViewLike.scala +++ b/src/library/scala/collection/parallel/ParIterableViewLike.scala @@ -47,7 +47,6 @@ extends GenIterableView[T, Coll] with ParIterableLike[T, This, ThisSeq] { self => - import tasksupport._ override def foreach[U](f: T => U): Unit = super[ParIterableLike].foreach(f) override protected[this] def newCombiner: Combiner[T, This] = throw new UnsupportedOperationException(this + ".newCombiner"); @@ -135,7 +134,7 @@ self => newZippedAllTryParSeq(that, thisElem, thatElem).asInstanceOf[That] override def force[U >: T, That](implicit bf: CanBuildFrom[Coll, U, That]) = bf ifParallel { pbf => - executeAndWaitResult(new Force(pbf, splitter).mapResult(_.result).asInstanceOf[Task[That, ResultMapping[_, Force[U, That], That]]]) + tasksupport.executeAndWaitResult(new Force(pbf, splitter).mapResult(_.result).asInstanceOf[Task[That, ResultMapping[_, Force[U, That], That]]]) } otherwise { val b = bf(underlying) b ++= this.iterator diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala index 6a5ee5c69b..9f28a286ca 100644 --- a/src/library/scala/collection/parallel/ParSeqLike.scala +++ b/src/library/scala/collection/parallel/ParSeqLike.scala @@ -44,8 +44,7 @@ trait ParSeqLike[+T, +Repr <: ParSeq[T], +Sequential <: Seq[T] with SeqLike[T, S extends scala.collection.GenSeqLike[T, Repr] with ParIterableLike[T, Repr, Sequential] { self => - import tasksupport._ - + type SuperParIterator = IterableSplitter[T] /** A more refined version of the iterator found in the `ParallelIterable` trait, @@ -107,7 +106,7 @@ self => val realfrom = if (from < 0) 0 else from val ctx = new DefaultSignalling with AtomicIndexFlag ctx.setIndexFlag(Int.MaxValue) - executeAndWaitResult(new SegmentLength(p, 0, splitter.psplitWithSignalling(realfrom, length - realfrom)(1) assign ctx))._1 + tasksupport.executeAndWaitResult(new SegmentLength(p, 0, splitter.psplitWithSignalling(realfrom, length - realfrom)(1) assign ctx))._1 } /** Finds the first element satisfying some predicate. @@ -125,7 +124,7 @@ self => val realfrom = if (from < 0) 0 else from val ctx = new DefaultSignalling with AtomicIndexFlag ctx.setIndexFlag(Int.MaxValue) - executeAndWaitResult(new IndexWhere(p, realfrom, splitter.psplitWithSignalling(realfrom, length - realfrom)(1) assign ctx)) + tasksupport.executeAndWaitResult(new IndexWhere(p, realfrom, splitter.psplitWithSignalling(realfrom, length - realfrom)(1) assign ctx)) } /** Finds the last element satisfying some predicate. @@ -143,18 +142,20 @@ self => val until = if (end >= length) length else end + 1 val ctx = new DefaultSignalling with AtomicIndexFlag ctx.setIndexFlag(Int.MinValue) - executeAndWaitResult(new LastIndexWhere(p, 0, splitter.psplitWithSignalling(until, length - until)(0) assign ctx)) + tasksupport.executeAndWaitResult(new LastIndexWhere(p, 0, splitter.psplitWithSignalling(until, length - until)(0) assign ctx)) } def reverse: Repr = { - executeAndWaitResult(new Reverse(() => newCombiner, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Reverse(() => newCombiner, splitter) mapResult { _.resultWithTaskSupport }) } def reverseMap[S, That](f: T => S)(implicit bf: CanBuildFrom[Repr, S, That]): That = if (bf(repr).isCombiner) { - executeAndWaitResult(new ReverseMap[S, That](f, () => bf(repr).asCombiner, splitter) mapResult { _.result }) - } else seq.reverseMap(f)(bf2seq(bf)) + tasksupport.executeAndWaitResult( + new ReverseMap[S, That](f, () => bf(repr).asCombiner, splitter) mapResult { _.resultWithTaskSupport } + ) + } else setTaskSupport(seq.reverseMap(f)(bf2seq(bf)), tasksupport) /*bf ifParallel { pbf => - executeAndWaitResult(new ReverseMap[S, That](f, pbf, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new ReverseMap[S, That](f, pbf, splitter) mapResult { _.result }) } otherwise seq.reverseMap(f)(bf2seq(bf))*/ /** Tests whether this $coll contains the given sequence at a given index. @@ -172,19 +173,21 @@ self => else if (pthat.length > length - offset) false else { val ctx = new DefaultSignalling with VolatileAbort - executeAndWaitResult(new SameElements(splitter.psplitWithSignalling(offset, pthat.length)(1) assign ctx, pthat.splitter)) + tasksupport.executeAndWaitResult( + new SameElements(splitter.psplitWithSignalling(offset, pthat.length)(1) assign ctx, pthat.splitter) + ) } } otherwise seq.startsWith(that, offset) override def sameElements[U >: T](that: GenIterable[U]): Boolean = that ifParSeq { pthat => val ctx = new DefaultSignalling with VolatileAbort - length == pthat.length && executeAndWaitResult(new SameElements(splitter assign ctx, pthat.splitter)) + length == pthat.length && tasksupport.executeAndWaitResult(new SameElements(splitter assign ctx, pthat.splitter)) } otherwise seq.sameElements(that) /** Tests whether this $coll ends with the given parallel sequence. - * + * * $abortsignalling - * + * * @tparam S the type of the elements of `that` sequence * @param that the sequence to test * @return `true` if this $coll has `that` as a suffix, `false` otherwise @@ -195,25 +198,24 @@ self => else { val ctx = new DefaultSignalling with VolatileAbort val tlen = that.length - executeAndWaitResult(new SameElements(splitter.psplitWithSignalling(length - tlen, tlen)(1) assign ctx, pthat.splitter)) + tasksupport.executeAndWaitResult(new SameElements(splitter.psplitWithSignalling(length - tlen, tlen)(1) assign ctx, pthat.splitter)) } } otherwise seq.endsWith(that) def patch[U >: T, That](from: Int, patch: GenSeq[U], replaced: Int)(implicit bf: CanBuildFrom[Repr, U, That]): That = { val realreplaced = replaced min (length - from) - if (patch.isParSeq && bf.isParallel && (size - realreplaced + patch.size) > MIN_FOR_COPY) { + if (patch.isParSeq && bf(repr).isCombiner && (size - realreplaced + patch.size) > MIN_FOR_COPY) { val that = patch.asParSeq - val pbf = bf.asParallel val pits = splitter.psplitWithSignalling(from, replaced, length - from - realreplaced) - val cfactory = combinerFactory(() => pbf(repr)) + val cfactory = combinerFactory(() => bf(repr).asCombiner) val copystart = new Copy[U, That](cfactory, pits(0)) val copymiddle = wrap { val tsk = new that.Copy[U, That](cfactory, that.splitter) tasksupport.executeAndWaitResult(tsk) } val copyend = new Copy[U, That](cfactory, pits(2)) - executeAndWaitResult(((copystart parallel copymiddle) { _ combine _ } parallel copyend) { _ combine _ } mapResult { - _.result + tasksupport.executeAndWaitResult(((copystart parallel copymiddle) { _ combine _ } parallel copyend) { _ combine _ } mapResult { + _.resultWithTaskSupport }) } else patch_sequential(from, patch.seq, replaced) } @@ -226,14 +228,18 @@ self => b ++= pits(0) b ++= patch b ++= pits(2) - b.result + setTaskSupport(b.result, tasksupport) } def updated[U >: T, That](index: Int, elem: U)(implicit bf: CanBuildFrom[Repr, U, That]): That = if (bf(repr).isCombiner) { - executeAndWaitResult(new Updated(index, elem, () => bf(repr).asCombiner, splitter) mapResult { _.result }) - } else seq.updated(index, elem)(bf2seq(bf)) + tasksupport.executeAndWaitResult( + new Updated(index, elem, combinerFactory(() => bf(repr).asCombiner), splitter) mapResult { + _.resultWithTaskSupport + } + ) + } else setTaskSupport(seq.updated(index, elem)(bf2seq(bf)), tasksupport) /*bf ifParallel { pbf => - executeAndWaitResult(new Updated(index, elem, pbf, splitter) mapResult { _.result }) + tasksupport.executeAndWaitResult(new Updated(index, elem, pbf, splitter) mapResult { _.result }) } otherwise seq.updated(index, elem)(bf2seq(bf))*/ def +:[U >: T, That](elem: U)(implicit bf: CanBuildFrom[Repr, U, That]): That = { @@ -248,10 +254,13 @@ self => patch(length, new immutable.Repetition(elem, len - length), 0) } else patch(length, Nil, 0); - override def zip[U >: T, S, That](that: GenIterable[S])(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf.isParallel && that.isParSeq) { - val pbf = bf.asParallel + override def zip[U >: T, S, That](that: GenIterable[S])(implicit bf: CanBuildFrom[Repr, (U, S), That]): That = if (bf(repr).isCombiner && that.isParSeq) { val thatseq = that.asParSeq - executeAndWaitResult(new Zip(length min thatseq.length, pbf, splitter, thatseq.splitter) mapResult { _.result }); + tasksupport.executeAndWaitResult( + new Zip(length min thatseq.length, combinerFactory(() => bf(repr).asCombiner), splitter, thatseq.splitter) mapResult { + _.resultWithTaskSupport + } + ); } else super.zip(that)(bf) /** Tests whether every element of this $coll relates to the @@ -268,7 +277,7 @@ self => */ def corresponds[S](that: GenSeq[S])(p: (T, S) => Boolean): Boolean = that ifParSeq { pthat => val ctx = new DefaultSignalling with VolatileAbort - length == pthat.length && executeAndWaitResult(new Corresponds(p, splitter assign ctx, pthat.splitter)) + length == pthat.length && tasksupport.executeAndWaitResult(new Corresponds(p, splitter assign ctx, pthat.splitter)) } otherwise seq.corresponds(that)(p) def diff[U >: T](that: GenSeq[U]): Repr = sequentially { @@ -424,7 +433,7 @@ self => override def requiresStrictSplitters = true } - protected[this] class Updated[U >: T, That](pos: Int, elem: U, pbf: () => Combiner[U, That], protected[this] val pit: SeqSplitter[T]) + protected[this] class Updated[U >: T, That](pos: Int, elem: U, pbf: CombinerFactory[U, That], protected[this] val pit: SeqSplitter[T]) extends Transformer[Combiner[U, That], Updated[U, That]] { @volatile var result: Combiner[U, That] = null def leaf(prev: Option[Combiner[U, That]]) = result = pit.updated2combiner(pos, elem, pbf()) @@ -437,10 +446,10 @@ self => override def requiresStrictSplitters = true } - protected[this] class Zip[U >: T, S, That](len: Int, pbf: CanCombineFrom[Repr, (U, S), That], protected[this] val pit: SeqSplitter[T], val otherpit: SeqSplitter[S]) + protected[this] class Zip[U >: T, S, That](len: Int, cf: CombinerFactory[(U, S), That], protected[this] val pit: SeqSplitter[T], val otherpit: SeqSplitter[S]) extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null - def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](otherpit, pbf(self.repr)) + def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](otherpit, cf()) protected[this] def newSubtask(p: SuperParIterator) = unsupported override def split = { val fp = len / 2 @@ -448,8 +457,8 @@ self => val pits = pit.psplitWithSignalling(fp, sp) val opits = otherpit.psplitWithSignalling(fp, sp) Seq( - new Zip(fp, pbf, pits(0), opits(0)), - new Zip(sp, pbf, pits(1), opits(1)) + new Zip(fp, cf, pits(0), opits(0)), + new Zip(sp, cf, pits(1), opits(1)) ) } override def merge(that: Zip[U, S, That]) = result = result combine that.result diff --git a/src/library/scala/collection/parallel/ParSeqViewLike.scala b/src/library/scala/collection/parallel/ParSeqViewLike.scala index 6fdc181793..e0d1a7d6ff 100644 --- a/src/library/scala/collection/parallel/ParSeqViewLike.scala +++ b/src/library/scala/collection/parallel/ParSeqViewLike.scala @@ -38,7 +38,6 @@ extends GenSeqView[T, Coll] with ParSeqLike[T, This, ThisSeq] { self => - import tasksupport._ trait Transformed[+S] extends ParSeqView[S, Coll, CollSeq] with super[ParIterableView].Transformed[S] with super[GenSeqViewLike].Transformed[S] { @@ -170,7 +169,7 @@ self => override def scanRight[S, That](z: S)(op: (T, S) => S)(implicit bf: CanBuildFrom[This, S, That]): That = newForced(thisParSeq.scanRight(z)(op)).asInstanceOf[That] override def groupBy[K](f: T => K): immutable.ParMap[K, This] = thisParSeq.groupBy(f).map(kv => (kv._1, newForced(kv._2).asInstanceOf[This])) override def force[U >: T, That](implicit bf: CanBuildFrom[Coll, U, That]) = bf ifParallel { pbf => - executeAndWaitResult(new Force(pbf, splitter).mapResult(_.result).asInstanceOf[Task[That, _]]) + tasksupport.executeAndWaitResult(new Force(pbf, splitter).mapResult(_.result).asInstanceOf[Task[That, _]]) } otherwise { val b = bf(underlying) b ++= this.iterator diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala index 8ed4583419..c5910ff2c8 100644 --- a/src/library/scala/collection/parallel/RemainsIterator.scala +++ b/src/library/scala/collection/parallel/RemainsIterator.scala @@ -28,7 +28,7 @@ private[collection] trait RemainsIterator[+T] extends Iterator[T] { * This method doesn't change the state of the iterator. */ def remaining: Int - + /** For most collections, this is a cheap operation. * Exceptions can override this method. */ @@ -386,22 +386,22 @@ extends AugmentedIterableIterator[T] with DelegatedSignalling { self => - + var signalDelegate: Signalling = IdleSignalling - + /** Creates a copy of this iterator. */ def dup: IterableSplitter[T] def split: Seq[IterableSplitter[T]] - + def splitWithSignalling: Seq[IterableSplitter[T]] = { val pits = split pits foreach { _.signalDelegate = signalDelegate } pits } - + def shouldSplitFurther[S](coll: ParIterable[S], parallelismLevel: Int) = remaining > thresholdFromSize(coll.size, parallelismLevel) - + /** The number of elements this iterator has yet to traverse. This method * doesn't change the state of the iterator. * @@ -554,13 +554,13 @@ self => pits foreach { _.signalDelegate = signalDelegate } pits } - + def psplitWithSignalling(sizes: Int*): Seq[SeqSplitter[T]] = { val pits = psplit(sizes: _*) pits foreach { _.signalDelegate = signalDelegate } pits } - + /** The number of elements this iterator has yet to traverse. This method * doesn't change the state of the iterator. Unlike the version of this method in the supertrait, * method `remaining` in `ParSeqLike.this.ParIterator` must return an exact number diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala index 20800250b4..59b75f523f 100644 --- a/src/library/scala/collection/parallel/TaskSupport.scala +++ b/src/library/scala/collection/parallel/TaskSupport.scala @@ -11,15 +11,46 @@ package scala.collection.parallel +import java.util.concurrent.ThreadPoolExecutor +import scala.concurrent.forkjoin.ForkJoinPool +import scala.concurrent.ExecutionContext - +/** A trait implementing the scheduling of + * a parallel collection operation. + * + * Task support objects handle how a task is split and + * distributed across processors. A task support object can be + * changed in a parallel collection after it has been created, + * but only during a quiescent period, i.e. while there are no + * concurrent invocations to parallel collection methods. + */ trait TaskSupport extends Tasks -private[collection] class ForkJoinTaskSupport extends TaskSupport with AdaptiveWorkStealingForkJoinTasks -private[collection] class ThreadPoolTaskSupport extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks +/** A task support that uses a fork join pool to schedule tasks */ +class ForkJoinTaskSupport(val environment: ForkJoinPool = ForkJoinTasks.defaultForkJoinPool) +extends TaskSupport with AdaptiveWorkStealingForkJoinTasks + + +/** A task support that uses a thread pool executor to schedule tasks */ +class ThreadPoolTaskSupport(val environment: ThreadPoolExecutor = ThreadPoolTasks.defaultThreadPool) +extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks + + +/** A task support that uses an execution context to schedule tasks. + * + * It can be used with the default execution context implementation in the `scala.concurrent` package. + * It internally forwards the call to either a forkjoin based task support or a thread pool executor one, + * depending on what the execution context uses. + * + * By default, parallel collections are parametrized with this task support object, so parallel collections + * share the same execution context backend as the rest of the `scala.concurrent` package. + */ +class ExecutionContextTaskSupport(val environment: ExecutionContext = scala.concurrent.executionContext) +extends TaskSupport with ExecutionContextTasks + diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index b705909cad..60a8bb1ed6 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -6,109 +6,109 @@ ** |/ ** \* */ - package scala.collection.parallel +import java.util.concurrent.ThreadPoolExecutor import scala.concurrent.forkjoin._ +import scala.concurrent.ExecutionContext import scala.util.control.Breaks._ - import annotation.unchecked.uncheckedVariance +trait Task[R, +Tp] { + type Result = R -/** A trait that declares task execution capabilities used - * by parallel collections. - */ -trait Tasks { - - private[parallel] val debugMessages = collection.mutable.ArrayBuffer[String]() - - private[parallel] def debuglog(s: String) = synchronized { - debugMessages += s - } - - trait Task[R, +Tp] { - type Result = R + def repr = this.asInstanceOf[Tp] - def repr = this.asInstanceOf[Tp] - - /** Body of the task - non-divisible unit of work done by this task. - * Optionally is provided with the result from the previous completed task - * or `None` if there was no previous task (or the previous task is uncompleted or unknown). - */ - def leaf(result: Option[R]) + /** Body of the task - non-divisible unit of work done by this task. + * Optionally is provided with the result from the previous completed task + * or `None` if there was no previous task (or the previous task is uncompleted or unknown). + */ + def leaf(result: Option[R]) - /** A result that can be accessed once the task is completed. */ - var result: R + /** A result that can be accessed once the task is completed. */ + var result: R - /** Decides whether or not this task should be split further. */ - def shouldSplitFurther: Boolean + /** Decides whether or not this task should be split further. */ + def shouldSplitFurther: Boolean - /** Splits this task into a list of smaller tasks. */ - private[parallel] def split: Seq[Task[R, Tp]] + /** Splits this task into a list of smaller tasks. */ + private[parallel] def split: Seq[Task[R, Tp]] - /** Read of results of `that` task and merge them into results of this one. */ - private[parallel] def merge(that: Tp @uncheckedVariance) {} + /** Read of results of `that` task and merge them into results of this one. */ + private[parallel] def merge(that: Tp @uncheckedVariance) {} - // exception handling mechanism - @volatile var throwable: Throwable = null - def forwardThrowable() = if (throwable != null) throw throwable + // exception handling mechanism + @volatile var throwable: Throwable = null + def forwardThrowable() = if (throwable != null) throw throwable - // tries to do the leaf computation, storing the possible exception - private[parallel] def tryLeaf(lastres: Option[R]) { - try { - tryBreakable { - leaf(lastres) - result = result // ensure that effects of `leaf` are visible to readers of `result` - } catchBreak { - signalAbort - } - } catch { - case thr: Exception => - result = result // ensure that effects of `leaf` are visible - throwable = thr - signalAbort + // tries to do the leaf computation, storing the possible exception + private[parallel] def tryLeaf(lastres: Option[R]) { + try { + tryBreakable { + leaf(lastres) + result = result // ensure that effects of `leaf` are visible to readers of `result` + } catchBreak { + signalAbort } + } catch { + case thr: Exception => + result = result // ensure that effects of `leaf` are visible + throwable = thr + signalAbort } + } - private[parallel] def tryMerge(t: Tp @uncheckedVariance) { - val that = t.asInstanceOf[Task[R, Tp]] - val local = result // ensure that any effects of modifying `result` are detected - // checkMerge(that) - if (this.throwable == null && that.throwable == null) merge(t) - mergeThrowables(that) - } + private[parallel] def tryMerge(t: Tp @uncheckedVariance) { + val that = t.asInstanceOf[Task[R, Tp]] + val local = result // ensure that any effects of modifying `result` are detected + // checkMerge(that) + if (this.throwable == null && that.throwable == null) merge(t) + mergeThrowables(that) + } - private def checkMerge(that: Task[R, Tp] @uncheckedVariance) { - if (this.throwable == null && that.throwable == null && (this.result == null || that.result == null)) { - println("This: " + this + ", thr=" + this.throwable + "; merged with " + that + ", thr=" + that.throwable) - } else if (this.throwable != null || that.throwable != null) { - println("merging this: " + this + " with thr: " + this.throwable + " with " + that + ", thr=" + that.throwable) - } + private def checkMerge(that: Task[R, Tp] @uncheckedVariance) { + if (this.throwable == null && that.throwable == null && (this.result == null || that.result == null)) { + println("This: " + this + ", thr=" + this.throwable + "; merged with " + that + ", thr=" + that.throwable) + } else if (this.throwable != null || that.throwable != null) { + println("merging this: " + this + " with thr: " + this.throwable + " with " + that + ", thr=" + that.throwable) } + } - private[parallel] def mergeThrowables(that: Task[_, _]) { - if (this.throwable != null && that.throwable != null) { - // merge exceptions, since there were multiple exceptions - this.throwable = this.throwable alongWith that.throwable - } else if (that.throwable != null) this.throwable = that.throwable + private[parallel] def mergeThrowables(that: Task[_, _]) { + if (this.throwable != null && that.throwable != null) { + // merge exceptions, since there were multiple exceptions + this.throwable = this.throwable alongWith that.throwable + } else if (that.throwable != null) this.throwable = that.throwable else this.throwable = this.throwable - } + } + + // override in concrete task implementations to signal abort to other tasks + private[parallel] def signalAbort() {} +} + + +/** A trait that declares task execution capabilities used + * by parallel collections. + */ +trait Tasks { - // override in concrete task implementations to signal abort to other tasks - private[parallel] def signalAbort() {} + private[parallel] val debugMessages = collection.mutable.ArrayBuffer[String]() + + private[parallel] def debuglog(s: String) = synchronized { + debugMessages += s } - trait TaskImpl[R, +Tp] { + trait WrappedTask[R, +Tp] { /** the body of this task - what it executes, how it gets split and how results are merged. */ val body: Task[R, Tp] - def split: Seq[TaskImpl[R, Tp]] + def split: Seq[WrappedTask[R, Tp]] /** Code that gets called after the task gets started - it may spawn other tasks instead of calling `leaf`. */ def compute() /** Start task. */ @@ -129,13 +129,10 @@ trait Tasks { def release() {} } - protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp] - /* task control */ - // safe to assume it will always have the same type, - // because the `tasksupport` in parallel iterable is final - var environment: AnyRef + /** The type of the environment is more specific in the implementations. */ + val environment: AnyRef /** Executes a task and returns a future. Forwards an exception if some task threw it. */ def execute[R, Tp](fjtask: Task[R, Tp]): () => R @@ -155,11 +152,11 @@ trait Tasks { */ trait AdaptiveWorkStealingTasks extends Tasks { - trait TaskImpl[R, Tp] extends super.TaskImpl[R, Tp] { - @volatile var next: TaskImpl[R, Tp] = null + trait WrappedTask[R, Tp] extends super.WrappedTask[R, Tp] { + @volatile var next: WrappedTask[R, Tp] = null @volatile var shouldWaitFor = true - def split: Seq[TaskImpl[R, Tp]] + def split: Seq[WrappedTask[R, Tp]] def compute() = if (body.shouldSplitFurther) { internal() @@ -171,12 +168,12 @@ trait AdaptiveWorkStealingTasks extends Tasks { def internal() = { var last = spawnSubtasks() - + last.body.tryLeaf(None) last.release() body.result = last.body.result body.throwable = last.body.throwable - + while (last.next != null) { // val lastresult = Option(last.body.result) val beforelast = last @@ -193,10 +190,10 @@ trait AdaptiveWorkStealingTasks extends Tasks { body.tryMerge(last.body.repr) } } - + def spawnSubtasks() = { - var last: TaskImpl[R, Tp] = null - var head: TaskImpl[R, Tp] = this + var last: WrappedTask[R, Tp] = null + var head: WrappedTask[R, Tp] = this do { val subtasks = head.split head = subtasks.head @@ -222,7 +219,7 @@ trait AdaptiveWorkStealingTasks extends Tasks { } // specialize ctor - protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp] + protected def newWrappedTask[R, Tp](b: Task[R, Tp]): WrappedTask[R, Tp] } @@ -231,13 +228,13 @@ trait AdaptiveWorkStealingTasks extends Tasks { trait ThreadPoolTasks extends Tasks { import java.util.concurrent._ - trait TaskImpl[R, +Tp] extends Runnable with super.TaskImpl[R, Tp] { + trait WrappedTask[R, +Tp] extends Runnable with super.WrappedTask[R, Tp] { // initially, this is null // once the task is started, this future is set and used for `sync` // utb: var future: Future[_] = null @volatile var owned = false @volatile var completed = false - + def start() = synchronized { // debuglog("Starting " + body) // utb: future = executor.submit(this) @@ -293,9 +290,9 @@ trait ThreadPoolTasks extends Tasks { } } - protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp] + protected def newWrappedTask[R, Tp](b: Task[R, Tp]): WrappedTask[R, Tp] - var environment: AnyRef = ThreadPoolTasks.defaultThreadPool + val environment: ThreadPoolExecutor def executor = environment.asInstanceOf[ThreadPoolExecutor] def queue = executor.getQueue.asInstanceOf[LinkedBlockingQueue[Runnable]] @volatile var totaltasks = 0 @@ -309,7 +306,7 @@ trait ThreadPoolTasks extends Tasks { } def execute[R, Tp](task: Task[R, Tp]): () => R = { - val t = newTaskImpl(task) + val t = newWrappedTask(task) // debuglog("-----------> Executing without wait: " + task) t.start() @@ -322,11 +319,11 @@ trait ThreadPoolTasks extends Tasks { } def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = { - val t = newTaskImpl(task) + val t = newWrappedTask(task) // debuglog("-----------> Executing with wait: " + task) t.start() - + t.sync() t.body.forwardThrowable t.body.result @@ -362,10 +359,11 @@ object ThreadPoolTasks { /** An implementation of tasks objects based on the Java thread pooling API and synchronization using futures. */ +@deprecated("This implementation is not used.") trait FutureThreadPoolTasks extends Tasks { import java.util.concurrent._ - trait TaskImpl[R, +Tp] extends Runnable with super.TaskImpl[R, Tp] { + trait WrappedTask[R, +Tp] extends Runnable with super.WrappedTask[R, Tp] { @volatile var future: Future[_] = null def start() = { @@ -380,13 +378,13 @@ trait FutureThreadPoolTasks extends Tasks { } } - protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp] + protected def newWrappedTask[R, Tp](b: Task[R, Tp]): WrappedTask[R, Tp] - var environment: AnyRef = FutureThreadPoolTasks.defaultThreadPool + val environment: AnyRef = FutureThreadPoolTasks.defaultThreadPool def executor = environment.asInstanceOf[ThreadPoolExecutor] def execute[R, Tp](task: Task[R, Tp]): () => R = { - val t = newTaskImpl(task) + val t = newWrappedTask(task) // debuglog("-----------> Executing without wait: " + task) t.start @@ -399,7 +397,7 @@ trait FutureThreadPoolTasks extends Tasks { } def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = { - val t = newTaskImpl(task) + val t = newWrappedTask(task) // debuglog("-----------> Executing with wait: " + task) t.start @@ -441,26 +439,26 @@ trait HavingForkJoinPool { */ trait ForkJoinTasks extends Tasks with HavingForkJoinPool { - trait TaskImpl[R, +Tp] extends RecursiveAction with super.TaskImpl[R, Tp] { + trait WrappedTask[R, +Tp] extends RecursiveAction with super.WrappedTask[R, Tp] { def start() = fork def sync() = join def tryCancel = tryUnfork } // specialize ctor - protected def newTaskImpl[R, Tp](b: Task[R, Tp]): TaskImpl[R, Tp] + protected def newWrappedTask[R, Tp](b: Task[R, Tp]): WrappedTask[R, Tp] /** The fork/join pool of this collection. */ def forkJoinPool: ForkJoinPool = environment.asInstanceOf[ForkJoinPool] - var environment: AnyRef = ForkJoinTasks.defaultForkJoinPool + val environment: ForkJoinPool /** Executes a task and does not wait for it to finish - instead returns a future. * * $fjdispatch */ def execute[R, Tp](task: Task[R, Tp]): () => R = { - val fjtask = newTaskImpl(task) + val fjtask = newWrappedTask(task) if (Thread.currentThread.isInstanceOf[ForkJoinWorkerThread]) { fjtask.fork @@ -483,7 +481,7 @@ trait ForkJoinTasks extends Tasks with HavingForkJoinPool { * @return the result of the task */ def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = { - val fjtask = newTaskImpl(task) + val fjtask = newWrappedTask(task) if (Thread.currentThread.isInstanceOf[ForkJoinWorkerThread]) { fjtask.fork @@ -513,25 +511,50 @@ object ForkJoinTasks { */ trait AdaptiveWorkStealingForkJoinTasks extends ForkJoinTasks with AdaptiveWorkStealingTasks { - class TaskImpl[R, Tp](val body: Task[R, Tp]) - extends super[ForkJoinTasks].TaskImpl[R, Tp] with super[AdaptiveWorkStealingTasks].TaskImpl[R, Tp] { - def split = body.split.map(b => newTaskImpl(b)) + class WrappedTask[R, Tp](val body: Task[R, Tp]) + extends super[ForkJoinTasks].WrappedTask[R, Tp] with super[AdaptiveWorkStealingTasks].WrappedTask[R, Tp] { + def split = body.split.map(b => newWrappedTask(b)) } - def newTaskImpl[R, Tp](b: Task[R, Tp]) = new TaskImpl[R, Tp](b) + def newWrappedTask[R, Tp](b: Task[R, Tp]) = new WrappedTask[R, Tp](b) } trait AdaptiveWorkStealingThreadPoolTasks extends ThreadPoolTasks with AdaptiveWorkStealingTasks { - class TaskImpl[R, Tp](val body: Task[R, Tp]) - extends super[ThreadPoolTasks].TaskImpl[R, Tp] with super[AdaptiveWorkStealingTasks].TaskImpl[R, Tp] { - def split = body.split.map(b => newTaskImpl(b)) + class WrappedTask[R, Tp](val body: Task[R, Tp]) + extends super[ThreadPoolTasks].WrappedTask[R, Tp] with super[AdaptiveWorkStealingTasks].WrappedTask[R, Tp] { + def split = body.split.map(b => newWrappedTask(b)) } - def newTaskImpl[R, Tp](b: Task[R, Tp]) = new TaskImpl[R, Tp](b) + def newWrappedTask[R, Tp](b: Task[R, Tp]) = new WrappedTask[R, Tp](b) + +} + +trait ExecutionContextTasks extends Tasks { + + def executionContext = environment + + val environment: ExecutionContext + + // this part is a hack which allows switching + val driver: Tasks = executionContext match { + case eci: scala.concurrent.impl.ExecutionContextImpl => eci.executorService match { + case fjp: ForkJoinPool => new ForkJoinTaskSupport(fjp) + case tpe: ThreadPoolExecutor => new ThreadPoolTaskSupport(tpe) + case _ => ??? + } + case _ => ??? + } + + def execute[R, Tp](task: Task[R, Tp]): () => R = driver execute task + + def executeAndWaitResult[R, Tp](task: Task[R, Tp]): R = driver executeAndWaitResult task + + def parallelismLevel = driver.parallelismLevel + } @@ -541,3 +564,6 @@ trait AdaptiveWorkStealingThreadPoolTasks extends ThreadPoolTasks with AdaptiveW + + + diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala index 7adf51cffb..266b179401 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala @@ -8,6 +8,8 @@ package scala.collection.parallel.immutable + + import scala.collection.parallel.ParMapLike import scala.collection.parallel.Combiner import scala.collection.parallel.IterableSplitter @@ -19,6 +21,9 @@ import scala.collection.generic.GenericParMapTemplate import scala.collection.generic.GenericParMapCompanion import scala.collection.immutable.{ HashMap, TrieIterator } import annotation.unchecked.uncheckedVariance +import collection.parallel.Task + + /** Immutable parallel hash map, based on hash tries. * @@ -153,7 +158,6 @@ private[parallel] abstract class HashMapCombiner[K, V] extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), HashMapCombiner[K, V]](HashMapCombiner.rootsize) { //self: EnvironmentPassingCombiner[(K, V), ParHashMap[K, V]] => import HashMapCombiner._ - import collection.parallel.tasksupport._ val emptyTrie = HashMap.empty[K, V] def +=(elem: (K, V)) = { @@ -173,7 +177,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has val bucks = buckets.filter(_ != null).map(_.headPtr) val root = new Array[HashMap[K, V]](bucks.length) - executeAndWaitResult(new CreateTrie(bucks, root, 0, bucks.length)) + combinerTaskSupport.executeAndWaitResult(new CreateTrie(bucks, root, 0, bucks.length)) var bitmap = 0 var i = 0 @@ -195,7 +199,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has val bucks = buckets.filter(_ != null).map(_.headPtr) val root = new Array[HashMap[K, AnyRef]](bucks.length) - executeAndWaitResult(new CreateGroupedTrie(cbf, bucks, root, 0, bucks.length)) + combinerTaskSupport.executeAndWaitResult(new CreateGroupedTrie(cbf, bucks, root, 0, bucks.length)) var bitmap = 0 var i = 0 @@ -256,7 +260,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has val fp = howmany / 2 List(new CreateTrie(bucks, root, offset, fp), new CreateTrie(bucks, root, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, combinerTaskSupport.parallelismLevel) } class CreateGroupedTrie[Repr](cbf: () => Combiner[V, Repr], bucks: Array[Unrolled[(K, V)]], root: Array[HashMap[K, AnyRef]], offset: Int, howmany: Int) @@ -321,7 +325,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has val fp = howmany / 2 List(new CreateGroupedTrie(cbf, bucks, root, offset, fp), new CreateGroupedTrie(cbf, bucks, root, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, combinerTaskSupport.parallelismLevel) } } diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 1cf0ccd391..0d7f04976e 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -8,6 +8,8 @@ package scala.collection.parallel.immutable + + import scala.collection.parallel.ParSetLike import scala.collection.parallel.Combiner import scala.collection.parallel.IterableSplitter @@ -19,6 +21,9 @@ import scala.collection.generic.GenericParTemplate import scala.collection.generic.GenericParCompanion import scala.collection.generic.GenericCompanion import scala.collection.immutable.{ HashSet, TrieIterator } +import collection.parallel.Task + + /** Immutable parallel hash set, based on hash tries. * @@ -127,7 +132,6 @@ private[immutable] abstract class HashSetCombiner[T] extends collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetCombiner[T]](HashSetCombiner.rootsize) { //self: EnvironmentPassingCombiner[T, ParHashSet[T]] => import HashSetCombiner._ - import collection.parallel.tasksupport._ val emptyTrie = HashSet.empty[T] def +=(elem: T) = { @@ -147,7 +151,7 @@ extends collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetCombine val bucks = buckets.filter(_ != null).map(_.headPtr) val root = new Array[HashSet[T]](bucks.length) - executeAndWaitResult(new CreateTrie(bucks, root, 0, bucks.length)) + combinerTaskSupport.executeAndWaitResult(new CreateTrie(bucks, root, 0, bucks.length)) var bitmap = 0 var i = 0 @@ -202,7 +206,7 @@ extends collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetCombine val fp = howmany / 2 List(new CreateTrie(bucks, root, offset, fp), new CreateTrie(bucks, root, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(root.length, combinerTaskSupport.parallelismLevel) } } diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index 72a8184b10..5c3da66be0 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -21,6 +21,7 @@ import scala.collection.generic.Sizing import scala.collection.parallel.Combiner import scala.collection.parallel.SeqSplitter import scala.collection.parallel.ParSeqLike +import scala.collection.parallel.Task import scala.collection.parallel.CHECK_RATE import scala.collection.mutable.ArraySeq import scala.collection.mutable.Builder @@ -56,7 +57,6 @@ extends ParSeq[T] with Serializable { self => - import collection.parallel.tasksupport._ @transient private var array: Array[Any] = arrayseq.array.asInstanceOf[Array[Any]] @@ -584,22 +584,22 @@ self => val targetarr = targarrseq.array.asInstanceOf[Array[Any]] // fill it in parallel - executeAndWaitResult(new Map[S](f, targetarr, 0, length)) + tasksupport.executeAndWaitResult(new Map[S](f, targetarr, 0, length)) // wrap it into a parallel array (new ParArray[S](targarrseq)).asInstanceOf[That] } else super.map(f)(bf) override def scan[U >: T, That](z: U)(op: (U, U) => U)(implicit cbf: CanBuildFrom[ParArray[T], U, That]): That = - if (parallelismLevel > 1 && buildsArray(cbf(repr))) { + if (tasksupport.parallelismLevel > 1 && buildsArray(cbf(repr))) { // reserve an array val targarrseq = new ArraySeq[U](length + 1) val targetarr = targarrseq.array.asInstanceOf[Array[Any]] targetarr(0) = z // do a parallel prefix scan - if (length > 0) executeAndWaitResult(new CreateScanTree[U](0, size, z, op, splitter) mapResult { - tree => executeAndWaitResult(new ScanToArray(tree, z, op, targetarr)) + if (length > 0) tasksupport.executeAndWaitResult(new CreateScanTree[U](0, size, z, op, splitter) mapResult { + tree => tasksupport.executeAndWaitResult(new ScanToArray(tree, z, op, targetarr)) }) // wrap the array into a parallel array @@ -661,7 +661,7 @@ self => val fp = howmany / 2 List(new Map(f, targetarr, offset, fp), new Map(f, targetarr, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(length, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(length, tasksupport.parallelismLevel) } /* serialization */ diff --git a/src/library/scala/collection/parallel/mutable/ParCtrie.scala b/src/library/scala/collection/parallel/mutable/ParCtrie.scala index cec2e6886d..470972adad 100644 --- a/src/library/scala/collection/parallel/mutable/ParCtrie.scala +++ b/src/library/scala/collection/parallel/mutable/ParCtrie.scala @@ -13,6 +13,7 @@ package scala.collection.parallel.mutable import scala.collection.generic._ import scala.collection.parallel.Combiner import scala.collection.parallel.IterableSplitter +import scala.collection.parallel.Task import scala.collection.mutable.BasicNode import scala.collection.mutable.TNode import scala.collection.mutable.LNode @@ -25,11 +26,11 @@ import scala.collection.mutable.CtrieIterator /** Parallel Ctrie collection. - * + * * It has its bulk operations parallelized, but uses the snapshot operation * to create the splitter. This means that parallel bulk operations can be * called concurrently with the modifications. - * + * * @author Aleksandar Prokopec * @since 2.10 */ @@ -40,42 +41,40 @@ extends ParMap[K, V] with ParCtrieCombiner[K, V] with Serializable { - import collection.parallel.tasksupport._ - def this() = this(new Ctrie) - + override def mapCompanion: GenericParMapCompanion[ParCtrie] = ParCtrie - + override def empty: ParCtrie[K, V] = ParCtrie.empty - + protected[this] override def newCombiner = ParCtrie.newCombiner - + override def seq = ctrie - + def splitter = new ParCtrieSplitter(0, ctrie.readOnlySnapshot().asInstanceOf[Ctrie[K, V]], true) - + override def clear() = ctrie.clear() - + def result = this - + def get(key: K): Option[V] = ctrie.get(key) - + def put(key: K, value: V): Option[V] = ctrie.put(key, value) - + def update(key: K, value: V): Unit = ctrie.update(key, value) - + def remove(key: K): Option[V] = ctrie.remove(key) - + def +=(kv: (K, V)): this.type = { ctrie.+=(kv) this } - + def -=(key: K): this.type = { ctrie.-=(key) this } - + override def size = { val in = ctrie.readRoot() val r = in.gcasRead(ctrie) @@ -83,15 +82,15 @@ extends ParMap[K, V] case tn: TNode[_, _] => tn.cachedSize(ctrie) case ln: LNode[_, _] => ln.cachedSize(ctrie) case cn: CNode[_, _] => - executeAndWaitResult(new Size(0, cn.array.length, cn.array)) + tasksupport.executeAndWaitResult(new Size(0, cn.array.length, cn.array)) cn.cachedSize(ctrie) } } - + override def stringPrefix = "ParCtrie" - + /* tasks */ - + /** Computes Ctrie size in parallel. */ class Size(offset: Int, howmany: Int, array: Array[BasicNode]) extends Task[Int, Size] { var result = -1 @@ -115,7 +114,7 @@ extends ParMap[K, V] def shouldSplitFurther = howmany > 1 override def merge(that: Size) = result = result + that.result } - + } @@ -126,63 +125,63 @@ extends CtrieIterator[K, V](lev, ct, mustInit) // only evaluated if `remaining` is invoked (which is not used by most tasks) lazy val totalsize = ct.par.size var iterated = 0 - + protected override def newIterator(_lev: Int, _ct: Ctrie[K, V], _mustInit: Boolean) = new ParCtrieSplitter[K, V](_lev, _ct, _mustInit) - + override def shouldSplitFurther[S](coll: collection.parallel.ParIterable[S], parallelismLevel: Int) = { val maxsplits = 3 + Integer.highestOneBit(parallelismLevel) level < maxsplits } - + def dup = { val it = newIterator(0, ct, false) dupTo(it) it.iterated = this.iterated it } - + override def next() = { iterated += 1 super.next() } - + def split: Seq[IterableSplitter[(K, V)]] = subdivide().asInstanceOf[Seq[IterableSplitter[(K, V)]]] - + override def isRemainingCheap = false - + def remaining: Int = totalsize - iterated } /** Only used within the `ParCtrie`. */ private[mutable] trait ParCtrieCombiner[K, V] extends Combiner[(K, V), ParCtrie[K, V]] { - + def combine[N <: (K, V), NewTo >: ParCtrie[K, V]](other: Combiner[N, NewTo]): Combiner[N, NewTo] = if (this eq other) this else { throw new UnsupportedOperationException("This shouldn't have been called in the first place.") - + val thiz = this.asInstanceOf[ParCtrie[K, V]] val that = other.asInstanceOf[ParCtrie[K, V]] val result = new ParCtrie[K, V] - + result ++= thiz.iterator result ++= that.iterator - + result } - + override def canBeShared = true - + } - + object ParCtrie extends ParMapFactory[ParCtrie] { - + def empty[K, V]: ParCtrie[K, V] = new ParCtrie[K, V] - + def newCombiner[K, V]: Combiner[(K, V), ParCtrie[K, V]] = new ParCtrie[K, V] - + implicit def canBuildFrom[K, V]: CanCombineFrom[Coll, (K, V), ParCtrie[K, V]] = new CanCombineFromMap[K, V] - + } diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 21a5b05749..6ce6c45460 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -17,6 +17,7 @@ import collection.mutable.DefaultEntry import collection.mutable.HashEntry import collection.mutable.HashTable import collection.mutable.UnrolledBuffer +import collection.parallel.Task @@ -156,8 +157,6 @@ private[mutable] abstract class ParHashMapCombiner[K, V](private val tableLoadFa extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntry[K, V], ParHashMapCombiner[K, V]](ParHashMapCombiner.numblocks) with collection.mutable.HashTable.HashUtils[K] { -//self: EnvironmentPassingCombiner[(K, V), ParHashMap[K, V]] => - import collection.parallel.tasksupport._ private var mask = ParHashMapCombiner.discriminantmask private var nonmasklen = ParHashMapCombiner.nonmasklength private var seedvalue = 27 @@ -179,7 +178,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntr // construct table val table = new AddingHashTable(size, tableLoadFactor, seedvalue) val bucks = buckets.map(b => if (b ne null) b.headPtr else null) - val insertcount = executeAndWaitResult(new FillBlocks(bucks, table, 0, bucks.length)) + val insertcount = combinerTaskSupport.executeAndWaitResult(new FillBlocks(bucks, table, 0, bucks.length)) table.setSize(insertcount) // TODO compare insertcount and size to see if compression is needed val c = table.hashTableContents @@ -300,7 +299,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], DefaultEntr override def merge(that: FillBlocks) { this.result += that.result } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(ParHashMapCombiner.numblocks, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(ParHashMapCombiner.numblocks, combinerTaskSupport.parallelismLevel) } } diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala index 6c5f513ad0..e0a2ab03df 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala @@ -8,10 +8,15 @@ package scala.collection.parallel.mutable + + import collection.generic._ import collection.mutable.FlatHashTable import collection.parallel.Combiner import collection.mutable.UnrolledBuffer +import collection.parallel.Task + + /** A parallel hash set. * @@ -113,11 +118,10 @@ private[mutable] abstract class ParHashSetCombiner[T](private val tableLoadFacto extends collection.parallel.BucketCombiner[T, ParHashSet[T], Any, ParHashSetCombiner[T]](ParHashSetCombiner.numblocks) with collection.mutable.FlatHashTable.HashUtils[T] { //self: EnvironmentPassingCombiner[T, ParHashSet[T]] => - import collection.parallel.tasksupport._ private var mask = ParHashSetCombiner.discriminantmask private var nonmasklen = ParHashSetCombiner.nonmasklength private var seedvalue = 27 - + def +=(elem: T) = { sz += 1 val hc = improve(elemHashCode(elem), seedvalue) @@ -139,7 +143,7 @@ with collection.mutable.FlatHashTable.HashUtils[T] { private def parPopulate: FlatHashTable.Contents[T] = { // construct it in parallel val table = new AddingFlatHashTable(size, tableLoadFactor, seedvalue) - val (inserted, leftovers) = executeAndWaitResult(new FillBlocks(buckets, table, 0, buckets.length)) + val (inserted, leftovers) = combinerTaskSupport.executeAndWaitResult(new FillBlocks(buckets, table, 0, buckets.length)) var leftinserts = 0 for (elem <- leftovers) leftinserts += table.insertEntry(0, table.tableLength, elem.asInstanceOf[T]) table.setSize(leftinserts + inserted) @@ -304,7 +308,7 @@ with collection.mutable.FlatHashTable.HashUtils[T] { // the total number of successfully inserted elements is adjusted accordingly result = (this.result._1 + that.result._1 + inserted, remainingLeftovers concat that.result._2) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(ParHashMapCombiner.numblocks, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(ParHashMapCombiner.numblocks, combinerTaskSupport.parallelismLevel) } } diff --git a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala index eadc93d422..01eb17024e 100644 --- a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala @@ -8,18 +8,20 @@ package scala.collection.parallel.mutable + + import scala.collection.generic.Sizing import scala.collection.mutable.ArraySeq import scala.collection.mutable.ArrayBuffer import scala.collection.parallel.TaskSupport -//import scala.collection.parallel.EnvironmentPassingCombiner import scala.collection.parallel.unsupportedop import scala.collection.parallel.Combiner +import scala.collection.parallel.Task + + /** An array combiner that uses a chain of arraybuffers to store elements. */ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedArrayBuffer[T]] { -//self: EnvironmentPassingCombiner[T, ParArray[T]] => - import collection.parallel.tasksupport._ override def sizeHint(sz: Int) = if (chain.length == 1) chain(0).sizeHint(sz) @@ -30,7 +32,7 @@ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedA val arrayseq = new ArraySeq[T](size) val array = arrayseq.array.asInstanceOf[Array[Any]] - executeAndWaitResult(new CopyChainToArray(array, 0, size)) + combinerTaskSupport.executeAndWaitResult(new CopyChainToArray(array, 0, size)) new ParArray(arrayseq) } else { // optimisation if there is only 1 array @@ -79,7 +81,7 @@ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedA val fp = howmany / 2 List(new CopyChainToArray(array, offset, fp), new CopyChainToArray(array, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(size, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(size, combinerTaskSupport.parallelismLevel) } } diff --git a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala index dc583fb4e7..410b542a68 100644 --- a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala @@ -18,9 +18,9 @@ import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.UnrolledBuffer import scala.collection.mutable.UnrolledBuffer.Unrolled import scala.collection.parallel.TaskSupport -//import scala.collection.parallel.EnvironmentPassingCombiner import scala.collection.parallel.unsupportedop import scala.collection.parallel.Combiner +import scala.collection.parallel.Task @@ -40,8 +40,6 @@ extends Combiner[T, ParArray[T]] { // because size is doubling, random access is O(logn)! val buff = new DoublingUnrolledBuffer[Any] - import collection.parallel.tasksupport._ - def +=(elem: T) = { buff += elem this @@ -51,7 +49,7 @@ extends Combiner[T, ParArray[T]] { val arrayseq = new ArraySeq[T](size) val array = arrayseq.array.asInstanceOf[Array[Any]] - executeAndWaitResult(new CopyUnrolledToArray(array, 0, size)) + combinerTaskSupport.executeAndWaitResult(new CopyUnrolledToArray(array, 0, size)) new ParArray(arrayseq) } @@ -109,7 +107,7 @@ extends Combiner[T, ParArray[T]] { val fp = howmany / 2 List(new CopyUnrolledToArray(array, offset, fp), new CopyUnrolledToArray(array, offset + fp, howmany - fp)) } - def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(size, parallelismLevel) + def shouldSplitFurther = howmany > collection.parallel.thresholdFromSize(size, combinerTaskSupport.parallelismLevel) override def toString = "CopyUnrolledToArray(" + offset + ", " + howmany + ")" } } diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index 8f19d0ecdb..943e0208c7 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -46,8 +46,16 @@ package object parallel { else new ThreadPoolTaskSupport } else new ThreadPoolTaskSupport - val tasksupport = getTaskSupport - + val defaultTaskSupport: TaskSupport = getTaskSupport + + def setTaskSupport[Coll](c: Coll, t: TaskSupport): Coll = { + c match { + case pc: ParIterableLike[_, _, _] => pc.tasksupport = t + case _ => // do nothing + } + c + } + /* implicit conversions */ implicit def factory2ops[From, Elem, To](bf: CanBuildFrom[From, Elem, To]) = new FactoryOps[From, Elem, To] { @@ -114,7 +122,7 @@ package parallel { } /* classes */ - + trait CombinerFactory[U, Repr] { /** Provides a combiner used to construct a collection. */ def apply(): Combiner[U, Repr] @@ -126,7 +134,7 @@ package parallel { */ def doesShareCombiners: Boolean } - + /** Composite throwable - thrown when multiple exceptions are thrown at the same time. */ final case class CompositeThrowable( val throwables: Set[Throwable] @@ -201,18 +209,18 @@ package parallel { //self: EnvironmentPassingCombiner[Elem, To] => protected var buckets: Array[UnrolledBuffer[Buck]] @uncheckedVariance = new Array[UnrolledBuffer[Buck]](bucketnumber) protected var sz: Int = 0 - + def size = sz - + def clear() = { buckets = new Array[UnrolledBuffer[Buck]](bucketnumber) sz = 0 } - + def beforeCombine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]) {} - + def afterCombine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]) {} - + def combine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]): Combiner[N, NewTo] = { if (this eq other) this else other match { diff --git a/src/library/scala/concurrent/Channel.scala b/src/library/scala/concurrent/Channel.scala index e79f76430f..f6d6341151 100644 --- a/src/library/scala/concurrent/Channel.scala +++ b/src/library/scala/concurrent/Channel.scala @@ -23,7 +23,7 @@ class Channel[A] { private var written = new LinkedList[A] // FIFO buffer, realized through private var lastWritten = written // aliasing of a linked list private var nreaders = 0 - + /** * @param x ... */ @@ -33,7 +33,7 @@ class Channel[A] { lastWritten = lastWritten.next if (nreaders > 0) notify() } - + def read: A = synchronized { while (written.next == null) { try { @@ -46,5 +46,5 @@ class Channel[A] { written = written.next x } - + } diff --git a/src/library/scala/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index 6aacd53de2..7d005838d3 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -8,26 +8,34 @@ package scala.concurrent + + +import java.util.concurrent.{ Executors, ExecutorService } +import scala.concurrent.forkjoin.ForkJoinPool import scala.util.{ Duration, Try, Success, Failure } import ConcurrentPackageObject._ + + /** This package object contains primitives for concurrent and parallel programming. */ abstract class ConcurrentPackageObject { /** A global execution environment for executing lightweight tasks. */ lazy val executionContext = - new impl.ExecutionContextImpl(java.util.concurrent.Executors.newCachedThreadPool()) - - /** A global service for scheduling tasks for execution. - */ - // lazy val scheduler = - // new default.SchedulerImpl + new impl.ExecutionContextImpl(getExecutorService) + + private[concurrent] def getExecutorService: AnyRef = + if (util.Properties.isJavaAtLeast("1.6")) { + val vendor = util.Properties.javaVmVendor + if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinPool + else Executors.newCachedThreadPool() + } else Executors.newCachedThreadPool() val handledFutureException: PartialFunction[Throwable, Throwable] = { case t: Throwable if isFutureThrowable(t) => t } - + // TODO rename appropriately and make public private[concurrent] def isFutureThrowable(t: Throwable) = t match { case e: Error => false @@ -35,7 +43,7 @@ abstract class ConcurrentPackageObject { case i: InterruptedException => false case _ => true } - + private[concurrent] def resolve[T](source: Try[T]): Try[T] = source match { case Failure(t: scala.runtime.NonLocalReturnControl[_]) => Success(t.value.asInstanceOf[T]) case Failure(t: scala.util.control.ControlThrowable) => Failure(new ExecutionException("Boxed ControlThrowable", t)) @@ -46,24 +54,24 @@ abstract class ConcurrentPackageObject { private[concurrent] def resolver[T] = resolverFunction.asInstanceOf[PartialFunction[Throwable, Try[T]]] - + /* concurrency constructs */ - + def future[T](body: =>T)(implicit execCtx: ExecutionContext = executionContext): Future[T] = execCtx future body - + def promise[T]()(implicit execCtx: ExecutionContext = executionContext): Promise[T] = execCtx promise - + /** Wraps a block of code into an awaitable object. */ def body2awaitable[T](body: =>T) = new Awaitable[T] { def await(atMost: Duration)(implicit cb: CanAwait) = body } - + /** Used to block on a piece of code which potentially blocks. - * + * * @param body A piece of code which contains potentially blocking or long running calls. - * + * * Calling this method may throw the following exceptions: * - CancellationException - if the computation was cancelled * - InterruptedException - in the case that a wait within the blockable object was interrupted @@ -71,11 +79,11 @@ abstract class ConcurrentPackageObject { */ def blocking[T](atMost: Duration)(body: =>T)(implicit execCtx: ExecutionContext): T = executionContext.blocking(atMost)(body) - + /** Blocks on an awaitable object. - * + * * @param awaitable An object with a `block` method which runs potentially blocking or long running calls. - * + * * Calling this method may throw the following exceptions: * - CancellationException - if the computation was cancelled * - InterruptedException - in the case that a wait within the blockable object was interrupted @@ -83,7 +91,7 @@ abstract class ConcurrentPackageObject { */ def blocking[T](awaitable: Awaitable[T], atMost: Duration)(implicit execCtx: ExecutionContext = executionContext): T = executionContext.blocking(awaitable, atMost) - + @inline implicit final def int2durationops(x: Int): DurationOps = new DurationOps(x) } diff --git a/src/library/scala/concurrent/DelayedLazyVal.scala b/src/library/scala/concurrent/DelayedLazyVal.scala index 0b7f54a27a..a17153bad5 100644 --- a/src/library/scala/concurrent/DelayedLazyVal.scala +++ b/src/library/scala/concurrent/DelayedLazyVal.scala @@ -26,23 +26,23 @@ package scala.concurrent class DelayedLazyVal[T](f: () => T, body: => Unit) { @volatile private[this] var _isDone = false private[this] lazy val complete = f() - + /** Whether the computation is complete. * * @return true if the computation is complete. */ def isDone = _isDone - + /** The current result of f(), or the final result if complete. * * @return the current value */ def apply(): T = if (isDone) complete else f() - + // TODO replace with scala.concurrent.future { ... } ops.future { body _isDone = true } - + } diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index 99cd264ac5..eb1b3355c0 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -21,41 +21,41 @@ import collection._ trait ExecutionContext { - + protected implicit object CanAwaitEvidence extends CanAwait - + def execute(runnable: Runnable): Unit - + def execute[U](body: () => U): Unit - + def promise[T]: Promise[T] - + def future[T](body: Callable[T]): Future[T] = future(body.call()) - + def future[T](body: => T): Future[T] - + def blocking[T](atMost: Duration)(body: =>T): T - + def blocking[T](awaitable: Awaitable[T], atMost: Duration): T - + def reportFailure(t: Throwable): Unit - + /* implementations follow */ - + private implicit val executionContext = this - + def keptPromise[T](result: T): Promise[T] = { val p = promise[T] p success result } - + def brokenPromise[T](t: Throwable): Promise[T] = { val p = promise[T] p failure t } - + /** TODO some docs - * + * */ def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]]): Future[Coll[T]] = { import nondeterministic._ @@ -63,13 +63,13 @@ trait ExecutionContext { val counter = new AtomicInteger(1) // how else could we do this? val p: Promise[Coll[T]] = promise[Coll[T]] // we need an implicit execctx in the signature var idx = 0 - + def tryFinish() = if (counter.decrementAndGet() == 0) { val builder = cbf(futures) builder ++= buffer p success builder.result } - + for (f <- futures) { val currentIndex = idx buffer += null.asInstanceOf[T] @@ -83,46 +83,46 @@ trait ExecutionContext { } idx += 1 } - + tryFinish() - + p.future } - + /** TODO some docs - * + * */ def any[T](futures: Traversable[Future[T]]): Future[T] = { val p = promise[T] val completeFirst: Try[T] => Unit = elem => p tryComplete elem - + futures foreach (_ onComplete completeFirst) - + p.future } - + /** TODO some docs - * + * */ def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean): Future[Option[T]] = { if (futures.isEmpty) Promise.kept[Option[T]](None).future else { val result = promise[Option[T]] val count = new AtomicInteger(futures.size) - val search: Try[T] => Unit = { + val search: Try[T] => Unit = { v => v match { case Success(r) => if (predicate(r)) result trySuccess Some(r) case _ => } if (count.decrementAndGet() == 0) result trySuccess None } - + futures.foreach(_ onComplete search) result.future } } - + } diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index 73f76bbbfb..eb54b61db0 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -28,9 +28,9 @@ import scala.collection.generic.CanBuildFrom /** The trait that represents futures. - * + * * Asynchronous computations that yield futures are created with the `future` call: - * + * * {{{ * val s = "Hello" * val f: Future[String] = future { @@ -40,9 +40,9 @@ import scala.collection.generic.CanBuildFrom * case msg => println(msg) * } * }}} - * + * * @author Philipp Haller, Heather Miller, Aleksandar Prokopec, Viktor Klang - * + * * @define multipleCallbacks * Multiple callbacks may be registered; there is no guarantee that they will be * executed in a particular order. @@ -54,18 +54,18 @@ import scala.collection.generic.CanBuildFrom * - `Error` - errors are not contained within futures * - `InterruptedException` - not contained within futures * - all `scala.util.control.ControlThrowable` except `NonLocalReturnControl` - not contained within futures - * + * * Instead, the future is completed with a ExecutionException with one of the exceptions above * as the cause. * If a future is failed with a `scala.runtime.NonLocalReturnControl`, * it is completed with a value instead from that throwable instead instead. - * + * * @define nonDeterministic * Note: using this method yields nondeterministic dataflow programs. - * + * * @define forComprehensionExamples * Example: - * + * * {{{ * val f = future { 5 } * val g = future { 3 } @@ -74,116 +74,116 @@ import scala.collection.generic.CanBuildFrom * y: Int <- g // returns Future(5) * } yield x + y * }}} - * + * * is translated to: - * + * * {{{ * f flatMap { (x: Int) => g map { (y: Int) => x + y } } * }}} */ trait Future[+T] extends Awaitable[T] { self => - + /* Callbacks */ - + /** When this future is completed successfully (i.e. with a value), * apply the provided partial function to the value if the partial function * is defined at that value. - * + * * If the future has already been completed with a value, * this will either be applied immediately or be scheduled asynchronously. - * + * * $multipleCallbacks */ def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete { case Failure(t) => // do nothing case Success(v) => if (pf isDefinedAt v) pf(v) else { /*do nothing*/ } } - + /** When this future is completed with a failure (i.e. with a throwable), * apply the provided callback to the throwable. - * + * * $caughtThrowables - * + * * If the future has already been completed with a failure, * this will either be applied immediately or be scheduled asynchronously. - * + * * Will not be called in case that the future is completed with a value. - * + * * $multipleCallbacks */ def onFailure[U](callback: PartialFunction[Throwable, U]): this.type = onComplete { case Failure(t) => if (isFutureThrowable(t) && callback.isDefinedAt(t)) callback(t) else { /*do nothing*/ } case Success(v) => // do nothing } - + /** When this future is completed, either through an exception, a timeout, or a value, * apply the provided function. - * + * * If the future has already been completed, * this will either be applied immediately or be scheduled asynchronously. - * + * * $multipleCallbacks */ def onComplete[U](func: Try[T] => U): this.type - - + + /* Miscellaneous */ - + /** Creates a new promise. */ def newPromise[S]: Promise[S] - - + + /* Projections */ - + /** Returns a failed projection of this future. - * + * * The failed projection is a future holding a value of type `Throwable`. - * + * * It is completed with a value which is the throwable of the original future * in case the original future is failed. - * + * * It is failed with a `NoSuchElementException` if the original future is completed successfully. - * + * * Blocking on this future returns a value if the original future is completed with an exception * and throws a corresponding exception if the original future fails. */ def failed: Future[Throwable] = { - def noSuchElem(v: T) = + def noSuchElem(v: T) = new NoSuchElementException("Future.failed not completed with a throwable. Instead completed with: " + v) - + val p = newPromise[Throwable] - + onComplete { case Failure(t) => p success t case Success(v) => p failure noSuchElem(v) } - + p.future } - - + + /* Monadic operations */ - + /** Asynchronously processes the value in the future once the value becomes available. - * + * * Will not be called if the future fails. */ def foreach[U](f: T => U): Unit = onComplete { case Success(r) => f(r) case Failure(_) => // do nothing } - + /** Creates a new future by applying a function to the successful result of * this future. If this future is completed with an exception then the new * future will also contain this exception. - * + * * $forComprehensionExample */ def map[S](f: T => S): Future[S] = { val p = newPromise[S] - + onComplete { case Failure(t) => p failure t case Success(v) => @@ -192,23 +192,23 @@ self => case t => p complete resolver(t) } } - + p.future } - + /** Creates a new future by applying a function to the successful result of * this future, and returns the result of the function as the new future. * If this future is completed with an exception then the new future will * also contain this exception. - * + * * $forComprehensionExample */ def flatMap[S](f: T => Future[S]): Future[S] = { val p = newPromise[S] - + onComplete { case Failure(t) => p failure t - case Success(v) => + case Success(v) => try { f(v) onComplete { case Failure(t) => p failure t @@ -218,15 +218,15 @@ self => case t: Throwable => p complete resolver(t) } } - + p.future } - + /** Creates a new future by filtering the value of the current future with a predicate. - * + * * If the current future contains a value which satisfies the predicate, the new future will also hold that value. * Otherwise, the resulting future will fail with a `NoSuchElementException`. - * + * * If the current future fails or times out, the resulting future also fails or times out, respectively. * * Example: @@ -240,7 +240,7 @@ self => */ def filter(pred: T => Boolean): Future[T] = { val p = newPromise[T] - + onComplete { case Failure(t) => p failure t case Success(v) => @@ -251,12 +251,12 @@ self => case t: Throwable => p complete resolver(t) } } - + p.future } - + /** Creates a new future by mapping the value of the current future if the given partial function is defined at that value. - * + * * If the current future contains a value for which the partial function is defined, the new future will also hold that value. * Otherwise, the resulting future will fail with a `NoSuchElementException`. * @@ -277,7 +277,7 @@ self => */ def collect[S](pf: PartialFunction[T, S]): Future[S] = { val p = newPromise[S] - + onComplete { case Failure(t) => p failure t case Success(v) => @@ -288,16 +288,16 @@ self => case t: Throwable => p complete resolver(t) } } - + p.future } - + /** Creates a new future that will handle any matching throwable that this * future might contain. If there is no match, or if this future contains * a valid result then the new future will contain the same. - * + * * Example: - * + * * {{{ * future (6 / 0) recover { case e: ArithmeticException ⇒ 0 } // result: 0 * future (6 / 0) recover { case e: NotFoundException ⇒ 0 } // result: exception @@ -306,25 +306,25 @@ self => */ def recover[U >: T](pf: PartialFunction[Throwable, U]): Future[U] = { val p = newPromise[U] - + onComplete { case Failure(t) if pf isDefinedAt t => try { p success pf(t) } catch { case t: Throwable => p complete resolver(t) } case otherwise => p complete otherwise } - + p.future } - + /** Creates a new future that will handle any matching throwable that this * future might contain by assigning it a value of another future. - * + * * If there is no match, or if this future contains * a valid result then the new future will contain the same result. - * + * * Example: - * + * * {{{ * val f = future { Int.MaxValue } * future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue @@ -332,7 +332,7 @@ self => */ def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]]): Future[U] = { val p = newPromise[U] - + onComplete { case Failure(t) if pf isDefinedAt t => try { @@ -342,13 +342,13 @@ self => } case otherwise => p complete otherwise } - + p.future } - + /** Zips the values of `this` and `that` future, and creates * a new future holding the tuple of their results. - * + * * If `this` future fails, the resulting future is failed * with the throwable stored in `this`. * Otherwise, if `that` future fails, the resulting future is failed @@ -356,27 +356,27 @@ self => */ def zip[U](that: Future[U]): Future[(T, U)] = { val p = newPromise[(T, U)] - + this onComplete { case Failure(t) => p failure t case Success(r) => that onSuccess { case r2 => p success ((r, r2)) } } - + that onFailure { case f => p failure f } - + p.future } - + /** Creates a new future which holds the result of this future if it was completed successfully, or, if not, * the result of the `that` future if `that` is completed successfully. * If both futures are failed, the resulting future holds the throwable object of the first future. - * + * * Using this method will not cause concurrent programs to become nondeterministic. - * + * * Example: * {{{ * val f = future { sys.error("failed") } @@ -387,7 +387,7 @@ self => */ def fallbackTo[U >: T](that: Future[U]): Future[U] = { val p = newPromise[U] - + onComplete { case Failure(t) => that onComplete { case Failure(_) => p failure t @@ -395,23 +395,23 @@ self => } case Success(v) => p success v } - + p.future } - + /** Applies the side-effecting function to the result of this future, and returns * a new future with the result of this future. - * + * * This method allows one to enforce that the callbacks are executed in a * specified order. - * + * * Note that if one of the chained `andThen` callbacks throws * an exception, that exception is not propagated to the subsequent `andThen` * callbacks. Instead, the subsequent `andThen` callbacks are given the original * value of this future. - * + * * The following example prints out `5`: - * + * * {{{ * val f = future { 5 } * f andThen { @@ -424,21 +424,21 @@ self => */ def andThen[U](pf: PartialFunction[Try[T], U]): Future[T] = { val p = newPromise[T] - + onComplete { case r => try if (pf isDefinedAt r) pf(r) finally p complete r } - + p.future } - + /** Creates a new future which holds the result of either this future or `that` future, depending on * which future was completed first. - * + * * $nonDeterministic - * + * * Example: * {{{ * val f = future { sys.error("failed") } @@ -449,42 +449,42 @@ self => */ def either[U >: T](that: Future[U]): Future[U] = { val p = self.newPromise[U] - + val completePromise: PartialFunction[Try[U], _] = { case Failure(t) => p tryFailure t case Success(v) => p trySuccess v } - + self onComplete completePromise that onComplete completePromise - + p.future } - + } /** TODO some docs - * + * * @define nonDeterministic * Note: using this method yields nondeterministic dataflow programs. */ object Future { - + // TODO make more modular by encoding all other helper methods within the execution context /** TODO some docs */ def all[T, Coll[X] <: Traversable[X]](futures: Coll[Future[T]])(implicit cbf: CanBuildFrom[Coll[_], T, Coll[T]], ec: ExecutionContext): Future[Coll[T]] = ec.all[T, Coll](futures) - + // move this to future companion object @inline def apply[T](body: =>T)(implicit executor: ExecutionContext): Future[T] = executor.future(body) def any[T](futures: Traversable[Future[T]])(implicit ec: ExecutionContext): Future[T] = ec.any(futures) def find[T](futures: Traversable[Future[T]])(predicate: T => Boolean)(implicit ec: ExecutionContext): Future[Option[T]] = ec.find(futures)(predicate) - + } diff --git a/src/library/scala/concurrent/JavaConversions.scala b/src/library/scala/concurrent/JavaConversions.scala index bac9d4f558..127a0e0055 100644 --- a/src/library/scala/concurrent/JavaConversions.scala +++ b/src/library/scala/concurrent/JavaConversions.scala @@ -48,9 +48,9 @@ object JavaConversions { // do nothing } } - + implicit def asExecutionContext(exec: ExecutorService): ExecutionContext = null // TODO - + implicit def asExecutionContext(exec: Executor): ExecutionContext = null // TODO - + } diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index f26deb77ab..4404e90971 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -24,36 +24,36 @@ import scala.util.{ Try, Success, Failure } * If the throwable used to fail this promise is an error, a control exception * or an interrupted exception, it will be wrapped as a cause within an * `ExecutionException` which will fail the promise. - * + * * @define nonDeterministic * Note: Using this method may result in non-deterministic concurrent programs. */ trait Promise[T] { - + import nondeterministic._ - + /** Future containing the value of this promise. */ def future: Future[T] - + /** Completes the promise with either an exception or a value. - * + * * @param result Either the value or the exception to complete the promise with. - * + * * $promiseCompletion */ def complete(result:Try[T]): this.type = if (tryComplete(result)) this else throwCompleted - + /** Tries to complete the promise with either a value or the exception. - * + * * $nonDeterministic - * + * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ def tryComplete(result: Try[T]): Boolean - + /** Completes this promise with the specified future, once that future is completed. - * + * * @return This promise */ final def completeWith(other: Future[T]): this.type = { @@ -62,64 +62,64 @@ trait Promise[T] { } this } - + /** Completes the promise with a value. - * + * * @param value The value to complete the promise with. - * + * * $promiseCompletion */ def success(v: T): this.type = if (trySuccess(v)) this else throwCompleted - + /** Tries to complete the promise with a value. - * + * * $nonDeterministic - * + * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ def trySuccess(value: T): Boolean = tryComplete(Success(value)) - + /** Completes the promise with an exception. - * + * * @param t The throwable to complete the promise with. - * + * * $allowedThrowables - * + * * $promiseCompletion */ def failure(t: Throwable): this.type = if (tryFailure(t)) this else throwCompleted - + /** Tries to complete the promise with an exception. - * + * * $nonDeterministic - * + * * @return If the promise has already been completed returns `false`, or `true` otherwise. */ def tryFailure(t: Throwable): Boolean = tryComplete(Failure(t)) - + /** Wraps a `Throwable` in an `ExecutionException` if necessary. TODO replace with `resolver` from scala.concurrent - * + * * $allowedThrowables */ protected def wrap(t: Throwable): Throwable = t match { case t: Throwable if isFutureThrowable(t) => t case _ => new ExecutionException(t) } - + private def throwCompleted = throw new IllegalStateException("Promise already completed.") - + } object Promise { - + def kept[T](result: T)(implicit execctx: ExecutionContext): Promise[T] = execctx keptPromise result - - def broken[T](t: Throwable)(implicit execctx: ExecutionContext): Promise[T] = + + def broken[T](t: Throwable)(implicit execctx: ExecutionContext): Promise[T] = execctx brokenPromise t - + } diff --git a/src/library/scala/concurrent/Task.scala b/src/library/scala/concurrent/Task.scala index d6f86bac31..eb3efbb422 100644 --- a/src/library/scala/concurrent/Task.scala +++ b/src/library/scala/concurrent/Task.scala @@ -3,11 +3,11 @@ package scala.concurrent trait Task[+T] { - + def start(): Unit - + def future: Future[T] - + } diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index af0eb66292..7984aa02b7 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -11,32 +11,37 @@ package scala.concurrent.impl import java.util.concurrent.{Callable, ExecutorService} +import scala.concurrent.forkjoin._ import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable} import scala.util.{ Duration, Try, Success, Failure } import scala.collection.mutable.Stack -class ExecutionContextImpl(executorService: ExecutorService) extends ExecutionContext { +class ExecutionContextImpl(val executorService: AnyRef) extends ExecutionContext { import ExecutionContextImpl._ - + def execute(runnable: Runnable): Unit = executorService match { - // case fj: ForkJoinPool => - // TODO fork if more applicable - // executorService execute runnable - case _ => + case fj: ForkJoinPool => + if (Thread.currentThread.isInstanceOf[ForkJoinWorkerThread]) { + val fjtask = ForkJoinTask.adapt(runnable) + fjtask.fork + } else { + fj.execute(runnable) + } + case executorService: ExecutorService => executorService execute runnable } - + def execute[U](body: () => U): Unit = execute(new Runnable { def run() = body() }) - + def promise[T]: Promise[T] = new Promise.DefaultPromise[T]()(this) - + def future[T](body: =>T): Future[T] = { val p = promise[T] - + dispatchFuture { () => p complete { @@ -47,39 +52,39 @@ class ExecutionContextImpl(executorService: ExecutorService) extends ExecutionCo } } } - + p.future } - + def blocking[T](atMost: Duration)(body: =>T): T = blocking(body2awaitable(body), atMost) - + def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = { currentExecutionContext.get match { case null => awaitable.await(atMost)(null) // outside - TODO - fix timeout case case x => x.blockingCall(awaitable) // inside an execution context thread } } - + def reportFailure(t: Throwable) = t match { case e: Error => throw e // rethrow serious errors case t => t.printStackTrace() } - + /** Only callable from the tasks running on the same execution context. */ private def blockingCall[T](body: Awaitable[T]): T = { releaseStack() - + // TODO see what to do with timeout body.await(Duration.fromNanos(0))(CanAwaitEvidence) } - + // an optimization for batching futures // TODO we should replace this with a public queue, // so that it can be stolen from // OR: a push to the local task queue should be so cheap that this is // not even needed, but stealing is still possible private val _taskStack = new ThreadLocal[Stack[() => Unit]]() - + private def releaseStack(): Unit = _taskStack.get match { case stack if (stack ne null) && stack.nonEmpty => @@ -92,7 +97,7 @@ class ExecutionContextImpl(executorService: ExecutorService) extends ExecutionCo case _ => _taskStack.remove() } - + private[impl] def dispatchFuture(task: () => Unit, force: Boolean = false): Unit = _taskStack.get match { case stack if (stack ne null) && !force => stack push task @@ -119,16 +124,16 @@ class ExecutionContextImpl(executorService: ExecutorService) extends ExecutionCo } ) } - + } object ExecutionContextImpl { - + private[concurrent] def currentExecutionContext: ThreadLocal[ExecutionContextImpl] = new ThreadLocal[ExecutionContextImpl] { override protected def initialValue = null } - + } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 24d0258cc8..9466761d4d 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -13,35 +13,35 @@ import scala.util.{ Try, Success, Failure } //import scala.util.continuations._ trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { - + implicit def executor: ExecutionContextImpl - + /** For use only within a Future.flow block or another compatible Delimited Continuations reset block. - * + * * Returns the result of this Future without blocking, by suspending execution and storing it as a * continuation until the result is available. */ //def apply(): T @cps[Future[Any]] = shift(this flatMap (_: T => Future[Any])) - + /** Tests whether this Future has been completed. */ final def isCompleted: Boolean = value.isDefined - + /** The contained value of this Future. Before this Future is completed * the value will be None. After completion the value will be Some(Right(t)) * if it contains a valid result, or Some(Left(error)) if it contains * an exception. */ def value: Option[Try[T]] - + def onComplete[U](func: Try[T] => U): this.type - + /** Creates a new Future[A] which is completed with this Future's result if * that conforms to A's erased type or a ClassCastException otherwise. */ final def mapTo[T](implicit m: Manifest[T]) = { val p = executor.promise[T] - + onComplete { case f @ Failure(t) => p complete f.asInstanceOf[Try[T]] case Success(v) => @@ -51,7 +51,7 @@ trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { case e: ClassCastException ⇒ Failure(e) }) } - + p.future } @@ -65,7 +65,7 @@ trait Future[+T] extends scala.concurrent.Future[T] with Awaitable[T] { def flatMap[B](f: A => Future[B]) = self filter p flatMap f def withFilter(q: A => Boolean): FutureWithFilter[A] = new FutureWithFilter[A](self, x ⇒ p(x) && q(x)) } - + } object Future { diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 7ef76e1501..585f71f3cf 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -23,11 +23,11 @@ import scala.annotation.tailrec trait Promise[T] extends scala.concurrent.Promise[T] with Future[T] { - + def future = this - + def newPromise[S]: Promise[S] = executor promise - + // TODO refine answer and return types here from Any to type parameters // then move this up in the hierarchy /* @@ -40,7 +40,7 @@ trait Promise[T] extends scala.concurrent.Promise[T] with Future[T] { cont: (Future[T] => Future[Any]) => val p = executor.promise[Any] val thisPromise = this - + thisPromise completeWith other thisPromise onComplete { v => try { @@ -49,12 +49,12 @@ trait Promise[T] extends scala.concurrent.Promise[T] with Future[T] { case e => p complete resolver(e) } } - + p.future } */ // TODO finish this once we introduce something like dataflow streams - + /* final def <<(stream: PromiseStreamOut[T]): Future[T] @cps[Future[Any]] = shift { cont: (Future[T] => Future[Any]) => val fr = executor.promise[Any] @@ -70,40 +70,40 @@ trait Promise[T] extends scala.concurrent.Promise[T] with Future[T] { fr } */ - + } object Promise { def dur2long(dur: Duration): Long = if (dur.isFinite) dur.toNanos else Long.MaxValue - + def EmptyPending[T](): FState[T] = emptyPendingValue.asInstanceOf[FState[T]] - + /** Represents the internal state. */ sealed trait FState[+T] { def value: Option[Try[T]] } - + case class Pending[T](listeners: List[Try[T] => Any] = Nil) extends FState[T] { def value: Option[Try[T]] = None } - + case class Success[T](value: Option[util.Success[T]] = None) extends FState[T] { def result: T = value.get.get } - + case class Failure[T](value: Option[util.Failure[T]] = None) extends FState[T] { def exception: Throwable = value.get.exception } - + private val emptyPendingValue = Pending[Nothing](Nil) - + /** Default promise implementation. */ class DefaultPromise[T](implicit val executor: ExecutionContextImpl) extends AbstractPromise with Promise[T] { self => - + updater.set(this, Promise.EmptyPending()) - + protected final def tryAwait(atMost: Duration): Boolean = { @tailrec def awaitUnsafe(waitTimeNanos: Long): Boolean = { @@ -118,36 +118,36 @@ object Promise { } catch { case e: InterruptedException => } - + awaitUnsafe(waitTimeNanos - (System.nanoTime() - start)) } else value.isDefined } - + executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), Duration.fromNanos(0)) } - + private def ready(atMost: Duration)(implicit permit: CanAwait): this.type = if (value.isDefined || tryAwait(atMost)) this else throw new TimeoutException("Futures timed out after [" + atMost.toMillis + "] milliseconds") - + def await(atMost: Duration)(implicit permit: CanAwait): T = ready(atMost).value.get match { case util.Failure(e) => throw e case util.Success(r) => r } - + def value: Option[Try[T]] = getState.value - + @inline private[this] final def updater = AbstractPromise.updater.asInstanceOf[AtomicReferenceFieldUpdater[AbstractPromise, FState[T]]] - + @inline protected final def updateState(oldState: FState[T], newState: FState[T]): Boolean = updater.compareAndSet(this, oldState, newState) - + @inline protected final def getState: FState[T] = updater.get(this) - + def tryComplete(value: Try[T]): Boolean = { val callbacks: List[Try[T] => Any] = { try { @@ -165,7 +165,7 @@ object Promise { synchronized { notifyAll() } // notify any blockers from `tryAwait` } } - + callbacks match { case null => false case cs if cs.isEmpty => true @@ -176,7 +176,7 @@ object Promise { true } } - + def onComplete[U](func: Try[T] => U): this.type = { @tailrec // Returns whether the future has already been completed or not def tryAddCallback(): Boolean = { @@ -188,17 +188,17 @@ object Promise { if (updateState(pt, pt.copy(listeners = func :: pt.listeners))) false else tryAddCallback() } } - + if (tryAddCallback()) { val result = value.get executor dispatchFuture { () => notifyCompleted(func, result) } } - + this } - + private final def notifyCompleted(func: Try[T] => Any, result: Try[T]) { try { func(result) @@ -207,16 +207,16 @@ object Promise { } } } - + /** An already completed Future is given its result at creation. - * + * * Useful in Future-composition when a value to contribute is already available. */ final class KeptPromise[T](suppliedValue: Try[T])(implicit val executor: ExecutionContextImpl) extends Promise[T] { val value = Some(resolve(suppliedValue)) - + def tryComplete(value: Try[T]): Boolean = false - + def onComplete[U](func: Try[T] => U): this.type = { val completedAs = value.get executor dispatchFuture { @@ -224,15 +224,15 @@ object Promise { } this } - + private def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this - + def await(atMost: Duration)(implicit permit: CanAwait): T = value.get match { case util.Failure(e) => throw e case util.Success(r) => r } } - + } diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index 6a98fd50c2..7cc48c09b2 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -25,31 +25,31 @@ package concurrent { catch { case _ => } awaitable } - + def result[T](atMost: Duration)(awaitable: Awaitable[T])(implicit execCtx: ExecutionContext = executionContext): T = { blocking(awaitable, atMost) } } - + /** Importing this object allows using some concurrency primitives * on futures and promises that can yield nondeterministic programs. - * + * * While program determinism is broken when using these primitives, * some programs cannot be written without them (e.g. multiple client threads * cannot send requests to a server thread through regular promises and futures). */ object nondeterministic { } - + /** A timeout exception. - * + * * Futures are failed with a timeout exception when their timeout expires. - * + * * Each timeout exception contains an origin future which originally timed out. */ class FutureTimeoutException(origin: Future[_], message: String) extends TimeoutException(message) { def this(origin: Future[_]) = this(origin, "Future timed out.") } - + final class DurationOps private[concurrent] (x: Int) { // TODO ADD OTHERS def ns = util.Duration.fromNanos(0) diff --git a/src/library/scala/reflect/ReflectionUtils.scala b/src/library/scala/reflect/ReflectionUtils.scala index dfadfb4976..510f0819c6 100644 --- a/src/library/scala/reflect/ReflectionUtils.scala +++ b/src/library/scala/reflect/ReflectionUtils.scala @@ -29,13 +29,13 @@ object ReflectionUtils { def singletonInstance(className: String, cl: ClassLoader = getClass.getClassLoader): AnyRef = { val name = if (className endsWith "$") className else className + "$" - val clazz = java.lang.Class.forName(name, true, cl) + val clazz = java.lang.Class.forName(name, true, cl) val singleton = clazz getField "MODULE$" get null singleton } // Retrieves the MODULE$ field for the given class name. - def singletonInstanceOpt(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = + def singletonInstanceOpt(className: String, cl: ClassLoader = getClass.getClassLoader): Option[AnyRef] = try Some(singletonInstance(className, cl)) catch { case _: ClassNotFoundException => None } } diff --git a/src/library/scala/reflect/api/Mirror.scala b/src/library/scala/reflect/api/Mirror.scala index 448dca752c..cea9e1a37d 100644 --- a/src/library/scala/reflect/api/Mirror.scala +++ b/src/library/scala/reflect/api/Mirror.scala @@ -13,11 +13,11 @@ trait Mirror extends Universe with RuntimeTypes with TreeBuildUtil { * to do: throws anything else? */ def symbolForName(name: String): Symbol - + /** Return a reference to the companion object of the given class symbol. */ def companionInstance(clazz: Symbol): AnyRef - + /** The Scala class symbol corresponding to the runtime class of the given instance. * @param instance The instance * @return The class Symbol for the instance diff --git a/src/library/scala/reflect/api/Modifier.scala b/src/library/scala/reflect/api/Modifier.scala index c0123ed955..cbfe91e59b 100644 --- a/src/library/scala/reflect/api/Modifier.scala +++ b/src/library/scala/reflect/api/Modifier.scala @@ -69,7 +69,7 @@ object Modifier extends immutable.Set[Modifier] { val parameter = SymbolModifier("parameter") val preSuper = SymbolModifier("preSuper") val static = SymbolModifier("static") - + val sourceModifiers: Set[SourceModifier] = SourceModifier.all.toSet val symbolModifiers: Set[SymbolModifier] = SymbolModifier.all.toSet val allModifiers: Set[Modifier] = sourceModifiers ++ symbolModifiers diff --git a/src/library/scala/reflect/api/Names.scala b/src/library/scala/reflect/api/Names.scala index 3a00f21c8c..c72774dfc7 100755 --- a/src/library/scala/reflect/api/Names.scala +++ b/src/library/scala/reflect/api/Names.scala @@ -6,7 +6,7 @@ package api * The same string can be a name in both universes. * Two names are equal if they represent the same string and they are * members of the same universe. - * + * * Names are interned. That is, for two names `name11 and `name2`, * `name1 == name2` implies `name1 eq name2`. */ @@ -42,7 +42,7 @@ trait Names { * Example: `foo_$plus$eq` becomes `foo_+=` */ def encoded: String - + /** The decoded name, still represented as a name. */ def decodedName: Name diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 15d754b5b4..44dc2ce1c2 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -18,7 +18,7 @@ trait Symbols { self: Universe => /** A list of annotations attached to this Symbol. */ def annotations: List[self.AnnotationInfo] - + /** Whether this symbol carries an annotation for which the given * symbol is its typeSymbol. */ @@ -99,7 +99,7 @@ trait Symbols { self: Universe => * method, or `NoSymbol` if none exists. */ def enclosingMethod: Symbol - + /** If this symbol is a package class, this symbol; otherwise the next enclosing * package class, or `NoSymbol` if none exists. */ @@ -170,7 +170,7 @@ trait Symbols { self: Universe => * `C`. Then `C.asType` is the type `C[T]`, but `C.asTypeConstructor` is `C`. */ def asTypeConstructor: Type // needed by LiftCode - + /** If this symbol is a class, the type `C.this`, otherwise `NoPrefix`. */ def thisPrefix: Type @@ -181,10 +181,10 @@ trait Symbols { self: Universe => def selfType: Type /** A fresh symbol with given name `name`, position `pos` and flags `flags` that has - * the current symbol as its owner. + * the current symbol as its owner. */ def newNestedSymbol(name: Name, pos: Position, flags: Long): Symbol // needed by LiftCode - + /** Low-level operation to set the symbol's flags * @return the symbol itself */ diff --git a/src/library/scala/reflect/api/TreePrinters.scala b/src/library/scala/reflect/api/TreePrinters.scala index 19bfd09b81..21b55e9c0e 100644 --- a/src/library/scala/reflect/api/TreePrinters.scala +++ b/src/library/scala/reflect/api/TreePrinters.scala @@ -55,7 +55,7 @@ trait TreePrinters { self: Universe => print(")") if (typesPrinted) print(".setType(", tree.tpe, ")") - case list: List[_] => + case list: List[_] => print("List(") val it = list.iterator while (it.hasNext) { @@ -64,16 +64,16 @@ trait TreePrinters { self: Universe => } print(")") case mods: Modifiers => - val parts = collection.mutable.ListBuffer[String]() + val parts = collection.mutable.ListBuffer[String]() parts += "Set(" + mods.modifiers.map(_.sourceString).mkString(", ") + ")" parts += "newTypeName(\"" + mods.privateWithin.toString + "\")" parts += "List(" + mods.annotations.map{showRaw}.mkString(", ") + ")" - + var keep = 3 if (keep == 3 && mods.annotations.isEmpty) keep -= 1 if (keep == 2 && mods.privateWithin == EmptyTypeName) keep -= 1 if (keep == 1 && mods.modifiers.isEmpty) keep -= 1 - + print("Modifiers(", parts.take(keep).mkString(", "), ")") case name: Name => if (name.isTermName) print("newTermName(\"") else print("newTypeName(\"") diff --git a/src/library/scala/reflect/api/Trees.scala b/src/library/scala/reflect/api/Trees.scala index bf427df09a..181ce85dac 100644 --- a/src/library/scala/reflect/api/Trees.scala +++ b/src/library/scala/reflect/api/Trees.scala @@ -491,6 +491,10 @@ trait Trees { self: Universe => if (argss.isEmpty) Apply(superRef, Nil) else (superRef /: argss) (Apply) } + /** 0-1 argument list new, based on a type. + */ + def New(tpe: Type, args: Tree*): Tree = + New(TypeTree(tpe), List(args.toList)) /** Type annotation, eliminated by explicit outer */ case class Typed(expr: Tree, tpt: Tree) diff --git a/src/library/scala/reflect/api/Types.scala b/src/library/scala/reflect/api/Types.scala index 8a91956320..cc8e85b9c8 100755 --- a/src/library/scala/reflect/api/Types.scala +++ b/src/library/scala/reflect/api/Types.scala @@ -140,7 +140,7 @@ trait Types { self: Universe => * If this is not a singleton type, returns this type itself. * * Example: - * + * * class Outer { class C ; val x: C } * val o: Outer * <o.x.type>.widen = o.C diff --git a/src/library/scala/reflect/macro/Context.scala b/src/library/scala/reflect/macro/Context.scala index ebbd4735e5..2fd9bb6484 100644 --- a/src/library/scala/reflect/macro/Context.scala +++ b/src/library/scala/reflect/macro/Context.scala @@ -2,11 +2,11 @@ package scala.reflect package macro trait Context extends api.Universe { - + /** Mark a variable as captured; i.e. force boxing in a *Ref type. */ def captureVariable(vble: Symbol): Unit - + /** Mark given identifier as a reference to a captured variable itself * suppressing dereferencing with the `elem` field. */ diff --git a/src/library/scala/runtime/NonLocalReturnControl.scala b/src/library/scala/runtime/NonLocalReturnControl.scala index 8be2745086..216e3e664b 100644 --- a/src/library/scala/runtime/NonLocalReturnControl.scala +++ b/src/library/scala/runtime/NonLocalReturnControl.scala @@ -6,12 +6,10 @@ ** |/ ** \* */ - - package scala.runtime import scala.util.control.ControlThrowable -class NonLocalReturnControl[T](val key: AnyRef, val value: T) extends ControlThrowable { +class NonLocalReturnControl[@specialized T](val key: AnyRef, val value: T) extends ControlThrowable { final override def fillInStackTrace(): Throwable = this } diff --git a/src/library/scala/specialized.scala b/src/library/scala/specialized.scala index b24474f35d..b876869afb 100644 --- a/src/library/scala/specialized.scala +++ b/src/library/scala/specialized.scala @@ -25,7 +25,7 @@ import Specializable._ * @since 2.8 */ // class tspecialized[T](group: Group[T]) extends annotation.StaticAnnotation { - + class specialized(group: SpecializedGroup) extends annotation.StaticAnnotation { def this(types: Specializable*) = this(new Group(types.toList)) def this() = this(Everything) diff --git a/src/library/scala/sys/process/BasicIO.scala b/src/library/scala/sys/process/BasicIO.scala index edc60a1bb5..77e36f6196 100644 --- a/src/library/scala/sys/process/BasicIO.scala +++ b/src/library/scala/sys/process/BasicIO.scala @@ -97,7 +97,7 @@ object BasicIO { * * @param withIn True if the process input should be attached to stdin. * @param buffer A `StringBuffer` which will receive the process normal - * output. + * output. * @param log An optional `ProcessLogger` to which the output should be * sent. If `None`, output will be sent to stderr. * @return A `ProcessIO` with the characteristics above. diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 22de5544a8..a62d74b1f6 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -142,7 +142,7 @@ private[scala] trait PropertiesTrait { */ def isWin = osName startsWith "Windows" def isMac = javaVendor startsWith "Apple" - + // This is looking for javac, tools.jar, etc. // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME, // and finally the system property based javaHome. diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index a05a75e0b7..c9bde81317 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -15,7 +15,7 @@ import collection.Seq /** - * The `Try` type represents a computation that may either result in an exception, + * The `Try` type represents a computation that may either result in an exception, * or return a success value. It's analagous to the `Either` type. */ sealed abstract class Try[+T] { @@ -55,9 +55,9 @@ sealed abstract class Try[+T] { def map[U](f: T => U): Try[U] def collect[U](pf: PartialFunction[T, U]): Try[U] - + def exists(p: T => Boolean): Boolean - + /** * Converts this to a `Failure` if the predicate is not satisfied. */ @@ -77,14 +77,14 @@ sealed abstract class Try[+T] { * Calls the exceptionHandler with the exception if this is a `Failure`. This is like map for the exception. */ def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] - + /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ def toOption = if (isSuccess) Some(get) else None def toSeq = if (isSuccess) Seq(get) else Seq() - + /** * Returns the given function applied to the value from this Success or returns this if this is a `Failure`. * Alias for `flatMap`. @@ -92,11 +92,11 @@ sealed abstract class Try[+T] { def andThen[U](f: T => Try[U]): Try[U] = flatMap(f) /** - * Transforms a nested `Try`, i.e., a `Try` of type `Try[Try[T]]`, + * Transforms a nested `Try`, i.e., a `Try` of type `Try[Try[T]]`, * into an un-nested `Try`, i.e., a `Try` of type `Try[T]`. */ def flatten[U](implicit ev: T <:< Try[U]): Try[U] - + def failed: Try[Throwable] } @@ -109,7 +109,7 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { if (rescueException.isDefinedAt(exception)) rescueException(exception) else this } catch { case e2 => Failure(e2) - } + } } def get: T = throw exception def flatMap[U](f: T => Try[U]): Try[U] = Failure[U](exception) @@ -118,7 +118,7 @@ final case class Failure[+T](val exception: Throwable) extends Try[T] { def map[U](f: T => U): Try[U] = Failure[U](exception) def collect[U](pf: PartialFunction[T, U]): Try[U] = Failure[U](exception) def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = + def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = if (rescueException.isDefinedAt(exception)) { Try(rescueException(exception)) } else { @@ -134,10 +134,10 @@ final case class Success[+T](r: T) extends Try[T] { def isSuccess = true def rescue[U >: T](rescueException: PartialFunction[Throwable, Try[U]]): Try[U] = Success(r) def get = r - def flatMap[U](f: T => Try[U]): Try[U] = - try f(r) - catch { - case e => Failure(e) + def flatMap[U](f: T => Try[U]): Try[U] = + try f(r) + catch { + case e => Failure(e) } def flatten[U](implicit ev: T <:< Try[U]): Try[U] = r def foreach[U](f: T => U): Unit = f(r) @@ -145,7 +145,7 @@ final case class Success[+T](r: T) extends Try[T] { def collect[U](pf: PartialFunction[T, U]): Try[U] = if (pf isDefinedAt r) Success(pf(r)) else Failure[U](new NoSuchElementException("Partial function not defined at " + r)) - def filter(p: T => Boolean): Try[T] = + def filter(p: T => Boolean): Try[T] = if (p(r)) this else Failure(new NoSuchElementException("Predicate does not hold for " + r)) def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this @@ -155,11 +155,11 @@ final case class Success[+T](r: T) extends Try[T] { object Try { - + def apply[T](r: => T): Try[T] = { try { Success(r) } catch { case e => Failure(e) } } - + } diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala index 4004a01ad9..27e9112fce 100644 --- a/src/library/scala/util/parsing/combinator/Parsers.scala +++ b/src/library/scala/util/parsing/combinator/Parsers.scala @@ -487,7 +487,7 @@ trait Parsers { } /** Changes the error message produced by a parser. - * + * * This doesn't change the behavior of a parser on neither * success nor failure, just on error. The semantics are * slightly different than those obtained by doing `| error(msg)`, diff --git a/src/manual/scala/tools/docutil/EmitManPage.scala b/src/manual/scala/tools/docutil/EmitManPage.scala index 3e0b02a415..39d68dbc18 100644 --- a/src/manual/scala/tools/docutil/EmitManPage.scala +++ b/src/manual/scala/tools/docutil/EmitManPage.scala @@ -165,7 +165,7 @@ object EmitManPage { def main(args: Array[String]) = args match{ case Array(classname) => emitManPage(classname) - case Array(classname, file, _*) => emitManPage(classname, new java.io.FileOutputStream(file)) + case Array(classname, file, _*) => emitManPage(classname, new java.io.FileOutputStream(file)) case _ => sys.exit(1) } diff --git a/src/partest/scala/tools/partest/CompilerTest.scala b/src/partest/scala/tools/partest/CompilerTest.scala index dd06c051a4..1cb09b433a 100644 --- a/src/partest/scala/tools/partest/CompilerTest.scala +++ b/src/partest/scala/tools/partest/CompilerTest.scala @@ -19,7 +19,7 @@ abstract class CompilerTest extends DirectTest { lazy val global: Global = newCompiler() lazy val units = compilationUnits(global)(sources: _ *) - + override def extraSettings = "-usejavacp -d " + testOutput.path def sources: List[String] = List(code) diff --git a/src/partest/scala/tools/partest/DirectTest.scala b/src/partest/scala/tools/partest/DirectTest.scala index 74f511aa4e..07444f8d4b 100644 --- a/src/partest/scala/tools/partest/DirectTest.scala +++ b/src/partest/scala/tools/partest/DirectTest.scala @@ -63,7 +63,7 @@ abstract class DirectTest extends App { global.reporter.reset() f(new global.Run) } - + // compile the code, optionally first adding to the settings def compile(args: String*) = compileString(newCompiler(args: _*))(code) diff --git a/src/partest/scala/tools/partest/nest/PathSettings.scala b/src/partest/scala/tools/partest/nest/PathSettings.scala index 4fe337b19f..ac04c64c33 100644 --- a/src/partest/scala/tools/partest/nest/PathSettings.scala +++ b/src/partest/scala/tools/partest/nest/PathSettings.scala @@ -44,7 +44,7 @@ object PathSettings { lazy val srcCodeLibDir = Directory(srcDir / "codelib") lazy val srcCodeLib: File = ( - findJar(srcCodeLibDir, "code") + findJar(srcCodeLibDir, "code") orElse findJar(Directory(testRoot / "files" / "codelib"), "code") // work with --srcpath pending getOrElse sys.error("No code.jar found in %s".format(srcCodeLibDir)) ) diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala index 84f28af7ce..1a4b3456b8 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala @@ -68,7 +68,7 @@ class ByteCode(val bytes : Array[Byte], val pos : Int, val length : Int) { val chunk: Array[Byte] = new Array[Byte](length) System.arraycopy(bytes, pos, chunk, 0, length) val str = new String(io.Codec.fromUTF8(bytes, pos, length)) - + StringBytesPair(str, chunk) } |