diff options
71 files changed, 1301 insertions, 527 deletions
@@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="sabbus" default="build"> +<project name="sabbus" default="build" xmlns:artifact="urn:maven-artifact-ant"> <description> SuperSabbus for Scala core, builds the scala library and compiler. It can also package it as a simple distribution, tests it for stable bootstrapping and against the Scala test suite. </description> @@ -238,6 +238,19 @@ INITIALISATION </touch> </target> + <!-- Add our maven ant tasks --> + <target name="init.maven.tasks" depends="init.jars.check"> + <path id="maven-ant-tasks.classpath" path="${lib.dir}/ant/maven-ant-tasks-2.1.1.jar" /> + <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" /> + </target> + + <!-- Resolve maven dependencies --> + <target name="init.maven.jars" depends="init.maven.tasks"> + <artifact:dependencies pathId="dependency.classpath" filesetId="dependency.fileset"> + <dependency groupId="org.skife.com.typesafe.config" artifactId="typesafe-config" version="0.3.0"/> + </artifact:dependencies> + </target> + <!-- Determines OSGi string + maven extension. --> <target name="init.hasbuildnum"> <condition property="version.hasbuildnum"> @@ -261,21 +274,7 @@ INITIALISATION <target name="init.build.suffix.done" depends="init.build.release, init.build.patch.release"/> - <target name="init" depends="init.jars, init.build.suffix.done"> - <!-- scalac.args.optimise is selectively overridden in certain antcall tasks. --> - <property name="scalac.args.optimise" value=""/> - <!-- scalac.args.quickonly are added to quick.* targets but not others (particularly, locker.) - This is to facilitate testing new command line options which do not yet exist in starr. --> - <property name="scalac.args.quickonly" value=""/> - <property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/> - <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/> - <!-- Setting-up Ant contrib tasks --> - <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/> - <!-- This is the start time for the distribution --> - <tstamp prefix="time"> - <format property="human" pattern="d MMMM yyyy, HH:mm:ss" locale="en,US"/> - <format property="short" pattern="yyyyMMddHHmmss"/> - </tstamp> + <target name="init.version.git" depends="init.build.suffix.done"> <!-- Find out whether we are running on Windows --> <condition property="os.win"> <os family="windows"/> @@ -292,15 +291,45 @@ INITIALISATION name="maven.version.number" value="${version.major}.${version.minor}.${version.patch}${version.suffix}${maven.version.suffix}"/> <property - name="version.number" - value="${version.major}.${version.minor}.${version.patch}${version.suffix}-${git.commit.date}-${git.commit.sha}"/> - <property name="osgi.version.number" value="${version.major}.${version.minor}.${version.patch}.v${git.commit.date}${version.suffix}-${git.commit.sha}"/> + </target> + + <target name="init.version.snapshot" unless="build.release" depends="init.version.git"> + <property + name="version.number" + value="${version.major}.${version.minor}.${version.patch}${version.suffix}-${git.commit.date}-${git.commit.sha}"/> + </target> + + <target name="init.version.release" if="build.release" depends="init.version.git"> + <property + name="version.number" + value="${maven.version.number}"/> + </target> + + <target name="init.version.done" depends="init.version.release, init.version.snapshot"/> + + <target name="init" depends="init.jars, init.maven.jars, init.version.done"> + <!-- scalac.args.optimise is selectively overridden in certain antcall tasks. --> + <property name="scalac.args.optimise" value=""/> + <!-- scalac.args.quickonly are added to quick.* targets but not others (particularly, locker.) + This is to facilitate testing new command line options which do not yet exist in starr. --> + <property name="scalac.args.quickonly" value=""/> + <property name="scalac.args.all" value="${scalac.args} ${scalac.args.optimise}"/> + <property name="scalac.args.quick" value="${scalac.args.all} ${scalac.args.quickonly}"/> + <!-- Setting-up Ant contrib tasks --> + <taskdef resource="net/sf/antcontrib/antlib.xml" classpath="${lib.dir}/ant/ant-contrib.jar"/> + <!-- This is the start time for the distribution --> + <tstamp prefix="time"> + <format property="human" pattern="d MMMM yyyy, HH:mm:ss" locale="en,US"/> + <format property="short" pattern="yyyyMMddHHmmss"/> + </tstamp> + <!-- some default in case something went wrong getting the revision --> <property name="version.number" value="-unknown-"/> <property name="init.avail" value="yes"/> + <!-- Local libs (developer use.) --> <mkdir dir="${lib-extra.dir}"/> @@ -321,6 +350,7 @@ INITIALISATION </fileset> <pathelement location="${ant.jar}"/> <path refid="lib.extra"/> + <path refid="dependency.classpath"/> </path> <!-- And print-out what we are building --> @@ -986,6 +1016,11 @@ PACKED QUICK BUILD (PACK) <target name="pack.lib" depends="pack.pre-lib" unless="pack.lib.available"> <mkdir dir="${build-pack.dir}/lib"/> + <!-- First copy maven dependencies --> + <copy todir="${build-pack.dir}/lib"> + <fileset refid="dependency.fileset" /> + <mapper type="flatten" /> + </copy> <jar destfile="${build-pack.dir}/lib/scala-library.jar"> <fileset dir="${build-quick.dir}/classes/library"> <exclude name="scala/dbc/**"/> diff --git a/classpath.SAMPLE b/classpath.SAMPLE index 69c2baeba7..9e607a41d9 100644 --- a/classpath.SAMPLE +++ b/classpath.SAMPLE @@ -3,10 +3,9 @@ <classpathentry kind="src" path="src/compiler"/> <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry exported="true" kind="lib" path="lib/msil.jar"/> + <classpathentry kind="lib" path="lib/msil.jar"/> <classpathentry kind="lib" path="lib/jline.jar"/> - <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> - <classpathentry exported="true" kind="lib" path="lib/fjbg.jar"/> + <classpathentry kind="lib" path="lib/fjbg.jar"/> <classpathentry kind="lib" path="lib/forkjoin.jar"/> <classpathentry kind="lib" path="lib/ant/ant.jar"/> <classpathentry kind="output" path="build/quick/classes/compiler"/> diff --git a/src/actors/scala/actors/Actor.scala b/src/actors/scala/actors/Actor.scala index aab533ae8d..bc9bbc6ef0 100644 --- a/src/actors/scala/actors/Actor.scala +++ b/src/actors/scala/actors/Actor.scala @@ -1,3 +1,5 @@ + + /* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2005-2011, LAMP/EPFL ** @@ -246,8 +248,8 @@ object Actor extends Combinators { rawSelf.react(new RecursiveProxyHandler(rawSelf, f)) private class RecursiveProxyHandler(a: InternalReplyReactor, f: PartialFunction[Any, Unit]) - extends scala.runtime.AbstractPartialFunction[Any, Unit] { - def _isDefinedAt(m: Any): Boolean = + extends PartialFunction[Any, Unit] { + def isDefinedAt(m: Any): Boolean = true // events are immediately removed from the mailbox def apply(m: Any) { if (f.isDefinedAt(m)) f(m) @@ -404,5 +406,5 @@ trait Actor extends InternalActor with ReplyReactor { this } -} + } diff --git a/src/actors/scala/actors/Future.scala b/src/actors/scala/actors/Future.scala index eec43013d3..735c13190b 100644 --- a/src/actors/scala/actors/Future.scala +++ b/src/actors/scala/actors/Future.scala @@ -200,8 +200,8 @@ object Futures { Actor.timer.schedule(timerTask, timeout) def awaitWith(partFuns: Seq[PartialFunction[Any, Pair[Int, Any]]]) { - val reaction: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] { - def _isDefinedAt(msg: Any) = msg match { + val reaction: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] { + def isDefinedAt(msg: Any) = msg match { case TIMEOUT => true case _ => partFuns exists (_ isDefinedAt msg) } diff --git a/src/actors/scala/actors/Reactor.scala b/src/actors/scala/actors/Reactor.scala index 8fc7578344..206a97d97c 100644 --- a/src/actors/scala/actors/Reactor.scala +++ b/src/actors/scala/actors/Reactor.scala @@ -38,8 +38,8 @@ private[actors] object Reactor { } } - val waitingForNone: PartialFunction[Any, Unit] = new scala.runtime.AbstractPartialFunction[Any, Unit] { - def _isDefinedAt(x: Any) = false + val waitingForNone: PartialFunction[Any, Unit] = new PartialFunction[Any, Unit] { + def isDefinedAt(x: Any) = false def apply(x: Any) {} } } diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml index 673c3dfada..c3f8a4531c 100644 --- a/src/build/maven/scala-library-pom.xml +++ b/src/build/maven/scala-library-pom.xml @@ -30,17 +30,24 @@ <system>JIRA</system> <url>https://issues.scala-lang.org/</url> </issueManagement> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> + <dependencies> + <dependency> + <groupId>org.skife.com.typesafe.config</groupId> + <artifactId>typesafe-config</artifactId> + <version>0.3.0</version> + </dependency> + </dependencies> + <distributionManagement> + <repository> + <id>scala-tools.org</id> + <url>@RELEASE_REPOSITORY@</url> + </repository> + <snapshotRepository> + <id>scala-tools.org</id> + <url>@SNAPSHOT_REPOSITORY@</url> + <uniqueVersion>false</uniqueVersion> + </snapshotRepository> + </distributionManagement> <developers> <developer> <id>lamp</id> diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index a2dd6fc4c3..8ea3cd511a 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -138,26 +138,47 @@ trait Definitions extends reflect.api.StandardDefinitions { // symbols related to packages var emptypackagescope: Scope = null //debug - // This is the package _root_. The actual root cannot be referenced at - // the source level, but _root_ is essentially a function () => <root>. - lazy val RootPackage: Symbol = { - val rp = ( - NoSymbol.newValue(nme.ROOTPKG, NoPosition, FINAL | MODULE | PACKAGE | JAVA) - setInfo NullaryMethodType(RootClass.tpe) - ) - RootClass.sourceModule = rp - rp + sealed trait WellKnownSymbol extends Symbol { + this initFlags TopLevelCreationFlags } + // Features common to RootClass and RootPackage, the roots of all + // type and term symbols respectively. + sealed trait RootSymbol extends WellKnownSymbol { + final override def isRootSymbol = true + } + // This is the package _root_. The actual root cannot be referenced at + // the source level, but _root_ is essentially a function => <root>. + final object RootPackage extends ModuleSymbol(NoSymbol, NoPosition, nme.ROOTPKG) with RootSymbol { + this setInfo NullaryMethodType(RootClass.tpe) + RootClass.sourceModule = this - // This is the actual root of everything, including the package _root_. - lazy val RootClass: ModuleClassSymbol = ( - NoSymbol.newModuleClassSymbol(tpnme.ROOT, NoPosition, FINAL | MODULE | PACKAGE | JAVA) - setInfo rootLoader - ) + override def isRootPackage = true + } + // This is <root>, the actual root of everything except the package _root_. + // <root> and _root_ (RootPackage and RootClass) should be the only "well known" + // symbols owned by NoSymbol. All owner chains should go through RootClass, + // although it is probable that some symbols are created as direct children + // of NoSymbol to ensure they will not be stumbled upon. (We should designate + // a better encapsulated place for that.) + final object RootClass extends ModuleClassSymbol(NoSymbol, NoPosition, tpnme.ROOT) with RootSymbol { + this setInfo rootLoader + + override def isRoot = true + override def isEffectiveRoot = true + override def isStatic = true + override def isNestedClass = false + override def ownerOfNewSymbols = EmptyPackageClass + } // The empty package, which holds all top level types without given packages. - lazy val EmptyPackage = RootClass.newPackage(nme.EMPTY_PACKAGE_NAME, NoPosition, FINAL) - lazy val EmptyPackageClass = EmptyPackage.moduleClass - + final object EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { + override def isEmptyPackage = true + } + final object EmptyPackageClass extends ModuleClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol { + override def isEffectiveRoot = true + override def isEmptyPackageClass = true + } + // It becomes tricky to create dedicated objects for other symbols because + // of initialization order issues. lazy val JavaLangPackage = getModule(sn.JavaLang) lazy val JavaLangPackageClass = JavaLangPackage.moduleClass lazy val ScalaPackage = getModule(nme.scala_) @@ -524,26 +545,54 @@ trait Definitions extends reflect.api.StandardDefinitions { else nme.genericWrapArray } + @deprecated("Use isTupleType", "2.10.0") + def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp) + def tupleField(n: Int, j: Int) = getMember(TupleClass(n), nme.productAccessorName(j)) - def isTupleType(tp: Type): Boolean = isTupleType(tp, false) - def isTupleTypeOrSubtype(tp: Type): Boolean = isTupleType(tp, true) - private def isTupleType(tp: Type, subtypeOK: Boolean) = tp.normalize match { - case TypeRef(_, sym, args) if args.nonEmpty => - val len = args.length - len <= MaxTupleArity && { - val tsym = TupleClass(len) - (sym == tsym) || (subtypeOK && !tp.isHigherKinded && sym.isSubClass(tsym)) - } - case _ => false + def isTupleSymbol(sym: Symbol) = TupleClass contains unspecializedSymbol(sym) + + def unspecializedSymbol(sym: Symbol): Symbol = { + if (sym hasFlag SPECIALIZED) { + // add initialization from its generic class constructor + val genericName = nme.unspecializedName(sym.name) + val member = sym.owner.info.decl(genericName.toTypeName) + member } + else sym + } - def tupleType(elems: List[Type]) = { - val len = elems.length - if (len <= MaxTupleArity) { - val sym = TupleClass(len) - typeRef(sym.typeConstructor.prefix, sym, elems) - } else NoType - } + // Checks whether the given type is true for the given condition, + // or if it is a specialized subtype of a type for which it is true. + // + // Origins notes: + // An issue was introduced with specialization in that the implementation + // of "isTupleType" in Definitions relied upon sym == TupleClass(elems.length). + // This test is untrue for specialized tuples, causing mysterious behavior + // because only some tuples are specialized. + def isPossiblySpecializedType(tp: Type)(cond: Type => Boolean) = { + cond(tp) || (tp match { + case TypeRef(pre, sym, args) if sym hasFlag SPECIALIZED => + cond(tp baseType unspecializedSymbol(sym)) + case _ => + false + }) + } + // No normalization. + def isTupleTypeDirect(tp: Type) = isPossiblySpecializedType(tp) { + case TypeRef(_, sym, args) if args.nonEmpty => + val len = args.length + len <= MaxTupleArity && sym == TupleClass(len) + case _ => false + } + def isTupleType(tp: Type) = isTupleTypeDirect(tp.normalize) + + def tupleType(elems: List[Type]) = { + val len = elems.length + if (len <= MaxTupleArity) { + val sym = TupleClass(len) + typeRef(sym.typeConstructor.prefix, sym, elems) + } else NoType + } lazy val ProductRootClass: Symbol = getRequiredClass("scala.Product") def Product_productArity = getMember(ProductRootClass, nme.productArity) @@ -601,8 +650,8 @@ trait Definitions extends reflect.api.StandardDefinitions { def isFunctionType(tp: Type): Boolean = tp.normalize match { case TypeRef(_, sym, args) if args.nonEmpty => - val len = args.length - len < MaxFunctionArity && sym == FunctionClass(len - 1) + val arity = args.length - 1 // -1 is the return type + arity <= MaxFunctionArity && sym == FunctionClass(arity) case _ => false } @@ -1090,9 +1139,14 @@ trait Definitions extends reflect.api.StandardDefinitions { def init() { if (isInitialized) return + // Still fiddling with whether it's cleaner to do some of this setup here + // or from constructors. The latter approach tends to invite init order issues. EmptyPackageClass setInfo ClassInfoType(Nil, newPackageScope(EmptyPackageClass), EmptyPackageClass) EmptyPackage setInfo EmptyPackageClass.tpe + connectModuleToClass(EmptyPackage, EmptyPackageClass) + connectModuleToClass(RootPackage, RootClass) + RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage diff --git a/src/compiler/scala/reflect/internal/Flags.scala b/src/compiler/scala/reflect/internal/Flags.scala index 3110d73461..ce1c8d0908 100644 --- a/src/compiler/scala/reflect/internal/Flags.scala +++ b/src/compiler/scala/reflect/internal/Flags.scala @@ -84,7 +84,7 @@ import scala.collection.{ mutable, immutable } */ class ModifierFlags { final val IMPLICIT = 0x00000200 - final val FINAL = 0x00000020 + final val FINAL = 0x00000020 // May not be overridden. Note that java final implies much more than scala final. final val PRIVATE = 0x00000004 final val PROTECTED = 0x00000001 diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 9fb7b5b747..e2c253628c 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -283,13 +283,13 @@ trait StdNames extends NameManglers { self: SymbolTable => val TYPE_ : NameType = "TYPE" val TypeTree: NameType = "TypeTree" val UNIT : NameType = "UNIT" - val _isDefinedAt: NameType = "_isDefinedAt" val add_ : NameType = "add" val annotation: NameType = "annotation" val anyValClass: NameType = "anyValClass" val append: NameType = "append" val apply: NameType = "apply" val applyDynamic: NameType = "applyDynamic" + val applyOrElse: NameType = "applyOrElse" val args : NameType = "args" val argv : NameType = "argv" val arrayValue: NameType = "arrayValue" @@ -357,7 +357,6 @@ trait StdNames extends NameManglers { self: SymbolTable => val main: NameType = "main" val map: NameType = "map" val mirror : NameType = "mirror" - val missingCase: NameType = "missingCase" val ne: NameType = "ne" val newArray: NameType = "newArray" val newScopeWith: NameType = "newScopeWith" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index b58a0ef7d5..bb11ca634a 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -55,6 +55,12 @@ abstract class SymbolTable extends api.Universe log(msg + ": " + result) result } + private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = { + if (cond(result)) + log(msg + ": " + result) + + result + } /** Are we compiling for Java SE? */ // def forJVM: Boolean diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index f4039cf6d3..4473d63f5f 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -451,12 +451,23 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isVarargsMethod = isMethod && hasFlag(VARARGS) /** Package tests */ - final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME - final def isEmptyPackageClass = isPackageClass && name == tpnme.EMPTY_PACKAGE_NAME final def isPackage = isModule && hasFlag(PACKAGE) final def isPackageClass = isClass && hasFlag(PACKAGE) - final def isRoot = isPackageClass && owner == NoSymbol - final def isRootPackage = isPackage && owner == NoSymbol + + /** Overridden in custom objects in Definitions */ + def isRoot = false + def isRootPackage = false + def isRootSymbol = false // RootPackage and RootClass. TODO: also NoSymbol. + def isEmptyPackage = false + def isEmptyPackageClass = false + + /** Is this symbol an effective root for fullname string? + */ + def isEffectiveRoot = false + + /** For RootClass, EmptyPackageClass. For all other symbols, itself. + */ + def ownerOfNewSymbols = this /** Does this symbol denote a wrapper created by the repl? */ final def isInterpreterWrapper = ( @@ -464,9 +475,6 @@ trait Symbols extends api.Symbols { self: SymbolTable => && owner.isPackageClass && nme.isReplWrapperName(name) ) - /** Is this symbol an effective root for fullname string? - */ - def isEffectiveRoot = isRoot || isEmptyPackageClass /** Term symbols with the exception of static parts of Java classes and packages. */ @@ -543,7 +551,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Conditions where we omit the prefix when printing a symbol, to avoid * unpleasantries like Predef.String, $iw.$iw.Foo and <empty>.Bippy. */ - final def isOmittablePrefix = !settings.debug.value && ( + final def isOmittablePrefix = /*!settings.debug.value &&*/ ( UnqualifiedOwners(skipPackageObject) || isEmptyPrefix ) @@ -652,8 +660,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isModuleVar = hasFlag(MODULEVAR) /** Is this symbol static (i.e. with no outer instance)? */ - final def isStatic: Boolean = - hasFlag(STATIC) || isRoot || owner.isStaticOwner + def isStatic = (this hasFlag STATIC) || owner.isStaticOwner /** Is this symbol a static constructor? */ final def isStaticConstructor: Boolean = @@ -685,8 +692,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def isConstant: Boolean = isStable && isConstantType(tpe.resultType) /** Is this class nested in another class or module (not a package)? */ - final def isNestedClass: Boolean = - isClass && !isRoot && !owner.isPackageClass + def isNestedClass = isClass && !owner.isPackageClass /** Is this class locally defined? * A class is local, if @@ -1191,9 +1197,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => var ph = phase while (ph.prev.keepsTypeParams) ph = ph.prev - - if (ph ne phase) - debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph) + // + // if (ph ne phase) + // debuglog("checking unsafeTypeParams(" + this + ") at: " + phase + " reading at: " + ph) ph } @@ -2045,7 +2051,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def fullNameString: String = { def recur(sym: Symbol): String = { - if (sym.isRoot || sym.isRootPackage || sym == NoSymbol) sym.nameString + if (sym.isRootSymbol || sym == NoSymbol) sym.nameString else if (sym.owner.isEffectiveRoot) sym.nameString else recur(sym.effectiveOwner.enclClass) + "." + sym.nameString } @@ -2095,7 +2101,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => case rt => " <: " + rt } ) - else if (isModule) moduleClass.infoString(tp) + else if (isModule) "" // avoid "object X of type X.type" else tp match { case PolyType(tparams, res) => typeParamsString(tp) + infoString(res) case NullaryMethodType(res) => infoString(res) @@ -2119,7 +2125,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => else "" def defaultFlagMask = - if (settings.debug.value) -1L + if (isAbstractType) ExplicitFlags + else if (settings.debug.value) -1L else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE else ExplicitFlags diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index bb9549deba..5afa5343ed 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -904,6 +904,12 @@ trait Types extends api.Types { self: SymbolTable => else str } + /** The string representation of this type when the direct object in a sentence. + * Normally this is no different from the regular representation, but modules + * read better as "object Foo" here and "Foo.type" the rest of the time. + */ + def directObjectString = safeToString + /** A test whether a type contains any unification type variables. */ def isGround: Boolean = this match { case TypeVar(_, constr) => @@ -1224,8 +1230,7 @@ trait Types extends api.Types { self: SymbolTable => else if (sym.isModuleClass) sym.fullNameString + "." else sym.nameString + ".this." override def safeToString: String = - if (sym.isRoot) "<root>" - else if (sym.isEmptyPackageClass) "<empty>" + if (sym.isEffectiveRoot) "" + sym.name else super.safeToString override def narrow: Type = this override def kind = "ThisType" @@ -1851,6 +1856,35 @@ trait Types extends api.Types { self: SymbolTable => // advantage to call TypeRef directly. override def typeConstructor = TypeRef(pre, sym, Nil) } + + class ModuleTypeRef(pre0: Type, sym0: Symbol) extends NoArgsTypeRef(pre0, sym0) with ClassTypeRef { + require(sym.isModuleClass, sym) + private[this] var narrowedCache: Type = _ + override def isStable = true + override def narrow = { + if (narrowedCache eq null) + narrowedCache = singleType(pre, sym.sourceModule) + + narrowedCache + } + final override def isNotNull = true + override protected def finishPrefix(rest: String) = objectPrefix + rest + override def directObjectString = super.safeToString + override def toLongString = toString + override def safeToString = narrow.toString + } + class PackageTypeRef(pre0: Type, sym0: Symbol) extends ModuleTypeRef(pre0, sym0) { + require(sym.isPackageClass, sym) + override protected def finishPrefix(rest: String) = packagePrefix + rest + } + class RefinementTypeRef(sym0: Symbol) extends NoArgsTypeRef(NoType, sym0) with ClassTypeRef { + require(sym.isRefinementClass, sym) + + // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers + override protected def normalizeImpl: Type = sym.info.normalize + override protected def finishPrefix(rest: String) = "" + thisInfo + } + class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType { // A reference (in a Scala program) to a type that has type parameters, but where the reference // does not include type arguments. Note that it doesn't matter whether the symbol refers @@ -1898,10 +1932,6 @@ trait Types extends api.Types { self: SymbolTable => // !!! 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 - override def baseType(clazz: Symbol): Type = if (sym == clazz) this else transform(sym.info.baseType(clazz)) @@ -2147,12 +2177,15 @@ trait Types extends api.Types { self: SymbolTable => } } - private def preString = ( - // ensure that symbol is not a local copy with a name coincidence - if (!settings.debug.value && shorthands(sym.fullName) && sym.ownerChain.forall(_.isClass)) "" - else pre.prefixString + // ensure that symbol is not a local copy with a name coincidence + private def needsPreString = ( + settings.debug.value + || !shorthands(sym.fullName) + || sym.ownerChain.exists(s => !s.isClass) ) + private def preString = if (needsPreString) pre.prefixString else "" private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]") + def refinementString = ( if (sym.isStructuralRefinement) ( decls filter (sym => sym.isPossibleInRefinement && sym.isPublic) @@ -2162,25 +2195,23 @@ trait Types extends api.Types { self: SymbolTable => else "" ) - private def finishPrefix(rest: String) = ( - if (sym.isPackageClass) packagePrefix + rest - else if (sym.isModuleClass) objectPrefix + rest - else if (!sym.isInitialized) rest - else if (sym.isAnonymousClass && !phase.erasedTypes) parentsString(thisInfo.parents) + refinementString - else if (sym.isRefinementClass) "" + thisInfo + protected def finishPrefix(rest: String) = ( + if (sym.isInitialized && sym.isAnonymousClass && !phase.erasedTypes) + parentsString(thisInfo.parents) + refinementString else rest ) private def customToString = this match { case TypeRef(_, RepeatedParamClass, arg :: _) => arg + "*" case TypeRef(_, ByNameParamClass, arg :: _) => "=> " + arg case _ => + def targs = normalize.typeArgs + if (isFunctionType(this)) { - val targs = normalize.typeArgs // Aesthetics: printing Function1 as T => R rather than (T) => R // ...but only if it's not a tuple, so ((T1, T2)) => R is distinguishable // from (T1, T2) => R. targs match { - case in :: out :: Nil if !isTupleTypeOrSubtype(in) => + case in :: out :: Nil if !isTupleType(in) => // A => B => C should be (A => B) => C or A => (B => C) val in_s = if (isFunctionType(in)) "(" + in + ")" else "" + in val out_s = if (isFunctionType(out)) "(" + out + ")" else "" + out @@ -2189,9 +2220,9 @@ trait Types extends api.Types { self: SymbolTable => xs.init.mkString("(", ", ", ")") + " => " + xs.last } } - else if (isTupleTypeOrSubtype(this)) - normalize.typeArgs.mkString("(", ", ", if (hasLength(normalize.typeArgs, 1)) ",)" else ")") - else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (normalize ne this)) + else if (isTupleType(this)) + targs.mkString("(", ", ", if (hasLength(targs, 1)) ",)" else ")") + else if (sym.isAliasType && prefixChain.exists(_.termSymbol.isSynthetic) && (this ne this.normalize)) "" + normalize else "" @@ -2226,6 +2257,9 @@ trait Types extends api.Types { self: SymbolTable => else { if (sym.isAliasType) new NoArgsTypeRef(pre, sym) with AliasTypeRef else if (sym.isAbstractType) new NoArgsTypeRef(pre, sym) with AbstractTypeRef + else if (sym.isRefinementClass) new RefinementTypeRef(sym) + else if (sym.isPackageClass) new PackageTypeRef(pre, sym) + else if (sym.isModuleClass) new ModuleTypeRef(pre, sym) else new NoArgsTypeRef(pre, sym) with ClassTypeRef } }) @@ -3615,6 +3649,23 @@ trait Types extends api.Types { self: SymbolTable => } } + class TypeUnwrapper(poly: Boolean, existential: Boolean, annotated: Boolean, nullary: Boolean) extends (Type => Type) { + def apply(tp: Type): Type = tp match { + case AnnotatedType(_, underlying, _) if annotated => apply(underlying) + case ExistentialType(_, underlying) if existential => apply(underlying) + case PolyType(_, underlying) if poly => apply(underlying) + case NullaryMethodType(underlying) if nullary => apply(underlying) + case tp => tp + } + } + class ClassUnwrapper(existential: Boolean) extends TypeUnwrapper(poly = true, existential, annotated = true, nullary = false) { + override def apply(tp: Type) = super.apply(tp.normalize) + } + + object unwrapToClass extends ClassUnwrapper(existential = true) { } + object unwrapToStableClass extends ClassUnwrapper(existential = false) { } + object unwrapWrapperTypes extends TypeUnwrapper(true, true, true, true) { } + trait AnnotationFilter extends TypeMap { def keepAnnotation(annot: AnnotationInfo): Boolean @@ -4585,31 +4636,22 @@ trait Types extends api.Types { self: SymbolTable => object adaptToNewRunMap extends TypeMap { private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { - if (phase.flatClasses) { + if (phase.flatClasses || sym.isRootSymbol || (pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) sym - } else if (sym == definitions.RootClass) { - definitions.RootClass - } else if (sym == definitions.RootPackage) { - definitions.RootPackage - } else if (sym.isModuleClass) { + else if (sym.isModuleClass) { val sourceModule1 = adaptToNewRun(pre, sym.sourceModule) - var result = sourceModule1.moduleClass - if (result == NoSymbol) result = sourceModule1.initialize.moduleClass - if (result != NoSymbol) result - else { + + sourceModule1.moduleClass orElse sourceModule1.initialize.moduleClass orElse { val msg = "Cannot adapt module class; sym = %s, sourceModule = %s, sourceModule.moduleClass = %s => sourceModule1 = %s, sourceModule1.moduleClass = %s" debuglog(msg.format(sym, sym.sourceModule, sym.sourceModule.moduleClass, sourceModule1, sourceModule1.moduleClass)) sym } - } else if ((pre eq NoPrefix) || (pre eq NoType) || sym.isPackageClass) { - sym - } else { - var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) - if (rebind0 == NoSymbol) { + } + else { + var rebind0 = pre.findMember(sym.name, BRIDGE, 0, true) orElse { if (sym.isAliasType) throw missingAliasException debugwarn(pre+"."+sym+" does no longer exist, phase = "+phase) throw new MissingTypeControl // For build manager and presentation compiler purposes - //assert(false, pre+"."+sym+" does no longer exist, phase = "+phase) } /** The two symbols have the same fully qualified name */ def corresponds(sym1: Symbol, sym2: Symbol): Boolean = @@ -4628,12 +4670,10 @@ trait Types extends api.Types { self: SymbolTable => ", rebind = " + rebind0.fullLocationString ) } - val rebind = rebind0.suchThat(sym => sym.isType || sym.isStable) - if (rebind == NoSymbol) { + rebind0.suchThat(sym => sym.isType || sym.isStable) orElse { debuglog("" + phase + " " +phase.flatClasses+sym.owner+sym.name+" "+sym.isType) throw new MalformedType(pre, sym.nameString) } - rebind } } def apply(tp: Type): Type = tp match { @@ -5454,9 +5494,14 @@ trait Types extends api.Types { self: SymbolTable => case _: ClassSymbol => if (isRaw(sym1, tr1.args)) isSubType(rawToExistential(tp1), tp2, depth) - else - sym1.name == tpnme.REFINE_CLASS_NAME && + else if (sym1.isModuleClass) tp2 match { + case SingleType(_, sym2) => sym1 == sym2 + case _ => false + } + else if (sym1.isRefinementClass) isSubType(sym1.info, tp2, depth) + else false + case _: TypeSymbol => if (sym1 hasFlag DEFERRED) { val tp1a = tp1.bounds.hi diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala index e4504702d4..3792c26c34 100644 --- a/src/compiler/scala/tools/cmd/FromString.scala +++ b/src/compiler/scala/tools/cmd/FromString.scala @@ -14,9 +14,9 @@ import scala.reflect.OptManifest * example instances are in the companion object, but in general * either IntFromString will suffice or you'll want custom transformers. */ -abstract class FromString[+T](implicit m: OptManifest[T]) extends scala.runtime.AbstractPartialFunction[String, T] { +abstract class FromString[+T](implicit m: OptManifest[T]) extends PartialFunction[String, T] { def apply(s: String): T - def _isDefinedAt(s: String): Boolean = true + def isDefinedAt(s: String): Boolean = true def zero: T = apply("") def targetString: String = m.toString @@ -30,20 +30,20 @@ object FromString { /** Path related stringifiers. */ val ExistingFile: FromString[File] = new FromString[File] { - override def _isDefinedAt(s: String) = toFile(s).isFile + override def isDefinedAt(s: String) = toFile(s).isFile def apply(s: String): File = if (isDefinedAt(s)) toFile(s) else cmd.runAndExit(println("'%s' is not an existing file." format s)) } val ExistingDir: FromString[Directory] = new FromString[Directory] { - override def _isDefinedAt(s: String) = toDir(s).isDirectory + override def isDefinedAt(s: String) = toDir(s).isDirectory def apply(s: String): Directory = if (isDefinedAt(s)) toDir(s) else cmd.runAndExit(println("'%s' is not an existing directory." format s)) } def ExistingDirRelativeTo(root: Directory) = new FromString[Directory] { private def resolve(s: String) = toDir(s) toAbsoluteWithRoot root toDirectory - override def _isDefinedAt(s: String) = resolve(s).isDirectory + override def isDefinedAt(s: String) = resolve(s).isDirectory def apply(s: String): Directory = if (isDefinedAt(s)) resolve(s) else cmd.runAndExit(println("'%s' is not an existing directory." format resolve(s))) @@ -65,7 +65,7 @@ object FromString { /** Implicit as the most likely to be useful as-is. */ implicit val IntFromString: FromString[Int] = new FromString[Int] { - override def _isDefinedAt(s: String) = safeToInt(s).isDefined + override def isDefinedAt(s: String) = safeToInt(s).isDefined def apply(s: String) = safeToInt(s).get def safeToInt(s: String): Option[Int] = try Some(java.lang.Integer.parseInt(s)) catch { case _: NumberFormatException => None } } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index 8e326c202a..7b7135d180 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -121,6 +121,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (settings.debug.value) inform("[running phase " + name + " on icode]") + if (settings.Xverify.value && !SigParser.isParserAvailable) + global.warning("signature verification requested by signature parser unavailable: signatures not checked") + if (settings.Xdce.value) for ((sym, cls) <- icodes.classes if inliner.isClosureClass(sym) && !deadCode.liveClosures(sym)) icodes.classes -= sym @@ -285,6 +288,15 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val emitLines = debugLevel >= 2 val emitVars = debugLevel >= 3 + // bug had phase with wrong name; leaving enabled for brief pseudo deprecation + private val checkSignatures = ( + (settings.check containsName phaseName) + || (settings.check.value contains "genjvm") && { + global.warning("This option will be removed: please use -Ycheck:%s, not -Ycheck:genjvm." format phaseName) + true + } + ) + /** For given symbol return a symbol corresponding to a class that should be declared as inner class. * * For example: @@ -726,10 +738,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with def addGenericSignature(jmember: JMember, sym: Symbol, owner: Symbol) { if (needsGenericSignature(sym)) { val memberTpe = beforeErasure(owner.thisType.memberInfo(sym)) - // println("addGenericSignature sym: " + sym.fullName + " : " + memberTpe + " sym.info: " + sym.info) - // println("addGenericSignature: "+ (sym.ownerChain map (x => (x.name, x.isImplClass)))) + erasure.javaSig(sym, memberTpe) foreach { sig => - debuglog("sig(" + jmember.getName + ", " + sym + ", " + owner + ") " + sig) + // This seems useful enough in the general case. + log(sig) /** Since we're using a sun internal class for signature validation, * we have to allow for it not existing or otherwise malfunctioning: * in which case we treat every signature as valid. Medium term we @@ -743,7 +755,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig)) return } - if ((settings.check.value contains "genjvm")) { + if (checkSignatures) { val normalizedTpe = beforeErasure(erasure.prepareSigMap(memberTpe)) val bytecodeTpe = owner.thisType.memberInfo(sym) if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) { @@ -871,7 +883,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with debuglog("Adding field: " + f.symbol.fullName) val jfield = jclass.addNewField( - javaFlags(f.symbol) | javaFieldFlags(f.symbol), + javaFieldFlags(f.symbol), javaName(f.symbol), javaType(f.symbol.tpe) ) @@ -1915,16 +1927,30 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with val privateFlag = sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) - // This does not check .isFinal (which checks flags for the FINAL flag), - // instead checking rawflags for that flag so as to exclude symbols which - // received lateFINAL. These symbols are eligible for inlining, but to - // avoid breaking proxy software which depends on subclassing, we avoid - // insisting on their finality in the bytecode. + // Final: the only fields which can receive ACC_FINAL are eager vals. + // Neither vars nor lazy vals can, because: + // + // Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3 + // "Another problem is that the specification allows aggressive + // optimization of final fields. Within a thread, it is permissible to + // reorder reads of a final field with those modifications of a final + // field that do not take place in the constructor." + // + // A var or lazy val which is marked final still has meaning to the + // scala compiler. The word final is heavily overloaded unfortunately; + // for us it means "not overridable". At present you can't override + // vars regardless; this may change. + // + // The logic does not check .isFinal (which checks flags for the FINAL flag, + // and includes symbols marked lateFINAL) instead inspecting rawflags so + // we can exclude lateFINAL. Such symbols are eligible for inlining, but to + // avoid breaking proxy software which depends on subclassing, we do not + // emit ACC_FINAL. val finalFlag = ( ((sym.rawflags & (Flags.FINAL | Flags.MODULE)) != 0) && !sym.enclClass.isInterface && !sym.isClassConstructor - && !sym.isMutable // fix for SI-3569, it is too broad? + && !sym.isMutable // lazy vals and vars both ) mkFlags( @@ -1939,13 +1965,13 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (sym.hasFlag(Flags.SYNCHRONIZED)) JAVA_ACC_SYNCHRONIZED else 0 ) } - def javaFieldFlags(sym: Symbol) = { - mkFlags( + def javaFieldFlags(sym: Symbol) = ( + javaFlags(sym) | mkFlags( if (sym hasAnnotation TransientAttr) ACC_TRANSIENT else 0, if (sym hasAnnotation VolatileAttr) ACC_VOLATILE else 0, if (sym.isMutable) 0 else ACC_FINAL ) - } + ) def isTopLevelModule(sym: Symbol): Boolean = afterPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass } diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index dd1c75c322..702d643fb4 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -620,7 +620,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { case tp: TypeRef if definitions.isByNameParamType(tp) => nameBuffer append "⇒ " appendType0(tp.args.head) - case tp: TypeRef if definitions.isTupleTypeOrSubtype(tp) => + case tp: TypeRef if definitions.isTupleType(tp) => val args = tp.normalize.typeArgs nameBuffer append '(' appendTypes0(args, ", ") diff --git a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala index 33ef4a432d..2f47685757 100644 --- a/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala +++ b/src/compiler/scala/tools/nsc/interpreter/AbstractOrMissingHandler.scala @@ -6,8 +6,8 @@ package scala.tools.nsc package interpreter -class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends scala.runtime.AbstractPartialFunction[Throwable, T] { - def _isDefinedAt(t: Throwable) = t match { +class AbstractOrMissingHandler[T](onError: String => Unit, value: T) extends PartialFunction[Throwable, T] { + def isDefinedAt(t: Throwable) = t match { case _: AbstractMethodError => true case _: NoSuchMethodError => true case _: MissingRequirementError => true diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala index 015dc2a7f1..808f549304 100644 --- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala +++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala @@ -15,7 +15,7 @@ trait CompletionOutput { val global: Global import global._ - import definitions.{ isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType } + import definitions.{ isTupleType, isFunctionType, isRepeatedParamType } /** Reducing fully qualified noise for some common packages. */ @@ -48,11 +48,11 @@ trait CompletionOutput { def typeToString(tp: Type): String = relativize( tp match { - case x if isFunctionType(x) => functionString(x) - case x if isTupleTypeOrSubtype(x) => tupleString(x) - case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*" - case mt @ MethodType(_, _) => methodTypeToString(mt) - case x => x.toString + case x if isFunctionType(x) => functionString(x) + case x if isTupleType(x) => tupleString(x) + case x if isRepeatedParamType(x) => typeToString(x.typeArgs.head) + "*" + case mt @ MethodType(_, _) => methodTypeToString(mt) + case x => x.toString } ) diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala index be5a9907b8..43aad9f591 100644 --- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala +++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala @@ -425,7 +425,7 @@ trait ParallelMatching extends ast.TreeDSL // Should the given pattern join the expanded pivot in the success matrix? If so, // this partial function will be defined for the pattern, and the result of the apply // is the expanded sequence of new patterns. - lazy val successMatrixFn = new scala.runtime.AbstractPartialFunction[Pattern, List[Pattern]] { + lazy val successMatrixFn = new PartialFunction[Pattern, List[Pattern]] { private def seqIsDefinedAt(x: SequenceLikePattern) = (hasStar, x.hasStar) match { case (true, true) => true case (true, false) => pivotLen <= x.nonStarLength @@ -433,7 +433,7 @@ trait ParallelMatching extends ast.TreeDSL case (false, false) => pivotLen == x.nonStarLength } - def _isDefinedAt(pat: Pattern) = pat match { + def isDefinedAt(pat: Pattern) = pat match { case x: SequenceLikePattern => seqIsDefinedAt(x) case WildcardPattern() => true case _ => false diff --git a/src/compiler/scala/tools/nsc/matching/Patterns.scala b/src/compiler/scala/tools/nsc/matching/Patterns.scala index 8bdf83fda4..4f6a4c8dc0 100644 --- a/src/compiler/scala/tools/nsc/matching/Patterns.scala +++ b/src/compiler/scala/tools/nsc/matching/Patterns.scala @@ -343,10 +343,9 @@ trait Patterns extends ast.TreeDSL { def apply(x: Apply): Pattern = { val Apply(fn, args) = x def isModule = x.symbol.isModule || x.tpe.termSymbol.isModule - def isTuple = isTupleTypeOrSubtype(fn.tpe) if (fn.isType) { - if (isTuple) TuplePattern(x) + if (isTupleType(fn.tpe)) TuplePattern(x) else ConstructorPattern(x) } else if (args.isEmpty) { diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index fdde8f9990..14b3bcc8ce 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -31,7 +31,7 @@ trait ScalaSettings extends AbsScalaSettings protected def defaultClasspath = sys.env.getOrElse("CLASSPATH", ".") /** Enabled under -Xexperimental. */ - protected def experimentalSettings = List[BooleanSetting](YmethodInfer, overrideObjects) + protected def experimentalSettings = List[BooleanSetting](YmethodInfer, overrideObjects, overrideVars) /** Enabled under -Xfuture. */ protected def futureSettings = List[BooleanSetting]() @@ -117,6 +117,7 @@ trait ScalaSettings extends AbsScalaSettings * -Y "Private" settings */ val overrideObjects = BooleanSetting ("-Yoverride-objects", "Allow member objects to be overridden.") + val overrideVars = BooleanSetting ("-Yoverride-vars", "Allow vars to be overridden.") val Yhelp = BooleanSetting ("-Y", "Print a synopsis of private options.") val browse = PhasesSetting ("-Ybrowse", "Browse the abstract syntax tree after") val check = PhasesSetting ("-Ycheck", "Check the tree at the end of") diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala index 59342a36ef..5f7deb87bd 100644 --- a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala @@ -105,7 +105,7 @@ abstract class BrowsingLoaders extends SymbolLoaders { */ override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) { try { - if (root == definitions.RootClass || root == definitions.EmptyPackageClass) + if (root.isEffectiveRoot) // RootClass or EmptyPackageClass super.enterToplevelsFromSource(root, name, src) else browseTopLevel(root, src) diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index f9ff147e82..7eb04eaf40 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -30,15 +30,11 @@ abstract class SymbolLoaders { member } - private def realOwner(root: Symbol): Symbol = { - if (root.isRoot) definitions.EmptyPackageClass else root - } - /** Enter class with given `name` into scope of `root` * and give them `completer` as type. */ def enterClass(root: Symbol, name: String, completer: SymbolLoader): Symbol = { - val owner = realOwner(root) + val owner = root.ownerOfNewSymbols val clazz = owner.newClass(newTypeName(name)) clazz setInfo completer enterIfNew(owner, clazz, completer) @@ -48,7 +44,7 @@ abstract class SymbolLoaders { * and give them `completer` as type. */ def enterModule(root: Symbol, name: String, completer: SymbolLoader): Symbol = { - val owner = realOwner(root) + val owner = root.ownerOfNewSymbols val module = owner.newModule(newTermName(name)) module setInfo completer module.moduleClass setInfo moduleClassLoader diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 61668b1a8a..9dee441527 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -433,10 +433,7 @@ abstract class ClassfileParser { sym.info.decl(part.encode) }//.suchThat(module == _.isModule) - sym = ( - if (sym1 ne NoSymbol) sym1 - else sym.info.decl(part.encode.toTypeName) - ) + sym = sym1 orElse sym.info.decl(part.encode.toTypeName) } } sym diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 7b0f5254b6..1afa1dbf58 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -134,16 +134,6 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case _ => false } - def unspecializedSymbol(sym: Symbol): Symbol = { - if (sym hasFlag SPECIALIZED) { - // add initialization from its generic class constructor - val genericName = nme.unspecializedName(sym.name) - val member = sym.owner.info.decl(genericName.toTypeName) - member - } - else NoSymbol - } - object TypeEnv { /** Return a new type environment binding specialized type parameters of sym to * the given args. Expects the lists to have the same length. @@ -318,7 +308,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else specializedTypeVars(sym).intersect(env.keySet) ) val (methparams, others) = tvars.toList sortBy ("" + _.name) partition (_.owner.isMethod) - debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars) + // debuglog("specName(" + sym + ") env: " + env + " tvars: " + tvars) specializedName(sym.name, methparams map env, others map env) } @@ -518,7 +508,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // 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") + // debuglog("Specializing " + clazz + ", but found " + bytecodeClazz + " already there") bytecodeClazz.info val sClass = clazz.owner.newClass(clazzName, clazz.pos, (clazz.flags | SPECIALIZED) & ~CASE) @@ -574,7 +564,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { parents = parents.head.parents.head :: parents val extraSpecializedMixins = specializedParents(clazz.info.parents map applyContext) if (extraSpecializedMixins.nonEmpty) - debuglog("specializeClass on " + clazz + " founds extra specialized mixins: " + extraSpecializedMixins.mkString(", ")) + debuglog("extra specialized mixins for %s: %s".format(clazz.name.decode, extraSpecializedMixins.mkString(", "))) // If the class being specialized has a self-type, the self type may // require specialization. First exclude classes whose self types have // the same type constructor as the class itself, since they will @@ -652,7 +642,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val NormalizedMember(original) = info(m) if (nonConflicting(env ++ typeEnv(m))) { if (info(m).degenerate) { - debuglog("degenerate normalized member " + m + " info(m): " + info(m)) + debuglog("degenerate normalized member " + m.defString) val specMember = enterMember(cloneInSpecializedClass(m, _ & ~DEFERRED)) info(specMember) = Implementation(original) @@ -660,7 +650,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else debuglog({ val om = forwardToOverload(m) - "normalizedMember " + m + " om: " + om + " typeEnv(om): " + typeEnv(om) + "normalizedMember " + m + " om: " + om + " " + pp(typeEnv(om)) }) } else @@ -668,7 +658,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else if (m.isDeferred) { // abstract methods val specMember = enterMember(cloneInSpecializedClass(m, _ | DEFERRED)) - debuglog("deferred " + specMember.fullName + " remains abstract") + // debuglog("deferred " + specMember.fullName + " remains abstract") info(specMember) = new Abstract(specMember) // was: new Forward(specMember) { @@ -698,20 +688,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { enterMember(specVal) // create accessors - debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name)) + // debuglog("m: " + m + " isLocal: " + nme.isLocalName(m.name) + " specVal: " + specVal.name + " isLocal: " + nme.isLocalName(specVal.name)) + if (nme.isLocalName(m.name)) { val specGetter = mkAccessor(specVal, nme.localToGetter(specVal.name)) setInfo MethodType(Nil, specVal.info) val origGetter = overrideIn(sClass, m.getter(clazz)) info(origGetter) = Forward(specGetter) enterMember(specGetter) enterMember(origGetter) - debuglog("created accessors: " + specGetter + " orig: " + origGetter) + debuglog("specialize accessor in %s: %s -> %s".format(sClass.name.decode, origGetter.name.decode, specGetter.name.decode)) clazz.caseFieldAccessors.find(_.name.startsWith(m.name)) foreach { cfa => val cfaGetter = overrideIn(sClass, cfa) info(cfaGetter) = SpecializedAccessor(specVal) enterMember(cfaGetter) - debuglog("found case field accessor for " + m + " added override " + cfaGetter); + debuglog("override case field accessor %s -> %s".format(m.name.decode, cfaGetter.name.decode)) } if (specVal.isVariable && m.setter(clazz) != NoSymbol) { @@ -724,11 +715,15 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { enterMember(specSetter) enterMember(origSetter) } - } else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses + } + else { // if there are no accessors, specialized methods will need to access this field in specialized subclasses m.resetFlag(PRIVATE) specVal.resetFlag(PRIVATE) + debuglog("no accessors for %s/%s, specialized methods must access field in subclass".format( + m.name.decode, specVal.name.decode)) } - } else if (m.isClass) { + } + else if (m.isClass) { val specClass: Symbol = cloneInSpecializedClass(m, x => x) typeEnv(specClass) = fullEnv specClass.name = specializedName(specClass, fullEnv).toTypeName @@ -787,10 +782,10 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * // etc. */ private def normalizeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv): List[Symbol] = { - debuglog("normalizeMember: " + sym.fullName) sym :: ( if (!sym.isMethod || beforeTyper(sym.typeParams.isEmpty)) Nil else { + // debuglog("normalizeMember: " + sym.fullNameAsName('.').decode) var specializingOn = specializedParams(sym) val unusedStvars = specializingOn filterNot specializedTypeVars(sym.info) @@ -810,7 +805,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val (keys, vals) = env.toList.unzip specMember.name = specializedName(sym, env) - debuglog("normalizing: " + sym + " to " + specMember + " with params " + tps) + // debuglog("%s normalizes to %s%s".format(sym, specMember, + // if (tps.isEmpty) "" else " with params " + tps.mkString(", "))) typeEnv(specMember) = outerEnv ++ env val tps1 = produceTypeParameters(tps, specMember, env) @@ -820,11 +816,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val methodType = sym.info.resultType.instantiateTypeParams(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember) specMember setInfo GenPolyType(tps1, methodType) - debuglog("expanded member: " + sym + ": " + sym.info + - " -> " + specMember + - ": " + specMember.info + - " env: " + env - ) + debuglog("%s expands to %s in %s".format(sym, specMember.name.decode, pp(env))) info(specMember) = NormalizedMember(sym) overloads(sym) ::= Overload(specMember, env) specMember @@ -833,6 +825,17 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { ) } + // concise printing of type env + private def pp(env: TypeEnv): String = { + env.toList.sortBy(_._1.name.toString) map { + case (k, v) => + val vsym = v.typeSymbol + if (k == vsym) "" + k.name + else k.name + ":" + vsym.name + + } mkString ("env(", ", ", ")") + } + /** Specialize member `m` w.r.t. to the outer environment and the type * parameters of the innermost enclosing class. * @@ -841,37 +844,38 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * Return a list of symbols that are specializations of 'sym', owned by 'owner'. */ private def specializeMember(owner: Symbol, sym: Symbol, outerEnv: TypeEnv, tps: List[Symbol]): List[Symbol] = { - def specializeOn(tparams: List[Symbol]): List[Symbol] = - for (spec0 <- specializations(tparams)) yield { - val spec = mapAnyRefsInOrigCls(spec0, owner) - if (sym.isPrivate/* || sym.isProtected*/) { - //sym.privateWithin = sym.enclosingPackage - sym.resetFlag(PRIVATE).setFlag(PROTECTED) - debuglog("-->d SETTING PRIVATE WITHIN TO " + sym.enclosingPackage + " for " + sym) - } + def specializeOn(tparams: List[Symbol]): List[Symbol] = specializations(tparams) map { spec0 => + val spec = mapAnyRefsInOrigCls(spec0, owner) + if (sym.isPrivate) { + sym.resetFlag(PRIVATE).setFlag(PROTECTED) + debuglog("Set %s to private[%s]".format(sym, sym.enclosingPackage)) + } - val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) - typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec - wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s } + val specMember = subst(outerEnv)(specializedOverload(owner, sym, spec)) + typeEnv(specMember) = typeEnv(sym) ++ outerEnv ++ spec + wasSpecializedForTypeVars(specMember) ++= spec collect { case (s, tp) if s.tpe == tp => s } - debuglog("sym " + specMember + " was specialized for type vars " + wasSpecializedForTypeVars(specMember)) - debuglog("added specialized overload: %s in env: %s".format(specMember, typeEnv(specMember))) + val wasSpec = wasSpecializedForTypeVars(specMember) + if (wasSpec.nonEmpty) + debuglog("specialized overload for %s in %s".format(specMember, pp(typeEnv(specMember)))) - overloads(sym) ::= Overload(specMember, spec) - specMember - } + overloads(sym) ::= Overload(specMember, spec) + info(specMember) = SpecialOverload(sym, typeEnv(specMember)) + + specMember + } if (sym.isMethod) { - debuglog("specializeMember %s with tps: %s stvars(sym): %s".format(sym, tps, specializedTypeVars(sym))) + val stvars = specializedTypeVars(sym) + if (stvars.nonEmpty) + debuglog("specialized %s on %s".format(sym.fullLocationString, stvars.map(_.name).mkString(", "))) val tps1 = if (sym.isConstructor) tps filter (sym.info.paramTypes contains _) else tps - val tps2 = tps1 intersect specializedTypeVars(sym).toList + val tps2 = tps1 filter stvars if (!sym.isDeferred) addConcreteSpecMethod(sym) - val ms = specializeOn(tps2) - ms foreach (m => info(m) = SpecialOverload(sym, typeEnv(m))) - ms + specializeOn(tps2) } else Nil } @@ -894,7 +898,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { * * this method will return List('apply$mcII$sp') */ - private def specialOverrides(clazz: Symbol): List[Symbol] = { + private def specialOverrides(clazz: Symbol) = logResultIf[List[Symbol]]("specialOverrides(" + clazz + ")", _.nonEmpty) { /** Return the overridden symbol in syms that needs a specialized overriding symbol, * together with its specialization environment. The overridden symbol may not be * the closest to 'overriding', in a given hierarchy. @@ -917,24 +921,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } if (!overriding.isParamAccessor) { for (overridden <- overriding.allOverriddenSymbols) { - debuglog( - "Overridden: " + overridden.fullName + - ": " + overridden.info + - "\n by " + overriding.fullName + - ": " + overriding.info - ) val stvars = specializedTypeVars(overridden.info) if (stvars.nonEmpty) { - debuglog("\t\tspecializedTVars: " + stvars) + debuglog("specialized override of %s by %s%s".format(overridden.fullLocationString, overriding.fullLocationString, + if (stvars.isEmpty) "" else stvars.map(_.name).mkString("(", ", ", ")"))) + if (currentRun compiles overriding) checkOverriddenTParams(overridden) val env = unify(overridden.info, overriding.info, emptyEnv, false) def atNext = afterSpecialize(overridden.owner.info.decl(specializedName(overridden, env))) - debuglog("\t\tenv: " + env + "isValid: " + TypeEnv.isValid(env, overridden) + "found: " + atNext) - if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) + if (TypeEnv.restrict(env, stvars).nonEmpty && TypeEnv.isValid(env, overridden) && atNext != NoSymbol) { + debuglog(" " + pp(env) + " found " + atNext) return (overridden, env) + } } } } @@ -945,7 +946,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { case (NoSymbol, _) => None case (overridden, env) => val om = specializedOverload(clazz, overridden, env) - debuglog("Added specialized overload %s for %s in env: %s with type: %s".format(om, overriding.fullName, env, om.info)) + debuglog("specialized overload %s for %s in %s: %s".format(om, overriding.name.decode, pp(env), om.info)) typeEnv(om) = env addConcreteSpecMethod(overriding) info(om) = ( @@ -993,7 +994,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { */ private def unify(tp1: Type, tp2: Type, env: TypeEnv, strict: Boolean): TypeEnv = (tp1, tp2) match { case (TypeRef(_, sym1, _), _) if isSpecialized(sym1) => - debuglog("Unify - basic case: " + tp1 + ", " + tp2) + debuglog("Unify " + tp1 + ", " + tp2) if (isPrimitiveValueClass(tp2.typeSymbol) || isSpecializedAnyRefSubtype(tp2, sym1)) env + ((sym1, tp2)) else if (isSpecializedAnyRefSubtype(tp2, sym1)) @@ -1003,19 +1004,21 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { else env case (TypeRef(_, sym1, args1), TypeRef(_, sym2, args2)) => - debuglog("Unify TypeRefs: " + tp1 + " and " + tp2 + " with args " + (args1, args2) + " - ") + if (args1.nonEmpty || args2.nonEmpty) + debuglog("Unify types " + tp1 + " and " + tp2) + if (strict && args1.length != args2.length) unifyError(tp1, tp2) val e = unify(args1, args2, env, strict) - debuglog("unified to: " + e) + if (e.nonEmpty) debuglog("unified to: " + e) e case (TypeRef(_, sym1, _), _) if sym1.isTypeParameterOrSkolem => env case (MethodType(params1, res1), MethodType(params2, res2)) => if (strict && params1.length != params2.length) unifyError(tp1, tp2) - debuglog("Unify MethodTypes: " + tp1 + " and " + tp2) + debuglog("Unify methods " + tp1 + " and " + tp2) unify(res1 :: (params1 map (_.tpe)), res2 :: (params2 map (_.tpe)), env, strict) case (PolyType(tparams1, res1), PolyType(tparams2, res2)) => - debuglog("Unify PolyTypes: " + tp1 + " and " + tp2) + debuglog("Unify polytypes " + tp1 + " and " + tp2) if (strict && tparams1.length != tparams2.length) unifyError(tp1, tp2) else @@ -1123,11 +1126,12 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { if (tparams.isEmpty) afterSpecialize(parents map (_.typeSymbol.info)) - val parents1 = parents map specializedType - debuglog("transformInfo %s %s with parents1 %s ph: %s".format( - if (tparams.nonEmpty) " (poly)" else "", - clazz, parents1, phase) - ) + val parents1 = parents mapConserve specializedType + if (parents ne parents1) { + debuglog("specialization transforms %s%s parents to %s".format( + if (tparams.nonEmpty) "(poly) " else "", clazz, parents1) + ) + } val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*) // If tparams.isEmpty, this is just the ClassInfoType. GenPolyType(tparams, ClassInfoType(parents1, newScope, clazz)) @@ -1253,7 +1257,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { override def traverse(tree: Tree) = tree match { case DefDef(_, _, _, vparams :: Nil, _, rhs) => if (concreteSpecMethods(tree.symbol) || tree.symbol.isConstructor) { - debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs)) + // debuglog("!!! adding body of a defdef %s, symbol %s: %s".format(tree, tree.symbol, rhs)) body(tree.symbol) = rhs // body(tree.symbol) = tree // whole method parameters(tree.symbol) = vparams.map(_.symbol) @@ -1559,7 +1563,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val env = typeEnv(symbol) val boundTvars = env.keySet val origtparams = source.typeParams.filter(tparam => !boundTvars(tparam) || !isScalaValueType(env(tparam))) - debuglog("substituting " + origtparams + " for " + symbol.typeParams) + if (origtparams.nonEmpty || symbol.typeParams.nonEmpty) + debuglog("substituting " + origtparams + " for " + symbol.typeParams) // skolemize type parameters val oldtparams = tparams map (_.symbol) @@ -1656,7 +1661,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { buf += ClassDef(specCls, atPos(impl.pos)(Template(parents, emptyValDef, List())) .setSymbol(specCls.newLocalDummy(sym1.pos))) setPos tree.pos - debuglog("created synthetic class: " + specCls + " of " + sym1 + " in env: " + env) + debuglog("created synthetic class: " + specCls + " of " + sym1 + " in " + pp(env)) } case _ => } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index e54e0289bb..0efdd9ab9f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -210,14 +210,15 @@ abstract class UnCurry extends InfoTransform * body = expr match { case P_i if G_i => E_i }_i=1..n * to: * + //TODO: correct code template below * class $anon() extends AbstractPartialFunction[T, R] with Serializable { - * def apply(x: T): R = (expr: @unchecked) match { + * def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = (expr: @unchecked) match { * case P_1 if G_1 => E_1 * ... - * case P_n if G_n => true - * case _ => this.missingCase(expr) + * case P_n if G_n => E_n + * case _ => default(expr) * } - * def _isDefinedAt(x: T): boolean = (x: @unchecked) match { + * def isDefinedAt(x: T): boolean = (x: @unchecked) match { * case P_1 if G_1 => true * ... * case P_n if G_n => true @@ -231,127 +232,107 @@ abstract class UnCurry extends InfoTransform * * def isDefinedAtCurrent(x: T): boolean = true */ - def transformFunction(fun: Function): Tree = { - val fun1 = deEta(fun) - def owner = fun.symbol.owner - def targs = fun.tpe.typeArgs - def isPartial = fun.tpe.typeSymbol == PartialFunctionClass - - // if the function was eta-expanded, it's not a match without a selector - if (fun1 ne fun) fun1 - else { - assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions - val (formals, restpe) = (targs.init, targs.last) - val anonClass = owner.newAnonymousFunctionClass(fun.pos, inConstructorFlag) - def parents = - if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) - else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) - else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) - - anonClass setInfo ClassInfoType(parents, newScope, anonClass) - val applyMethod = anonClass.newMethod(nme.apply, fun.pos, FINAL) - applyMethod setInfoAndEnter MethodType(applyMethod newSyntheticValueParams formals, restpe) - anonClass addAnnotation serialVersionUIDAnnotation - - fun.vparams foreach (_.symbol.owner = applyMethod) - fun.body.changeOwner(fun.symbol -> applyMethod) - - def missingCaseCall(scrutinee: Tree): Tree = Apply(Select(This(anonClass), nme.missingCase), List(scrutinee)) - - def applyMethodDef() = { - val body = localTyper.typedPos(fun.pos) { - if (isPartial) gen.mkUncheckedMatch(gen.withDefaultCase(fun.body, missingCaseCall)) - else fun.body - } - // Have to repack the type to avoid mismatches when existentials - // appear in the result - see SI-4869. - val applyResultType = localTyper.packedType(body, applyMethod) - DefDef(Modifiers(FINAL), nme.apply, Nil, List(fun.vparams), TypeTree(applyResultType), body) setSymbol applyMethod - } - def isDefinedAtMethodDef() = { - val isDefinedAtName = { - if (anonClass.info.member(nme._isDefinedAt) != NoSymbol) nme._isDefinedAt - else nme.isDefinedAt - } - val m = anonClass.newMethod(isDefinedAtName, fun.pos, FINAL) - val params = m newSyntheticValueParams formals - m setInfoAndEnter MethodType(params, BooleanClass.tpe) + def transformFunction(fun: Function): Tree = + deEta(fun) match { + // nullary or parameterless + case fun1 if fun1 ne fun => fun1 + case _ => + def owner = fun.symbol.owner + def targs = fun.tpe.typeArgs + def isPartial = fun.tpe.typeSymbol == PartialFunctionClass + assert(!(opt.virtPatmat && isPartial)) // empty-selector matches have already been translated into instantiations of anonymous (partial) functions - val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) - def substTree[T <: Tree](t: T): T = substParam(resetLocalAttrs(t)) + def parents = + if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) + else if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) + else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) - object isDefinedAtTransformer extends gen.MatchMatcher { - // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly - override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { - def transformCase(cdef: CaseDef): CaseDef = - CaseDef(cdef.pat, cdef.guard, Literal(Constant(true))) + val anonClass = owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation + anonClass setInfo ClassInfoType(parents, newScope, anonClass) - def defaultCase = CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) + val (formals, restpe) = (targs.init, targs.last) -// val casesNoSynthCatchAll = dropSyntheticCatchAll(cases) + def applyMethodDef = { + val methSym = anonClass.newMethod(nme.apply, fun.pos, FINAL) + methSym setInfoAndEnter MethodType(methSym newSyntheticValueParams formals, restpe) - gen.mkUncheckedMatch( - if (cases exists treeInfo.isDefaultCase) Literal(Constant(true)) - else substTree(wrap(Match(selector, (cases map transformCase) :+ defaultCase)).duplicate) - ) + fun.vparams foreach (_.symbol.owner = methSym) + fun.body changeOwner (fun.symbol -> methSym) + + val body = localTyper.typedPos(fun.pos)(fun.body) + val methDef = DefDef(methSym, List(fun.vparams), body) + + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + methDef.tpt setType localTyper.packedType(body, methSym) + methDef + } + + // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + def applyOrElseMethodDef = { + val methSym = anonClass.newMethod(fun.pos, nme.applyOrElse) setFlag (FINAL | OVERRIDE) + + val List(argtpe) = formals + val A1 = methSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argtpe) + val B1 = methSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.lower(restpe) + val methFormals = List(A1.tpe, functionType(List(A1.tpe), B1.tpe)) + val params@List(x, default) = methSym newSyntheticValueParams methFormals + methSym setInfoAndEnter polyType(List(A1, B1), MethodType(params, B1.tpe)) + + val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), List(x)) + val body = localTyper.typedPos(fun.pos) { import CODE._ + gen.mkUncheckedMatch(gen.withDefaultCase(substParam(fun.body), scrut => REF(default) APPLY (REF(x)))) } + body.changeOwner(fun.symbol -> methSym) + + val methDef = DefDef(methSym, body) - override def caseVirtualizedMatch(orig: Tree, _match: Tree, targs: List[Tree], scrut: Tree, matcher: Tree): Tree = {assert(false); orig} - // { - // object noOne extends Transformer { - // override val treeCopy = newStrictTreeCopier // must duplicate everything - // val one = _match.tpe member newTermName("one") - // override def transform(tree: Tree): Tree = tree match { - // case Apply(fun, List(a)) if fun.symbol == one => - // // blow one's argument away since all we want to know is whether the match succeeds or not - // // (the alternative, making `one` CBN, would entail moving away from Option) - // Apply(fun.duplicate, List(gen.mkZeroContravariantAfterTyper(a.tpe))) - // case _ => - // super.transform(tree) - // } - // } - // substTree(Apply(Apply(TypeApply(Select(_match.duplicate, _match.tpe.member(newTermName("isSuccess"))), targs map (_.duplicate)), List(scrut.duplicate)), List(noOne.transform(matcher)))) - // } - - override def caseVirtualizedMatchOpt(orig: Tree, zero: ValDef, x: ValDef, matchRes: ValDef, keepGoing: ValDef, stats: List[Tree], epilogue: Tree, wrap: Tree => Tree) = {assert(false); orig} - // { - // object dropMatchResAssign extends Transformer { - // // override val treeCopy = newStrictTreeCopier // will duplicate below - // override def transform(tree: Tree): Tree = tree match { - // // don't compute the result of the match -- remove the block for the RHS (emitted by pmgen.one), except for the assignment to keepGoing - // case gen.VirtualCaseDef(assignKeepGoing, matchRes, zero) if assignKeepGoing.lhs.symbol eq keepGoing.symbol => - // Block(List(assignKeepGoing), zero) - // case _ => - // super.transform(tree) - // } - // } - // val statsNoMatchRes: List[Tree] = stats map (dropMatchResAssign.transform) toList - // val idaBlock = wrap(Block( - // zero :: - // x :: - // /* drop matchRes def */ - // keepGoing :: - // statsNoMatchRes, - // NOT(REF(keepGoing.symbol)) // replace `if (keepGoing) throw new MatchError(...) else matchRes` epilogue by `!keepGoing` - // )) - // substTree(idaBlock.duplicate) // duplicate on block as a whole to ensure valdefs are properly cloned and substed - // } + // Have to repack the type to avoid mismatches when existentials + // appear in the result - see SI-4869. + methDef.tpt setType localTyper.packedType(body, methSym) + methDef } - DefDef(m, isDefinedAtTransformer(fun.body)) - } + // duplicate before applyOrElseMethodDef is run so we start with the same symbols as applyOrElseMethodDef + // otherwise `TreeSymSubstituter(fun.vparams map (_.symbol), params)` won't work as the subst has been run already + val bodyForIDA = fun.body.duplicate + def isDefinedAtMethodDef = { + val methSym = anonClass.newMethod(nme.isDefinedAt, fun.pos, FINAL) + val params = methSym newSyntheticValueParams formals + methSym setInfoAndEnter MethodType(params, BooleanClass.tpe) + + val substParam = new TreeSymSubstituter(fun.vparams map (_.symbol), params) + def doSubst(x: Tree) = substParam(resetLocalAttrs(x)) // see pos/t1761 for why `resetLocalAttrs` + object isDefinedAtTransformer extends gen.MatchMatcher { + // TODO: optimize duplication, but make sure ValDef's introduced by wrap are treated correctly + override def caseMatch(orig: Tree, selector: Tree, cases: List[CaseDef], wrap: Tree => Tree): Tree = { import CODE._ + gen.mkUncheckedMatch( + if (cases exists treeInfo.isDefaultCase) TRUE_typed + else + doSubst(wrap( + Match(selector, + (cases map (c => deriveCaseDef(c)(x => TRUE_typed))) :+ ( + DEFAULT ==> FALSE_typed) + ))) + ) + } + } + val body = isDefinedAtTransformer(bodyForIDA) + body.changeOwner(fun.symbol -> methSym) - val members = - if (isPartial) List(applyMethodDef, isDefinedAtMethodDef) - else List(applyMethodDef) + DefDef(methSym, body) + } + + val members = + if (isPartial) List(applyOrElseMethodDef, isDefinedAtMethodDef) + else List(applyMethodDef) - localTyper.typedPos(fun.pos) { - Block( - List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), - Typed(New(anonClass.tpe), TypeTree(fun.tpe))) + localTyper.typedPos(fun.pos) { + Block( + List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, fun.pos)), + Typed(New(anonClass.tpe), TypeTree(fun.tpe))) + } } - } - } def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = { val isJava = fun.isJavaDefined diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 764823d786..49ddb985dc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -317,7 +317,7 @@ trait ContextErrors { } withAddendum(qual.pos)( if (name == nme.CONSTRUCTOR) target + " does not have a constructor" - else nameString + " is not a member of " + targetKindString + target + addendum + else nameString + " is not a member of " + targetKindString + target.directObjectString + addendum ) } issueNormalTypeError(sel, errMsg) @@ -677,7 +677,7 @@ trait ContextErrors { def AccessError(tree: Tree, sym: Symbol, pre: Type, owner0: Symbol, explanation: String) = { def errMsg = { - val location = if (sym.isClassConstructor) owner0 else pre.widen + val location = if (sym.isClassConstructor) owner0 else pre.widen.directObjectString underlyingSymbol(sym).fullLocationString + " cannot be accessed in " + location + explanation diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala index eb0d489901..f6d1e42c32 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala @@ -79,7 +79,17 @@ abstract class Duplicators extends Analyzer { override def mapOver(tpe: Type): Type = tpe match { case TypeRef(NoPrefix, sym, args) if sym.isTypeParameterOrSkolem => - val sym1 = context.scope.lookup(sym.name) + var sym1 = context.scope.lookup(sym.name) + if (sym1 eq NoSymbol) { + // try harder (look in outer scopes) + // with virtpatmat, this can happen when the sym is referenced in the scope of a LabelDef but is defined in the scope of an outer DefDef (e.g., in AbstractPartialFunction's andThen) + BodyDuplicator.super.silent(_.typedType(Ident(sym.name))) match { + case SilentResultValue(t) => + sym1 = t.symbol + debuglog("fixed by trying harder: "+(sym, sym1, context)) + case _ => + } + } // assert(sym1 ne NoSymbol, tpe) if ((sym1 ne NoSymbol) && (sym1 ne sym)) { debuglog("fixing " + sym + " -> " + sym1) @@ -255,7 +265,10 @@ abstract class Duplicators extends Analyzer { case ldef @ LabelDef(name, params, rhs) => // log("label def: " + ldef) + // in case the rhs contains any definitions -- TODO: is this necessary? + invalidate(rhs) ldef.tpe = null + // since typer does not create the symbols for a LabelDef's params, // we do that manually here -- we should really refactor LabelDef to be a subclass of DefDef def newParam(p: Tree): Ident = { @@ -265,6 +278,7 @@ abstract class Duplicators extends Analyzer { val params1 = params map newParam val rhs1 = (new TreeSubstituter(params map (_.symbol), params1) transform rhs) // TODO: duplicate? rhs1.tpe = null + super.typed(treeCopy.LabelDef(tree, name, params1, rhs1), mode, pt) case Bind(name, _) => diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 6b27c27652..8604366bf2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -315,9 +315,10 @@ trait Namers extends MethodSynthesis { case DefDef(_, _, _, _, _, _) => owner.newMethod(name.toTermName, pos, flags) case ClassDef(_, _, _, _) => owner.newClassSymbol(name.toTypeName, pos, flags) case ModuleDef(_, _, _) => owner.newModule(name, pos, flags) - case ValDef(_, _, _, _) if isParameter => owner.newValueParameter(name, pos, flags) case PackageDef(pid, _) => createPackageSymbol(pos, pid) - case ValDef(_, _, _, _) => owner.newValue(name, pos, flags) + case ValDef(_, _, _, _) => + if (isParameter) owner.newValueParameter(name, pos, flags) + else owner.newValue(name, pos, flags) } } private def createFieldSymbol(tree: ValDef): TermSymbol = diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 013a74da7e..045614e773 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -267,6 +267,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R sym1.locationString + (if (sym1.isAliasType) ", which equals "+self.memberInfo(sym1) else if (sym1.isAbstractType) " with bounds"+self.memberInfo(sym1) + else if (sym1.isModule) "" else if (sym1.isTerm) " of type "+self.memberInfo(sym1) else "") else "") @@ -394,9 +395,14 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R overrideError("needs `override' modifier") } else if (other.isAbstractOverride && other.isIncompleteIn(clazz) && !member.isAbstractOverride) { overrideError("needs `abstract override' modifiers") - } else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) { - overrideError("cannot override a mutable variable") - } else if (member.isAnyOverride && + } + else if (member.isAnyOverride && (other hasFlag ACCESSOR) && other.accessed.isVariable && !other.accessed.isLazy) { + // !?! this is not covered by the spec. We need to resolve this either by changing the spec or removing the test here. + // !!! is there a !?! convention? I'm !!!ing this to make sure it turns up on my searches. + if (!settings.overrideVars.value) + overrideError("cannot override a mutable variable") + } + else if (member.isAnyOverride && !(member.owner.thisType.baseClasses exists (_ isSubClass other.owner)) && !member.isDeferred && !other.isDeferred && intersectionIsEmpty(member.extendedOverriddenSymbols, other.extendedOverriddenSymbols)) { @@ -1248,9 +1254,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } List(tree1) } - case Import(_, _) => Nil + case Import(_, _) => Nil case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) => Nil - case _ => List(transform(tree)) + case _ => List(transform(tree)) } /* Check whether argument types conform to bounds of type parameters */ diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 4248b6f024..94733369a8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -259,7 +259,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT 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) + if (!settings.overrideVars.value) + 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") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 06a7311f79..2aff00f6a5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -235,32 +235,41 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { result } } + def isNonRefinementClassType(tpe: Type) = tpe match { + case SingleType(_, sym) => sym.isModuleClass + case TypeRef(_, sym, _) => sym.isClass && !sym.isRefinementClass + case ErrorType => true + case _ => false + } + private def errorNotClass(tpt: Tree, found: Type) = { ClassTypeRequiredError(tpt, found); false } + private def errorNotStable(tpt: Tree, found: Type) = { TypeNotAStablePrefixError(tpt, found); false } /** Check that `tpt` refers to a non-refinement class type */ - def checkClassType(tpt: Tree, existentialOK: Boolean, stablePrefix: Boolean): Boolean = { - def errorNotClass(found: AnyRef) = { ClassTypeRequiredError(tpt, found); false } - def check(tpe: Type): Boolean = tpe.normalize match { - case TypeRef(pre, sym, _) if sym.isClass && !sym.isRefinementClass => - if (stablePrefix && !isPastTyper) - if (!pre.isStable) { - TypeNotAStablePrefixError(tpt, pre) - false - } else - // A type projection like X#Y can get by the stable check if the - // prefix is singleton-bounded, so peek at the tree too. - tpt match { - case SelectFromTypeTree(qual, _) if !isSingleType(qual.tpe) => errorNotClass(tpt) - case _ => true - } - else - true - case ErrorType => true - case PolyType(_, restpe) => check(restpe) - case ExistentialType(_, restpe) if existentialOK => check(restpe) - case AnnotatedType(_, underlying, _) => check(underlying) - case t => errorNotClass(t) + def checkClassType(tpt: Tree): Boolean = { + val tpe = unwrapToClass(tpt.tpe) + isNonRefinementClassType(tpe) || errorNotClass(tpt, tpe) + } + + /** Check that `tpt` refers to a class type with a stable prefix. */ + def checkStablePrefixClassType(tpt: Tree): Boolean = { + val tpe = unwrapToStableClass(tpt.tpe) + def prefixIsStable = { + def checkPre = tpe match { + case TypeRef(pre, _, _) => pre.isStable || errorNotStable(tpt, pre) + case _ => false + } + // A type projection like X#Y can get by the stable check if the + // prefix is singleton-bounded, so peek at the tree too. + def checkTree = tpt match { + case SelectFromTypeTree(qual, _) => isSingleType(qual.tpe) || errorNotClass(tpt, tpe) + case _ => true + } + checkPre && checkTree } - check(tpt.tpe) + + ( (isNonRefinementClassType(tpe) || errorNotClass(tpt, tpe)) + && (isPastTyper || prefixIsStable) + ) } /** Check that type <code>tp</code> is not a subtype of itself. @@ -643,13 +652,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - private def isNarrowable(tpe: Type): Boolean = tpe match { + private def isNarrowable(tpe: Type): Boolean = unwrapWrapperTypes(tpe) match { case TypeRef(_, _, _) | RefinedType(_, _) => true - case ExistentialType(_, tpe1) => isNarrowable(tpe1) - case AnnotatedType(_, tpe1, _) => isNarrowable(tpe1) - case PolyType(_, tpe1) => isNarrowable(tpe1) - case NullaryMethodType(tpe1) => isNarrowable(tpe1) - case _ => !phase.erasedTypes + case _ => !phase.erasedTypes } /** @@ -1438,7 +1443,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def validateParentClass(parent: Tree, superclazz: Symbol) { if (!parent.isErrorTyped) { val psym = parent.tpe.typeSymbol.initialize - checkClassType(parent, false, true) + checkStablePrefixClassType(parent) if (psym != superclazz) { if (psym.isTrait) { val ps = psym.info.parents @@ -2186,17 +2191,24 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass addAnnotation serialVersionUIDAnnotation - def mkParams(methodSym: Symbol) = { + def deriveFormals = + selOverride match { + case None if targs.isEmpty => Nil + case None => targs.init // is there anything we can do if targs.isEmpty?? + case Some((vparams, _)) => + vparams map {p => if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe} + } + + def mkParams(methodSym: Symbol, formals: List[Type] = deriveFormals) = { selOverride match { case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree) case None => - val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty?? + val ps = methodSym newSyntheticValueParams formals // is there anything we can do if targs.isEmpty?? val ids = ps map (p => Ident(p.name)) val sel = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) } (ps, sel) case Some((vparams, sel)) => - val newParamSyms = vparams map {p => - val tp = if(p.tpt.tpe == null) typedType(p.tpt).tpe else p.tpt.tpe + val newParamSyms = (vparams, formals).zipped map {(p, tp) => methodSym.newValueParameter(p.name, focusPos(p.pos), SYNTHETIC) setInfo tp } @@ -2209,7 +2221,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // need to duplicate the cases before typing them to generate the apply method, or the symbols will be all messed up val casesTrue = if (isPartial) cases map (c => deriveCaseDef(c)(x => TRUE_typed).duplicate) else Nil - val applyMethod = { + def applyMethod = { // rig the show so we can get started typing the method body -- later we'll correct the infos... anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL) @@ -2224,25 +2236,59 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) - val formalTypes = paramSyms map (_.tpe) - val parents = - if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) - else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) + val methFormals = paramSyms map (_.tpe) + val parents = List(appliedType(AbstractFunctionClass(arity).typeConstructor, methFormals :+ resTp), SerializableClass.tpe) anonClass setInfo ClassInfoType(parents, newScope, anonClass) methodSym setInfoAndEnter MethodType(paramSyms, resTp) - // use apply's parameter since the scrut's type has been widened - def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) + DefDef(methodSym, methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation)) + } + } + + // def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + def applyOrElseMethodDef = { + // rig the show so we can get started typing the method body -- later we'll correct the infos... + // targs were type arguments for PartialFunction, so we know they will work for AbstractPartialFunction as well + def parents(targs: List[Type]) = List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) + + anonClass setInfo ClassInfoType(parents(targs), newScope, anonClass) + val methodSym = anonClass.newMethod(nme.applyOrElse, tree.pos, FINAL | OVERRIDE) + + // create the parameter that corresponds to the function's parameter + val List(argTp) = deriveFormals + val A1 = methodSym newTypeParameter(newTypeName("A1")) setInfo TypeBounds.upper(argTp) + val (List(x), selector) = mkParams(methodSym, List(A1.tpe)) + + if (selector eq EmptyTree) EmptyTree + else { + // applyOrElse's default parameter: + val B1 = methodSym newTypeParameter(newTypeName("B1")) setInfo TypeBounds.empty //lower(resTp) + val default = methodSym newValueParameter(newTermName("default"), focusPos(tree.pos), SYNTHETIC) setInfo functionType(List(A1.tpe), B1.tpe) + + val paramSyms = List(x, default) + methodSym setInfoAndEnter polyType(List(A1, B1), MethodType(paramSyms, B1.tpe)) + + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) + + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + + anonClass setInfo ClassInfoType(parents(List(argTp, resTp)), newScope, anonClass) + B1 setInfo TypeBounds.lower(resTp) + anonClass.info.decls enter methodSym // methodSym's info need not change (B1's bound has been updated instead) + + // use applyOrElse's first parameter since the scrut's type has been widened + def doDefault(scrut_ignored: Tree) = REF(default) APPLY (REF(x)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, B1.tpe, doTranslation, Some(doDefault)) DefDef(methodSym, body) } } def isDefinedAtMethod = { - val methodSym = anonClass.newMethod(nme._isDefinedAt, tree.pos, FINAL) + val methodSym = anonClass.newMethod(nme.isDefinedAt, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) if (selector eq EmptyTree) EmptyTree else { @@ -2257,7 +2303,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod) + val members = if (!isPartial) List(applyMethod) else List(applyOrElseMethodDef, isDefinedAtMethod) if (members.head eq EmptyTree) setError(tree) else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) } @@ -3312,7 +3358,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } def typedClassOf(tree: Tree, tpt: Tree, noGen: Boolean = false) = - if (!checkClassType(tpt, true, false) && noGen) tpt + if (!checkClassType(tpt) && noGen) tpt else atPos(tree.pos)(gen.mkClassOf(tpt.tpe)) protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = { @@ -3624,7 +3670,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def typedNew(tpt: Tree) = { val tpt1 = { val tpt0 = typedTypeConstructor(tpt) - if (checkClassType(tpt0, false, true)) + if (checkStablePrefixClassType(tpt0)) if (tpt0.hasSymbol && !tpt0.symbol.typeParams.isEmpty) { context.undetparams = cloneSymbols(tpt0.symbol.typeParams) TypeTree().setOriginal(tpt0) @@ -4142,7 +4188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope var cx = startingIdentContext - while (defSym == NoSymbol && cx != NoContext) { + while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators // !!! Shouldn't the argument to compileSourceFor be cx, not context? // I can't tell because those methods do nothing in the standard compiler, // presumably they are overridden in the IDE. diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala index 4a10b65735..9fa56a332f 100644 --- a/src/library/scala/Function.scala +++ b/src/library/scala/Function.scala @@ -29,6 +29,7 @@ object Function { /** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`. * + * TODO: check if the paragraph below is still correct * '''Important note''': this transformation implies the original function * will be called 2 or more times on each logical invocation, because the * only way to supply an implementation of `isDefinedAt` is to call the @@ -39,11 +40,7 @@ object Function { * f returns `Some(_)` and undefined where `f` returns `None`. * @see [[scala.PartialFunction#lift]] */ - def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = new runtime.AbstractPartialFunction[T, R] { - def apply(x: T): R = f(x).get - def _isDefinedAt(x: T): Boolean = f(x).isDefined - override def lift: T => Option[R] = f - } + def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f) /** Uncurrying for functions of arity 2. This transforms a unary function * returning another unary function into a function of arity 2. diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index 3c5d6d0d23..7154b8da34 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -8,6 +8,7 @@ package scala + /** A partial function of type `PartialFunction[A, B]` is a unary function * where the domain does not necessarily include all values of type `A`. * The function `isDefinedAt` allows to test dynamically if a value is in @@ -43,10 +44,11 @@ package scala * }}} * * - * @author Martin Odersky + * @author Martin Odersky, Pavel Pavlov, Adriaan Moors * @version 1.0, 16/07/2003 */ -trait PartialFunction[-A, +B] extends (A => B) { +trait PartialFunction[-A, +B] extends (A => B) { self => + import PartialFunction._ /** Checks if a value is contained in the function's domain. * @@ -55,10 +57,6 @@ trait PartialFunction[-A, +B] extends (A => B) { */ def isDefinedAt(x: A): Boolean - //protected def missingCase[A1 <: A, B1 >: B]: PartialFunction[A1, B1] = PartialFunction.empty - - protected def missingCase(x: A): B = throw new MatchError(x) - /** Composes this partial function with a fallback partial function which * gets applied where this partial function is not defined. * @@ -70,16 +68,8 @@ trait PartialFunction[-A, +B] extends (A => B) { * takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not. */ def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = - new runtime.AbstractPartialFunction[A1, B1] { - def _isDefinedAt(x: A1): Boolean = - PartialFunction.this.isDefinedAt(x) || that.isDefinedAt(x) - def apply(x: A1): B1 = - if (PartialFunction.this.isDefinedAt(x)) PartialFunction.this.apply(x) - else that.apply(x) - } - - def orElseFast[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = - orElse(that) + new OrElse[A1, B1] (this, that) + //TODO: why not overload it with orElse(that: F1): F1? /** Composes this partial function with a transformation function that * gets applied to results of this partial function. @@ -88,9 +78,9 @@ trait PartialFunction[-A, +B] extends (A => B) { * @return a partial function with the same domain as this partial function, which maps * arguments `x` to `k(this(x))`. */ - override def andThen[C](k: B => C) : PartialFunction[A, C] = new runtime.AbstractPartialFunction[A, C] { - def _isDefinedAt(x: A): Boolean = PartialFunction.this.isDefinedAt(x) - def apply(x: A): C = k(PartialFunction.this.apply(x)) + override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] { + def isDefinedAt(x: A): Boolean = self isDefinedAt x + def apply(x: A): C = k(self(x)) } /** Turns this partial function into an plain function returning an `Option` result. @@ -98,9 +88,30 @@ trait PartialFunction[-A, +B] extends (A => B) { * @return a function that takes an argument `x` to `Some(this(x))` if `this` * is defined for `x`, and to `None` otherwise. */ - def lift: A => Option[B] = new (A => Option[B]) { - def apply(x: A): Option[B] = if (isDefinedAt(x)) Some(PartialFunction.this.apply(x)) else None - } + def lift: A => Option[B] = new Lifted(this) + + /** + * TODO: comment + * @since 2.10 + */ + def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + if (isDefinedAt(x)) apply(x) else default(x) + + /** + * TODO: comment + * @since 2.10 + */ + def run[U](x: A)(action: B => U): Boolean = + applyOrElse(x, fallbackToken) match { + case FallbackToken => false + case z => action(z); true + } + + /** + * TODO: comment + * @since 2.10 + */ + def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) } } /** A few handy operations which leverage the extra bit of information @@ -119,14 +130,73 @@ trait PartialFunction[-A, +B] extends (A => B) { * @since 2.8 */ object PartialFunction { - private[this] final val empty_pf: PartialFunction[Any, Nothing] = new runtime.AbstractPartialFunction[Any, Nothing] { - def _isDefinedAt(x: Any) = false - override def isDefinedAt(x: Any) = false - def apply(x: Any): Nothing = throw new MatchError(x) - override def orElse[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that - override def orElseFast[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that - override def lift = (x: Any) => None + /** Composite function produced by `PartialFunction#orElse` method + */ + private final class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] { + def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x) + + def apply(x: A): B = f1.applyOrElse(x, f2) + + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + f1.applyOrElse(x, fallbackToken) match { + case FallbackToken => f2.applyOrElse(x, default) + case z => z + } + + override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) = + new OrElse[A1, B1] (f1, f2 orElse that) + + override def andThen[C](k: B => C) = + new OrElse[A, C] (f1 andThen k, f2 andThen k) } + + private[scala] lazy val FallbackToken: PartialFunction[Any, PartialFunction[Any, Nothing]] = { case _ => FallbackToken.asInstanceOf[PartialFunction[Any, Nothing]] } + private[scala] final def fallbackToken[B] = FallbackToken.asInstanceOf[PartialFunction[Any, B]] + //TODO: check generated code for PF literal here + + private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B]) + extends runtime.AbstractFunction1[A, Option[B]] { + + def apply(x: A): Option[B] = pf.applyOrElse(x, fallbackToken) match { + case FallbackToken => None + case z => Some(z) + } + } + + private final class Unlifted[A, B] (f: A => Option[B]) extends runtime.AbstractPartialFunction[A, B] { + def isDefinedAt(x: A): Boolean = f(x).isDefined + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + f(x) getOrElse default(x) //TODO: check generated code and inline getOrElse if needed + override def lift = f + } + + private[scala] def unlifted[A, B](f: A => Option[B]): PartialFunction[A, B] = f match { + case lf: Lifted[A, B] => lf.pf + case ff => new Unlifted(ff) + } + + /** Converts ordinary function to partial one + * @since 2.10 + */ + //TODO: check generated code for PF literal here + def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) } + + private[this] final val constFalse: Any => Boolean = { _ => false} + + private[this] final val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] { + def isDefinedAt(x: Any) = false + def apply(x: Any) = throw new MatchError(x) + override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that + override def andThen[C](k: Nothing => C) = this + override val lift = (x: Any) => None + override def run[U](x: Any)(action: Nothing => U) = false + override def runWith[U](action: Nothing => U) = constFalse + } + + /** + * TODO: comment + * @since 2.10 + */ def empty[A, B] : PartialFunction[A, B] = empty_pf /** Creates a Boolean test based on a value and a partial function. @@ -137,8 +207,7 @@ object PartialFunction { * @param pf the partial function * @return true, iff `x` is in the domain of `pf` and `pf(x) == true`. */ - def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = - (pf isDefinedAt x) && pf(x) + def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = pf.applyOrElse(x, constFalse) /** Transforms a PartialFunction[T, U] `pf` into Function1[T, Option[U]] `f` * whose result is `Some(x)` if the argument is in `pf`'s domain and `None` @@ -150,6 +219,5 @@ object PartialFunction { * @param pf the PartialFunction[T, U] * @return `Some(pf(x))` if `pf isDefinedAt x`, `None` otherwise. */ - def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = - if (pf isDefinedAt x) Some(pf(x)) else None + def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = pf.lift(x) } diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 75ab3f28f5..a978a9a783 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -127,3 +127,5 @@ object JavaConversions extends WrapAsScala with WrapAsJava { @deprecated("use propertiesAsScalaMap instead", "2.9.0") def asScalaMap(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) } + + diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 13f1f19f81..f8a9466caf 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -100,4 +100,4 @@ object JavaConverters extends DecorateAsJava with DecorateAsScala { @deprecated("Use propertiesAsScalaMapConverter instead", "2.9.0") def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = propertiesAsScalaMapConverter(p) -}
\ No newline at end of file +} diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 76837d937c..e05bfc41cd 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -291,6 +291,26 @@ trait DecorateAsJava { * @return An object with an `asJava` method that returns a Java * `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(asJavaConcurrentMap(m)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable + * `concurrent.Map` to a Java `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java `ConcurrentMap` will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return An object with an `asJava` method that returns a Java + * `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = + new AsJava(asJavaConcurrentMap(m)) } diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index bb14228e67..722f0b9af9 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -156,10 +156,29 @@ trait DecorateAsScala { * @return An object with an `asScala` method that returns a Scala mutable * `ConcurrentMap` view of the argument. */ - implicit def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = + @deprecated("Use `mapAsScalaConcurrentMapConverter` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = new AsScala(asScalaConcurrentMap(m)) /** + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` + * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is + * backed by the provided Java `ConcurrentMap` and any side-effects of using + * it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * If the Java `ConcurrentMap` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala `concurrent.Map` will be returned. + * + * @param m The `ConcurrentMap` to be converted. + * @return An object with an `asScala` method that returns a Scala mutable + * `concurrent.Map` view of the argument. + */ + implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] = + new AsScala(mapAsScalaConcurrentMap(m)) + + /** * Adds an `asScala` method that implicitly converts a Java `Dictionary` * to a Scala mutable `Map[String, String]`. The returned Scala * `Map[String, String]` is backed by the provided Java `Dictionary` and diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 6274518d1a..cdec72b9fe 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -241,16 +241,45 @@ trait WrapAsJava { * will be visible via the Scala interface and vice versa. * * If the Scala `ConcurrentMap` was previously obtained from an implicit or - * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * explicit call of `asScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` * then the original Java ConcurrentMap will be returned. * * @param m The `ConcurrentMap` to be converted. * @return A Java `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { + case JConcurrentMapDeprecatedWrapper(wrapped) => wrapped + case _ => new ConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Scala mutable `concurrent.Map` to a Java + * `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java ConcurrentMap will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return A Java `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { case JConcurrentMapWrapper(wrapped) => wrapped case _ => new ConcurrentMapWrapper(m) } } object WrapAsJava extends WrapAsJava { } + + + + + + + + diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index 02b58f55a4..56e13b2105 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -154,9 +154,28 @@ trait WrapAsScala { * @param m The ConcurrentMap to be converted. * @return A Scala mutable ConcurrentMap view of the argument. */ - implicit def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { - case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying - case _ => new JConcurrentMapWrapper(m) + @deprecated("Use `mapAsScalaConcurrentMap` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { + case cmw: ConcurrentMapDeprecatedWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap. + * The returned Scala ConcurrentMap is backed by the provided Java + * ConcurrentMap and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * If the Java ConcurrentMap was previously obtained from an implicit or + * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala ConcurrentMap will be returned. + * + * @param m The ConcurrentMap to be converted. + * @return A Scala mutable ConcurrentMap view of the argument. + */ + implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { + case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 8136e462cb..b1b48b760f 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -268,7 +268,7 @@ private[collection] trait Wrappers { override def empty = JMapWrapper(new ju.HashMap[A, B]) } - class ConcurrentMapWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + class ConcurrentMapDeprecatedWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { case Some(v) => v @@ -290,7 +290,54 @@ private[collection] trait Wrappers { def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } - case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + class ConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + + def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def remove(k: AnyRef, v: AnyRef) = try { + underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B]) + } catch { + case ex: ClassCastException => + false + } + + def replace(k: A, v: B): B = underlying.replace(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) + } + + case class JConcurrentMapDeprecatedWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapDeprecatedWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + override def get(k: A) = { + val v = underlying get k + if (v != null) Some(v) + else None + } + + override def empty = new JConcurrentMapDeprecatedWrapper(new juc.ConcurrentHashMap[A, B]) + + def putIfAbsent(k: A, v: B): Option[B] = { + val r = underlying.putIfAbsent(k, v) + if (r != null) Some(r) else None + } + + def remove(k: A, v: B): Boolean = underlying.remove(k, v) + + def replace(k: A, v: B): Option[B] = { + val prev = underlying.replace(k, v) + if (prev != null) Some(prev) else None + } + + def replace(k: A, oldvalue: B, newvalue: B): Boolean = + underlying.replace(k, oldvalue, newvalue) + } + + case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] { override def get(k: A) = { val v = underlying get k if (v != null) Some(v) diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 870c179b2d..1b75c10113 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -58,7 +58,7 @@ import java.io._ * @author Martin Odersky and others * @version 2.8 * @since 1.0 - * @see [["http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists" "Scala's Collection Library overview"]] + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists "Scala's Collection Library overview"]] * section on `Lists` for more information. * * @define coll list diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index cc0aed6963..06b7d40bfc 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -366,7 +366,7 @@ private[collection] object HashTable { private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt - private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = thr * loadFactorDenum / _loadFactor + private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt private[collection] final def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index 8fad131009..b70df05c55 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -44,7 +44,7 @@ object Stack extends SeqFactory[Stack] { * @author Martin Odersky * @version 2.8 * @since 1 - * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks"Scala's Collection Library overview"]] + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks "Scala's Collection Library overview"]] * section on `Stacks` for more information. * @define Coll Stack * @define coll stack diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala index 49b00bebdb..e630a9dbed 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala @@ -36,7 +36,9 @@ import collection.parallel.Task * * @author Aleksandar Prokopec * @since 2.9 - * + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tries for more information. + * * @define Coll immutable.ParHashMap * @define coll immutable parallel hash map */ diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 11d92a27c9..084637c5dc 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -35,6 +35,8 @@ import collection.parallel.Task * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tries for more information. * * @define Coll immutable.ParHashSet * @define coll immutable parallel hash set diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index 9cac433460..277fd5fdd3 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -25,6 +25,8 @@ import scala.collection.Iterator * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_range Scala's Parallel Collections Library overview]] + * section on `ParRange` for more information. * * @define Coll immutable.ParRange * @define coll immutable parallel range diff --git a/src/library/scala/collection/parallel/immutable/ParVector.scala b/src/library/scala/collection/parallel/immutable/ParVector.scala index 5d9c431bc1..8baa84b77c 100644 --- a/src/library/scala/collection/parallel/immutable/ParVector.scala +++ b/src/library/scala/collection/parallel/immutable/ParVector.scala @@ -34,6 +34,8 @@ import immutable.VectorIterator * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_vector Scala's Parallel Collections Library overview]] + * section on `ParVector` for more information. * * @define Coll immutable.ParVector * @define coll immutable parallel vector diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index c33495bd39..8cc0b95997 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -44,10 +44,14 @@ import scala.collection.GenTraversableOnce * * @tparam T type of the elements in the array * + * @author Aleksandar Prokopec + * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_array Scala's Parallel Collections Library overview]] + * section on `ParArray` for more information. + * * @define Coll ParArray * @define coll parallel array * - * @author Aleksandar Prokopec */ @SerialVersionUID(1L) class ParArray[T] private[mutable] (val arrayseq: ArraySeq[T]) diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 6ce6c45460..23b23d55a1 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -32,6 +32,8 @@ import collection.parallel.Task * @define coll parallel hash map * * @author Aleksandar Prokopec + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tables for more information. */ @SerialVersionUID(1L) class ParHashMap[K, V] private[collection] (contents: HashTable.Contents[K, DefaultEntry[K, V]]) diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala index e0a2ab03df..4e9a38c13f 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala @@ -29,6 +29,8 @@ import collection.parallel.Task * @define coll parallel hash set * * @author Aleksandar Prokopec + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tables for more information. */ @SerialVersionUID(1L) class ParHashSet[T] private[collection] (contents: FlatHashTable.Contents[T]) diff --git a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala index fa19990b91..359c35f1dd 100644 --- a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala @@ -33,6 +33,8 @@ import scala.collection.concurrent.TrieMapIterator * * @author Aleksandar Prokopec * @since 2.10 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_concurrent_tries Scala's Parallel Collections Library overview]] + * section on `ParTrieMap` for more information. */ final class ParTrieMap[K, V] private[collection] (private val ctrie: TrieMap[K, V]) extends ParMap[K, V] diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index c1f45eccfb..cb42b76b51 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -183,7 +183,8 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that case that: BigInt => this.toBigIntExact exists (that equals _) - case _: Float | _: Double => unifiedPrimitiveEquals(that) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case _ => isValidLong && unifiedPrimitiveEquals(that) } override def isValidByte = noArithmeticException(toByteExact) @@ -191,6 +192,18 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue override def isValidInt = noArithmeticException(toIntExact) def isValidLong = noArithmeticException(toLongExact) + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val f = toFloat + !f.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(f)) == 0 + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val d = toDouble + !d.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(d)) == 0 + } private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 8a53afaa62..dbec30b2fe 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -20,6 +20,7 @@ object BigInt { private val minCached = -1024 private val maxCached = 1024 private val cache = new Array[BigInt](maxCached - minCached + 1) + private val minusOne = BigInteger.valueOf(-1) @deprecated("Use Long.MinValue", "2.9.0") val MinLong = BigInt(Long.MinValue) @@ -122,6 +123,8 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def equals(that: Any): Boolean = that match { case that: BigInt => this equals that case that: BigDecimal => that.toBigIntExact exists (this equals _) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case x => isValidLong && unifiedPrimitiveEquals(x) } override def isValidByte = this >= Byte.MinValue && this <= Byte.MaxValue @@ -129,6 +132,41 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def isValidChar = this >= Char.MinValue && this <= Char.MaxValue override def isValidInt = this >= Int.MinValue && this <= Int.MaxValue def isValidLong = this >= Long.MinValue && this <= Long.MaxValue + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val bitLen = bitLength + (bitLen <= 24 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Float.MAX_EXPONENT + 1 && // exclude this < -2^128 && this >= 2^128 + lowest >= bitLen - 24 && + lowest < java.lang.Float.MAX_EXPONENT + 1 // exclude this == -2^128 + } + ) && !bitLengthOverflow + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val bitLen = bitLength + (bitLen <= 53 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Double.MAX_EXPONENT + 1 && // exclude this < -2^1024 && this >= 2^1024 + lowest >= bitLen - 53 && + lowest < java.lang.Double.MAX_EXPONENT + 1 // exclude this == -2^1024 + } + ) && !bitLengthOverflow + } + /** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue . + * The BigInteger.bitLength method returns truncated bit length in this case . + * This method tests if result of bitLength is valid. + * This method will become unnecessary if BigInt constructors reject huge BigIntegers. + */ + private def bitLengthOverflow = { + val shifted = bigInteger.shiftRight(Int.MaxValue) + (shifted.signum != 0) && !(shifted equals BigInt.minusOne) + } protected[math] def isWhole = true def underlying = bigInteger diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index cbe778f09b..2e435d8a7e 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -8,45 +8,61 @@ package scala.runtime -import scala.annotation.unchecked.uncheckedVariance - -/** This class provides a default implementation of partial functions - * that is used for all partial function literals. - * It contains an optimized `orElse` method which supports - * chained `orElse` in linear time, and with no slow-down - * if the `orElse` part is not needed. - * The implementation of `orElse` works by cloning the abstract function object - * and modifying a private `fallBack` variable that encodes the `getorElse` part. +/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`. + * + * This allows more efficient implementations in many cases: + * - optimized `orElse` method supports chained `orElse` in linear time, + * and with no slow-down if the `orElse` part is not needed. + * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards + * of partial function literals. + * + * This trait is used as a basis for implementation of all partial function literals + * with non-exhaustive matchers. + * + * Use of `AbstractPartialFunction` instead of `PartialFunction` as a base trait for + * user-defined partial functions may result in better performance + * and more predictable behavior w.r.t. side effects. + * + * @author Pavel Pavlov + * @since 2.10 */ -abstract class AbstractPartialFunction[-T1, +R] - extends AbstractFunction1[T1, R] - with PartialFunction[T1, R] - with Cloneable { - - private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _ +abstract class AbstractPartialFunction[@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 Function1[T1, R] with PartialFunction[T1, R] { self => + // this method must be overridden for better performance, + // for backwards compatibility, fall back to the one inherited from PartialFunction + // this assumes the old-school partial functions override the apply method, though + // override def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = ??? - def fallBack: PartialFunction[T1, R] = synchronized { - if (fallBackField eq null) fallBackField = PartialFunction.empty - fallBackField - } + // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction + // let's not make it final so as not to confuse anyone + /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty) - override protected def missingCase(x: T1): R = fallBack(x) - - // Question: Need to ensure that fallBack is overwritten before any access - // Is the `synchronized` here the right thing to achieve this? - // Is there a cheaper way? - override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = { - val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]] - result.synchronized { - result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that - result + override final def andThen[C](k: R => C) : PartialFunction[T1, C] = + new AbstractPartialFunction[T1, C] { + def isDefinedAt(x: T1): Boolean = self.isDefinedAt(x) + override def applyOrElse[A1 <: T1, C1 >: C](x: A1, default: A1 => C1): C1 = + self.applyOrElse(x, PartialFunction.fallbackToken) match { + case PartialFunction.FallbackToken => default(x) + case z => k(z) + } } - } - - def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) || fallBack.isDefinedAt(x) - def _isDefinedAt(x: T1): scala.Boolean + // TODO: remove + protected def missingCase(x: T1): R = throw new MatchError(x) } - +/** `AbstractTotalFunction` is a partial function whose `isDefinedAt` method always returns `true`. + * + * This class is used as base class for partial function literals with + * certainly exhaustive pattern matchers. + * + * @author Pavel Pavlov + * @since 2.10 + */ +abstract class AbstractTotalFunction[@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 Function1[T1, R] with PartialFunction[T1, R] { + final def isDefinedAt(x: T1): Boolean = true + override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x) + override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this + //TODO: check generated code for PF literal here + override final def andThen[C](k: R => C): PartialFunction[T1, C] = { case x => k(apply(x)) } +} diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index 5e3f8b6451..20a179a884 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -230,8 +230,5 @@ object Exception { classes exists (_ isAssignableFrom x.getClass) private def pfFromExceptions(exceptions: Class[_]*): PartialFunction[Throwable, Nothing] = - new scala.runtime.AbstractPartialFunction[Throwable, Nothing] { - def apply(x: Throwable) = throw x - def _isDefinedAt(x: Throwable) = wouldMatch(x, exceptions) - } + { case x if wouldMatch(x, exceptions) => throw x } } diff --git a/test/files/neg/override-object-flag.check b/test/files/neg/override-object-flag.check index 152d31ff8a..344165138d 100644 --- a/test/files/neg/override-object-flag.check +++ b/test/files/neg/override-object-flag.check @@ -1,4 +1,4 @@ -override-object-flag.scala:3: error: overriding object Foo in trait A of type object B.this.Foo; +override-object-flag.scala:3: error: overriding object Foo in trait A; object Foo cannot override final member trait B extends A { override object Foo } ^ diff --git a/test/files/neg/override-object-no.check b/test/files/neg/override-object-no.check index f9fb37381b..52bad2b937 100644 --- a/test/files/neg/override-object-no.check +++ b/test/files/neg/override-object-no.check @@ -10,7 +10,7 @@ an overriding object must conform to the overridden object's class bound; required: Object{def g: Int} trait Quux2 extends Quux1 { override object Bar { def g = "abc" } } // err ^ -override-object-no.scala:25: error: overriding object Bar in trait Quux3 of type object Quux4.this.Bar; +override-object-no.scala:25: error: overriding object Bar in trait Quux3; object Bar cannot override final member trait Quux4 extends Quux3 { override object Bar } // err ^ diff --git a/test/files/neg/t961.check b/test/files/neg/t961.check index 48273f764d..14d39b0f42 100644 --- a/test/files/neg/t961.check +++ b/test/files/neg/t961.check @@ -1,4 +1,4 @@ -t961.scala:11: error: object Temp.B does not take parameters +t961.scala:11: error: Temp.B.type does not take parameters B() match { ^ one error found diff --git a/test/files/pos/t4545.scala b/test/files/pos/t4545.scala new file mode 100644 index 0000000000..8c7a3236c4 --- /dev/null +++ b/test/files/pos/t4545.scala @@ -0,0 +1,14 @@ +object Test { + def f[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T](table: Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T) => Unit) { + } + def g[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U](table: Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U])(fun: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U) => Unit) { + } + + def g20 = f( + ( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t)) => () } + + def g21 = g( + (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) + ) { case ((a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u)) => () } +} diff --git a/test/files/presentation/callcc-interpreter.check b/test/files/presentation/callcc-interpreter.check index 3385ef12b7..c50e171b4e 100644 --- a/test/files/presentation/callcc-interpreter.check +++ b/test/files/presentation/callcc-interpreter.check @@ -52,7 +52,7 @@ retrieved 64 members `method wait(x$1: Long, x$2: Int)Unit` `method x=> callccInterpreter.type` `method →[B](y: B)(callccInterpreter.type, B)` -`object Wrongobject callccInterpreter.Wrong` +`object WrongcallccInterpreter.Wrong.type` `trait TermcallccInterpreter.Term` `trait ValuecallccInterpreter.Value` `type AnswercallccInterpreter.Answer` diff --git a/test/files/run/concurrent-map-conversions.scala b/test/files/run/concurrent-map-conversions.scala new file mode 100644 index 0000000000..0350b69642 --- /dev/null +++ b/test/files/run/concurrent-map-conversions.scala @@ -0,0 +1,36 @@ + + + + + +object Test { + + def main(args: Array[String]) { + testConversions() + testConverters() + } + + def needPackageConcurrentMap(map: collection.concurrent.Map[Int, Int]) { + } + def needJavaConcurrent(map: java.util.concurrent.ConcurrentMap[Int, Int]) { + } + + def testConversions() { + import collection.JavaConversions._ + val skiplist = new java.util.concurrent.ConcurrentSkipListMap[Int, Int] + val ctrie = new collection.concurrent.TrieMap[Int, Int] + + needPackageConcurrentMap(skiplist) + needJavaConcurrent(ctrie) + } + + def testConverters() { + import collection.JavaConverters._ + val skiplist = new java.util.concurrent.ConcurrentSkipListMap[Int, Int] + val ctrie = new collection.concurrent.TrieMap[Int, Int] + + needPackageConcurrentMap(skiplist.asScala) + needJavaConcurrent(ctrie.asJava) + } + +} diff --git a/test/files/run/finalvar.check b/test/files/run/finalvar.check new file mode 100644 index 0000000000..2496293972 --- /dev/null +++ b/test/files/run/finalvar.check @@ -0,0 +1,6 @@ +(2,2,2,2,1) +(2,2,2,2) +(2,2,2,2,1001) +(2,2,2,2) +2 +10 diff --git a/test/files/run/finalvar.flags b/test/files/run/finalvar.flags new file mode 100644 index 0000000000..aee3039bec --- /dev/null +++ b/test/files/run/finalvar.flags @@ -0,0 +1 @@ +-Yoverride-vars -Yinline
\ No newline at end of file diff --git a/test/files/run/finalvar.scala b/test/files/run/finalvar.scala new file mode 100644 index 0000000000..010813e520 --- /dev/null +++ b/test/files/run/finalvar.scala @@ -0,0 +1,37 @@ +object Final { + class X(final var x: Int) { } + def f = new X(0).x += 1 +} + +class A { + var x = 1 + def y0 = x + def y1 = this.x + def y2 = (this: A).x +} + +class B extends A { + override def x = 2 + def z = super.x +} + +object Test { + def main(args: Array[String]): Unit = { + Final.f + val a = new B + println((a.x, a.y0, a.y1, a.y2, a.z)) + val a0: A = a + println((a0.x, a0.y0, a0.y1, a0.y2)) + a.x = 1001 + println((a.x, a.y0, a.y1, a.y2, a.z)) + println((a0.x, a0.y0, a0.y1, a0.y2)) + + val d = new D + println(d.w) + d.ten + println(d.w) + } +} + +class C { var w = 1 ; def ten = this.w = 10 } +class D extends C { override var w = 2 }
\ No newline at end of file diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala index f919a21dee..9c43e98911 100644 --- a/test/files/run/is-valid-num.scala +++ b/test/files/run/is-valid-num.scala @@ -1,11 +1,15 @@ object Test { def x = BigInt("10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") def y = BigDecimal("" + (Short.MaxValue + 1) + ".0") + def y1 = BigDecimal("0.1") + def y2 = BigDecimal("0.5") def l1 = Int.MaxValue.toLong + 1 def l2 = Int.MinValue.toLong - 1 def main(args: Array[String]): Unit = { + assert(!x.isValidDouble, x) + assert(!x.isValidFloat, x) assert(!x.isValidLong, x) assert(!x.isValidInt, x) assert(!x.isValidChar, x) @@ -13,8 +17,81 @@ object Test { assert(!y.isValidShort, y) assert(y.isValidChar, y) assert(y.isValidInt, y) + assert(y.isValidFloat, y) + assert(y.isValidDouble, y) + assert(!y1.isValidLong, y1) + assert(!y1.isValidFloat, y1) + assert(!y1.isValidDouble, y1) + assert(!y2.isValidLong, y2) + assert(y2.isValidFloat, y2) + assert(y2.isValidDouble, y2) + + testBigIntIsFloat() + testBigIntIsDouble() assert(!l1.isValidInt && (l1 - 1).isValidInt, l1) assert(!l2.isValidInt && (l2 + 1).isValidInt, l2) } + + def biExp2(e: Int) = BigInt(1) << e + + def testBigIntIsFloat() { + val prec = 24 + def checkFloatT(x: BigInt) = { + assert(x.isValidFloat, x) + assert((-x).isValidFloat, -x) + } + def checkFloatF(x: BigInt) = { + assert(!x.isValidFloat, x) + assert(!(-x).isValidFloat, -x) + } + checkFloatT(biExp2(prec) - 1) + checkFloatT(biExp2(prec)) + checkFloatF(biExp2(prec) + 1) + checkFloatT(biExp2(prec) + 2) + checkFloatT(biExp2(prec) - 2) + checkFloatF(biExp2(prec + 1) - 1) + checkFloatT(biExp2(prec + 1)) + checkFloatF(biExp2(prec + 1) + 1) + checkFloatF(biExp2(prec + 1) + 2) + checkFloatF(biExp2(prec + 1) + 3) + checkFloatT(biExp2(prec + 1) + 4) + checkFloatT(biExp2(64)) + checkFloatF(biExp2(64) + biExp2(64 - prec)) + checkFloatT(biExp2(64) + biExp2(64 - prec + 1)) + checkFloatT(biExp2(127)) + checkFloatT(biExp2(128) - biExp2(128 - prec)) + checkFloatF(biExp2(128) - biExp2(128 - prec - 1)) + checkFloatF(biExp2(128)) + } + + def testBigIntIsDouble() { + val prec = 53 + def checkDoubleT(x: BigInt) = { + assert(x.isValidDouble, x) + assert((-x).isValidDouble, -x) + } + def checkDoubleF(x: BigInt) = { + assert(!x.isValidDouble, x) + assert(!(-x).isValidDouble, -x) + } + checkDoubleT(biExp2(prec) - 1) + checkDoubleT(biExp2(prec)) + checkDoubleF(biExp2(prec) + 1) + checkDoubleT(biExp2(prec) + 2) + checkDoubleT(biExp2(prec + 1) - 2) + checkDoubleF(biExp2(prec + 1) - 1) + checkDoubleT(biExp2(prec + 1)) + checkDoubleF(biExp2(prec + 1) + 1) + checkDoubleF(biExp2(prec + 1) + 2) + checkDoubleF(biExp2(prec + 1) + 3) + checkDoubleT(biExp2(prec + 1) + 4) + checkDoubleT(biExp2(64)) + checkDoubleF(biExp2(64) + biExp2(64 - prec)) + checkDoubleT(biExp2(64) + biExp2(64 - prec + 1)) + checkDoubleT(biExp2(1023)) + checkDoubleT(biExp2(1024) - biExp2(1024 - prec)) + checkDoubleF(biExp2(1024) - biExp2(1024 - prec - 1)) + checkDoubleF(biExp2(1024)) + } } diff --git a/test/files/run/lift-and-unlift.scala b/test/files/run/lift-and-unlift.scala index b944c70155..a4a5d9502e 100644 --- a/test/files/run/lift-and-unlift.scala +++ b/test/files/run/lift-and-unlift.scala @@ -2,7 +2,7 @@ import Function.unlift object Test { def evens1(x: Int) = if (x % 2 == 0) Some(x) else None - def evens2: PartialFunction[Int, Int] = { + val evens2: PartialFunction[Int, Int] = { case x if x % 2 == 0 => x } @@ -21,7 +21,7 @@ object Test { }) assert(f1 eq f3.lift) - // Hmm, why is this not true: - // assert(f2 eq f4.lift) + assert(f4 eq unlift(f2)) + assert(f4 eq evens2) } } diff --git a/test/files/run/numbereq.scala b/test/files/run/numbereq.scala index 77a217df36..a1f11da205 100644 --- a/test/files/run/numbereq.scala +++ b/test/files/run/numbereq.scala @@ -16,7 +16,20 @@ object Test { base ::: extras } - + + def mkNumbers(x: BigInt): List[AnyRef] = { + List( + List(BigDecimal(x, java.math.MathContext.UNLIMITED)), + List(x), + if (x.isValidDouble) List(new java.lang.Double(x.toDouble)) else Nil, + if (x.isValidFloat) List(new java.lang.Float(x.toFloat)) else Nil, + if (x.isValidLong) List(new java.lang.Long(x.toLong)) else Nil, + if (x.isValidInt) List(new java.lang.Integer(x.toInt)) else Nil, + if (x.isValidShort) List(new java.lang.Short(x.toShort)) else Nil, + if (x.isValidByte) List(new java.lang.Byte(x.toByte)) else Nil, + if (x.isValidChar) List(new java.lang.Character(x.toChar)) else Nil + ).flatten + } def main(args: Array[String]): Unit = { val ints = (0 to 15).toList map (Short.MinValue >> _) @@ -37,5 +50,23 @@ object Test { assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) } + + val bigInts = (0 to 1024).toList map (BigInt(-1) << _) + val bigInts2 = bigInts map (x => -x) + val bigInts3 = bigInts map (_ + 1) + val bigInts4 = bigInts2 map (_ - 1) + + val setneg1b = bigInts map mkNumbers + val setneg2b = bigInts3 map mkNumbers + val setpos1b = bigInts2 map mkNumbers + val setpos2b = bigInts4 map mkNumbers + + val sets2 = setneg1 ++ setneg1b ++ setneg2 ++ setneg2b ++ List(zero) ++ setpos1 ++ setpos1b ++ setpos2 ++ setpos2b + + for (set <- sets2 ; x <- set ; y <- set) { +// println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) + assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) +// assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) Disable until Double.## is fixed (SI-5640) + } } -}
\ No newline at end of file +} diff --git a/test/pending/pos/t1476.scala b/test/pending/pos/t1476.scala new file mode 100644 index 0000000000..1f8e95c28f --- /dev/null +++ b/test/pending/pos/t1476.scala @@ -0,0 +1,23 @@ +abstract class Module { + def moduleDemands(): List[Module] +} + +object Test { + new Module { owner: Module => + def moduleDemands() = Nil + + val a = new Module { def moduleDemands(): List[Module] = Nil } + val b = new Module { def moduleDemands(): List[Module] = owner :: c :: Nil } + val c = new Module { def moduleDemands(): List[Module] = owner :: a :: Nil } + } +} + +object Test2 { + new Module { owner => + def moduleDemands() = Nil + + val a = new Module { def moduleDemands(): List[Module] = Nil } + val b = new Module { def moduleDemands(): List[Module] = owner :: c :: Nil } + val c = new Module { def moduleDemands(): List[Module] = owner :: a :: Nil } + } +} diff --git a/test/pending/pos/t5626.scala b/test/pending/pos/t5626.scala new file mode 100644 index 0000000000..7ab3881827 --- /dev/null +++ b/test/pending/pos/t5626.scala @@ -0,0 +1,12 @@ +object Test { + val blob0 = new { + case class Foo(i : Int) + } + val foo0 = blob0.Foo(22) + + val blob1 = new { + class Foo(i: Int) + object Foo { def apply(i: Int): Foo = new Foo(i) } + } + val foo1 = blob1.Foo(22) +} diff --git a/test/pending/run/t5629.check b/test/pending/run/t5629.check new file mode 100644 index 0000000000..6a2d630f4e --- /dev/null +++ b/test/pending/run/t5629.check @@ -0,0 +1,2 @@ +int child got: 33 +any child got: 33 diff --git a/test/pending/run/t5629.scala b/test/pending/run/t5629.scala new file mode 100644 index 0000000000..28e74a1c94 --- /dev/null +++ b/test/pending/run/t5629.scala @@ -0,0 +1,25 @@ +import scala.{specialized => spec} + +trait GrandParent[@spec(Int) -A] { + def foo(a:A): Unit + def bar[B <: A](b:B): Unit = println("grandparent got: %s" format b) +} + +trait Parent[@spec(Int) -A] extends GrandParent[A] { + def foo(a:A) = bar(a) +} + +class IntChild extends Parent[Int] { + override def bar[B <: Int](b:B): Unit = println("int child got: %s" format b) +} + +class AnyChild extends Parent[Any] { + override def bar[B <: Any](b:B): Unit = println("any child got: %s" format b) +} + +object Test { + def main(args:Array[String]) { + new IntChild().foo(33) + new AnyChild().foo(33) + } +} |