diff options
Diffstat (limited to 'src')
51 files changed, 728 insertions, 449 deletions
diff --git a/src/actors-migration/scala/actors/Pattern.scala b/src/actors-migration/scala/actors/Pattern.scala index fa2db79152..a97ee3ba07 100644 --- a/src/actors-migration/scala/actors/Pattern.scala +++ b/src/actors-migration/scala/actors/Pattern.scala @@ -1,6 +1,6 @@ package scala.actors -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration import scala.language.implicitConversions object pattern { diff --git a/src/actors-migration/scala/actors/StashingActor.scala b/src/actors-migration/scala/actors/StashingActor.scala index 29f370a3e2..775d115d0b 100644 --- a/src/actors-migration/scala/actors/StashingActor.scala +++ b/src/actors-migration/scala/actors/StashingActor.scala @@ -1,7 +1,7 @@ package scala.actors import scala.collection._ -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration import java.util.concurrent.TimeUnit import scala.language.implicitConversions diff --git a/src/actors-migration/scala/actors/Timeout.scala b/src/actors-migration/scala/actors/Timeout.scala index 5540d2880e..c3017d8569 100644 --- a/src/actors-migration/scala/actors/Timeout.scala +++ b/src/actors-migration/scala/actors/Timeout.scala @@ -8,7 +8,7 @@ package scala.actors -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration import java.util.concurrent.TimeUnit import scala.language.implicitConversions diff --git a/src/actors/scala/actors/ActorRef.scala b/src/actors/scala/actors/ActorRef.scala index 8f70b13e01..7768f04c2b 100644 --- a/src/actors/scala/actors/ActorRef.scala +++ b/src/actors/scala/actors/ActorRef.scala @@ -1,7 +1,7 @@ package scala.actors import java.util.concurrent.TimeoutException -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration /** * Trait used for migration of Scala actors to Akka. diff --git a/src/build/bnd/continuations.bnd b/src/build/bnd/continuations.bnd new file mode 100644 index 0000000000..748502f653 --- /dev/null +++ b/src/build/bnd/continuations.bnd @@ -0,0 +1,5 @@ +Bundle-Name: Scala Continuations Plugin +Bundle-SymbolicName: org.scala-lang.plugins.continuations +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} diff --git a/src/build/bnd/scala-actors-migration.bnd b/src/build/bnd/scala-actors-migration.bnd new file mode 100644 index 0000000000..2cddfb620a --- /dev/null +++ b/src/build/bnd/scala-actors-migration.bnd @@ -0,0 +1,5 @@ +Bundle-Name: Scala Actors Migration +Bundle-SymbolicName: org.scala-lang.scala-actors-migration +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} diff --git a/src/build/bnd/scala-actors.bnd b/src/build/bnd/scala-actors.bnd new file mode 100644 index 0000000000..8d0555777f --- /dev/null +++ b/src/build/bnd/scala-actors.bnd @@ -0,0 +1,5 @@ +Bundle-Name: Scala Actors +Bundle-SymbolicName: org.scala-lang.scala-actors +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} diff --git a/src/build/bnd/scala-compiler.bnd b/src/build/bnd/scala-compiler.bnd new file mode 100644 index 0000000000..c289843447 --- /dev/null +++ b/src/build/bnd/scala-compiler.bnd @@ -0,0 +1,8 @@ +Bundle-Name: Scala Compiler +Bundle-SymbolicName: org.scala-lang.scala-compiler +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} +Import-Package: scala.tools.jline.*;resolution:=optional, \ + org.apache.tools.ant.*;resolution:=optional, \ + * diff --git a/src/build/bnd/scala-library.bnd b/src/build/bnd/scala-library.bnd new file mode 100644 index 0000000000..03aff45672 --- /dev/null +++ b/src/build/bnd/scala-library.bnd @@ -0,0 +1,6 @@ +Bundle-Name: Scala Standard Library +Bundle-SymbolicName: org.scala-lang.scala-library +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} +Import-Package: sun.misc;resolution:=optional, * diff --git a/src/build/bnd/scala-reflect.bnd b/src/build/bnd/scala-reflect.bnd new file mode 100644 index 0000000000..6cda346d3a --- /dev/null +++ b/src/build/bnd/scala-reflect.bnd @@ -0,0 +1,6 @@ +Bundle-Name: Scala Reflect +Bundle-SymbolicName: org.scala-lang.scala-reflect +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} +Import-Package: scala.tools.nsc;resolution:=optional, * diff --git a/src/build/bnd/scala-swing.bnd b/src/build/bnd/scala-swing.bnd new file mode 100644 index 0000000000..eeacb9bd3f --- /dev/null +++ b/src/build/bnd/scala-swing.bnd @@ -0,0 +1,5 @@ +Bundle-Name: Scala Swing +Bundle-SymbolicName: org.scala-lang.scala-swing +ver: @VERSION@ +Bundle-Version: ${ver} +Export-Package: *;version=${ver} diff --git a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala index ebde4447d7..b5c988ca83 100644 --- a/src/compiler/scala/reflect/macros/runtime/Enclosures.scala +++ b/src/compiler/scala/reflect/macros/runtime/Enclosures.scala @@ -14,7 +14,7 @@ trait Enclosures { // vals are eager to simplify debugging // after all we wouldn't save that much time by making them lazy val macroApplication: Tree = expandee - val enclosingClass: Tree = site.enclClass.tree + val enclosingClass: Tree = enclTrees collectFirst { case x: ImplDef => x } getOrElse EmptyTree val enclosingImplicits: List[(Type, Tree)] = site.openImplicits val enclosingMacros: List[Context] = this :: universe.analyzer.openMacros // include self val enclosingMethod: Tree = site.enclMethod.tree diff --git a/src/compiler/scala/reflect/reify/package.scala b/src/compiler/scala/reflect/reify/package.scala index 2600956805..5a23ab7214 100644 --- a/src/compiler/scala/reflect/reify/package.scala +++ b/src/compiler/scala/reflect/reify/package.scala @@ -72,7 +72,7 @@ package object reify { def reifyEnclosingRuntimeClass(global: Global)(typer0: global.analyzer.Typer): global.Tree = { import global._ import definitions._ - def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[Template]) + def isThisInScope = typer0.context.enclosingContextChain exists (_.tree.isInstanceOf[ImplDef]) if (isThisInScope) { val enclosingClasses = typer0.context.enclosingContextChain map (_.tree) collect { case classDef: ClassDef => classDef } val classInScope = enclosingClasses.headOption getOrElse EmptyTree diff --git a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl index 3c0d1d77ca..a347df6d6e 100644 --- a/src/compiler/scala/tools/ant/templates/tool-windows.tmpl +++ b/src/compiler/scala/tools/ant/templates/tool-windows.tmpl @@ -1,91 +1,91 @@ -@@echo off
-
-rem ##########################################################################
-rem # Copyright 2002-2012 LAMP/EPFL
-rem #
-rem # This is free software; see the distribution for copying conditions.
-rem # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
-rem # PARTICULAR PURPOSE.
-rem ##########################################################################
-
-setlocal enableextensions enabledelayedexpansion
-
-set _LINE_TOOLCP=
-
-:another_param
-
-if "%1%"=="-toolcp" (
- set _LINE_TOOLCP=%2%
- shift
- shift
- goto another_param
-)
-
-set _LINE_PARAMS=%1
-:param_loop
-shift
-if [%1]==[] goto param_afterloop
-set _LINE_PARAMS=%_LINE_PARAMS% %1
-goto param_loop
-:param_afterloop
-if "%OS%" NEQ "Windows_NT" (
- echo "Warning, your version of Windows is not supported. Attempting to start scala anyway."
-)
-
-@@setlocal
-call :set_home
-
-rem We use the value of the JAVACMD environment variable if defined
-set _JAVACMD=%JAVACMD%
-
-if not defined _JAVACMD (
- if not "%JAVA_HOME%"=="" (
- if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe"
- )
-)
-
-if "%_JAVACMD%"=="" set _JAVACMD=java
-
-rem We use the value of the JAVA_OPTS environment variable if defined
-set _JAVA_OPTS=%JAVA_OPTS%
-if not defined _JAVA_OPTS set _JAVA_OPTS=@javaflags@
-
-set _TOOL_CLASSPATH=@classpath@
-if "%_TOOL_CLASSPATH%"=="" (
- for %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f"
- for /d %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f"
-)
-
-if not "%_LINE_TOOLCP%"=="" call :add_cpath "%_LINE_TOOLCP%"
-
-set _PROPS=-Dscala.home="!_SCALA_HOME!" -Denv.emacs="%EMACS%" -Dscala.usejavacp=true @properties@
-
-rem echo "%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %*
-"%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %*
-goto end
-
-rem ##########################################################################
-rem # subroutines
-
-:add_cpath
- if "%_TOOL_CLASSPATH%"=="" (
- set _TOOL_CLASSPATH=%~1
- ) else (
- set _TOOL_CLASSPATH=%_TOOL_CLASSPATH%;%~1
- )
-goto :eof
-
-rem Variable "%~dps0" works on WinXP SP2 or newer
-rem (see http://support.microsoft.com/?kbid=833431)
-rem set _SCALA_HOME=%~dps0..
-:set_home
- set _BIN_DIR=
- for %%i in (%~sf0) do set _BIN_DIR=%_BIN_DIR%%%~dpsi
- set _SCALA_HOME=%_BIN_DIR%..
-goto :eof
-
-:end
-@@endlocal
-
-REM exit code fix, see http://stackoverflow.com/questions/4632891/exiting-batch-with-exit-b-x-where-x-1-acts-as-if-command-completed-successfu
-@@%COMSPEC% /C exit %errorlevel% >nul
+@@echo off + +rem ########################################################################## +rem # Copyright 2002-2012 LAMP/EPFL +rem # +rem # This is free software; see the distribution for copying conditions. +rem # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A +rem # PARTICULAR PURPOSE. +rem ########################################################################## + +setlocal enableextensions enabledelayedexpansion + +set _LINE_TOOLCP= + +:another_param + +if "%1%"=="-toolcp" ( + set _LINE_TOOLCP=%2% + shift + shift + goto another_param +) + +set _LINE_PARAMS=%1 +:param_loop +shift +if [%1]==[] goto param_afterloop +set _LINE_PARAMS=%_LINE_PARAMS% %1 +goto param_loop +:param_afterloop +if "%OS%" NEQ "Windows_NT" ( + echo "Warning, your version of Windows is not supported. Attempting to start scala anyway." +) + +@@setlocal +call :set_home + +rem We use the value of the JAVACMD environment variable if defined +set _JAVACMD=%JAVACMD% + +if not defined _JAVACMD ( + if not "%JAVA_HOME%"=="" ( + if exist "%JAVA_HOME%\bin\java.exe" set "_JAVACMD=%JAVA_HOME%\bin\java.exe" + ) +) + +if "%_JAVACMD%"=="" set _JAVACMD=java + +rem We use the value of the JAVA_OPTS environment variable if defined +set _JAVA_OPTS=%JAVA_OPTS% +if not defined _JAVA_OPTS set _JAVA_OPTS=@javaflags@ + +set _TOOL_CLASSPATH=@classpath@ +if "%_TOOL_CLASSPATH%"=="" ( + for %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f" + for /d %%f in ("!_SCALA_HOME!\lib\*") do call :add_cpath "%%f" +) + +if not "%_LINE_TOOLCP%"=="" call :add_cpath "%_LINE_TOOLCP%" + +set _PROPS=-Dscala.home="!_SCALA_HOME!" -Denv.emacs="%EMACS%" -Dscala.usejavacp=true @properties@ + +rem echo "%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %* +"%_JAVACMD%" %_JAVA_OPTS% %_PROPS% -cp "%_TOOL_CLASSPATH%" @class@ @toolflags@ %* +goto end + +rem ########################################################################## +rem # subroutines + +:add_cpath + if "%_TOOL_CLASSPATH%"=="" ( + set _TOOL_CLASSPATH=%~1 + ) else ( + set _TOOL_CLASSPATH=%_TOOL_CLASSPATH%;%~1 + ) +goto :eof + +rem Variable "%~dps0" works on WinXP SP2 or newer +rem (see http://support.microsoft.com/?kbid=833431) +rem set _SCALA_HOME=%~dps0.. +:set_home + set _BIN_DIR= + for %%i in (%~sf0) do set _BIN_DIR=%_BIN_DIR%%%~dpsi + set _SCALA_HOME=%_BIN_DIR%.. +goto :eof + +:end +@@endlocal + +REM exit code fix, see http://stackoverflow.com/questions/4632891/exiting-batch-with-exit-b-x-where-x-1-acts-as-if-command-completed-successfu +@@%COMSPEC% /C exit %errorlevel% >nul diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 6fb6b1736b..58fcee4b30 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1094,6 +1094,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) // TODO - trim these to the absolute minimum. @inline final def afterErasure[T](op: => T): T = afterPhase(currentRun.erasurePhase)(op) + @inline final def afterPostErasure[T](op: => T): T = afterPhase(currentRun.posterasurePhase)(op) @inline final def afterExplicitOuter[T](op: => T): T = afterPhase(currentRun.explicitouterPhase)(op) @inline final def afterFlatten[T](op: => T): T = afterPhase(currentRun.flattenPhase)(op) @inline final def afterIcode[T](op: => T): T = afterPhase(currentRun.icodePhase)(op) @@ -1403,6 +1404,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) val specializePhase = phaseNamed("specialize") val explicitouterPhase = phaseNamed("explicitouter") val erasurePhase = phaseNamed("erasure") + val posterasurePhase = phaseNamed("posterasure") // val lazyvalsPhase = phaseNamed("lazyvals") val lambdaliftPhase = phaseNamed("lambdalift") // val constructorsPhase = phaseNamed("constructors") diff --git a/src/compiler/scala/tools/nsc/io/package.scala b/src/compiler/scala/tools/nsc/io/package.scala index 775ad6bde0..ae83a7728b 100644 --- a/src/compiler/scala/tools/nsc/io/package.scala +++ b/src/compiler/scala/tools/nsc/io/package.scala @@ -11,6 +11,23 @@ import java.util.jar.{ Attributes } import scala.language.implicitConversions package object io { + // Forwarders from scala.reflect.io + type AbstractFile = scala.reflect.io.AbstractFile + val AbstractFile = scala.reflect.io.AbstractFile + type Directory = scala.reflect.io.Directory + val Directory = scala.reflect.io.Directory + type File = scala.reflect.io.File + val File = scala.reflect.io.File + type Path = scala.reflect.io.Path + val Path = scala.reflect.io.Path + type PlainFile = scala.reflect.io.PlainFile + val PlainFile = scala.reflect.io.PlainFile + val Streamable = scala.reflect.io.Streamable + type VirtualDirectory = scala.reflect.io.VirtualDirectory + type VirtualFile = scala.reflect.io.VirtualFile + val ZipArchive = scala.reflect.io.ZipArchive + type ZipArchive = scala.reflect.io.ZipArchive + implicit def postfixOps = scala.language.postfixOps // make all postfix ops in this package compile without warning type JManifest = java.util.jar.Manifest diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index b3b0c82d38..072d823c60 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -167,6 +167,8 @@ abstract class Erasure extends AddInterfaces case tp => tp :: Nil } + private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] + /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ @@ -373,18 +375,18 @@ abstract class Erasure extends AddInterfaces } } - class ComputeBridges(owner: Symbol) { + class ComputeBridges(unit: CompilationUnit, root: Symbol) { assert(phase == currentRun.erasurePhase, phase) var toBeRemoved = immutable.Set[Symbol]() - val site = owner.thisType + val site = root.thisType val bridgesScope = newScope val bridgeTarget = mutable.HashMap[Symbol, Symbol]() var bridges = List[Tree]() val opc = beforeExplicitOuter { - new overridingPairs.Cursor(owner) { - override def parents = List(owner.info.firstParent) + new overridingPairs.Cursor(root) { + override def parents = List(root.info.firstParent) override def exclude(sym: Symbol) = !sym.isMethod || sym.isPrivate || super.exclude(sym) } } @@ -402,8 +404,58 @@ abstract class Erasure extends AddInterfaces (bridges, toBeRemoved) } + /** Check that a bridge only overrides members that are also overridden by the original member. + * This test is necessary only for members that have a value class in their type. + * Such members are special because their types after erasure and after post-erasure differ/. + * This means we generate them after erasure, but the post-erasure transform might introduce + * a name clash. The present method guards against these name clashes. + * + * @param member The original member + * @param other The overidden symbol for which the bridge was generated + * @param bridge The bridge + */ + def checkBridgeOverrides(member: Symbol, other: Symbol, bridge: Symbol): Boolean = { + def fulldef(sym: Symbol) = + if (sym == NoSymbol) sym.toString + else s"$sym: ${sym.tpe} in ${sym.owner}" + var noclash = true + def clashError(what: String) = { + noclash = false + unit.error( + if (member.owner == root) member.pos else root.pos, + s"""bridge generated for member ${fulldef(member)} + |which overrides ${fulldef(other)} + |clashes with definition of $what; + |both have erased type ${afterPostErasure(bridge.tpe)}""".stripMargin) + } + for (bc <- root.baseClasses) { + if (settings.debug.value) + afterPostErasure(println( + s"""check bridge overrides in $bc + ${bc.info.nonPrivateDecl(bridge.name)} + ${site.memberType(bridge)} + ${site.memberType(bc.info.nonPrivateDecl(bridge.name) orElse IntClass)} + ${(bridge.matchingSymbol(bc, site))}""".stripMargin)) + + def overriddenBy(sym: Symbol) = + sym.matchingSymbol(bc, site).alternatives filter (sym => !sym.isBridge) + for (overBridge <- afterPostErasure(overriddenBy(bridge))) { + if (overBridge == member) { + clashError("the member itself") + } else { + val overMembers = overriddenBy(member) + if (!overMembers.exists(overMember => + afterPostErasure(overMember.tpe =:= overBridge.tpe))) { + clashError(fulldef(overBridge)) + } + } + } + } + noclash + } + def checkPair(member: Symbol, other: Symbol) { - val otpe = erasure(owner)(other.tpe) + val otpe = erasure(root)(other.tpe) val bridgeNeeded = afterErasure ( !(other.tpe =:= member.tpe) && !(deconstMap(other.tpe) =:= deconstMap(member.tpe)) && @@ -417,24 +469,29 @@ abstract class Erasure extends AddInterfaces return val newFlags = (member.flags | BRIDGE) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED) - val bridge = other.cloneSymbolImpl(owner, newFlags) setPos owner.pos + val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos debuglog("generating bridge from %s (%s): %s to %s: %s".format( other, flagsToString(newFlags), otpe + other.locationString, member, - erasure(owner)(member.tpe) + member.locationString) + erasure(root)(member.tpe) + member.locationString) ) // the parameter symbols need to have the new owner bridge setInfo (otpe cloneInfo bridge) bridgeTarget(bridge) = member - afterErasure(owner.info.decls enter bridge) - if (other.owner == owner) { - afterErasure(owner.info.decls.unlink(other)) - toBeRemoved += other + + if (!(member.tpe exists (_.typeSymbol.isDerivedValueClass)) || + checkBridgeOverrides(member, other, bridge)) { + afterErasure(root.info.decls enter bridge) + if (other.owner == root) { + afterErasure(root.info.decls.unlink(other)) + toBeRemoved += other + } + + bridgesScope enter bridge + bridges ::= makeBridgeDefDef(bridge, member, other) } - bridgesScope enter bridge - bridges ::= makeBridgeDefDef(bridge, member, other) } def makeBridgeDefDef(bridge: Symbol, member: Symbol, other: Symbol) = afterErasure { @@ -466,7 +523,7 @@ abstract class Erasure extends AddInterfaces val rhs = member.tpe match { case MethodType(Nil, ConstantType(c)) => Literal(c) case _ => - val sel: Tree = Select(This(owner), member) + val sel: Tree = Select(This(root), member) val bridgingCall = (sel /: bridge.paramss)((fun, vparams) => Apply(fun, vparams map Ident)) maybeWrap(bridgingCall) @@ -480,8 +537,6 @@ abstract class Erasure extends AddInterfaces private def isPrimitiveValueType(tpe: Type) = isPrimitiveValueClass(tpe.typeSymbol) - private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] - private def isDifferentErasedValueType(tpe: Type, other: Type) = isErasedValueType(tpe) && (tpe ne other) @@ -814,7 +869,6 @@ abstract class Erasure extends AddInterfaces * but their erased types are the same. */ private def checkNoDoubleDefs(root: Symbol) { - def afterErasure[T](op: => T): T = atPhase(phase.next.next)(op) def doubleDefError(sym1: Symbol, sym2: Symbol) { // the .toString must also be computed at the earlier phase val tpe1 = afterRefchecks(root.thisType.memberType(sym1)) @@ -830,7 +884,7 @@ abstract class Erasure extends AddInterfaces sym2 + ":" + afterRefchecks(tpe2.toString) + (if (sym2.owner == root) " at line " + (sym2.pos).line else sym2.locationString) + "\nhave same type" + - (if (afterRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + afterErasure(sym1.tpe))) + (if (afterRefchecks(tpe1 =:= tpe2)) "" else " after erasure: " + afterPostErasure(sym1.tpe))) sym1.setInfo(ErrorType) } @@ -840,7 +894,7 @@ abstract class Erasure extends AddInterfaces if (e.sym.isTerm) { var e1 = decls.lookupNextEntry(e) while (e1 ne null) { - if (afterErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) + if (afterPostErasure(e1.sym.info =:= e.sym.info)) doubleDefError(e.sym, e1.sym) e1 = decls.lookupNextEntry(e1) } } @@ -854,7 +908,7 @@ abstract class Erasure extends AddInterfaces || !sym.hasTypeAt(currentRun.refchecksPhase.id)) override def matches(sym1: Symbol, sym2: Symbol): Boolean = - afterErasure(sym1.tpe =:= sym2.tpe) + afterPostErasure(sym1.tpe =:= sym2.tpe) } while (opc.hasNext) { if (!afterRefchecks( @@ -902,7 +956,7 @@ abstract class Erasure extends AddInterfaces private def bridgeDefs(owner: Symbol): (List[Tree], immutable.Set[Symbol]) = { assert(phase == currentRun.erasurePhase, phase) debuglog("computing bridges for " + owner) - new ComputeBridges(owner) compute() + new ComputeBridges(unit, owner) compute() } def addBridges(stats: List[Tree], base: Symbol): List[Tree] = @@ -1000,7 +1054,7 @@ abstract class Erasure extends AddInterfaces preEraseIsInstanceOf } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos - } else if (fn.symbol.isMethodWithExtension) { + } else if (fn.symbol.isMethodWithExtension && !fn.symbol.tpe.isErroneous) { Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) } else { tree diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 0820d3e714..8a9d0e58ec 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -70,7 +70,8 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { val companionInfo = imeth.owner.companionModule.info val candidates = extensionNames(imeth) map (companionInfo.decl(_)) val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) - assert(matching.nonEmpty, "no extension method found for "+imeth+" among "+candidates+"/"+extensionNames(imeth)) + assert(matching.nonEmpty, + s"no extension method found for $imeth:${imeth.tpe}+among ${candidates map (c => c.name+":"+c.tpe)} / ${extensionNames(imeth)}") matching.head } @@ -135,7 +136,9 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { tree match { case Template(_, _, _) => if (currentOwner.isDerivedValueClass) { - checkNonCyclic(currentOwner.pos, Set(), currentOwner) + /* This is currently redundant since value classes may not + wrap over other value classes anyway. + checkNonCyclic(currentOwner.pos, Set(), currentOwner) */ extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] currentOwner.primaryConstructor.makeNotPrivate(NoSymbol) super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala index f9d8d19b10..0b58292f28 100644 --- a/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala +++ b/src/compiler/scala/tools/nsc/transform/OverridingPairs.scala @@ -104,8 +104,11 @@ abstract class OverridingPairs { /** A map from baseclasses of <base> to ints, with smaller ints meaning lower in * linearization order. + * symbols that are not baseclasses map to -1. */ - private val index = new mutable.HashMap[Symbol, Int] + private val index = new mutable.HashMap[Symbol, Int] { + override def default(key: Symbol) = -1 + } // Note: overridingPairs can be called at odd instances by the Eclipse plugin // Soemtimes symbols are not yet defined and we get missing keys. @@ -133,28 +136,30 @@ abstract class OverridingPairs { { for (i <- List.range(0, size)) subParents(i) = new BitSet(size); for (p <- parents) { - index get p.typeSymbol match { - case Some(pIndex) => - for (bc <- p.baseClasses) - if (p.baseType(bc) =:= self.baseType(bc)) - index get bc match { - case Some(bcIndex) => - include(subParents(bcIndex), pIndex) - case None => - } - else debuglog("SKIPPING "+p+" -> "+p.baseType(bc)+" / "+self.baseType(bc)+" from "+base) - case None => - } + val pIndex = index(p.typeSymbol) + if (pIndex >= 0) + for (bc <- p.baseClasses) + if (p.baseType(bc) =:= self.baseType(bc)) { + val bcIndex = index(bc) + if (bcIndex >= 0) + include(subParents(bcIndex), pIndex) + } } } /** Do `sym1` and `sym2` have a common subclass in `parents`? * In that case we do not follow their overriding pairs */ - private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = ( - for (index1 <- index get sym1.owner ; index2 <- index get sym2.owner) yield - intersectionContainsElementLeq(subParents(index1), subParents(index2), index1 min index2) - ).exists(_ == true) + private def hasCommonParentAsSubclass(sym1: Symbol, sym2: Symbol) = { + val index1 = index(sym1.owner) + (index1 >= 0) && { + val index2 = index(sym2.owner) + (index2 >= 0) && { + intersectionContainsElementLeq( + subParents(index1), subParents(index2), index1 min index2) + } + } + } /** The scope entries that have already been visited as overridden * (maybe excluded because of hasCommonParentAsSubclass). diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 9adf86e44b..f9a35ba9a0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -710,7 +710,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType var typechecked = typecheck("macro def return type", expanded, expectedTpe) typechecked = typecheck("expected type", typechecked, pt) - typechecked updateAttachment MacroExpansionAttachment(expandee) + typechecked } finally { popMacroContext() } @@ -776,7 +776,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces { macroLogLite("" + expanded.tree + "\n" + showRaw(expanded.tree)) val freeSyms = expanded.tree.freeTerms ++ expanded.tree.freeTypes freeSyms foreach (sym => MacroFreeSymbolError(expandee, sym)) - Success(atPos(enclosingMacroPosition.focus)(expanded.tree)) + Success(atPos(enclosingMacroPosition.focus)(expanded.tree updateAttachment MacroExpansionAttachment(expandee))) case _ => MacroExpansionIsNotExprError(expandee, expanded) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Tags.scala b/src/compiler/scala/tools/nsc/typechecker/Tags.scala index 0dbeafadbe..d82fbd7c77 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Tags.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Tags.scala @@ -59,11 +59,14 @@ trait Tags { * EmptyTree if `concrete` is true and the result contains unresolved (i.e. not spliced) type parameters and abstract type members. * EmptyTree if `allowMaterialization` is false, and there is no array tag in scope. */ - def resolveTypeTag(pos: Position, pre: Type, tp: Type, concrete: Boolean, allowMaterialization: Boolean = true): Tree = { - val tagSym = if (concrete) TypeTagClass else WeakTypeTagClass - val tagTp = if (pre == NoType) TypeRef(ApiUniverseClass.toTypeConstructor, tagSym, List(tp)) else singleType(pre, pre member tagSym.name) - val taggedTp = appliedType(tagTp, List(tp)) - resolveTag(pos, taggedTp, allowMaterialization) - } + def resolveTypeTag(pos: Position, pre: Type, tp: Type, concrete: Boolean, allowMaterialization: Boolean = true): Tree = + // if someone requests a type tag, but scala-reflect.jar isn't on the library classpath, then bail + if (pre == NoType && ApiUniverseClass == NoSymbol) EmptyTree + else { + val tagSym = if (concrete) TypeTagClass else WeakTypeTagClass + val tagTp = if (pre == NoType) TypeRef(ApiUniverseClass.toTypeConstructor, tagSym, List(tp)) else singleType(pre, pre member tagSym.name) + val taggedTp = appliedType(tagTp, List(tp)) + resolveTag(pos, taggedTp, allowMaterialization) + } } }
\ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ae08a9f64d..af89af74d0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1197,7 +1197,7 @@ trait Typers extends Modes with Adaptations with Tags { val found = tree.tpe if (!found.isErroneous && !pt.isErroneous) { - if (!context.reportErrors && isPastTyper) { + if ((!context.reportErrors && isPastTyper) || tree.attachments.get[MacroExpansionAttachment].isDefined) { val (bound, req) = pt match { case ExistentialType(qs, tpe) => (qs, tpe) case _ => (Nil, pt) @@ -1230,6 +1230,17 @@ trait Typers extends Modes with Adaptations with Tags { // to consistently transform skolems and fix 6029), I'd like to // investigate ways to avoid skolems completely. // + // upd. The same problem happens when we try to typecheck the result of macro expansion against its expected type + // (which is the return type of the macro definition instantiated in the context of expandee): + // + // Test.scala:2: error: type mismatch; + // found : $u.Expr[Class[_ <: Object]] + // required: reflect.runtime.universe.Expr[Class[?0(in value <local Test>)]] where type ?0(in value <local Test>) <: Object + // scala.reflect.runtime.universe.reify(new Object().getClass) + // ^ + // Therefore following Martin's advice I use this logic to recover from skolem errors after macro expansions + // (by adding the ` || tree.attachments.get[MacroExpansionAttachment].isDefined` clause to the conditional above). + // log("recovering from existential or skolem type error in tree \n" + tree + "\nwith type " + tree.tpe + "\n expected type = " + pt + "\n context = " + context.tree) return adapt(tree, mode, deriveTypeWithWildcards(boundOrSkolems)(pt)) } @@ -1394,8 +1405,10 @@ trait Typers extends Modes with Adaptations with Tags { case List(acc) => def isUnderlyingAcc(sym: Symbol) = sym == acc || acc.hasAccessorFlag && sym == acc.accessed - if (acc.accessBoundary(clazz) != rootMirror.RootClass) + if (acc.accessBoundary(clazz) != rootMirror.RootClass) unit.error(acc.pos, "value class needs to have a publicly accessible val parameter") + else if (acc.tpe.typeSymbol.isDerivedValueClass) + unit.error(acc.pos, "value class may not wrap another user-defined value class") for (stat <- body) if (!treeInfo.isAllowedInUniversalTrait(stat) && !isUnderlyingAcc(stat.symbol)) unit.error(stat.pos, @@ -1976,32 +1989,44 @@ trait Typers extends Modes with Adaptations with Tags { * - the self-type of the refinement * - a type member of the refinement * - an abstract type declared outside of the refinement. + * - an instance of a value class + * Furthermore, the result type may not be a value class either */ - def checkMethodStructuralCompatible(meth: Symbol): Unit = { - def fail(msg: String) = unit.error(meth.pos, msg) + def checkMethodStructuralCompatible(ddef: DefDef): Unit = { + val meth = ddef.symbol + def fail(pos: Position, msg: String) = unit.error(pos, msg) val tp: Type = meth.tpe match { case mt @ MethodType(_, _) => mt case NullaryMethodType(restpe) => restpe // TODO_NMT: drop NullaryMethodType from resultType? case PolyType(_, restpe) => restpe case _ => NoType } - def failStruct(what: String) = - fail(s"Parameter type in structural refinement may not refer to $what") - for (paramType <- tp.paramTypes) { + def nthParamPos(n: Int) = ddef.vparamss match { + case xs :: _ if xs.length > n => xs(n).pos + case _ => meth.pos + } + def failStruct(pos: Position, what: String, where: String = "Parameter") = + fail(pos, s"$where type in structural refinement may not refer to $what") + + foreachWithIndex(tp.paramTypes) { (paramType, idx) => val sym = paramType.typeSymbol + def paramPos = nthParamPos(idx) if (sym.isAbstractType) { if (!sym.hasTransOwner(meth.owner)) - failStruct("an abstract type defined outside that refinement") + failStruct(paramPos, "an abstract type defined outside that refinement") else if (!sym.hasTransOwner(meth)) - failStruct("a type member of that refinement") + failStruct(paramPos, "a type member of that refinement") } if (sym.isDerivedValueClass) - failStruct("a user-defined value class") + failStruct(paramPos, "a user-defined value class") if (paramType.isInstanceOf[ThisType] && sym == meth.owner) - failStruct("the type of that refinement (self type)") + failStruct(paramPos, "the type of that refinement (self type)") } + if (tp.resultType.typeSymbol.isDerivedValueClass) + failStruct(ddef.tpt.pos, "a user-defined value class", where = "Result") } + def typedUseCase(useCase: UseCase) { def stringParser(str: String): syntaxAnalyzer.Parser = { val file = new BatchSourceFile(context.unit.source.file, str) { @@ -2118,7 +2143,7 @@ trait Typers extends Modes with Adaptations with Tags { } } if (meth.isStructuralRefinementMember) - checkMethodStructuralCompatible(meth) + checkMethodStructuralCompatible(ddef) if (meth.isImplicit && !meth.isSynthetic) meth.info.paramss match { case List(param) :: _ if !param.isImplicit => diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 27d62e2bac..f985eedf99 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -69,6 +69,14 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } } + def wrapIntoTerm(tree: Tree): Tree = + if (!tree.isTerm) Block(List(tree), Literal(Constant(()))) else tree + + def unwrapFromTerm(tree: Tree): Tree = tree match { + case Block(List(tree), Literal(Constant(()))) => tree + case tree => tree + } + def extractFreeTerms(expr0: Tree, wrapFreeTermRefs: Boolean): (Tree, scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]) = { val freeTerms = expr0.freeTerms val freeTermNames = scala.collection.mutable.LinkedHashMap[FreeTermSymbol, TermName]() @@ -101,7 +109,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => // need to wrap the expr, because otherwise you won't be able to typecheck macros against something that contains free vars var (expr, freeTerms) = extractFreeTerms(expr0, wrapFreeTermRefs = false) val dummies = freeTerms.map{ case (freeTerm, name) => ValDef(NoMods, name, TypeTree(freeTerm.info), Select(Ident(PredefModule), newTermName("$qmark$qmark$qmark"))) }.toList - expr = Block(dummies, expr) + expr = Block(dummies, wrapIntoTerm(expr)) // [Eugene] how can we implement that? // !!! Why is this is in the empty package? If it's only to make @@ -110,7 +118,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => val ownerClass = rootMirror.EmptyPackageClass.newClassSymbol(newTypeName("<expression-owner>")) build.setTypeSignature(ownerClass, ClassInfoType(List(ObjectClass.tpe), newScope, ownerClass)) val owner = ownerClass.newLocalDummy(expr.pos) - var currentTyper = typer.atOwner(expr, owner) + var currentTyper = analyzer.newTyper(analyzer.rootContext(NoCompilationUnit, EmptyTree).make(expr, owner)) val wrapper1 = if (!withImplicitViewsDisabled) (currentTyper.context.withImplicitsEnabled[Tree] _) else (currentTyper.context.withImplicitsDisabled[Tree] _) val wrapper2 = if (!withMacrosDisabled) (currentTyper.context.withMacrosEnabled[Tree] _) else (currentTyper.context.withMacrosDisabled[Tree] _) def wrapper (tree: => Tree) = wrapper1(wrapper2(tree)) @@ -136,6 +144,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } }.transform(unwrapped) new TreeTypeSubstituter(dummies1 map (_.symbol), dummies1 map (dummy => SingleType(NoPrefix, invertedIndex(dummy.symbol.name)))).traverse(unwrapped) + unwrapped = if (expr0.isTerm) unwrapped else unwrapFromTerm(unwrapped) unwrapped } @@ -169,7 +178,9 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => } }) - def compile(expr: Tree): () => Any = { + def compile(expr0: Tree): () => Any = { + val expr = wrapIntoTerm(expr0) + val freeTerms = expr.freeTerms // need to calculate them here, because later on they will be erased val thunks = freeTerms map (fte => () => fte.value) // need to be lazy in order not to distort evaluation order verify(expr) diff --git a/src/library/scala/concurrent/Awaitable.scala b/src/library/scala/concurrent/Awaitable.scala index 655115349a..3bd7617bce 100644 --- a/src/library/scala/concurrent/Awaitable.scala +++ b/src/library/scala/concurrent/Awaitable.scala @@ -10,7 +10,7 @@ package scala.concurrent -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration diff --git a/src/library/scala/concurrent/duration/Deadline.scala b/src/library/scala/concurrent/duration/Deadline.scala new file mode 100644 index 0000000000..50e9a75ff7 --- /dev/null +++ b/src/library/scala/concurrent/duration/Deadline.scala @@ -0,0 +1,81 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.concurrent.duration + +/** + * This class stores a deadline, as obtained via `Deadline.now` or the + * duration DSL: + * + * {{{ + * import scala.concurrent.duration._ + * 3.seconds.fromNow + * }}} + * + * Its main purpose is to manage repeated attempts to achieve something (like + * awaiting a condition) by offering the methods `hasTimeLeft` and `timeLeft`. All + * durations are measured according to `System.nanoTime` aka wall-time; this + * does not take into account changes to the system clock (such as leap + * seconds). + */ +case class Deadline private (time: FiniteDuration) extends Ordered[Deadline] { + /** + * Return a deadline advanced (i.e. moved into the future) by the given duration. + */ + def +(other: FiniteDuration): Deadline = copy(time = time + other) + /** + * Return a deadline moved backwards (i.e. towards the past) by the given duration. + */ + def -(other: FiniteDuration): Deadline = copy(time = time - other) + /** + * Calculate time difference between this and the other deadline, where the result is directed (i.e. may be negative). + */ + def -(other: Deadline): FiniteDuration = time - other.time + /** + * Calculate time difference between this duration and now; the result is negative if the deadline has passed. + * + * '''''Note that on some systems this operation is costly because it entails a system call.''''' + * Check `System.nanoTime` for your platform. + */ + def timeLeft: FiniteDuration = this - Deadline.now + /** + * Determine whether the deadline still lies in the future at the point where this method is called. + * + * '''''Note that on some systems this operation is costly because it entails a system call.''''' + * Check `System.nanoTime` for your platform. + */ + def hasTimeLeft(): Boolean = !isOverdue() + /** + * Determine whether the deadline lies in the past at the point where this method is called. + * + * '''''Note that on some systems this operation is costly because it entails a system call.''''' + * Check `System.nanoTime` for your platform. + */ + def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0 + /** + * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration. + */ + def compare(other: Deadline) = time compare other.time +} + +object Deadline { + /** + * Construct a deadline due exactly at the point where this method is called. Useful for then + * advancing it to obtain a future deadline, or for sampling the current time exactly once and + * then comparing it to multiple deadlines (using subtraction). + */ + def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS)) + + /** + * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration. + */ + implicit object DeadlineIsOrdered extends Ordering[Deadline] { + def compare(a: Deadline, b: Deadline) = a compare b + } + +} diff --git a/src/library/scala/concurrent/util/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index 3f8b98831e..79f9b4db86 100644 --- a/src/library/scala/concurrent/util/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -6,90 +6,12 @@ ** |/ ** \* */ -package scala.concurrent.util +package scala.concurrent.duration -import java.util.concurrent.TimeUnit -import TimeUnit._ import java.lang.{ Double => JDouble, Long => JLong } import scala.language.implicitConversions -/** - * This class stores a deadline, as obtained via `Deadline.now` or the - * duration DSL: - * - * {{{ - * import scala.concurrent.util.duration._ - * 3.seconds.fromNow - * }}} - * - * Its main purpose is to manage repeated attempts to achieve something (like - * awaiting a condition) by offering the methods `hasTimeLeft` and `timeLeft`. All - * durations are measured according to `System.nanoTime` aka wall-time; this - * does not take into account changes to the system clock (such as leap - * seconds). - */ -case class Deadline private (time: FiniteDuration) extends Ordered[Deadline] { - /** - * Return a deadline advanced (i.e. moved into the future) by the given duration. - */ - def +(other: FiniteDuration): Deadline = copy(time = time + other) - /** - * Return a deadline moved backwards (i.e. towards the past) by the given duration. - */ - def -(other: FiniteDuration): Deadline = copy(time = time - other) - /** - * Calculate time difference between this and the other deadline, where the result is directed (i.e. may be negative). - */ - def -(other: Deadline): FiniteDuration = time - other.time - /** - * Calculate time difference between this duration and now; the result is negative if the deadline has passed. - * - * '''''Note that on some systems this operation is costly because it entails a system call.''''' - * Check `System.nanoTime` for your platform. - */ - def timeLeft: FiniteDuration = this - Deadline.now - /** - * Determine whether the deadline still lies in the future at the point where this method is called. - * - * '''''Note that on some systems this operation is costly because it entails a system call.''''' - * Check `System.nanoTime` for your platform. - */ - def hasTimeLeft(): Boolean = !isOverdue() - /** - * Determine whether the deadline lies in the past at the point where this method is called. - * - * '''''Note that on some systems this operation is costly because it entails a system call.''''' - * Check `System.nanoTime` for your platform. - */ - def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0 - /** - * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration. - */ - def compare(other: Deadline) = time compare other.time -} - -object Deadline { - /** - * Construct a deadline due exactly at the point where this method is called. Useful for then - * advancing it to obtain a future deadline, or for sampling the current time exactly once and - * then comparing it to multiple deadlines (using subtraction). - */ - def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS)) - - /** - * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration. - */ - implicit object DeadlineIsOrdered extends Ordering[Deadline] { - def compare(a: Deadline, b: Deadline) = a compare b - } -} - object Duration { - /** - * This implicit conversion allows the use of a Deadline in place of a Duration, which will - * insert the time left until the deadline in its place. - */ - implicit def timeLeft(implicit d: Deadline): Duration = d.timeLeft /** * Construct a Duration from the given length and unit. Observe that nanosecond precision may be lost if @@ -102,11 +24,13 @@ object Duration { * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]] */ def apply(length: Double, unit: TimeUnit): Duration = fromNanos(unit.toNanos(1) * length) + /** * Construct a finite duration from the given length and time unit. The unit given is retained * throughout calculations as long as possible, so that it can be retrieved later. */ def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit) + /** * Construct a finite duration from the given length and time unit, where the latter is * looked up in a list of string representation. Valid choices are: @@ -117,7 +41,7 @@ object Duration { def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit)) // Double stores 52 bits mantissa, but there is an implied '1' in front, making the limit 2^53 - final val maxPreciseDouble = 9007199254740992d + private[this] final val maxPreciseDouble = 9007199254740992d /** * Parse String into Duration. Format is `"<length><unit>"`, where @@ -161,11 +85,11 @@ object Duration { ) // TimeUnit => standard label - protected[util] val timeUnitName: Map[TimeUnit, String] = + protected[duration] val timeUnitName: Map[TimeUnit, String] = timeUnitLabels.toMap mapValues (s => words(s).last) toMap // Label => TimeUnit - protected[util] val timeUnit: Map[String, TimeUnit] = + protected[duration] val timeUnit: Map[String, TimeUnit] = timeUnitLabels flatMap { case (unit, names) => expandLabels(names) map (_ -> unit) } toMap /** @@ -275,13 +199,13 @@ object Duration { if (factor == 0d || factor.isNaN) Undefined else if (factor < 0d) -this else this - def /(factor: Double): Duration = - if (factor.isNaN || factor.isInfinite) Undefined - else if ((factor compare 0d) < 0) -this + def /(divisor: Double): Duration = + if (divisor.isNaN || divisor.isInfinite) Undefined + else if ((divisor compare 0d) < 0) -this else this - def /(other: Duration): Double = other match { + def /(divisor: Duration): Double = divisor match { case _: Infinite => Double.NaN - case x => Double.PositiveInfinity * (if ((this > Zero) ^ (other >= Zero)) -1 else 1) + case x => Double.PositiveInfinity * (if ((this > Zero) ^ (divisor >= Zero)) -1 else 1) } final def isFinite() = false @@ -380,8 +304,7 @@ object Duration { * <p/> * Examples: * {{{ - * import scala.concurrent.util.Duration - * import java.util.concurrent.TimeUnit + * import scala.concurrent.duration._ * * val duration = Duration(100, MILLISECONDS) * val duration = Duration(100, "millis") @@ -396,7 +319,7 @@ object Duration { * <p/> * Implicits are also provided for Int, Long and Double. Example usage: * {{{ - * import scala.concurrent.util.Duration._ + * import scala.concurrent.duration._ * * val duration = 100 millis * }}} @@ -529,12 +452,12 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] { * * $ovf */ - def /(factor: Double): Duration + def /(divisor: Double): Duration /** * Return the quotient of this and that duration as floating-point number. The semantics are * determined by Double as if calculating the quotient of the nanosecond lengths of both factors. */ - def /(other: Duration): Double + def /(divisor: Duration): Double /** * Negate this duration. The only two values which are mapped to themselves are [[Duration.Zero]] and [[Duration.Undefined]]. */ @@ -561,7 +484,7 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] { * * $ovf */ - def div(factor: Double) = this / factor + def div(divisor: Double) = this / divisor /** * Return the quotient of this and that duration as floating-point number. The semantics are * determined by Double as if calculating the quotient of the nanosecond lengths of both factors. @@ -599,6 +522,7 @@ sealed abstract class Duration extends Serializable with Ordered[Duration] { } object FiniteDuration { + implicit object FiniteDurationIsOrdered extends Ordering[FiniteDuration] { def compare(a: FiniteDuration, b: FiniteDuration) = a compare b } @@ -691,29 +615,77 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio else if ((factor > 0) ^ (this < Zero)) Inf else MinusInf - def /(factor: Double) = - if (!factor.isInfinite) fromNanos(toNanos / factor) - else if (factor.isNaN) Undefined + def /(divisor: Double) = + if (!divisor.isInfinite) fromNanos(toNanos / divisor) + else if (divisor.isNaN) Undefined else Zero // if this is made a constant, then scalac will elide the conditional and always return +0.0, SI-6331 private[this] def minusZero = -0d - def /(other: Duration): Double = - if (other.isFinite) toNanos.toDouble / other.toNanos - else if (other eq Undefined) Double.NaN - else if ((length < 0) ^ (other > Zero)) 0d + def /(divisor: Duration): Double = + if (divisor.isFinite) toNanos.toDouble / divisor.toNanos + else if (divisor eq Undefined) Double.NaN + else if ((length < 0) ^ (divisor > Zero)) 0d else minusZero - // overridden methods taking FiniteDurations, so that you can calculate while statically staying finite + // overloaded methods taking FiniteDurations, so that you can calculate while statically staying finite def +(other: FiniteDuration) = add(other.length, other.unit) def -(other: FiniteDuration) = add(-other.length, other.unit) def plus(other: FiniteDuration) = this + other def minus(other: FiniteDuration) = this - other - override def div(factor: Double) = this / factor - override def mul(factor: Double) = this * factor def min(other: FiniteDuration) = if (this < other) this else other def max(other: FiniteDuration) = if (this > other) this else other + // overloaded methods taking Long so that you can calculate while statically staying finite + + /** + * Return the quotient of this duration and the given integer factor. + * + * @throws ArithmeticException if the factor is 0 + */ + def /(divisor: Long) = fromNanos(toNanos / divisor) + + /** + * Return the product of this duration and the given integer factor. + * + * @throws IllegalArgumentException if the result would overflow the range of FiniteDuration + */ + def *(factor: Long) = new FiniteDuration(safeMul(length, factor), unit) + + /* + * This method avoids the use of Long division, which saves 95% of the time spent, + * by checking that there are enough leading zeros so that the result has a chance + * to fit into a Long again; the remaining edge cases are caught by using the sign + * of the product for overflow detection. + * + * This method is not general purpose because it disallows the (otherwise legal) + * case of Long.MinValue * 1, but that is okay for use in FiniteDuration, since + * Long.MinValue is not a legal `length` anyway. + */ + private def safeMul(_a: Long, _b: Long): Long = { + val a = math.abs(_a) + val b = math.abs(_b) + import java.lang.Long.{ numberOfLeadingZeros => leading } + if (leading(a) + leading(b) < 64) throw new IllegalArgumentException("multiplication overflow") + val product = a * b + if (product < 0) throw new IllegalArgumentException("multiplication overflow") + if (a == _a ^ b == _b) -product else product + } + + /** + * Return the quotient of this duration and the given integer factor. + * + * @throws ArithmeticException if the factor is 0 + */ + def div(divisor: Long) = this / divisor + + /** + * Return the product of this duration and the given integer factor. + * + * @throws IllegalArgumentException if the result would overflow the range of FiniteDuration + */ + def mul(factor: Long) = this * factor + def unary_- = Duration(-length, unit) final def isFinite() = true @@ -724,78 +696,3 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio } override def hashCode = toNanos.toInt } - -trait DurationConversions extends Any { - import duration.Classifier - protected def durationIn(unit: TimeUnit): FiniteDuration - - def nanoseconds = durationIn(NANOSECONDS) - def nanos = nanoseconds - def nanosecond = nanoseconds - def nano = nanoseconds - - def microseconds = durationIn(MICROSECONDS) - def micros = microseconds - def microsecond = microseconds - def micro = microseconds - - def milliseconds = durationIn(MILLISECONDS) - def millis = milliseconds - def millisecond = milliseconds - def milli = milliseconds - - def seconds = durationIn(SECONDS) - def second = seconds - - def minutes = durationIn(MINUTES) - def minute = minutes - - def hours = durationIn(HOURS) - def hour = hours - - def days = durationIn(DAYS) - def day = days - - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(nanoseconds) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = nanoseconds(c) - - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(microseconds) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = microseconds(c) - - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(milliseconds) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = milliseconds(c) - - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(seconds) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = seconds(c) - - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(minutes) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = minutes(c) - - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(hours) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = hours(c) - - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(days) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = days(c) -} - -final class DurationInt(val n: Int) extends AnyVal with DurationConversions { - override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) -} - -final class DurationLong(val n: Long) extends AnyVal with DurationConversions { - override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) -} - -final class DurationDouble(val d: Double) extends AnyVal with DurationConversions { - override protected def durationIn(unit: TimeUnit): FiniteDuration = - Duration(d, unit) match { - case f: FiniteDuration => f - case _ => throw new IllegalArgumentException("Duration DSL not applicable to " + d) - } -} diff --git a/src/library/scala/concurrent/duration/DurationConversions.scala b/src/library/scala/concurrent/duration/DurationConversions.scala new file mode 100644 index 0000000000..2c7e192a0e --- /dev/null +++ b/src/library/scala/concurrent/duration/DurationConversions.scala @@ -0,0 +1,92 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2012, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.concurrent.duration + +import DurationConversions._ + +// Would be nice to limit the visibility of this trait a little bit, +// but it crashes scalac to do so. +trait DurationConversions extends Any { + protected def durationIn(unit: TimeUnit): FiniteDuration + + def nanoseconds = durationIn(NANOSECONDS) + def nanos = nanoseconds + def nanosecond = nanoseconds + def nano = nanoseconds + + def microseconds = durationIn(MICROSECONDS) + def micros = microseconds + def microsecond = microseconds + def micro = microseconds + + def milliseconds = durationIn(MILLISECONDS) + def millis = milliseconds + def millisecond = milliseconds + def milli = milliseconds + + def seconds = durationIn(SECONDS) + def second = seconds + + def minutes = durationIn(MINUTES) + def minute = minutes + + def hours = durationIn(HOURS) + def hour = hours + + def days = durationIn(DAYS) + def day = days + + def nanoseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(nanoseconds) + def nanos[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c) + def nanosecond[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c) + def nano[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c) + + def microseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(microseconds) + def micros[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c) + def microsecond[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c) + def micro[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c) + + def milliseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(milliseconds) + def millis[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c) + def millisecond[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c) + def milli[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c) + + def seconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(seconds) + def second[C](c: C)(implicit ev: Classifier[C]): ev.R = seconds(c) + + def minutes[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(minutes) + def minute[C](c: C)(implicit ev: Classifier[C]): ev.R = minutes(c) + + def hours[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(hours) + def hour[C](c: C)(implicit ev: Classifier[C]): ev.R = hours(c) + + def days[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(days) + def day[C](c: C)(implicit ev: Classifier[C]): ev.R = days(c) +} + +/** + * This object just holds some cogs which make the DSL machine work, not for direct consumption. + */ +object DurationConversions { + trait Classifier[C] { + type R + def convert(d: FiniteDuration): R + } + + implicit object spanConvert extends Classifier[span.type] { + type R = FiniteDuration + def convert(d: FiniteDuration) = d + } + + implicit object fromNowConvert extends Classifier[fromNow.type] { + type R = Deadline + def convert(d: FiniteDuration) = Deadline.now + d + } + +} diff --git a/src/library/scala/concurrent/duration/package.scala b/src/library/scala/concurrent/duration/package.scala new file mode 100644 index 0000000000..2fd735f19e --- /dev/null +++ b/src/library/scala/concurrent/duration/package.scala @@ -0,0 +1,75 @@ +package scala.concurrent + +import scala.language.implicitConversions + +package object duration { + /** + * This object can be used as closing token if you prefer dot-less style but do not want + * to enable language.postfixOps: + * + * {{{ + * import scala.concurrent.duration._ + * + * val duration = 2 seconds span + * }}} + */ + object span + + /** + * This object can be used as closing token for declaring a deadline at some future point + * in time: + * + * {{{ + * import scala.concurrent.duration._ + * + * val deadline = 3 seconds fromNow + * }}} + */ + object fromNow + + type TimeUnit = java.util.concurrent.TimeUnit + final val DAYS = java.util.concurrent.TimeUnit.DAYS + final val HOURS = java.util.concurrent.TimeUnit.HOURS + final val MICROSECONDS = java.util.concurrent.TimeUnit.MICROSECONDS + final val MILLISECONDS = java.util.concurrent.TimeUnit.MILLISECONDS + final val MINUTES = java.util.concurrent.TimeUnit.MINUTES + final val NANOSECONDS = java.util.concurrent.TimeUnit.NANOSECONDS + final val SECONDS = java.util.concurrent.TimeUnit.SECONDS + + implicit def pairIntToDuration(p: (Int, TimeUnit)): Duration = Duration(p._1, p._2) + implicit def pairLongToDuration(p: (Long, TimeUnit)): FiniteDuration = Duration(p._1, p._2) + implicit def durationToPair(d: Duration): (Long, TimeUnit) = (d.length, d.unit) + + implicit final class DurationInt(val n: Int) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) + } + + implicit final class DurationLong(val n: Long) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit) + } + + implicit final class DurationDouble(val d: Double) extends AnyVal with DurationConversions { + override protected def durationIn(unit: TimeUnit): FiniteDuration = + Duration(d, unit) match { + case f: FiniteDuration => f + case _ => throw new IllegalArgumentException("Duration DSL not applicable to " + d) + } + } + + /* + * Avoid reflection based invocation by using non-duck type + */ + implicit final class IntMult(val i: Int) extends AnyVal { + def *(d: Duration) = d * i + def *(d: FiniteDuration) = d * i + } + + implicit final class LongMult(val i: Long) extends AnyVal { + def *(d: Duration) = d * i + def *(d: FiniteDuration) = d * i + } + + implicit final class DoubleMult(val f: Double) extends AnyVal { + def *(d: Duration) = d * f + } +} diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 9228872f2b..a1a3305db0 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -8,16 +8,12 @@ package scala.concurrent.impl - - -import java.util.concurrent.TimeUnit.NANOSECONDS import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException } -import scala.concurrent.util.{ Duration, Deadline, FiniteDuration } +import scala.concurrent.duration.{ Duration, Deadline, FiniteDuration, NANOSECONDS } import scala.annotation.tailrec import scala.util.control.NonFatal import scala.util.{ Try, Success, Failure } - private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] { def future: this.type = this } @@ -48,7 +44,7 @@ private[concurrent] object Promise { case Failure(t) => resolver(t) case _ => source } - + private def resolver[T](throwable: Throwable): Try[T] = throwable match { case t: scala.runtime.NonLocalReturnControl[_] => Success(t.value.asInstanceOf[T]) case t: scala.util.control.ControlThrowable => Failure(new ExecutionException("Boxed ControlThrowable", t)) @@ -56,12 +52,12 @@ private[concurrent] object Promise { case e: Error => Failure(new ExecutionException("Boxed Error", e)) case t => Failure(t) } - + /** Default promise implementation. */ class DefaultPromise[T] extends AbstractPromise with Promise[T] { self => updateState(null, Nil) // Start at "No callbacks" - + protected final def tryAwait(atMost: Duration): Boolean = { @tailrec def awaitUnsafe(deadline: Deadline, nextWait: FiniteDuration): Boolean = { diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index 1d06341d4d..e683732e41 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -8,7 +8,7 @@ package scala -import scala.concurrent.util.Duration +import scala.concurrent.duration.Duration import scala.annotation.implicitNotFound /** This package object contains primitives for concurrent and parallel programming. diff --git a/src/library/scala/concurrent/util/duration/Classifier.scala b/src/library/scala/concurrent/util/duration/Classifier.scala deleted file mode 100644 index 10faf0a5ce..0000000000 --- a/src/library/scala/concurrent/util/duration/Classifier.scala +++ /dev/null @@ -1,9 +0,0 @@ -package scala.concurrent.util.duration - -import scala.concurrent.util.{ FiniteDuration } - -trait Classifier[C] { - type R - def convert(d: FiniteDuration): R -} - diff --git a/src/library/scala/concurrent/util/duration/IntMult.scala b/src/library/scala/concurrent/util/duration/IntMult.scala deleted file mode 100644 index 94c58fb8c2..0000000000 --- a/src/library/scala/concurrent/util/duration/IntMult.scala +++ /dev/null @@ -1,18 +0,0 @@ -package scala.concurrent.util.duration - -import scala.concurrent.util.{ Duration } - -/* - * Avoid reflection based invocation by using non-duck type - */ -protected[duration] class IntMult(i: Int) { - def *(d: Duration) = d * i -} - -protected[duration] class LongMult(i: Long) { - def *(d: Duration) = d * i -} - -protected[duration] class DoubleMult(f: Double) { - def *(d: Duration) = d * f -} diff --git a/src/library/scala/concurrent/util/duration/package.scala b/src/library/scala/concurrent/util/duration/package.scala deleted file mode 100644 index d5ae3f1544..0000000000 --- a/src/library/scala/concurrent/util/duration/package.scala +++ /dev/null @@ -1,31 +0,0 @@ -package scala.concurrent.util - -import java.util.concurrent.TimeUnit -import scala.language.implicitConversions - -package object duration { - - object span - implicit object spanConvert extends Classifier[span.type] { - type R = FiniteDuration - def convert(d: FiniteDuration) = d - } - - object fromNow - implicit object fromNowConvert extends Classifier[fromNow.type] { - type R = Deadline - def convert(d: FiniteDuration) = Deadline.now + d - } - - implicit def intToDurationInt(n: Int) = new DurationInt(n) - implicit def longToDurationLong(n: Long) = new DurationLong(n) - implicit def doubleToDurationDouble(d: Double) = new DurationDouble(d) - - implicit def pairIntToDuration(p: (Int, TimeUnit)) = Duration(p._1, p._2) - implicit def pairLongToDuration(p: (Long, TimeUnit)) = Duration(p._1, p._2) - implicit def durationToPair(d: Duration) = (d.length, d.unit) - - implicit def intMult(i: Int) = new IntMult(i) - implicit def longMult(l: Long) = new LongMult(l) - implicit def doubleMult(f: Double) = new DoubleMult(f) -} diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala index 542673ff00..78345e27f2 100644 --- a/src/reflect/scala/reflect/api/Symbols.scala +++ b/src/reflect/scala/reflect/api/Symbols.scala @@ -210,7 +210,7 @@ trait Symbols { self: Universe => /** Source file if this symbol is created during this compilation run, * or a class file if this symbol is loaded from a *.class or *.jar. */ - def associatedFile: scala.tools.nsc.io.AbstractFile + def associatedFile: scala.reflect.io.AbstractFile /** A list of annotations attached to this Symbol. */ diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 50e5afd21e..a0e28bf735 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -11,7 +11,7 @@ import scala.collection.mutable.ListBuffer import util.Statistics import Flags._ import scala.annotation.tailrec -import scala.tools.nsc.io.AbstractFile +import scala.reflect.io.AbstractFile trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala index cc5b5bb406..977398909f 100644 --- a/src/reflect/scala/reflect/internal/transform/Erasure.scala +++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala @@ -203,28 +203,26 @@ trait Erasure { def specialErasure(sym: Symbol)(tp: Type): Type = if (sym != NoSymbol && sym.enclClass.isJavaDefined) erasure(sym)(tp) - else if (sym.isTerm && sym.owner.isDerivedValueClass) - specialErasureAvoiding(sym.owner, tp) - else if (sym.isValue && sym.owner.isMethodWithExtension) - specialErasureAvoiding(sym.owner.owner, tp) + else if (sym.isClassConstructor) + specialConstructorErasure(sym.owner, tp) else specialScalaErasure(tp) - def specialErasureAvoiding(clazz: Symbol, tpe: Type): Type = { + def specialConstructorErasure(clazz: Symbol, tpe: Type): Type = { tpe match { case PolyType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) + specialConstructorErasure(clazz, restpe) case ExistentialType(tparams, restpe) => - specialErasureAvoiding(clazz, restpe) + specialConstructorErasure(clazz, restpe) case mt @ MethodType(params, restpe) => MethodType( - cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)), - if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass) - else specialErasureAvoiding(clazz, (mt.resultType(mt.paramTypes)))) + cloneSymbolsAndModify(params, specialScalaErasure), + specialConstructorErasure(clazz, restpe)) case TypeRef(pre, `clazz`, args) => typeRef(pre, clazz, List()) - case _ => - specialScalaErasure(tpe) + case tp => + assert(clazz == ArrayClass || tp.isError, s"unexpected constructor erasure $tp for $clazz") + specialScalaErasure(tp) } } diff --git a/src/reflect/scala/reflect/internal/util/SourceFile.scala b/src/reflect/scala/reflect/internal/util/SourceFile.scala index 9a71e02e08..788c7532d1 100644 --- a/src/reflect/scala/reflect/internal/util/SourceFile.scala +++ b/src/reflect/scala/reflect/internal/util/SourceFile.scala @@ -6,7 +6,7 @@ package scala.reflect.internal.util -import scala.tools.nsc.io.{ AbstractFile, VirtualFile } +import scala.reflect.io.{ AbstractFile, VirtualFile } import scala.collection.mutable.ArrayBuffer import scala.annotation.tailrec import java.util.regex.Pattern diff --git a/src/reflect/scala/tools/nsc/io/AbstractFile.scala b/src/reflect/scala/reflect/io/AbstractFile.scala index 018a017c6d..e32207c58c 100644 --- a/src/reflect/scala/tools/nsc/io/AbstractFile.scala +++ b/src/reflect/scala/reflect/io/AbstractFile.scala @@ -4,7 +4,7 @@ */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ FileOutputStream, IOException, InputStream, OutputStream, BufferedOutputStream } @@ -13,6 +13,10 @@ import java.net.URL import scala.collection.mutable.ArrayBuffer /** + * An abstraction over files for use in the reflection/compiler libraries. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' + * * @author Philippe Altherr * @version 1.0, 23/03/2004 */ @@ -81,6 +85,8 @@ object AbstractFile { * all other cases, the class <code>SourceFile</code> is used, which honors * <code>global.settings.encoding.value</code>. * </p> + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ abstract class AbstractFile extends Iterable[AbstractFile] { diff --git a/src/reflect/scala/tools/nsc/io/Directory.scala b/src/reflect/scala/reflect/io/Directory.scala index ebd6edc8d8..a24534137d 100644 --- a/src/reflect/scala/tools/nsc/io/Directory.scala +++ b/src/reflect/scala/reflect/io/Directory.scala @@ -6,11 +6,13 @@ ** |/ ** \* */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ File => JFile } - +/** + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' + */ object Directory { import scala.util.Properties.{ tmpDir, userHome, userDir } @@ -34,6 +36,8 @@ import Path._ * * @author Paul Phillips * @since 2.8 + * + * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ class Directory(jfile: JFile) extends Path(jfile) { override def toAbsolute: Directory = if (isAbsolute) this else super.toAbsolute.toDirectory diff --git a/src/reflect/scala/tools/nsc/io/File.scala b/src/reflect/scala/reflect/io/File.scala index fce0e339e0..9e306371f7 100644 --- a/src/reflect/scala/tools/nsc/io/File.scala +++ b/src/reflect/scala/reflect/io/File.scala @@ -7,7 +7,7 @@ \* */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ @@ -17,7 +17,9 @@ import java.io.{ File => JFile } import java.nio.channels.{ Channel, FileChannel } import scala.io.Codec import scala.language.{reflectiveCalls, implicitConversions} - +/** + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' + */ object File { def pathSeparator = java.io.File.pathSeparator def separator = java.io.File.separator @@ -74,6 +76,8 @@ import Path._ * * @author Paul Phillips * @since 2.8 + * + * ''Note: This is library is considered experimental and should not be used unless you know what you are doing.'' */ class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars { override val creationCodec = constructorCodec diff --git a/src/reflect/scala/tools/nsc/io/FileOperationException.scala b/src/reflect/scala/reflect/io/FileOperationException.scala index f23658efbc..6bce799cea 100644 --- a/src/reflect/scala/tools/nsc/io/FileOperationException.scala +++ b/src/reflect/scala/reflect/io/FileOperationException.scala @@ -7,7 +7,7 @@ \* */ -package scala.tools.nsc +package scala.reflect package io - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ case class FileOperationException(msg: String) extends RuntimeException(msg) diff --git a/src/reflect/scala/tools/nsc/io/NoAbstractFile.scala b/src/reflect/scala/reflect/io/NoAbstractFile.scala index 2af933c27b..d503328a37 100644 --- a/src/reflect/scala/tools/nsc/io/NoAbstractFile.scala +++ b/src/reflect/scala/reflect/io/NoAbstractFile.scala @@ -3,7 +3,7 @@ * @author Paul Phillips */ -package scala.tools.nsc +package scala.reflect package io import java.io.InputStream @@ -11,6 +11,8 @@ import java.io.{ File => JFile } /** A distinguished object so you can avoid both null * and Option. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object NoAbstractFile extends AbstractFile { def absolute: AbstractFile = this diff --git a/src/reflect/scala/tools/nsc/io/Path.scala b/src/reflect/scala/reflect/io/Path.scala index 0a27e49686..9a1ff395a3 100644 --- a/src/reflect/scala/tools/nsc/io/Path.scala +++ b/src/reflect/scala/reflect/io/Path.scala @@ -3,7 +3,7 @@ * @author Paul Phillips */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ @@ -27,8 +27,9 @@ import scala.language.implicitConversions * * @author Paul Phillips * @since 2.8 + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ - object Path { def isExtensionJarOrZip(jfile: JFile): Boolean = isExtensionJarOrZip(jfile.getName) def isExtensionJarOrZip(name: String): Boolean = { @@ -83,6 +84,8 @@ import Path._ /** The Path constructor is private so we can enforce some * semantics regarding how a Path might relate to the world. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class Path private[io] (val jfile: JFile) { val separator = java.io.File.separatorChar diff --git a/src/reflect/scala/tools/nsc/io/PlainFile.scala b/src/reflect/scala/reflect/io/PlainFile.scala index a4f378ad5e..14cb09317c 100644 --- a/src/reflect/scala/tools/nsc/io/PlainFile.scala +++ b/src/reflect/scala/reflect/io/PlainFile.scala @@ -4,12 +4,12 @@ */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ FileInputStream, FileOutputStream, IOException } import PartialFunction._ - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object PlainFile { /** * If the specified File exists, returns an abstract file backed @@ -20,7 +20,7 @@ object PlainFile { else if (file.isFile) new PlainFile(file) else null } - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { override def isDirectory = true override def iterator = givenPath.list filter (_.exists) map (x => new PlainFile(x)) @@ -28,6 +28,8 @@ class PlainDirectory(givenPath: Directory) extends PlainFile(givenPath) { } /** This class implements an abstract file backed by a File. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class PlainFile(val givenPath: Path) extends AbstractFile { assert(path ne null) diff --git a/src/reflect/scala/tools/nsc/io/Streamable.scala b/src/reflect/scala/reflect/io/Streamable.scala index 625429bdb3..a083890e09 100644 --- a/src/reflect/scala/tools/nsc/io/Streamable.scala +++ b/src/reflect/scala/reflect/io/Streamable.scala @@ -3,7 +3,7 @@ * @author Paul Phillips */ -package scala.tools.nsc +package scala.reflect package io import java.net.{ URI, URL } @@ -17,12 +17,15 @@ import Path.fail * * @author Paul Phillips * @since 2.8 + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ - object Streamable { /** Traits which can be viewed as a sequence of bytes. Source types * which know their length should override def length: Long for more * efficient method implementations. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ trait Bytes { def inputStream(): InputStream @@ -66,6 +69,8 @@ object Streamable { } /** For objects which can be viewed as Chars. + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ trait Chars extends Bytes { /** Calls to methods requiring byte<->char transformations should be offered diff --git a/src/reflect/scala/tools/nsc/io/VirtualDirectory.scala b/src/reflect/scala/reflect/io/VirtualDirectory.scala index fa016f86f4..e71c5cbb6b 100644 --- a/src/reflect/scala/tools/nsc/io/VirtualDirectory.scala +++ b/src/reflect/scala/reflect/io/VirtualDirectory.scala @@ -2,7 +2,7 @@ * Copyright 2005-2012 LAMP/EPFL */ -package scala.tools.nsc +package scala.reflect package io import scala.collection.mutable @@ -11,6 +11,8 @@ import scala.collection.mutable * An in-memory directory. * * @author Lex Spoon + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class VirtualDirectory(val name: String, maybeContainer: Option[VirtualDirectory]) extends AbstractFile { diff --git a/src/reflect/scala/tools/nsc/io/VirtualFile.scala b/src/reflect/scala/reflect/io/VirtualFile.scala index 8a5114bfe7..4884561f4e 100644 --- a/src/reflect/scala/tools/nsc/io/VirtualFile.scala +++ b/src/reflect/scala/reflect/io/VirtualFile.scala @@ -4,7 +4,7 @@ */ -package scala.tools.nsc +package scala.reflect package io import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, InputStream, OutputStream } @@ -14,6 +14,8 @@ import java.io.{ File => JFile } * * @author Philippe Altherr * @version 1.0, 23/03/2004 + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class VirtualFile(val name: String, override val path: String) extends AbstractFile { /** diff --git a/src/reflect/scala/tools/nsc/io/ZipArchive.scala b/src/reflect/scala/reflect/io/ZipArchive.scala index 49d2200895..2512c4d92f 100644 --- a/src/reflect/scala/tools/nsc/io/ZipArchive.scala +++ b/src/reflect/scala/reflect/io/ZipArchive.scala @@ -3,7 +3,7 @@ * @author Paul Phillips */ -package scala.tools.nsc +package scala.reflect package io import java.net.URL @@ -20,6 +20,8 @@ import scala.annotation.tailrec * @author Philippe Altherr (original version) * @author Paul Phillips (this one) * @version 2.0, + * + * ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ object ZipArchive { def fromPath(path: String): FileZipArchive = fromFile(new JFile(path)) @@ -57,7 +59,7 @@ object ZipArchive { } } import ZipArchive._ - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Equals { self => @@ -78,13 +80,14 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq } } def deepIterator = walkIterator(iterator) - + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ sealed abstract class Entry(path: String) extends VirtualFile(baseName(path), path) { // have to keep this name for compat with sbt's compiler-interface def getArchive: ZipFile = null override def underlyingSource = Some(self) override def toString = self.path + "(" + path + ")" } + /** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ class DirEntry(path: String) extends Entry(path) { val entries = mutable.HashMap[String, Entry]() @@ -120,7 +123,7 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq else ensureDir(dirs, dirName(entry.getName), null) } } - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ final class FileZipArchive(file: JFile) extends ZipArchive(file) { def iterator: Iterator[Entry] = { val zipFile = new ZipFile(file) @@ -161,7 +164,7 @@ final class FileZipArchive(file: JFile) extends ZipArchive(file) { case _ => false } } - +/** ''Note: This library is considered experimental and should not be used unless you know what you are doing.'' */ final class URLZipArchive(val url: URL) extends ZipArchive(null) { def iterator: Iterator[Entry] = { val root = new DirEntry("/") diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala index eaf7d8326f..44d9d94a46 100644 --- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala +++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala @@ -49,7 +49,7 @@ object ReflectionUtils { case cl: java.net.URLClassLoader => (cl.getURLs mkString ",") case cl if cl != null && isAbstractFileClassLoader(cl.getClass) => - cl.asInstanceOf[{val root: scala.tools.nsc.io.AbstractFile}].root.canonicalPath + cl.asInstanceOf[{val root: scala.reflect.io.AbstractFile}].root.canonicalPath case null => inferBootClasspath case _ => diff --git a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala index 7705610efb..3c2885a9f4 100644 --- a/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala +++ b/src/reflect/scala/reflect/runtime/SynchronizedSymbols.scala @@ -1,7 +1,7 @@ package scala.reflect package runtime -import scala.tools.nsc.io.AbstractFile +import scala.reflect.io.AbstractFile trait SynchronizedSymbols extends internal.Symbols { self: SymbolTable => diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala index 49c272cc28..a514f0d5a1 100644 --- a/src/scalap/scala/tools/scalap/Main.scala +++ b/src/scalap/scala/tools/scalap/Main.scala @@ -97,9 +97,14 @@ class Main { */ def process(args: Arguments, path: ClassPath[AbstractFile])(classname: String): Unit = { // find the classfile - val encName = NameTransformer.encode( - if (classname == "scala.AnyRef") "java.lang.Object" - else classname) + val encName = classname match { + case "scala.AnyRef" => "java.lang.Object" + case _ => + // we have to encode every fragment of a name separately, otherwise the NameTransformer + // will encode using unicode escaping dot separators as well + // we can afford allocations because this is not a performance critical code + classname.split('.').map(NameTransformer.encode).mkString(".") + } val cls = path.findClass(encName) if (cls.isDefined && cls.get.binary.isDefined) { val cfile = cls.get.binary.get |