summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml4
-rw-r--r--lib/scala-compiler-src.jar.desired.sha12
-rw-r--r--lib/scala-compiler.jar.desired.sha12
-rw-r--r--lib/scala-library-src.jar.desired.sha12
-rw-r--r--lib/scala-library.jar.desired.sha12
-rw-r--r--lib/scala-reflect-src.jar.desired.sha12
-rw-r--r--lib/scala-reflect.jar.desired.sha12
-rw-r--r--src/compiler/scala/reflect/macros/runtime/AbortMacroException.scala3
-rw-r--r--src/compiler/scala/reflect/macros/runtime/Aliases.scala2
-rw-r--r--src/compiler/scala/reflect/macros/runtime/FrontEnds.scala9
-rw-r--r--src/compiler/scala/reflect/macros/runtime/Settings.scala2
-rw-r--r--src/compiler/scala/reflect/macros/util/Traces.scala4
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala6
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala8
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala195
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala159
-rwxr-xr-xsrc/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala42
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala802
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/ICodes.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala28
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala659
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala2
-rw-r--r--src/compiler/scala/tools/nsc/doc/html/page/Template.scala6
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala5
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Imports.scala4
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaParsers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/package.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala136
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala312
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala40
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala64
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypingTransformers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala89
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala286
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala16
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Duplicators.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala70
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala49
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala950
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala31
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala21
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala37
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala1449
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala4
-rw-r--r--src/compiler/scala/tools/reflect/FastTrack.scala11
-rw-r--r--src/library/scala/Function.scala4
-rw-r--r--src/library/scala/Option.scala2
-rw-r--r--src/library/scala/PartialFunction.scala135
-rw-r--r--src/library/scala/collection/GenTraversableLike.scala12
-rw-r--r--src/library/scala/collection/JavaConversions.scala3
-rwxr-xr-xsrc/library/scala/collection/LinearSeqOptimized.scala13
-rw-r--r--src/library/scala/collection/TraversableLike.scala18
-rw-r--r--src/library/scala/collection/convert/WrapAsScala.scala22
-rw-r--r--src/library/scala/collection/immutable/HashMap.scala78
-rw-r--r--src/library/scala/collection/immutable/List.scala10
-rw-r--r--src/library/scala/collection/immutable/ListMap.scala14
-rw-r--r--src/library/scala/collection/immutable/Stream.scala42
-rw-r--r--src/library/scala/collection/mutable/Builder.scala20
-rw-r--r--src/library/scala/collection/mutable/DoubleLinkedList.scala7
-rw-r--r--src/library/scala/collection/mutable/Queue.scala12
-rw-r--r--src/library/scala/collection/parallel/immutable/ParHashMap.scala5
-rw-r--r--src/library/scala/reflect/ClassTag.scala9
-rw-r--r--src/library/scala/reflect/base/Base.scala1
-rw-r--r--src/library/scala/reflect/base/Symbols.scala16
-rw-r--r--src/library/scala/reflect/base/TypeTags.scala2
-rw-r--r--src/library/scala/runtime/AbstractPartialFunction.scala40
-rw-r--r--src/library/scala/util/control/Exception.scala43
-rw-r--r--src/library/scala/util/hashing/MurmurHash3.scala20
-rw-r--r--src/library/scala/util/parsing/combinator/Parsers.scala18
-rw-r--r--src/reflect/scala/reflect/api/FlagSets.scala2
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala2
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala6
-rw-r--r--src/reflect/scala/reflect/api/Types.scala7
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala23
-rw-r--r--src/reflect/scala/reflect/internal/BaseTypeSeqs.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Names.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Scopes.scala9
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala6
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala75
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala2
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala34
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala167
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala611
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala15
-rw-r--r--src/reflect/scala/reflect/internal/transform/Erasure.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Collections.scala4
-rw-r--r--src/reflect/scala/reflect/internal/util/Statistics.scala22
-rw-r--r--src/reflect/scala/reflect/internal/util/ThreeValues.scala14
-rw-r--r--src/reflect/scala/reflect/macros/Aliases.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/SynchronizedTypes.scala11
-rw-r--r--src/reflect/scala/tools/nsc/io/ZipArchive.scala27
-rw-r--r--src/scalap/scala/tools/scalap/Main.scala6
-rw-r--r--test/files/jvm/future-spec/TryTests.scala14
-rw-r--r--test/files/jvm/manifests-new.scala2
-rw-r--r--test/files/neg/javaConversions-2.10-ambiguity.check6
-rw-r--r--test/files/neg/javaConversions-2.10-ambiguity.scala10
-rw-r--r--test/files/neg/macro-invalidshape-a.check3
-rw-r--r--test/files/neg/macro-invalidshape-b.check3
-rw-r--r--test/files/neg/macro-invalidshape-c.check11
-rw-r--r--test/files/neg/macro-invalidsig-context-bounds.check11
-rw-r--r--test/files/neg/macro-invalidsig-implicit-params.check11
-rw-r--r--test/files/neg/macro-invalidsig-params-namemismatch.check1
-rw-r--r--test/files/neg/macro-invalidsig-tparams-badtype.check2
-rw-r--r--test/files/neg/macro-invalidsig-tparams-notparams-a.check2
-rw-r--r--test/files/neg/macro-invalidsig-tparams-notparams-b.check2
-rw-r--r--test/files/neg/macro-invalidusage-badbounds-a.check (renamed from test/files/neg/macro-invalidusage-badbounds.check)0
-rw-r--r--test/files/neg/macro-invalidusage-badbounds-a.flags (renamed from test/files/neg/macro-invalidusage-badbounds.flags)0
-rw-r--r--test/files/neg/macro-invalidusage-badbounds-a/Impls_1.scala5
-rw-r--r--test/files/neg/macro-invalidusage-badbounds-a/Macros_Test_2.scala (renamed from test/files/neg/macro-invalidusage-badbounds/Macros_Test_2.scala)0
-rw-r--r--test/files/neg/static-annot.scala6
-rw-r--r--test/files/neg/t6227.check4
-rw-r--r--test/files/neg/t6227.scala6
-rw-r--r--test/files/neg/t6264.check4
-rw-r--r--test/files/neg/t6264.flags1
-rw-r--r--test/files/neg/t6264.scala6
-rw-r--r--test/files/neg/t6283.check4
-rw-r--r--test/files/neg/t6283.scala1
-rw-r--r--test/files/pos/SI-5788.scala5
-rw-r--r--test/files/pos/hk-match/a.scala5
-rw-r--r--test/files/pos/hk-match/b.scala1
-rw-r--r--test/files/pos/javaConversions-2.10-regression.scala17
-rw-r--r--test/files/pos/specializes-sym-crash.scala26
-rw-r--r--test/files/pos/t5667.scala2
-rw-r--r--test/files/pos/t6208.scala4
-rw-r--r--test/files/run/classtags_core.check60
-rw-r--r--test/files/run/existentials3-new.check16
-rw-r--r--test/files/run/existentials3-new.scala2
-rw-r--r--test/files/run/inline-ex-handlers.check27
-rw-r--r--test/files/run/macro-def-path-dependent-d1.check (renamed from test/files/run/macro-def-path-dependent-d.check)0
-rw-r--r--test/files/run/macro-def-path-dependent-d1.flags (renamed from test/files/run/macro-def-path-dependent-d.flags)0
-rw-r--r--test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala (renamed from test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala)0
-rw-r--r--test/files/run/macro-def-path-dependent-d1/Test_2.scala (renamed from test/files/run/macro-def-path-dependent-d/Test_2.scala)0
-rw-r--r--test/files/run/macro-def-path-dependent-d2.check1
-rw-r--r--test/files/run/macro-def-path-dependent-d2.flags1
-rw-r--r--test/files/run/macro-def-path-dependent-d2/Impls_1.scala7
-rw-r--r--test/files/run/macro-def-path-dependent-d2/Macros_2.scala7
-rw-r--r--test/files/run/macro-def-path-dependent-d2/Test_3.scala3
-rw-r--r--test/files/run/macro-expand-implicit-argument.check1
-rw-r--r--test/files/run/macro-expand-implicit-argument.flags1
-rw-r--r--test/files/run/macro-expand-implicit-argument/Macros_1.scala59
-rw-r--r--test/files/run/macro-expand-implicit-argument/Test_2.scala4
-rw-r--r--test/files/run/partialfun.check6
-rw-r--r--test/files/run/partialfun.scala86
-rw-r--r--test/files/run/reflection-sorted-decls.check4
-rw-r--r--test/files/run/reflection-sorted-decls.scala2
-rw-r--r--test/files/run/reflection-sorted-members.check30
-rw-r--r--test/files/run/reflection-sorted-members.scala2
-rw-r--r--test/files/run/static-annot-repl.check32
-rw-r--r--test/files/run/static-annot-repl.scala22
-rw-r--r--test/files/run/static-annot/field.scala13
-rw-r--r--test/files/run/stream-stack-overflow-filter-map.scala44
-rw-r--r--test/files/run/t1987b.check1
-rw-r--r--test/files/run/t1987b/PullIteratees.scala17
-rw-r--r--test/files/run/t1987b/a.scala6
-rw-r--r--test/files/run/t1987b/cce_test.scala15
-rw-r--r--test/files/run/t1987b/pkg1.scala4
-rw-r--r--test/files/run/t1987b/pkg2.scala3
-rw-r--r--test/files/run/t6052.scala21
-rw-r--r--test/files/run/t6236.check2
-rw-r--r--test/files/run/t6236/file_1.scala9
-rw-r--r--test/files/run/t6236/file_2.scala10
-rw-r--r--test/files/run/t6261.scala130
-rw-r--r--test/files/run/t6272.check10
-rw-r--r--test/files/run/t6272.scala62
-rw-r--r--test/files/run/t6292.scala18
-rw-r--r--test/files/run/try-catch-unify.check4
-rw-r--r--test/files/run/try-catch-unify.scala16
-rw-r--r--test/pending/neg/macro-invalidusage-badbounds-b.check4
-rw-r--r--test/pending/neg/macro-invalidusage-badbounds-b.flags1
-rw-r--r--test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala (renamed from test/files/neg/macro-invalidusage-badbounds/Impls_1.scala)0
-rw-r--r--test/pending/neg/macro-invalidusage-badbounds-b/Macros_Test_2.scala8
184 files changed, 4808 insertions, 3353 deletions
diff --git a/build.xml b/build.xml
index 647697bed5..99b68ced84 100644
--- a/build.xml
+++ b/build.xml
@@ -281,6 +281,8 @@ INITIALISATION
<!-- Resolve maven dependencies -->
<target name="init.maven.jars" depends="init.maven.tasks">
+ <!-- This target has an issue where if the user directory does not exist, we BOMB. ugh. -->
+ <mkdir dir="${user.home}/.m2/repository"/>
<artifact:dependencies pathId="dependency.classpath" filesetId="dependency.fileset">
<!--<dependency groupId="com.typesafe" artifactId="config" version="0.4.0"/>-->
</artifact:dependencies>
@@ -2178,7 +2180,7 @@ DOCUMENTATION
docfooter="epfl"
docsourceurl="${scaladoc.url}€{FILE_PATH}.scala#L1"
docUncompilable="${src.dir}/library-aux"
- skipPackages="scala.reflect.macros"
+ skipPackages="scala.reflect.macros.internal"
sourcepath="${src.dir}"
classpathref="pack.classpath"
addparams="${scalac.args.all}"
diff --git a/lib/scala-compiler-src.jar.desired.sha1 b/lib/scala-compiler-src.jar.desired.sha1
index 95973402e6..bfbcc5a7a3 100644
--- a/lib/scala-compiler-src.jar.desired.sha1
+++ b/lib/scala-compiler-src.jar.desired.sha1
@@ -1 +1 @@
-67257bb7ce010e2ceac800d737e202cfbfc2a1f6 ?scala-compiler-src.jar
+7bad3afb569e2c57d1b299b61e0d3c0fa1b1d8d9 ?scala-compiler-src.jar
diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1
index 7f023e00be..ef2063bc3d 100644
--- a/lib/scala-compiler.jar.desired.sha1
+++ b/lib/scala-compiler.jar.desired.sha1
@@ -1 +1 @@
-c52277de9e76187f34a5ae073e5d2aacc592ac50 ?scala-compiler.jar
+5f73d19a6ec70f67e6d8a2f08cde3551e51b2b79 ?scala-compiler.jar
diff --git a/lib/scala-library-src.jar.desired.sha1 b/lib/scala-library-src.jar.desired.sha1
index f2d287f120..0709415f43 100644
--- a/lib/scala-library-src.jar.desired.sha1
+++ b/lib/scala-library-src.jar.desired.sha1
@@ -1 +1 @@
-40b9c97e0c3abea4c460b73ca178f60a3bfea242 ?scala-library-src.jar
+26c6c1cf7be57afa519ec641fb78e16a771a534a ?scala-library-src.jar
diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1
index 99a06c2024..edc3614c6d 100644
--- a/lib/scala-library.jar.desired.sha1
+++ b/lib/scala-library.jar.desired.sha1
@@ -1 +1 @@
-0a8e0e39e1e6713323a2e659aab743ccfa57c071 ?scala-library.jar
+4f14def979133788dd91117a203a40e35cd24528 ?scala-library.jar
diff --git a/lib/scala-reflect-src.jar.desired.sha1 b/lib/scala-reflect-src.jar.desired.sha1
index 1752dec7f6..a7a9eddd93 100644
--- a/lib/scala-reflect-src.jar.desired.sha1
+++ b/lib/scala-reflect-src.jar.desired.sha1
@@ -1 +1 @@
-d1abf389fbf5dfc95889a181d28f94a6779c6165 ?scala-reflect-src.jar
+60c61467bc992752bf81bc0ca783a9d6a72db588 ?scala-reflect-src.jar
diff --git a/lib/scala-reflect.jar.desired.sha1 b/lib/scala-reflect.jar.desired.sha1
index 4cc99695e0..a1732595b8 100644
--- a/lib/scala-reflect.jar.desired.sha1
+++ b/lib/scala-reflect.jar.desired.sha1
@@ -1 +1 @@
-02b44e860b9b9abd1353bbaa1004b3f0004dd0b3 ?scala-reflect.jar
+b3764f8b2f7719d1fbfaf9767a3a68f6ef7ad876 ?scala-reflect.jar
diff --git a/src/compiler/scala/reflect/macros/runtime/AbortMacroException.scala b/src/compiler/scala/reflect/macros/runtime/AbortMacroException.scala
index f45dde8a85..4e4d88c0be 100644
--- a/src/compiler/scala/reflect/macros/runtime/AbortMacroException.scala
+++ b/src/compiler/scala/reflect/macros/runtime/AbortMacroException.scala
@@ -2,5 +2,6 @@ package scala.reflect.macros
package runtime
import scala.reflect.internal.util.Position
+import scala.util.control.ControlThrowable
-class AbortMacroException(val pos: Position, val msg: String) extends Throwable(msg)
+class AbortMacroException(val pos: Position, val msg: String) extends Throwable(msg) with ControlThrowable \ No newline at end of file
diff --git a/src/compiler/scala/reflect/macros/runtime/Aliases.scala b/src/compiler/scala/reflect/macros/runtime/Aliases.scala
index 8b742755cd..5e15b61dbd 100644
--- a/src/compiler/scala/reflect/macros/runtime/Aliases.scala
+++ b/src/compiler/scala/reflect/macros/runtime/Aliases.scala
@@ -21,6 +21,8 @@ trait Aliases {
override type TypeTag[T] = universe.TypeTag[T]
override val AbsTypeTag = universe.AbsTypeTag
override val TypeTag = universe.TypeTag
+ override def absTypeTag[T](implicit attag: AbsTypeTag[T]) = attag
override def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+ override def absTypeOf[T](implicit attag: AbsTypeTag[T]): Type = attag.tpe
override def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala b/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala
index 69fa416f8f..9f328eb82b 100644
--- a/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala
+++ b/src/compiler/scala/reflect/macros/runtime/FrontEnds.scala
@@ -35,13 +35,10 @@ trait FrontEnds extends scala.tools.reflect.FrontEnds {
def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg)
- def abort(pos: Position, msg: String): Nothing = {
- callsiteTyper.context.error(pos, msg)
- throw new AbortMacroException(pos, msg)
- }
+ def abort(pos: Position, msg: String): Nothing = throw new AbortMacroException(pos, msg)
def interactive(): Unit = universe.reporter match {
- case reporter: tools.nsc.reporters.AbstractReporter => reporter.displayPrompt()
+ case reporter: scala.tools.nsc.reporters.AbstractReporter => reporter.displayPrompt()
case _ => ()
}
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/reflect/macros/runtime/Settings.scala b/src/compiler/scala/reflect/macros/runtime/Settings.scala
index c602532ea4..e9d9a17b81 100644
--- a/src/compiler/scala/reflect/macros/runtime/Settings.scala
+++ b/src/compiler/scala/reflect/macros/runtime/Settings.scala
@@ -17,7 +17,7 @@ trait Settings {
setCompilerSettings(options.split(" ").toList)
def setCompilerSettings(options: List[String]): this.type = {
- val settings = new tools.nsc.Settings(_ => ())
+ val settings = new scala.tools.nsc.Settings(_ => ())
settings.copyInto(universe.settings)
this
}
diff --git a/src/compiler/scala/reflect/macros/util/Traces.scala b/src/compiler/scala/reflect/macros/util/Traces.scala
index 078cd2b74f..d16916b753 100644
--- a/src/compiler/scala/reflect/macros/util/Traces.scala
+++ b/src/compiler/scala/reflect/macros/util/Traces.scala
@@ -2,7 +2,7 @@ package scala.reflect.macros
package util
trait Traces {
- def globalSettings: tools.nsc.Settings
+ def globalSettings: scala.tools.nsc.Settings
val macroDebugLite = globalSettings.YmacrodebugLite.value
val macroDebugVerbose = globalSettings.YmacrodebugVerbose.value
@@ -10,4 +10,4 @@ trait Traces {
val macroTraceVerbose = scala.tools.nsc.util.trace when macroDebugVerbose
@inline final def macroLogLite(msg: => Any) { if (macroDebugLite || macroDebugVerbose) println(msg) }
@inline final def macroLogVerbose(msg: => Any) { if (macroDebugVerbose) println(msg) }
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 574129a2f1..80e9ede271 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -1220,8 +1220,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
var reportedFeature = Set[Symbol]()
- /** A flag whether macro expansions failed */
- var macroExpansionFailed = false
+ /** Has any macro expansion used a fallback during this run? */
+ var seenMacroExpansionsFallingBack = false
/** To be initialized from firstPhase. */
private var terminalPhase: Phase = NoPhase
@@ -1511,7 +1511,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
else {
allConditionalWarnings foreach (_.summarize)
- if (macroExpansionFailed)
+ if (seenMacroExpansionsFallingBack)
warning("some macros could not be expanded and code fell back to overridden methods;"+
"\nrecompiling with generated classfiles on the classpath might help.")
// todo: migrationWarnings
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 2ee38d4b91..e90d779885 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -95,7 +95,7 @@ trait TreeDSL {
def INT_>= (other: Tree) = fn(target, getMember(IntClass, nme.GE), other)
def INT_== (other: Tree) = fn(target, getMember(IntClass, nme.EQ), other)
def INT_!= (other: Tree) = fn(target, getMember(IntClass, nme.NE), other)
-
+
// generic operations on ByteClass, IntClass, LongClass
def GEN_| (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.OR), other)
def GEN_& (other: Tree, kind: ClassSymbol) = fn(target, getMember(kind, nme.AND), other)
@@ -234,7 +234,7 @@ trait TreeDSL {
}
class DefTreeStart(val name: Name) extends TreeVODDStart with DefCreator {
def tparams: List[TypeDef] = Nil
- def vparamss: List[List[ValDef]] = List(Nil)
+ def vparamss: List[List[ValDef]] = ListOfNil
}
class IfStart(cond: Tree, thenp: Tree) {
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index ca8a377c6f..b22681e52b 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -44,7 +44,7 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
setInfo analyzer.ImportType(qual)
)
val importTree = (
- Import(qual, List(ImportSelector(nme.WILDCARD, -1, null, -1)))
+ Import(qual, ImportSelector.wildList)
setSymbol importSym
setType NoType
)
@@ -58,7 +58,7 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) {
// This can't be "Annotated(New(UncheckedClass), expr)" because annotations
// are very picky about things and it crashes the compiler with "unexpected new".
- Annotated(New(scalaDot(UncheckedClass.name), List(Nil)), expr)
+ Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr)
}
// if it's a Match, mark the selector unchecked; otherwise nothing.
def mkUncheckedMatch(tree: Tree) = tree match {
@@ -357,8 +357,8 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL {
*/
def mkSynchronizedCheck(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
mkSynchronizedCheck(mkAttributedThis(clazz), cond, syncBody, stats)
-
- def mkSynchronizedCheck(attrThis: Tree, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
+
+ def mkSynchronizedCheck(attrThis: Tree, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
Block(mkSynchronized(
attrThis,
If(cond, Block(syncBody: _*), EmptyTree)) ::
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index 6f17a7d625..085ce82025 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -50,7 +50,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
/** Array selection <qualifier> . <name> only used during erasure */
case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type)
- extends TermTree with RefTree
+ extends RefTree with TermTree
/** Derived value class injection (equivalent to: new C(arg) after easure); only used during erasure
* The class C is stored as the symbol of the tree node.
@@ -111,7 +111,7 @@ trait Trees extends reflect.internal.Trees { self: Global =>
if (body forall treeInfo.isInterfaceMember) List()
else List(
atPos(wrappingPos(superPos, lvdefs)) (
- DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), List(List()), TypeTree(), Block(lvdefs, Literal(Constant())))))
+ DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), ListOfNil, TypeTree(), Block(lvdefs, Literal(Constant())))))
} else {
// convert (implicit ... ) to ()(implicit ... ) if its the only parameter section
if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 391874c488..17bea7f796 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -192,7 +192,7 @@ self =>
override def blockExpr(): Tree = skipBraces(EmptyTree)
- override def templateBody(isPre: Boolean) = skipBraces((emptyValDef, List(EmptyTree)))
+ override def templateBody(isPre: Boolean) = skipBraces((emptyValDef, EmptyTree.asList))
}
class UnitParser(val unit: global.CompilationUnit, patches: List[BracePatch]) extends SourceFileParser(unit.source) {
@@ -395,7 +395,7 @@ self =>
NoMods,
nme.CONSTRUCTOR,
Nil,
- List(Nil),
+ ListOfNil,
TypeTree(),
Block(List(Apply(gen.mkSuperSelect, Nil)), Literal(Constant(())))
)
@@ -404,7 +404,7 @@ self =>
def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String)))
def mainParameter = List(ValDef(Modifiers(Flags.PARAM), nme.argv, mainParamType, EmptyTree))
def mainSetArgv = List(ValDef(NoMods, nme.args, TypeTree(), Ident(nme.argv)))
- def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition)
+ def mainNew = makeNew(Nil, emptyValDef, stmts, ListOfNil, NoPosition, NoPosition)
def mainDef = DefDef(NoMods, nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, mainNew))
// object Main
@@ -1302,23 +1302,25 @@ self =>
placeholderParams = placeholderParams ::: savedPlaceholderParams
res
}
+
- def expr0(location: Int): Tree = in.token match {
+ def expr0(location: Int): Tree = (in.token: @scala.annotation.switch) match {
case IF =>
- atPos(in.skipToken()) {
+ def parseIf = atPos(in.skipToken()) {
val cond = condExpr()
newLinesOpt()
val thenp = expr()
val elsep = if (in.token == ELSE) { in.nextToken(); expr() }
- else Literal(Constant())
+ else Literal(Constant())
If(cond, thenp, elsep)
}
+ parseIf
case TRY =>
- atPos(in.skipToken()) {
+ def parseTry = atPos(in.skipToken()) {
val body = in.token match {
- case LBRACE => inBracesOrUnit(block())
- case LPAREN => inParensOrUnit(expr())
- case _ => expr()
+ case LBRACE => inBracesOrUnit(block())
+ case LPAREN => inParensOrUnit(expr())
+ case _ => expr()
}
def catchFromExpr() = List(makeCatchFromExpr(expr()))
val catches: List[CaseDef] =
@@ -1332,32 +1334,39 @@ self =>
}
}
val finalizer = in.token match {
- case FINALLY => in.nextToken() ; expr()
- case _ => EmptyTree
+ case FINALLY => in.nextToken(); expr()
+ case _ => EmptyTree
}
Try(body, catches, finalizer)
}
+ parseTry
case WHILE =>
- val start = in.offset
- atPos(in.skipToken()) {
- val lname: Name = freshTermName(nme.WHILE_PREFIX)
- val cond = condExpr()
- newLinesOpt()
- val body = expr()
- makeWhile(lname, cond, body)
+ def parseWhile = {
+ val start = in.offset
+ atPos(in.skipToken()) {
+ val lname: Name = freshTermName(nme.WHILE_PREFIX)
+ val cond = condExpr()
+ newLinesOpt()
+ val body = expr()
+ makeWhile(lname, cond, body)
+ }
}
+ parseWhile
case DO =>
- val start = in.offset
- atPos(in.skipToken()) {
- val lname: Name = freshTermName(nme.DO_WHILE_PREFIX)
- val body = expr()
- if (isStatSep) in.nextToken()
- accept(WHILE)
- val cond = condExpr()
- makeDoWhile(lname, body, cond)
+ def parseDo = {
+ val start = in.offset
+ atPos(in.skipToken()) {
+ val lname: Name = freshTermName(nme.DO_WHILE_PREFIX)
+ val body = expr()
+ if (isStatSep) in.nextToken()
+ accept(WHILE)
+ val cond = condExpr()
+ makeDoWhile(lname, body, cond)
+ }
}
+ parseDo
case FOR =>
- atPos(in.skipToken()) {
+ def parseFor = atPos(in.skipToken()) {
val enums =
if (in.token == LBRACE) inBracesOrNil(enumerators())
else inParensOrNil(enumerators())
@@ -1369,70 +1378,78 @@ self =>
makeFor(enums, expr())
}
}
+ parseFor
case RETURN =>
- atPos(in.skipToken()) {
- Return(if (isExprIntro) expr() else Literal(Constant()))
- }
+ def parseReturn =
+ atPos(in.skipToken()) {
+ Return(if (isExprIntro) expr() else Literal(Constant()))
+ }
+ parseReturn
case THROW =>
- atPos(in.skipToken()) {
- Throw(expr())
- }
+ def parseThrow =
+ atPos(in.skipToken()) {
+ Throw(expr())
+ }
+ parseThrow
case IMPLICIT =>
implicitClosure(in.skipToken(), location)
case _ =>
- var t = postfixExpr()
- if (in.token == EQUALS) {
- t match {
- case Ident(_) | Select(_, _) | Apply(_, _) =>
- t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) }
- case _ =>
- }
- } else if (in.token == COLON) {
- t = stripParens(t)
- val colonPos = in.skipToken()
- if (in.token == USCORE) {
- //todo: need to handle case where USCORE is a wildcard in a type
- val uscorePos = in.skipToken()
- if (isIdent && in.name == nme.STAR) {
- in.nextToken()
- t = atPos(t.pos.startOrPoint, colonPos) {
- Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) })
- }
- } else {
- syntaxErrorOrIncomplete("`*' expected", true)
+ def parseOther = {
+ var t = postfixExpr()
+ if (in.token == EQUALS) {
+ t match {
+ case Ident(_) | Select(_, _) | Apply(_, _) =>
+ t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) }
+ case _ =>
}
- } else if (in.token == AT) {
- t = (t /: annotations(skipNewLines = false)) (makeAnnotated)
- } else {
- t = atPos(t.pos.startOrPoint, colonPos) {
- val tpt = typeOrInfixType(location)
- if (isWildcard(t))
- (placeholderParams: @unchecked) match {
- case (vd @ ValDef(mods, name, _, _)) :: rest =>
- placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest
+ } else if (in.token == COLON) {
+ t = stripParens(t)
+ val colonPos = in.skipToken()
+ if (in.token == USCORE) {
+ //todo: need to handle case where USCORE is a wildcard in a type
+ val uscorePos = in.skipToken()
+ if (isIdent && in.name == nme.STAR) {
+ in.nextToken()
+ t = atPos(t.pos.startOrPoint, colonPos) {
+ Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) })
}
- // this does not correspond to syntax, but is necessary to
- // accept closures. We might restrict closures to be between {...} only.
- Typed(t, tpt)
+ } else {
+ syntaxErrorOrIncomplete("`*' expected", true)
+ }
+ } else if (in.token == AT) {
+ t = (t /: annotations(skipNewLines = false))(makeAnnotated)
+ } else {
+ t = atPos(t.pos.startOrPoint, colonPos) {
+ val tpt = typeOrInfixType(location)
+ if (isWildcard(t))
+ (placeholderParams: @unchecked) match {
+ case (vd @ ValDef(mods, name, _, _)) :: rest =>
+ placeholderParams = treeCopy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest
+ }
+ // this does not correspond to syntax, but is necessary to
+ // accept closures. We might restrict closures to be between {...} only.
+ Typed(t, tpt)
+ }
}
+ } else if (in.token == MATCH) {
+ t = atPos(t.pos.startOrPoint, in.skipToken())(Match(stripParens(t), inBracesOrNil(caseClauses())))
+ }
+ // in order to allow anonymous functions as statements (as opposed to expressions) inside
+ // templates, we have to disambiguate them from self type declarations - bug #1565
+ // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which
+ // may be impossible to distinguish from a self-type and so remains an error. (See #1564)
+ def lhsIsTypedParamList() = t match {
+ case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true
+ case _ => false
}
- } else if (in.token == MATCH) {
- t = atPos(t.pos.startOrPoint, in.skipToken())(Match(stripParens(t), inBracesOrNil(caseClauses())))
- }
- // in order to allow anonymous functions as statements (as opposed to expressions) inside
- // templates, we have to disambiguate them from self type declarations - bug #1565
- // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which
- // may be impossible to distinguish from a self-type and so remains an error. (See #1564)
- def lhsIsTypedParamList() = t match {
- case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true
- case _ => false
- }
- if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) {
- t = atPos(t.pos.startOrPoint, in.skipToken()) {
- Function(convertToParams(t), if (location != InBlock) expr() else block())
+ if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) {
+ t = atPos(t.pos.startOrPoint, in.skipToken()) {
+ Function(convertToParams(t), if (location != InBlock) expr() else block())
+ }
}
+ stripParens(t)
}
- stripParens(t)
+ parseOther
}
/** {{{
@@ -2093,7 +2110,7 @@ self =>
def annotationExpr(): Tree = atPos(in.offset) {
val t = exprSimpleType()
if (in.token == LPAREN) New(t, multipleArgumentExprs())
- else New(t, List(Nil))
+ else New(t, ListOfNil)
}
/* -------- PARAMETERS ------------------------------------------- */
@@ -2732,10 +2749,10 @@ self =>
def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = {
val parents = new ListBuffer[Tree] += startAnnotType()
val argss = (
- // TODO: the insertion of List(Nil) here is where "new Foo" becomes
+ // TODO: the insertion of ListOfNil here is where "new Foo" becomes
// indistinguishable from "new Foo()".
if (in.token == LPAREN && !isTrait) multipleArgumentExprs()
- else List(Nil)
+ else ListOfNil
)
while (in.token == WITH) {
@@ -2773,7 +2790,7 @@ self =>
val (self1, body1) = templateBodyOpt(traitParentSeen = isTrait)
(parents, argss, self1, earlyDefs ::: body1)
} else {
- (List(), List(List()), self, body)
+ (List(), ListOfNil, self, body)
}
} else {
val (parents, argss) = templateParents(isTrait = isTrait)
@@ -2800,7 +2817,7 @@ self =>
else {
newLineOptWhenFollowedBy(LBRACE)
val (self, body) = templateBodyOpt(traitParentSeen = false)
- (List(), List(List()), self, body)
+ (List(), ListOfNil, self, body)
}
)
def anyrefParents() = {
@@ -2813,7 +2830,7 @@ self =>
def anyvalConstructor() = (
// Not a well-formed constructor, has to be finished later - see note
// regarding AnyVal constructor in AddInterfaces.
- DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(Nil, Literal(Constant())))
+ DefDef(NoMods, nme.CONSTRUCTOR, Nil, ListOfNil, TypeTree(), Block(Nil, Literal(Constant())))
)
val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart
@@ -2834,7 +2851,7 @@ self =>
* @param isPre specifies whether in early initializer (true) or not (false)
*/
def templateBody(isPre: Boolean) = inBraces(templateStatSeq(isPre = isPre)) match {
- case (self, Nil) => (self, List(EmptyTree))
+ case (self, Nil) => (self, EmptyTree.asList)
case result => result
}
def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = {
@@ -2938,7 +2955,7 @@ self =>
/** Informal - for the repl and other direct parser accessors.
*/
def templateStats(): List[Tree] = templateStatSeq(isPre = false)._2 match {
- case Nil => List(EmptyTree)
+ case Nil => EmptyTree.asList
case stats => stats
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index f99b9a66c9..e6bf43fe93 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -360,16 +360,19 @@ trait Scanners extends ScannersCommon {
if (ch == '"' && token == IDENTIFIER)
token = INTERPOLATIONID
case '<' => // is XMLSTART?
- val last = if (charOffset >= 2) buf(charOffset - 2) else ' '
- nextChar()
- last match {
- case ' '|'\t'|'\n'|'{'|'('|'>' if isNameStart(ch) || ch == '!' || ch == '?' =>
- token = XMLSTART
- case _ =>
- // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG
- putChar('<')
- getOperatorRest()
+ def fetchLT = {
+ val last = if (charOffset >= 2) buf(charOffset - 2) else ' '
+ nextChar()
+ last match {
+ case ' ' | '\t' | '\n' | '{' | '(' | '>' if isNameStart(ch) || ch == '!' || ch == '?' =>
+ token = XMLSTART
+ case _ =>
+ // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG
+ putChar('<')
+ getOperatorRest()
+ }
}
+ fetchLT
case '~' | '!' | '@' | '#' | '%' |
'^' | '*' | '+' | '-' | /*'<' | */
'>' | '?' | ':' | '=' | '&' |
@@ -386,78 +389,87 @@ trait Scanners extends ScannersCommon {
getOperatorRest()
}
case '0' =>
- putChar(ch)
- nextChar()
- if (ch == 'x' || ch == 'X') {
+ def fetchZero = {
+ putChar(ch)
nextChar()
- base = 16
- }
- else {
- /** What should leading 0 be in the future? It is potentially dangerous
- * to let it be base-10 because of history. Should it be an error? Is
- * there a realistic situation where one would need it?
- */
- if (isDigit(ch)) {
- if (opt.future) syntaxError("Non-zero numbers may not have a leading zero.")
- else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.")
+ if (ch == 'x' || ch == 'X') {
+ nextChar()
+ base = 16
+ } else {
+ /**
+ * What should leading 0 be in the future? It is potentially dangerous
+ * to let it be base-10 because of history. Should it be an error? Is
+ * there a realistic situation where one would need it?
+ */
+ if (isDigit(ch)) {
+ if (opt.future) syntaxError("Non-zero numbers may not have a leading zero.")
+ else deprecationWarning("Treating numbers with a leading zero as octal is deprecated.")
+ }
+ base = 8
}
- base = 8
+ getNumber()
}
- getNumber()
+ fetchZero
case '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
base = 10
getNumber()
case '`' =>
getBackquotedIdent()
case '\"' =>
- if (token == INTERPOLATIONID) {
- nextRawChar()
- if (ch == '\"') {
+ def fetchDoubleQuote = {
+ if (token == INTERPOLATIONID) {
nextRawChar()
if (ch == '\"') {
nextRawChar()
- getStringPart(multiLine = true)
- sepRegions = STRINGPART :: sepRegions // indicate string part
- sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part
+ if (ch == '\"') {
+ nextRawChar()
+ getStringPart(multiLine = true)
+ sepRegions = STRINGPART :: sepRegions // indicate string part
+ sepRegions = STRINGLIT :: sepRegions // once more to indicate multi line string part
+ } else {
+ token = STRINGLIT
+ strVal = ""
+ }
} else {
- token = STRINGLIT
- strVal = ""
+ getStringPart(multiLine = false)
+ sepRegions = STRINGLIT :: sepRegions // indicate single line string part
}
} else {
- getStringPart(multiLine = false)
- sepRegions = STRINGLIT :: sepRegions // indicate single line string part
- }
- } else {
- nextChar()
- if (ch == '\"') {
nextChar()
if (ch == '\"') {
- nextRawChar()
- getRawStringLit()
+ nextChar()
+ if (ch == '\"') {
+ nextRawChar()
+ getRawStringLit()
+ } else {
+ token = STRINGLIT
+ strVal = ""
+ }
} else {
- token = STRINGLIT
- strVal = ""
+ getStringLit()
}
- } else {
- getStringLit()
}
}
+ fetchDoubleQuote
case '\'' =>
- nextChar()
- if (isIdentifierStart(ch))
- charLitOr(getIdentRest)
- else if (isOperatorPart(ch) && (ch != '\\'))
- charLitOr(getOperatorRest)
- else {
- getLitChar()
- if (ch == '\'') {
- nextChar()
- token = CHARLIT
- setStrVal()
- } else {
- syntaxError("unclosed character literal")
+ def fetchSingleQuote = {
+ nextChar()
+ if (isIdentifierStart(ch))
+ charLitOr(getIdentRest)
+ else if (isOperatorPart(ch) && (ch != '\\'))
+ charLitOr(getOperatorRest)
+ else {
+ getLitChar()
+ if (ch == '\'') {
+ nextChar()
+ token = CHARLIT
+ setStrVal()
+ } else {
+ syntaxError("unclosed character literal")
+ }
}
}
+ fetchSingleQuote
case '.' =>
nextChar()
if ('0' <= ch && ch <= '9') {
@@ -488,22 +500,25 @@ trait Scanners extends ScannersCommon {
nextChar()
}
case _ =>
- if (ch == '\u21D2') {
- nextChar(); token = ARROW
- } else if (ch == '\u2190') {
- nextChar(); token = LARROW
- } else if (Character.isUnicodeIdentifierStart(ch)) {
- putChar(ch)
- nextChar()
- getIdentRest()
- } else if (isSpecial(ch)) {
- putChar(ch)
- nextChar()
- getOperatorRest()
- } else {
- syntaxError("illegal character '" + ("" + '\\' + 'u' + "%04x".format(ch: Int)) + "'")
- nextChar()
+ def fetchOther = {
+ if (ch == '\u21D2') {
+ nextChar(); token = ARROW
+ } else if (ch == '\u2190') {
+ nextChar(); token = LARROW
+ } else if (Character.isUnicodeIdentifierStart(ch)) {
+ putChar(ch)
+ nextChar()
+ getIdentRest()
+ } else if (isSpecial(ch)) {
+ putChar(ch)
+ nextChar()
+ getOperatorRest()
+ } else {
+ syntaxError("illegal character '" + ("" + '\\' + 'u' + "%04x".format(ch: Int)) + "'")
+ nextChar()
+ }
}
+ fetchOther
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
index 5afec611e9..146329183c 100755
--- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
@@ -162,7 +162,7 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) {
/** could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. */
def makeXMLseq(pos: Position, args: Seq[Tree]) = {
- val buffer = ValDef(NoMods, _buf, TypeTree(), New(_scala_xml_NodeBuffer, List(Nil)))
+ val buffer = ValDef(NoMods, _buf, TypeTree(), New(_scala_xml_NodeBuffer, ListOfNil))
val applies = args filterNot isEmptyText map (t => Apply(Select(Ident(_buf), _plus), List(t)))
atPos(pos)( Block(buffer :: applies.toList, Ident(_buf)) )
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 898045e410..edf747486a 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -217,12 +217,12 @@ abstract class TreeBuilder {
atPos(cpos) {
ClassDef(
Modifiers(FINAL), x, Nil,
- Template(parents, self, NoMods, List(Nil), argss, stats, cpos.focus))
+ Template(parents, self, NoMods, ListOfNil, argss, stats, cpos.focus))
}),
atPos(npos) {
New(
Ident(x) setPos npos.focus,
- List(Nil))
+ ListOfNil)
}
)
}
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 3f0cef6703..486a43614b 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -20,6 +20,12 @@ trait BasicBlocks {
import global.{ ifDebug, settings, log, nme }
import nme.isExceptionResultName
+ /** Override Array creation for efficiency (to not go through reflection). */
+ private implicit val instructionTag: scala.reflect.ClassTag[Instruction] = new scala.reflect.ClassTag[Instruction] {
+ def runtimeClass: java.lang.Class[Instruction] = classOf[Instruction]
+ final override def newArray(len: Int): Array[Instruction] = new Array[Instruction](len)
+ }
+
object NoBasicBlock extends BasicBlock(-1, null)
/** This class represents a basic block. Each
@@ -36,10 +42,14 @@ trait BasicBlocks {
private final class SuccessorList() {
private var successors: List[BasicBlock] = Nil
+ /** This method is very hot! Handle with care. */
private def updateConserve() {
- var lb: ListBuffer[BasicBlock] = null
- var matches = 0
- var remaining = successors
+ var lb: ListBuffer[BasicBlock] = null
+ var matches = 0
+ var remaining = successors
+ val direct = directSuccessors
+ var scratchHandlers: List[ExceptionHandler] = method.exh
+ var scratchBlocks: List[BasicBlock] = direct
def addBlock(bb: BasicBlock) {
if (matches < 0)
@@ -54,25 +64,27 @@ trait BasicBlocks {
}
}
- // exceptionSuccessors
- method.exh foreach { handler =>
- if (handler covers outer)
- addBlock(handler.startBlock)
+ while (scratchBlocks ne Nil) {
+ addBlock(scratchBlocks.head)
+ scratchBlocks = scratchBlocks.tail
}
- // directSuccessors
- val direct = directSuccessors
- direct foreach addBlock
-
/** Return a list of successors for 'b' that come from exception handlers
* covering b's (non-exceptional) successors. These exception handlers
* might not cover 'b' itself. This situation corresponds to an
* exception being thrown as the first thing of one of b's successors.
*/
- method.exh foreach { handler =>
- direct foreach { block =>
- if (handler covers block)
+ while (scratchHandlers ne Nil) {
+ val handler = scratchHandlers.head
+ if (handler covers outer)
+ addBlock(handler.startBlock)
+
+ scratchBlocks = direct
+ while (scratchBlocks ne Nil) {
+ if (handler covers scratchBlocks.head)
addBlock(handler.startBlock)
+ scratchBlocks = scratchBlocks.tail
}
+ scratchHandlers = scratchHandlers.tail
}
// Blocks did not align: create a new list.
if (matches < 0)
@@ -95,7 +107,7 @@ trait BasicBlocks {
}
/** Flags of this basic block. */
- private var flags: Int = 0
+ private[this] var flags: Int = 0
/** Does this block have the given flag? */
def hasFlag(flag: Int): Boolean = (flags & flag) != 0
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index a480429026..431802d185 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -628,48 +628,54 @@ abstract class GenICode extends SubComponent {
val resCtx: Context = tree match {
case LabelDef(name, params, rhs) =>
- val ctx1 = ctx.newBlock
- if (nme.isLoopHeaderLabel(name))
- ctx1.bb.loopHeader = true
-
- ctx1.labels.get(tree.symbol) match {
- case Some(label) =>
- debuglog("Found existing label for " + tree.symbol.fullLocationString)
- label.anchor(ctx1.bb)
- label.patch(ctx.method.code)
-
- case None =>
- val pair = (tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (_.symbol))))
- debuglog("Adding label " + tree.symbol.fullLocationString + " in genLoad.")
- ctx1.labels += pair
- ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)));
- }
-
- ctx.bb.closeWith(JUMP(ctx1.bb), tree.pos)
- genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/)
-
- case ValDef(_, nme.THIS, _, _) =>
- debuglog("skipping trivial assign to _$this: " + tree)
- ctx
-
- case ValDef(_, _, _, rhs) =>
- val sym = tree.symbol
- val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false))
+ def genLoadLabelDef = {
+ val ctx1 = ctx.newBlock
+ if (nme.isLoopHeaderLabel(name))
+ ctx1.bb.loopHeader = true
+
+ ctx1.labels.get(tree.symbol) match {
+ case Some(label) =>
+ debuglog("Found existing label for " + tree.symbol.fullLocationString)
+ label.anchor(ctx1.bb)
+ label.patch(ctx.method.code)
+
+ case None =>
+ val pair = (tree.symbol -> (new Label(tree.symbol) anchor ctx1.bb setParams (params map (_.symbol))))
+ debuglog("Adding label " + tree.symbol.fullLocationString + " in genLoad.")
+ ctx1.labels += pair
+ ctx.method.addLocals(params map (p => new Local(p.symbol, toTypeKind(p.symbol.info), false)));
+ }
- if (rhs == EmptyTree) {
- debuglog("Uninitialized variable " + tree + " at: " + (tree.pos));
- ctx.bb.emit(getZeroOf(local.kind))
+ ctx.bb.closeWith(JUMP(ctx1.bb), tree.pos)
+ genLoad(rhs, ctx1, expectedType /*toTypeKind(tree.symbol.info.resultType)*/)
}
-
- var ctx1 = ctx
- if (rhs != EmptyTree)
- ctx1 = genLoad(rhs, ctx, local.kind);
-
- ctx1.bb.emit(STORE_LOCAL(local), tree.pos)
- ctx1.scope.add(local)
- ctx1.bb.emit(SCOPE_ENTER(local))
- generatedType = UNIT
- ctx1
+ genLoadLabelDef
+
+ case ValDef(_, name, _, rhs) =>
+ def genLoadValDef =
+ if (name == nme.THIS) {
+ debuglog("skipping trivial assign to _$this: " + tree)
+ ctx
+ } else {
+ val sym = tree.symbol
+ val local = ctx.method.addLocal(new Local(sym, toTypeKind(sym.info), false))
+
+ if (rhs == EmptyTree) {
+ debuglog("Uninitialized variable " + tree + " at: " + (tree.pos));
+ ctx.bb.emit(getZeroOf(local.kind))
+ }
+
+ var ctx1 = ctx
+ if (rhs != EmptyTree)
+ ctx1 = genLoad(rhs, ctx, local.kind);
+
+ ctx1.bb.emit(STORE_LOCAL(local), tree.pos)
+ ctx1.scope.add(local)
+ ctx1.bb.emit(SCOPE_ENTER(local))
+ generatedType = UNIT
+ ctx1
+ }
+ genLoadValDef
case t @ If(cond, thenp, elsep) =>
val (newCtx, resKind) = genLoadIf(t, ctx, expectedType)
@@ -677,51 +683,55 @@ abstract class GenICode extends SubComponent {
newCtx
case Return(expr) =>
- val returnedKind = toTypeKind(expr.tpe)
- debuglog("Return(" + expr + ") with returnedKind = " + returnedKind)
-
- var ctx1 = genLoad(expr, ctx, returnedKind)
- lazy val tmp = ctx1.makeLocal(tree.pos, expr.tpe, "tmp")
- val saved = savingCleanups(ctx1) {
- var savedFinalizer = false
- ctx1.cleanups foreach {
- case MonitorRelease(m) =>
- debuglog("removing " + m + " from cleanups: " + ctx1.cleanups)
- ctx1.bb.emit(Seq(LOAD_LOCAL(m), MONITOR_EXIT()))
- ctx1.exitSynchronized(m)
-
- case Finalizer(f, finalizerCtx) =>
- debuglog("removing " + f + " from cleanups: " + ctx1.cleanups)
- if (returnedKind != UNIT && mayCleanStack(f)) {
- log("Emitting STORE_LOCAL for " + tmp + " to save finalizer.")
- ctx1.bb.emit(STORE_LOCAL(tmp))
- savedFinalizer = true
- }
+ def genLoadReturn = {
+ val returnedKind = toTypeKind(expr.tpe)
+ debuglog("Return(" + expr + ") with returnedKind = " + returnedKind)
+
+ var ctx1 = genLoad(expr, ctx, returnedKind)
+ lazy val tmp = ctx1.makeLocal(tree.pos, expr.tpe, "tmp")
+ val saved = savingCleanups(ctx1) {
+ var savedFinalizer = false
+ ctx1.cleanups foreach {
+ case MonitorRelease(m) =>
+ debuglog("removing " + m + " from cleanups: " + ctx1.cleanups)
+ ctx1.bb.emit(Seq(LOAD_LOCAL(m), MONITOR_EXIT()))
+ ctx1.exitSynchronized(m)
+
+ case Finalizer(f, finalizerCtx) =>
+ debuglog("removing " + f + " from cleanups: " + ctx1.cleanups)
+ if (returnedKind != UNIT && mayCleanStack(f)) {
+ log("Emitting STORE_LOCAL for " + tmp + " to save finalizer.")
+ ctx1.bb.emit(STORE_LOCAL(tmp))
+ savedFinalizer = true
+ }
- // duplicate finalizer (takes care of anchored labels)
- val f1 = duplicateFinalizer(Set.empty ++ ctx1.labels.keySet, ctx1, f)
+ // duplicate finalizer (takes care of anchored labels)
+ val f1 = duplicateFinalizer(Set.empty ++ ctx1.labels.keySet, ctx1, f)
- // we have to run this without the same finalizer in
- // the list, otherwise infinite recursion happens for
- // finalizers that contain 'return'
- val fctx = finalizerCtx.newBlock
- ctx1.bb.closeWith(JUMP(fctx.bb))
- ctx1 = genLoad(f1, fctx, UNIT)
+ // we have to run this without the same finalizer in
+ // the list, otherwise infinite recursion happens for
+ // finalizers that contain 'return'
+ val fctx = finalizerCtx.newBlock
+ ctx1.bb.closeWith(JUMP(fctx.bb))
+ ctx1 = genLoad(f1, fctx, UNIT)
+ }
+ savedFinalizer
}
- savedFinalizer
- }
- if (saved) {
- log("Emitting LOAD_LOCAL for " + tmp + " after saving finalizer.")
- ctx1.bb.emit(LOAD_LOCAL(tmp))
- }
- adapt(returnedKind, ctx1.method.returnType, ctx1, tree.pos)
- ctx1.bb.emit(RETURN(ctx.method.returnType), tree.pos)
- ctx1.bb.enterIgnoreMode
- generatedType = expectedType
- ctx1
+ if (saved) {
+ log("Emitting LOAD_LOCAL for " + tmp + " after saving finalizer.")
+ ctx1.bb.emit(LOAD_LOCAL(tmp))
+ }
+ adapt(returnedKind, ctx1.method.returnType, ctx1, tree.pos)
+ ctx1.bb.emit(RETURN(ctx.method.returnType), tree.pos)
+ ctx1.bb.enterIgnoreMode
+ generatedType = expectedType
+ ctx1
+ }
+ genLoadReturn
- case t @ Try(_, _, _) => genLoadTry(t, ctx, generatedType = _)
+ case t @ Try(_, _, _) =>
+ genLoadTry(t, ctx, generatedType = _)
case Throw(expr) =>
val (ctx1, expectedType) = genThrow(expr, ctx)
@@ -733,41 +743,42 @@ abstract class GenICode extends SubComponent {
" Call was genLoad" + ((tree, ctx, expectedType)))
case Apply(TypeApply(fun, targs), _) =>
- val sym = fun.symbol
- val cast = sym match {
- case Object_isInstanceOf => false
- case Object_asInstanceOf => true
- case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree)
- }
-
- val Select(obj, _) = fun
- val l = toTypeKind(obj.tpe)
- val r = toTypeKind(targs.head.tpe)
- val ctx1 = genLoadQualifier(fun, ctx)
-
- if (l.isValueType && r.isValueType)
- genConversion(l, r, ctx1, cast)
- else if (l.isValueType) {
- ctx1.bb.emit(DROP(l), fun.pos)
- if (cast) {
- ctx1.bb.emit(Seq(
- NEW(REFERENCE(definitions.ClassCastExceptionClass)),
- DUP(ObjectReference),
- THROW(definitions.ClassCastExceptionClass)
- ))
- } else
- ctx1.bb.emit(CONSTANT(Constant(false)))
- }
- else if (r.isValueType && cast) {
- assert(false, tree) /* Erasure should have added an unboxing operation to prevent that. */
+ def genLoadApply1 = {
+ val sym = fun.symbol
+ val cast = sym match {
+ case Object_isInstanceOf => false
+ case Object_asInstanceOf => true
+ case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullName + "]" + " in: " + tree)
+ }
+
+ val Select(obj, _) = fun
+ val l = toTypeKind(obj.tpe)
+ val r = toTypeKind(targs.head.tpe)
+ val ctx1 = genLoadQualifier(fun, ctx)
+
+ if (l.isValueType && r.isValueType)
+ genConversion(l, r, ctx1, cast)
+ else if (l.isValueType) {
+ ctx1.bb.emit(DROP(l), fun.pos)
+ if (cast) {
+ ctx1.bb.emit(Seq(
+ NEW(REFERENCE(definitions.ClassCastExceptionClass)),
+ DUP(ObjectReference),
+ THROW(definitions.ClassCastExceptionClass)
+ ))
+ } else
+ ctx1.bb.emit(CONSTANT(Constant(false)))
+ } else if (r.isValueType && cast) {
+ assert(false, tree) /* Erasure should have added an unboxing operation to prevent that. */
+ } else if (r.isValueType) {
+ ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol))))
+ } else {
+ genCast(l, r, ctx1, cast)
+ }
+ generatedType = if (cast) r else BOOL;
+ ctx1
}
- else if (r.isValueType)
- ctx.bb.emit(IS_INSTANCE(REFERENCE(definitions.boxedClass(r.toType.typeSymbol))))
- else
- genCast(l, r, ctx1, cast);
-
- generatedType = if (cast) r else BOOL;
- ctx1
+ genLoadApply1
// 'super' call: Note: since constructors are supposed to
// return an instance of what they construct, we have to take
@@ -776,93 +787,102 @@ abstract class GenICode extends SubComponent {
// therefore, we can ignore this fact, and generate code that leaves nothing
// on the stack (contrary to what the type in the AST says).
case Apply(fun @ Select(Super(_, mix), _), args) =>
- debuglog("Call to super: " + tree);
- val invokeStyle = SuperCall(mix)
-// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
+ def genLoadApply2 = {
+ debuglog("Call to super: " + tree);
+ val invokeStyle = SuperCall(mix)
+ // if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);
- ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)
-
- ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos)
- generatedType =
- if (fun.symbol.isConstructor) UNIT
- else toTypeKind(fun.symbol.info.resultType)
- ctx1
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
+ val ctx1 = genLoadArguments(args, fun.symbol.info.paramTypes, ctx)
+
+ ctx1.bb.emit(CALL_METHOD(fun.symbol, invokeStyle), tree.pos)
+ generatedType =
+ if (fun.symbol.isConstructor) UNIT
+ else toTypeKind(fun.symbol.info.resultType)
+ ctx1
+ }
+ genLoadApply2
// 'new' constructor call: Note: since constructors are
// thought to return an instance of what they construct,
// we have to 'simulate' it by DUPlicating the freshly created
// instance (on JVM, <init> methods return VOID).
case Apply(fun @ Select(New(tpt), nme.CONSTRUCTOR), args) =>
- val ctor = fun.symbol
- debugassert(ctor.isClassConstructor,
- "'new' call to non-constructor: " + ctor.name)
-
- generatedType = toTypeKind(tpt.tpe)
- debugassert(generatedType.isReferenceType || generatedType.isArrayType,
- "Non reference type cannot be instantiated: " + generatedType)
-
- generatedType match {
- case arr @ ARRAY(elem) =>
- val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
- val dims = arr.dimensions
- var elemKind = arr.elementKind
- if (args.length > dims)
- unit.error(tree.pos, "too many arguments for array constructor: found " + args.length +
- " but array has only " + dims + " dimension(s)")
- if (args.length != dims)
- for (i <- args.length until dims) elemKind = ARRAY(elemKind)
- ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
- ctx1
+ def genLoadApply3 = {
+ val ctor = fun.symbol
+ debugassert(ctor.isClassConstructor,
+ "'new' call to non-constructor: " + ctor.name)
+
+ generatedType = toTypeKind(tpt.tpe)
+ debugassert(generatedType.isReferenceType || generatedType.isArrayType,
+ "Non reference type cannot be instantiated: " + generatedType)
- case rt @ REFERENCE(cls) =>
- debugassert(ctor.owner == cls,
- "Symbol " + ctor.owner.fullName + " is different than " + tpt)
-
- val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) {
- /* parameterful constructors are the only possible custom constructors,
- a default constructor can't be defined for valuetypes, CLR dixit */
- val isDefaultConstructor = args.isEmpty
- if (isDefaultConstructor) {
- msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false)
- ctx
+ generatedType match {
+ case arr @ ARRAY(elem) =>
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ val dims = arr.dimensions
+ var elemKind = arr.elementKind
+ if (args.length > dims)
+ unit.error(tree.pos, "too many arguments for array constructor: found " + args.length +
+ " but array has only " + dims + " dimension(s)")
+ if (args.length != dims)
+ for (i <- args.length until dims) elemKind = ARRAY(elemKind)
+ ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
+ ctx1
+
+ case rt @ REFERENCE(cls) =>
+ debugassert(ctor.owner == cls,
+ "Symbol " + ctor.owner.fullName + " is different than " + tpt)
+
+ val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) {
+ /* parameterful constructors are the only possible custom constructors,
+ a default constructor can't be defined for valuetypes, CLR dixit */
+ val isDefaultConstructor = args.isEmpty
+ if (isDefaultConstructor) {
+ msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false)
+ ctx
+ } else {
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos)
+ ctx1
+ }
} else {
+ val nw = NEW(rt)
+ ctx.bb.emit(nw, tree.pos)
+ ctx.bb.emit(DUP(generatedType))
val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
- ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos)
+
+ val init = CALL_METHOD(ctor, Static(true))
+ nw.init = init
+ ctx1.bb.emit(init, tree.pos)
ctx1
}
- } else {
- val nw = NEW(rt)
- ctx.bb.emit(nw, tree.pos)
- ctx.bb.emit(DUP(generatedType))
- val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
-
- val init = CALL_METHOD(ctor, Static(true))
- nw.init = init
- ctx1.bb.emit(init, tree.pos)
- ctx1
- }
- ctx2
-
- case _ =>
- abort("Cannot instantiate " + tpt + " of kind: " + generatedType)
+ ctx2
+
+ case _ =>
+ abort("Cannot instantiate " + tpt + " of kind: " + generatedType)
+ }
}
+ genLoadApply3
case Apply(fun @ _, List(expr)) if (definitions.isBox(fun.symbol)) =>
- debuglog("BOX : " + fun.symbol.fullName);
- val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
- val nativeKind = toTypeKind(expr.tpe)
- if (settings.Xdce.value) {
- // we store this boxed value to a local, even if not really needed.
- // boxing optimization might use it, and dead code elimination will
- // take care of unnecessary stores
- var loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed")
- ctx1.bb.emit(STORE_LOCAL(loc1))
- ctx1.bb.emit(LOAD_LOCAL(loc1))
+ def genLoadApply4 = {
+ debuglog("BOX : " + fun.symbol.fullName);
+ val ctx1 = genLoad(expr, ctx, toTypeKind(expr.tpe))
+ val nativeKind = toTypeKind(expr.tpe)
+ if (settings.Xdce.value) {
+ // we store this boxed value to a local, even if not really needed.
+ // boxing optimization might use it, and dead code elimination will
+ // take care of unnecessary stores
+ var loc1 = ctx.makeLocal(tree.pos, expr.tpe, "boxed")
+ ctx1.bb.emit(STORE_LOCAL(loc1))
+ ctx1.bb.emit(LOAD_LOCAL(loc1))
+ }
+ ctx1.bb.emit(BOX(nativeKind), expr.pos)
+ generatedType = toTypeKind(fun.symbol.tpe.resultType)
+ ctx1
}
- ctx1.bb.emit(BOX(nativeKind), expr.pos)
- generatedType = toTypeKind(fun.symbol.tpe.resultType)
- ctx1
+ genLoadApply4
case Apply(fun @ _, List(expr)) if (definitions.isUnbox(fun.symbol)) =>
debuglog("UNBOX : " + fun.symbol.fullName)
@@ -880,14 +900,30 @@ abstract class GenICode extends SubComponent {
case app @ Apply(fun @ Select(qual, _), args)
if !ctx.method.symbol.isStaticConstructor
- && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation =>
+ && fun.symbol.isAccessor && fun.symbol.accessed.hasStaticAnnotation
+ && qual.tpe.typeSymbol.orElse(fun.symbol.owner).companionClass != NoSymbol =>
// bypass the accessor to the companion object and load the static field directly
- // the only place were this bypass is not done, is the static intializer for the static field itself
+ // this bypass is not done:
+ // - if the static intializer for the static field itself
+ // - if there is no companion class of the object owner - this happens in the REPL
+ def genLoadApply5 = {
val sym = fun.symbol
generatedType = toTypeKind(sym.accessed.info)
- val hostClass = qual.tpe.typeSymbol.orElse(sym.owner).companionClass
- val staticfield = hostClass.info.findMember(sym.accessed.name, NoFlags, NoFlags, false)
-
+ val hostOwner = qual.tpe.typeSymbol.orElse(sym.owner)
+ val hostClass = hostOwner.companionClass
+ val staticfield = hostClass.info.findMember(sym.accessed.name, NoFlags, NoFlags, false) orElse {
+ if (!currentRun.compiles(hostOwner)) {
+ // hostOwner was separately compiled -- the static field symbol needs to be recreated in hostClass
+ import Flags._
+ debuglog("recreating sym.accessed.name: " + sym.accessed.name)
+ val objectfield = hostOwner.info.findMember(sym.accessed.name, NoFlags, NoFlags, false)
+ val staticfield = hostClass.newVariable(newTermName(sym.accessed.name.toString), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo objectfield.tpe
+ staticfield.addAnnotation(definitions.StaticClass)
+ hostClass.info.decls enter staticfield
+ staticfield
+ } else NoSymbol
+ }
+
if (sym.isGetter) {
ctx.bb.emit(LOAD_FIELD(staticfield, true) setHostClass hostClass, tree.pos)
ctx
@@ -900,84 +936,89 @@ abstract class GenICode extends SubComponent {
assert(false, "supposedly unreachable")
ctx
}
+ }
+ genLoadApply5
case app @ Apply(fun, args) =>
- val sym = fun.symbol
+ def genLoadApply6 = {
+ val sym = fun.symbol
- if (sym.isLabel) { // jump to a label
- val label = ctx.labels.getOrElse(sym, {
- // it is a forward jump, scan for labels
- resolveForwardLabel(ctx.defdef, ctx, sym)
- ctx.labels.get(sym) match {
- case Some(l) =>
- log("Forward jump for " + sym.fullLocationString + ": scan found label " + l)
- l
- case _ =>
- abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx)
- }
- })
- // note: when one of the args to genLoadLabelArguments is a jump to a label,
- // it will call back into genLoad and arrive at this case, which will then set ctx1.bb.ignore to true,
- // this is okay, since we're jumping unconditionally, so the loads and jumps emitted by the outer
- // call to genLoad (by calling genLoadLabelArguments and emitOnly) can safely be ignored,
- // however, as emitOnly will close the block, which reverses its instructions (when it's still open),
- // we better not reverse when the block has already been closed but is in ignore mode
- // (if it's not in ignore mode, double-closing is an error)
- val ctx1 = genLoadLabelArguments(args, label, ctx)
- ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
- ctx1.bb.enterIgnoreMode
- ctx1
- } else if (isPrimitive(sym)) { // primitive method call
- val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
- generatedType = resKind
- newCtx
- } else { // normal method call
- debuglog("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
- val invokeStyle =
- if (sym.isStaticMember)
- Static(false)
- else if (sym.isPrivate || sym.isClassConstructor)
- Static(true)
- else
- Dynamic
-
- var ctx1 =
- if (invokeStyle.hasInstance) {
- if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym))
- msil_genLoadQualifierAddress(fun, ctx)
+ if (sym.isLabel) { // jump to a label
+ val label = ctx.labels.getOrElse(sym, {
+ // it is a forward jump, scan for labels
+ resolveForwardLabel(ctx.defdef, ctx, sym)
+ ctx.labels.get(sym) match {
+ case Some(l) =>
+ log("Forward jump for " + sym.fullLocationString + ": scan found label " + l)
+ l
+ case _ =>
+ abort("Unknown label target: " + sym + " at: " + (fun.pos) + ": ctx: " + ctx)
+ }
+ })
+ // note: when one of the args to genLoadLabelArguments is a jump to a label,
+ // it will call back into genLoad and arrive at this case, which will then set ctx1.bb.ignore to true,
+ // this is okay, since we're jumping unconditionally, so the loads and jumps emitted by the outer
+ // call to genLoad (by calling genLoadLabelArguments and emitOnly) can safely be ignored,
+ // however, as emitOnly will close the block, which reverses its instructions (when it's still open),
+ // we better not reverse when the block has already been closed but is in ignore mode
+ // (if it's not in ignore mode, double-closing is an error)
+ val ctx1 = genLoadLabelArguments(args, label, ctx)
+ ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
+ ctx1.bb.enterIgnoreMode
+ ctx1
+ } else if (isPrimitive(sym)) { // primitive method call
+ val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
+ generatedType = resKind
+ newCtx
+ } else { // normal method call
+ debuglog("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
+ val invokeStyle =
+ if (sym.isStaticMember)
+ Static(false)
+ else if (sym.isPrivate || sym.isClassConstructor)
+ Static(true)
else
- genLoadQualifier(fun, ctx)
- } else ctx
-
- ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1)
- val cm = CALL_METHOD(sym, invokeStyle)
-
- /** In a couple cases, squirrel away a little extra information in the
- * CALL_METHOD for use by GenJVM.
- */
- fun match {
- case Select(qual, _) =>
- val qualSym = findHostClass(qual.tpe, sym)
-
- if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe)
- else cm setHostClass qualSym
-
- log(
- if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName
- else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym"
- )
- case _ =>
- }
- ctx1.bb.emit(cm, tree.pos)
+ Dynamic
+
+ var ctx1 =
+ if (invokeStyle.hasInstance) {
+ if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym))
+ msil_genLoadQualifierAddress(fun, ctx)
+ else
+ genLoadQualifier(fun, ctx)
+ } else ctx
+
+ ctx1 = genLoadArguments(args, sym.info.paramTypes, ctx1)
+ val cm = CALL_METHOD(sym, invokeStyle)
+
+ /** In a couple cases, squirrel away a little extra information in the
+ * CALL_METHOD for use by GenJVM.
+ */
+ fun match {
+ case Select(qual, _) =>
+ val qualSym = findHostClass(qual.tpe, sym)
+
+ if (qualSym == ArrayClass) cm setTargetTypeKind toTypeKind(qual.tpe)
+ else cm setHostClass qualSym
+
+ log(
+ if (qualSym == ArrayClass) "Stored target type kind " + toTypeKind(qual.tpe) + " for " + sym.fullName
+ else s"Set more precise host class for ${sym.fullName} hostClass: $qualSym"
+ )
+ case _ =>
+ }
+ ctx1.bb.emit(cm, tree.pos)
- if (sym == ctx1.method.symbol) {
- ctx1.method.recursive = true
+ if (sym == ctx1.method.symbol) {
+ ctx1.method.recursive = true
+ }
+ generatedType =
+ if (sym.isClassConstructor) UNIT
+ else toTypeKind(sym.info.resultType);
+ ctx1
}
- generatedType =
- if (sym.isClassConstructor) UNIT
- else toTypeKind(sym.info.resultType);
- ctx1
}
+ genLoadApply6
case ApplyDynamic(qual, args) =>
assert(!forMSIL, tree)
@@ -989,20 +1030,22 @@ abstract class GenICode extends SubComponent {
// ctx1
case This(qual) =>
- assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass,
- "Trying to access the this of another class: " +
- "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit)
- if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
- genLoadModule(ctx, tree)
- generatedType = REFERENCE(tree.symbol)
- }
- else {
- ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- generatedType = REFERENCE(
- if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
- )
+ def genLoadThis = {
+ assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass,
+ "Trying to access the this of another class: " +
+ "tree.symbol = " + tree.symbol + ", ctx.clazz.symbol = " + ctx.clazz.symbol + " compilation unit:"+unit)
+ if (tree.symbol.isModuleClass && tree.symbol != ctx.clazz.symbol) {
+ genLoadModule(ctx, tree)
+ generatedType = REFERENCE(tree.symbol)
+ } else {
+ ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
+ generatedType = REFERENCE(
+ if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
+ )
+ }
+ ctx
}
- ctx
+ genLoadThis
case Select(Ident(nme.EMPTY_PACKAGE_NAME), module) =>
debugassert(tree.symbol.isModule,
@@ -1012,60 +1055,67 @@ abstract class GenICode extends SubComponent {
genLoadModule(ctx, tree)
case Select(qualifier, selector) =>
- val sym = tree.symbol
- generatedType = toTypeKind(sym.info)
- val hostClass = findHostClass(qualifier.tpe, sym)
- log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass")
-
- if (sym.isModule) {
- genLoadModule(ctx, tree)
- }
- else if (sym.isStaticMember) {
- ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos)
- ctx
- }
- else {
- val ctx1 = genLoadQualifier(tree, ctx)
- ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos)
- ctx1
- }
+ def genLoadSelect = {
+ val sym = tree.symbol
+ generatedType = toTypeKind(sym.info)
+ val hostClass = findHostClass(qualifier.tpe, sym)
+ log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass")
- case Ident(name) =>
- val sym = tree.symbol
- if (!sym.isPackage) {
if (sym.isModule) {
genLoadModule(ctx, tree)
- generatedType = toTypeKind(sym.info)
}
- else {
- try {
- val Some(l) = ctx.method.lookupLocal(sym)
- ctx.bb.emit(LOAD_LOCAL(l), tree.pos)
- generatedType = l.kind
- } catch {
- case ex: MatchError =>
- abort("symbol " + sym + " does not exist in " + ctx.method)
+ else if (sym.isStaticMember) {
+ ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos)
+ ctx
+ } else {
+ val ctx1 = genLoadQualifier(tree, ctx)
+ ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos)
+ ctx1
+ }
+ }
+ genLoadSelect
+
+ case Ident(name) =>
+ def genLoadIdent = {
+ val sym = tree.symbol
+ if (!sym.isPackage) {
+ if (sym.isModule) {
+ genLoadModule(ctx, tree)
+ generatedType = toTypeKind(sym.info)
+ } else {
+ try {
+ val Some(l) = ctx.method.lookupLocal(sym)
+ ctx.bb.emit(LOAD_LOCAL(l), tree.pos)
+ generatedType = l.kind
+ } catch {
+ case ex: MatchError =>
+ abort("symbol " + sym + " does not exist in " + ctx.method)
+ }
}
}
+ ctx
}
- ctx
+ genLoadIdent
case Literal(value) =>
- if (value.tag != UnitTag) (value.tag, expectedType) match {
- case (IntTag, LONG) =>
- ctx.bb.emit(CONSTANT(Constant(value.longValue)), tree.pos);
- generatedType = LONG
- case (FloatTag, DOUBLE) =>
- ctx.bb.emit(CONSTANT(Constant(value.doubleValue)), tree.pos);
- generatedType = DOUBLE
- case (NullTag, _) =>
- ctx.bb.emit(CONSTANT(value), tree.pos);
- generatedType = NullReference
- case _ =>
- ctx.bb.emit(CONSTANT(value), tree.pos);
- generatedType = toTypeKind(tree.tpe)
+ def genLoadLiteral = {
+ if (value.tag != UnitTag) (value.tag, expectedType) match {
+ case (IntTag, LONG) =>
+ ctx.bb.emit(CONSTANT(Constant(value.longValue)), tree.pos);
+ generatedType = LONG
+ case (FloatTag, DOUBLE) =>
+ ctx.bb.emit(CONSTANT(Constant(value.doubleValue)), tree.pos);
+ generatedType = DOUBLE
+ case (NullTag, _) =>
+ ctx.bb.emit(CONSTANT(value), tree.pos);
+ generatedType = NullReference
+ case _ =>
+ ctx.bb.emit(CONSTANT(value), tree.pos);
+ generatedType = toTypeKind(tree.tpe)
+ }
+ ctx
}
- ctx
+ genLoadLiteral
case Block(stats, expr) =>
ctx.enterScope
@@ -1085,66 +1135,72 @@ abstract class GenICode extends SubComponent {
genStat(tree, ctx)
case ArrayValue(tpt @ TypeTree(), _elems) =>
- var ctx1 = ctx
- val elmKind = toTypeKind(tpt.tpe)
- generatedType = ARRAY(elmKind)
- val elems = _elems.toIndexedSeq
-
- ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos)
- ctx1.bb.emit(CREATE_ARRAY(elmKind, 1))
- // inline array literals
- var i = 0
- while (i < elems.length) {
- ctx1.bb.emit(DUP(generatedType), tree.pos)
- ctx1.bb.emit(CONSTANT(new Constant(i)))
- ctx1 = genLoad(elems(i), ctx1, elmKind)
- ctx1.bb.emit(STORE_ARRAY_ITEM(elmKind))
- i = i + 1
+ def genLoadArrayValue = {
+ var ctx1 = ctx
+ val elmKind = toTypeKind(tpt.tpe)
+ generatedType = ARRAY(elmKind)
+ val elems = _elems.toIndexedSeq
+
+ ctx1.bb.emit(CONSTANT(new Constant(elems.length)), tree.pos)
+ ctx1.bb.emit(CREATE_ARRAY(elmKind, 1))
+ // inline array literals
+ var i = 0
+ while (i < elems.length) {
+ ctx1.bb.emit(DUP(generatedType), tree.pos)
+ ctx1.bb.emit(CONSTANT(new Constant(i)))
+ ctx1 = genLoad(elems(i), ctx1, elmKind)
+ ctx1.bb.emit(STORE_ARRAY_ITEM(elmKind))
+ i = i + 1
+ }
+ ctx1
}
- ctx1
+ genLoadArrayValue
case Match(selector, cases) =>
- debuglog("Generating SWITCH statement.");
- var ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue)
- val afterCtx = ctx1.newBlock
- var caseCtx: Context = null
- generatedType = toTypeKind(tree.tpe)
-
- var targets: List[BasicBlock] = Nil
- var tags: List[Int] = Nil
- var default: BasicBlock = afterCtx.bb
-
- for (caze @ CaseDef(pat, guard, body) <- cases) {
- assert(guard == EmptyTree, guard)
- val tmpCtx = ctx1.newBlock
- pat match {
- case Literal(value) =>
- tags = value.intValue :: tags
- targets = tmpCtx.bb :: targets
- case Ident(nme.WILDCARD) =>
- default = tmpCtx.bb
- case Alternative(alts) =>
- alts foreach {
- case Literal(value) =>
- tags = value.intValue :: tags
- targets = tmpCtx.bb :: targets
- case _ =>
- abort("Invalid case in alternative in switch-like pattern match: " +
- tree + " at: " + tree.pos)
- }
- case _ =>
- abort("Invalid case statement in switch-like pattern match: " +
- tree + " at: " + (tree.pos))
+ def genLoadMatch = {
+ debuglog("Generating SWITCH statement.");
+ var ctx1 = genLoad(selector, ctx, INT) // TODO: Java 7 allows strings in switches (so, don't assume INT and don't convert the literals using intValue)
+ val afterCtx = ctx1.newBlock
+ var caseCtx: Context = null
+ generatedType = toTypeKind(tree.tpe)
+
+ var targets: List[BasicBlock] = Nil
+ var tags: List[Int] = Nil
+ var default: BasicBlock = afterCtx.bb
+
+ for (caze @ CaseDef(pat, guard, body) <- cases) {
+ assert(guard == EmptyTree, guard)
+ val tmpCtx = ctx1.newBlock
+ pat match {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case Ident(nme.WILDCARD) =>
+ default = tmpCtx.bb
+ case Alternative(alts) =>
+ alts foreach {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case _ =>
+ abort("Invalid case in alternative in switch-like pattern match: " +
+ tree + " at: " + tree.pos)
+ }
+ case _ =>
+ abort("Invalid case statement in switch-like pattern match: " +
+ tree + " at: " + (tree.pos))
+ }
+
+ caseCtx = genLoad(body, tmpCtx, generatedType)
+ // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body)
+ caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos)
}
-
- caseCtx = genLoad(body, tmpCtx, generatedType)
- // close the block unless it's already been closed by the body, which closes the block if it ends in a jump (which is emitted to have alternatives share their body)
- caseCtx.bb.closeWith(JUMP(afterCtx.bb) setPos caze.pos)
+ ctx1.bb.emitOnly(
+ SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
+ )
+ afterCtx
}
- ctx1.bb.emitOnly(
- SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
- )
- afterCtx
+ genLoadMatch
case EmptyTree =>
if (expectedType != UNIT)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
index 81fd285cdb..d43013c644 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
@@ -2,11 +2,6 @@
* Copyright 2005-2012 LAMP/EPFL
* @author Martin Odersky
*/
-/* NSC -- new scala compiler
- * Copyright 2005-2012 LAMP/EPFL
- * @author Martin Odersky
- */
-
package scala.tools.nsc
package backend
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
index 0f7080ef3c..1fcb406e96 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -82,6 +82,8 @@ trait Opcodes { self: ICodes =>
final val jumpsCat = 10
final val retCat = 11
+ private lazy val ObjectReferenceList = ObjectReference :: Nil
+
/** This class represents an instruction of the intermediate code.
* Each case subclass will represent a specific operation.
*/
@@ -392,14 +394,13 @@ trait Opcodes { self: ICodes =>
else args
}
- override def produced =
- if (producedType == UNIT || method.isConstructor) 0
- else 1
-
- private def producedType: TypeKind = toTypeKind(method.info.resultType)
- override def producedTypes =
- if (produced == 0) Nil
- else producedType :: Nil
+ private val producedList = toTypeKind(method.info.resultType) match {
+ case UNIT => Nil
+ case _ if method.isConstructor => Nil
+ case kind => kind :: Nil
+ }
+ override def produced = producedList.size
+ override def producedTypes = producedList
/** object identity is equality for CALL_METHODs. Needed for
* being able to store such instructions into maps, when more
@@ -423,7 +424,7 @@ trait Opcodes { self: ICodes =>
assert(boxType.isValueType && !boxType.isInstanceOf[BOXED] && (boxType ne UNIT)) // documentation
override def toString(): String = "UNBOX " + boxType
override def consumed = 1
- override def consumedTypes = ObjectReference :: Nil
+ override def consumedTypes = ObjectReferenceList
override def produced = 1
override def producedTypes = boxType :: Nil
override def category = objsCat
@@ -474,7 +475,7 @@ trait Opcodes { self: ICodes =>
override def consumed = 1
override def produced = 1
- override def consumedTypes = ObjectReference :: Nil
+ override def consumedTypes = ObjectReferenceList
override def producedTypes = BOOL :: Nil
override def category = castsCat
@@ -490,7 +491,7 @@ trait Opcodes { self: ICodes =>
override def consumed = 1
override def produced = 1
- override def consumedTypes = ObjectReference :: Nil
+ override def consumedTypes = ObjectReferenceList
override def producedTypes = typ :: Nil
override def category = castsCat
@@ -576,7 +577,6 @@ trait Opcodes { self: ICodes =>
override def produced = 0
override def consumedTypes = kind :: Nil
-
override def category = jumpsCat
}
@@ -799,7 +799,7 @@ trait Opcodes { self: ICodes =>
case class CIL_UNBOX(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_UNBOX " + valueType
override def consumed = 1
- override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType'
+ override def consumedTypes = ObjectReferenceList // actually consumes a 'boxed valueType'
override def produced = 1
override def producedTypes = msil_mgdptr(valueType) :: Nil
override def category = objsCat
@@ -808,7 +808,7 @@ trait Opcodes { self: ICodes =>
case class CIL_INITOBJ(valueType: TypeKind) extends Instruction {
override def toString(): String = "CIL_INITOBJ " + valueType
override def consumed = 1
- override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer
+ override def consumedTypes = ObjectReferenceList // actually consumes a managed pointer
override def produced = 0
override def category = objsCat
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 17b479e5e5..b57f5e86a3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -277,7 +277,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
// Nested objects won't receive ACC_FINAL in order to allow for their overriding.
val finalFlag = (
- (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym))
+ (((sym.rawflags & Flags.FINAL) != 0) || isTopLevelModule(sym))
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
@@ -448,6 +448,17 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
val JAVA_LANG_OBJECT = asm.Type.getObjectType("java/lang/Object")
val JAVA_LANG_STRING = asm.Type.getObjectType("java/lang/String")
+ /**
+ * We call many Java varargs methods from ASM library that expect Arra[asm.Type] as argument so
+ * we override default (compiler-generated) ClassTag so we can provide specialized newArray implementation.
+ *
+ * Examples of methods that should pick our definition are: JBuilder.javaType and JPlainBuilder.genMethod.
+ */
+ private implicit val asmTypeTag: scala.reflect.ClassTag[asm.Type] = new scala.reflect.ClassTag[asm.Type] {
+ def runtimeClass: java.lang.Class[asm.Type] = classOf[asm.Type]
+ final override def newArray(len: Int): Array[asm.Type] = new Array[asm.Type](len)
+ }
+
/** basic functionality for class file building */
abstract class JBuilder(bytecodeWriter: BytecodeWriter) {
@@ -641,7 +652,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def javaType(s: Symbol): asm.Type = {
if (s.isMethod) {
val resT: asm.Type = if (s.isClassConstructor) asm.Type.VOID_TYPE else javaType(s.tpe.resultType);
- asm.Type.getMethodType( resT, (s.tpe.paramTypes map javaType): _* )
+ asm.Type.getMethodType( resT, (s.tpe.paramTypes map javaType): _*)
} else { javaType(s.tpe) }
}
@@ -2217,15 +2228,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def getMerged(): collection.Map[Local, List[Interval]] = {
// TODO should but isn't: unbalanced start(s) of scope(s)
val shouldBeEmpty = pending filter { p => val Pair(k, st) = p; st.nonEmpty };
-
- val merged = mutable.Map.empty[Local, List[Interval]]
-
- def addToMerged(lv: Local, start: Label, end: Label) {
- val ranges = merged.getOrElseUpdate(lv, Nil)
- val coalesced = fuse(ranges, Interval(start, end))
- merged.update(lv, coalesced)
- }
-
+ val merged = mutable.Map[Local, List[Interval]]()
+ def addToMerged(lv: Local, start: Label, end: Label) {
+ val intv = Interval(start, end)
+ merged(lv) = if (merged contains lv) fuse(merged(lv), intv) else intv :: Nil
+ }
for(LocVarEntry(lv, start, end) <- seen) { addToMerged(lv, start, end) }
/* for each var with unbalanced start(s) of scope(s):
@@ -2375,8 +2382,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
def genBlock(b: BasicBlock) {
jmethod.visitLabel(labels(b))
- import asm.Opcodes;
-
debuglog("Generating code for block: " + b)
// val lastInstr = b.lastInstruction
@@ -2395,287 +2400,308 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
}
}
- (instr.category: @scala.annotation.switch) match {
-
- case icodes.localsCat => (instr: @unchecked) match {
- case THIS(_) => jmethod.visitVarInsn(Opcodes.ALOAD, 0)
- case LOAD_LOCAL(local) => jcode.load(indexOf(local), local.kind)
- case STORE_LOCAL(local) => jcode.store(indexOf(local), local.kind)
- case STORE_THIS(_) =>
- // this only works for impl classes because the self parameter comes first
- // in the method signature. If that changes, this code has to be revisited.
- jmethod.visitVarInsn(Opcodes.ASTORE, 0)
-
- case SCOPE_ENTER(lv) =>
- // locals removed by closelim (via CopyPropagation) may have left behind SCOPE_ENTER, SCOPE_EXIT that are to be ignored
- val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
- if(relevant) { // TODO check: does GenICode emit SCOPE_ENTER, SCOPE_EXIT for synthetic vars?
- // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
- // similarly, these labels aren't tracked in the `labels` map.
- val start = new asm.Label
- jmethod.visitLabel(start)
- scoping.pushScope(lv, start)
- }
+ genInstr(instr, b)
- case SCOPE_EXIT(lv) =>
- val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
- if(relevant) {
- // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
- // similarly, these labels aren't tracked in the `labels` map.
- val end = new asm.Label
- jmethod.visitLabel(end)
- scoping.popScope(lv, end, instr.pos)
- }
- }
+ }
- case icodes.stackCat => (instr: @unchecked) match {
+ }
- case LOAD_MODULE(module) =>
- // assert(module.isModule, "Expected module: " + module)
- debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags));
- if (clasz.symbol == module.moduleClass && jMethodName != nme.readResolve.toString) {
- jmethod.visitVarInsn(Opcodes.ALOAD, 0)
- } else {
- jmethod.visitFieldInsn(
- Opcodes.GETSTATIC,
- javaName(module) /* + "$" */ ,
- strMODULE_INSTANCE_FIELD,
- descriptor(module)
- )
- }
+ def genInstr(instr: Instruction, b: BasicBlock) {
+ import asm.Opcodes
+ (instr.category: @scala.annotation.switch) match {
+
+ case icodes.localsCat =>
+ def genLocalInstr = (instr: @unchecked) match {
+ case THIS(_) => jmethod.visitVarInsn(Opcodes.ALOAD, 0)
+ case LOAD_LOCAL(local) => jcode.load(indexOf(local), local.kind)
+ case STORE_LOCAL(local) => jcode.store(indexOf(local), local.kind)
+ case STORE_THIS(_) =>
+ // this only works for impl classes because the self parameter comes first
+ // in the method signature. If that changes, this code has to be revisited.
+ jmethod.visitVarInsn(Opcodes.ASTORE, 0)
+
+ case SCOPE_ENTER(lv) =>
+ // locals removed by closelim (via CopyPropagation) may have left behind SCOPE_ENTER, SCOPE_EXIT that are to be ignored
+ val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
+ if (relevant) { // TODO check: does GenICode emit SCOPE_ENTER, SCOPE_EXIT for synthetic vars?
+ // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
+ // similarly, these labels aren't tracked in the `labels` map.
+ val start = new asm.Label
+ jmethod.visitLabel(start)
+ scoping.pushScope(lv, start)
+ }
- case DROP(kind) => emit(if(kind.isWideType) Opcodes.POP2 else Opcodes.POP)
+ case SCOPE_EXIT(lv) =>
+ val relevant = (!lv.sym.isSynthetic && m.locals.contains(lv))
+ if (relevant) {
+ // this label will have DEBUG bit set in its flags (ie ASM ignores it for dataflow purposes)
+ // similarly, these labels aren't tracked in the `labels` map.
+ val end = new asm.Label
+ jmethod.visitLabel(end)
+ scoping.popScope(lv, end, instr.pos)
+ }
+ }
+ genLocalInstr
+
+ case icodes.stackCat =>
+ def genStackInstr = (instr: @unchecked) match {
+
+ case LOAD_MODULE(module) =>
+ // assert(module.isModule, "Expected module: " + module)
+ debuglog("generating LOAD_MODULE for: " + module + " flags: " + Flags.flagsToString(module.flags));
+ if (clasz.symbol == module.moduleClass && jMethodName != nme.readResolve.toString) {
+ jmethod.visitVarInsn(Opcodes.ALOAD, 0)
+ } else {
+ jmethod.visitFieldInsn(
+ Opcodes.GETSTATIC,
+ javaName(module) /* + "$" */ ,
+ strMODULE_INSTANCE_FIELD,
+ descriptor(module))
+ }
- case DUP(kind) => emit(if(kind.isWideType) Opcodes.DUP2 else Opcodes.DUP)
+ case DROP(kind) => emit(if (kind.isWideType) Opcodes.POP2 else Opcodes.POP)
- case LOAD_EXCEPTION(_) => ()
- }
+ case DUP(kind) => emit(if (kind.isWideType) Opcodes.DUP2 else Opcodes.DUP)
- case icodes.constCat => genConstant(jmethod, instr.asInstanceOf[CONSTANT].constant)
+ case LOAD_EXCEPTION(_) => ()
+ }
+ genStackInstr
- case icodes.arilogCat => genPrimitive(instr.asInstanceOf[CALL_PRIMITIVE].primitive, instr.pos)
+ case icodes.constCat => genConstant(jmethod, instr.asInstanceOf[CONSTANT].constant)
- case icodes.castsCat => (instr: @unchecked) match {
+ case icodes.arilogCat => genPrimitive(instr.asInstanceOf[CALL_PRIMITIVE].primitive, instr.pos)
- case IS_INSTANCE(tpe) =>
- val jtyp: asm.Type =
- tpe match {
- case REFERENCE(cls) => asm.Type.getObjectType(javaName(cls))
- case ARRAY(elem) => javaArrayType(javaType(elem))
- case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
- }
- jmethod.visitTypeInsn(Opcodes.INSTANCEOF, jtyp.getInternalName)
+ case icodes.castsCat =>
+ def genCastInstr = (instr: @unchecked) match {
- case CHECK_CAST(tpe) =>
+ case IS_INSTANCE(tpe) =>
+ val jtyp: asm.Type =
tpe match {
-
- case REFERENCE(cls) =>
- if (cls != ObjectClass) { // No need to checkcast for Objects
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, javaName(cls))
- }
-
- case ARRAY(elem) =>
- val iname = javaArrayType(javaType(elem)).getInternalName
- jmethod.visitTypeInsn(Opcodes.CHECKCAST, iname)
-
- case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
+ case REFERENCE(cls) => asm.Type.getObjectType(javaName(cls))
+ case ARRAY(elem) => javaArrayType(javaType(elem))
+ case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
}
+ jmethod.visitTypeInsn(Opcodes.INSTANCEOF, jtyp.getInternalName)
- }
-
- case icodes.objsCat => (instr: @unchecked) match {
+ case CHECK_CAST(tpe) =>
+ tpe match {
- case BOX(kind) =>
- val MethodNameAndType(mname, mdesc) = jBoxTo(kind)
- jcode.invokestatic(BoxesRunTime, mname, mdesc)
+ case REFERENCE(cls) =>
+ if (cls != ObjectClass) { // No need to checkcast for Objects
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, javaName(cls))
+ }
- case UNBOX(kind) =>
- val MethodNameAndType(mname, mdesc) = jUnboxTo(kind)
- jcode.invokestatic(BoxesRunTime, mname, mdesc)
+ case ARRAY(elem) =>
+ val iname = javaArrayType(javaType(elem)).getInternalName
+ jmethod.visitTypeInsn(Opcodes.CHECKCAST, iname)
- case NEW(REFERENCE(cls)) =>
- val className = javaName(cls)
- jmethod.visitTypeInsn(Opcodes.NEW, className)
+ case _ => abort("Unknown reference type in IS_INSTANCE: " + tpe)
+ }
- case MONITOR_ENTER() => emit(Opcodes.MONITORENTER)
- case MONITOR_EXIT() => emit(Opcodes.MONITOREXIT)
- }
+ }
+ genCastInstr
- case icodes.fldsCat => (instr: @unchecked) match {
+ case icodes.objsCat =>
+ def genObjsInstr = (instr: @unchecked) match {
- case lf @ LOAD_FIELD(field, isStatic) =>
- var owner = javaName(lf.hostClass)
- debuglog("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags))
- val fieldJName = javaName(field)
- val fieldDescr = descriptor(field)
- val opc = if (isStatic) Opcodes.GETSTATIC else Opcodes.GETFIELD
- jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+ case BOX(kind) =>
+ val MethodNameAndType(mname, mdesc) = jBoxTo(kind)
+ jcode.invokestatic(BoxesRunTime, mname, mdesc)
- case STORE_FIELD(field, isStatic) =>
- val owner = javaName(field.owner)
- val fieldJName = javaName(field)
- val fieldDescr = descriptor(field)
- val opc = if (isStatic) Opcodes.PUTSTATIC else Opcodes.PUTFIELD
- jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+ case UNBOX(kind) =>
+ val MethodNameAndType(mname, mdesc) = jUnboxTo(kind)
+ jcode.invokestatic(BoxesRunTime, mname, mdesc)
- }
+ case NEW(REFERENCE(cls)) =>
+ val className = javaName(cls)
+ jmethod.visitTypeInsn(Opcodes.NEW, className)
- case icodes.mthdsCat => (instr: @unchecked) match {
+ case MONITOR_ENTER() => emit(Opcodes.MONITORENTER)
+ case MONITOR_EXIT() => emit(Opcodes.MONITOREXIT)
+ }
+ genObjsInstr
+
+ case icodes.fldsCat =>
+ def genFldsInstr = (instr: @unchecked) match {
+
+ case lf @ LOAD_FIELD(field, isStatic) =>
+ var owner = javaName(lf.hostClass)
+ debuglog("LOAD_FIELD with owner: " + owner + " flags: " + Flags.flagsToString(field.owner.flags))
+ val fieldJName = javaName(field)
+ val fieldDescr = descriptor(field)
+ val opc = if (isStatic) Opcodes.GETSTATIC else Opcodes.GETFIELD
+ jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
+
+ case STORE_FIELD(field, isStatic) =>
+ val owner = javaName(field.owner)
+ val fieldJName = javaName(field)
+ val fieldDescr = descriptor(field)
+ val opc = if (isStatic) Opcodes.PUTSTATIC else Opcodes.PUTFIELD
+ jmethod.visitFieldInsn(opc, owner, fieldJName, fieldDescr)
- /** Special handling to access native Array.clone() */
- case call @ CALL_METHOD(definitions.Array_clone, Dynamic) =>
- val target: String = javaType(call.targetTypeKind).getInternalName
- jcode.invokevirtual(target, "clone", mdesc_arrayClone)
+ }
+ genFldsInstr
- case call @ CALL_METHOD(method, style) => genCallMethod(call)
+ case icodes.mthdsCat =>
+ def genMethodsInstr = (instr: @unchecked) match {
- }
+ /** Special handling to access native Array.clone() */
+ case call @ CALL_METHOD(definitions.Array_clone, Dynamic) =>
+ val target: String = javaType(call.targetTypeKind).getInternalName
+ jcode.invokevirtual(target, "clone", mdesc_arrayClone)
- case icodes.arraysCat => (instr: @unchecked) match {
- case LOAD_ARRAY_ITEM(kind) => jcode.aload(kind)
- case STORE_ARRAY_ITEM(kind) => jcode.astore(kind)
- case CREATE_ARRAY(elem, 1) => jcode newarray elem
- case CREATE_ARRAY(elem, dims) => jmethod.visitMultiANewArrayInsn(descriptor(ArrayN(elem, dims)), dims)
- }
+ case call @ CALL_METHOD(method, style) => genCallMethod(call)
- case icodes.jumpsCat => (instr: @unchecked) match {
-
- case sw @ SWITCH(tagss, branches) =>
- assert(branches.length == tagss.length + 1, sw)
- val flatSize = sw.flatTagsCount
- val flatKeys = new Array[Int](flatSize)
- val flatBranches = new Array[asm.Label](flatSize)
-
- var restTagss = tagss
- var restBranches = branches
- var k = 0 // ranges over flatKeys and flatBranches
- while(restTagss.nonEmpty) {
- val currLabel = labels(restBranches.head)
- for(cTag <- restTagss.head) {
- flatKeys(k) = cTag;
- flatBranches(k) = currLabel
- k += 1
- }
- restTagss = restTagss.tail
- restBranches = restBranches.tail
+ }
+ genMethodsInstr
+
+ case icodes.arraysCat =>
+ def genArraysInstr = (instr: @unchecked) match {
+ case LOAD_ARRAY_ITEM(kind) => jcode.aload(kind)
+ case STORE_ARRAY_ITEM(kind) => jcode.astore(kind)
+ case CREATE_ARRAY(elem, 1) => jcode newarray elem
+ case CREATE_ARRAY(elem, dims) => jmethod.visitMultiANewArrayInsn(descriptor(ArrayN(elem, dims)), dims)
+ }
+ genArraysInstr
+
+ case icodes.jumpsCat =>
+ def genJumpInstr = (instr: @unchecked) match {
+
+ case sw @ SWITCH(tagss, branches) =>
+ assert(branches.length == tagss.length + 1, sw)
+ val flatSize = sw.flatTagsCount
+ val flatKeys = new Array[Int](flatSize)
+ val flatBranches = new Array[asm.Label](flatSize)
+
+ var restTagss = tagss
+ var restBranches = branches
+ var k = 0 // ranges over flatKeys and flatBranches
+ while (restTagss.nonEmpty) {
+ val currLabel = labels(restBranches.head)
+ for (cTag <- restTagss.head) {
+ flatKeys(k) = cTag;
+ flatBranches(k) = currLabel
+ k += 1
}
- val defaultLabel = labels(restBranches.head)
- assert(restBranches.tail.isEmpty)
- debuglog("Emitting SWITCH:\ntags: " + tagss + "\nbranches: " + branches)
- jcode.emitSWITCH(flatKeys, flatBranches, defaultLabel, MIN_SWITCH_DENSITY)
-
- case JUMP(whereto) =>
- if (nextBlock != whereto) {
- jcode goTo labels(whereto)
- } else if(m.exh.exists(eh => eh.covers(b))) {
- // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH.
- // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range"
- val isSthgLeft = b.toList.exists {
- case _: LOAD_EXCEPTION => false
- case _: SCOPE_ENTER => false
- case _: SCOPE_EXIT => false
- case _: JUMP => false
- case _ => true
- }
- if(!isSthgLeft) {
- emit(asm.Opcodes.NOP)
- }
+ restTagss = restTagss.tail
+ restBranches = restBranches.tail
+ }
+ val defaultLabel = labels(restBranches.head)
+ assert(restBranches.tail.isEmpty)
+ debuglog("Emitting SWITCH:\ntags: " + tagss + "\nbranches: " + branches)
+ jcode.emitSWITCH(flatKeys, flatBranches, defaultLabel, MIN_SWITCH_DENSITY)
+
+ case JUMP(whereto) =>
+ if (nextBlock != whereto) {
+ jcode goTo labels(whereto)
+ } else if (m.exh.exists(eh => eh.covers(b))) {
+ // SI-6102: Determine whether eliding this JUMP results in an empty range being covered by some EH.
+ // If so, emit a NOP in place of the elided JUMP, to avoid "java.lang.ClassFormatError: Illegal exception table range"
+ val isSthgLeft = b.toList.exists {
+ case _: LOAD_EXCEPTION => false
+ case _: SCOPE_ENTER => false
+ case _: SCOPE_EXIT => false
+ case _: JUMP => false
+ case _ => true
+ }
+ if (!isSthgLeft) {
+ emit(asm.Opcodes.NOP)
}
+ }
- case CJUMP(success, failure, cond, kind) =>
- if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
- if (nextBlock == success) {
- jcode.emitIF_ICMP(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF_ICMP(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
- } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
- if (nextBlock == success) {
- jcode.emitIF_ACMP(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF_ACMP(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ case CJUMP(success, failure, cond, kind) =>
+ if (kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
+ if (nextBlock == success) {
+ jcode.emitIF_ICMP(cond.negate, labels(failure))
+ // .. and fall through to success label
} else {
- (kind: @unchecked) match {
- case LONG => emit(Opcodes.LCMP)
- case FLOAT =>
- if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
- else emit(Opcodes.FCMPL)
- case DOUBLE =>
- if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
- else emit(Opcodes.DCMPL)
- }
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- // .. and fall through to success label
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ jcode.emitIF_ICMP(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
}
-
- case CZJUMP(success, failure, cond, kind) =>
- if(kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
- } else if(kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
- val Success = success
- val Failure = failure
- // @unchecked because references aren't compared with GT, GE, LT, LE.
- ((cond, nextBlock) : @unchecked) match {
- case (EQ, Success) => jcode emitIFNONNULL labels(failure)
- case (NE, Failure) => jcode emitIFNONNULL labels(success)
- case (EQ, Failure) => jcode emitIFNULL labels(success)
- case (NE, Success) => jcode emitIFNULL labels(failure)
- case (EQ, _) =>
- jcode emitIFNULL labels(success)
- jcode goTo labels(failure)
- case (NE, _) =>
- jcode emitIFNONNULL labels(success)
- jcode goTo labels(failure)
- }
+ } else if (kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ if (nextBlock == success) {
+ jcode.emitIF_ACMP(cond.negate, labels(failure))
+ // .. and fall through to success label
} else {
- (kind: @unchecked) match {
- case LONG =>
- emit(Opcodes.LCONST_0)
- emit(Opcodes.LCMP)
- case FLOAT =>
- emit(Opcodes.FCONST_0)
- if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
- else emit(Opcodes.FCMPL)
- case DOUBLE =>
- emit(Opcodes.DCONST_0)
- if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
- else emit(Opcodes.DCMPL)
- }
- if (nextBlock == success) {
- jcode.emitIF(cond.negate, labels(failure))
- } else {
- jcode.emitIF(cond, labels(success))
- if (nextBlock != failure) { jcode goTo labels(failure) }
- }
+ jcode.emitIF_ACMP(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
}
+ } else {
+ (kind: @unchecked) match {
+ case LONG => emit(Opcodes.LCMP)
+ case FLOAT =>
+ if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
+ else emit(Opcodes.FCMPL)
+ case DOUBLE =>
+ if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
+ else emit(Opcodes.DCMPL)
+ }
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ // .. and fall through to success label
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ }
- }
-
- case icodes.retCat => (instr: @unchecked) match {
- case RETURN(kind) => jcode emitRETURN kind
- case THROW(_) => emit(Opcodes.ATHROW)
- }
+ case CZJUMP(success, failure, cond, kind) =>
+ if (kind.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ } else if (kind.isRefOrArrayType) { // REFERENCE(_) | ARRAY(_)
+ val Success = success
+ val Failure = failure
+ // @unchecked because references aren't compared with GT, GE, LT, LE.
+ ((cond, nextBlock): @unchecked) match {
+ case (EQ, Success) => jcode emitIFNONNULL labels(failure)
+ case (NE, Failure) => jcode emitIFNONNULL labels(success)
+ case (EQ, Failure) => jcode emitIFNULL labels(success)
+ case (NE, Success) => jcode emitIFNULL labels(failure)
+ case (EQ, _) =>
+ jcode emitIFNULL labels(success)
+ jcode goTo labels(failure)
+ case (NE, _) =>
+ jcode emitIFNONNULL labels(success)
+ jcode goTo labels(failure)
+ }
+ } else {
+ (kind: @unchecked) match {
+ case LONG =>
+ emit(Opcodes.LCONST_0)
+ emit(Opcodes.LCMP)
+ case FLOAT =>
+ emit(Opcodes.FCONST_0)
+ if (cond == LT || cond == LE) emit(Opcodes.FCMPG)
+ else emit(Opcodes.FCMPL)
+ case DOUBLE =>
+ emit(Opcodes.DCONST_0)
+ if (cond == LT || cond == LE) emit(Opcodes.DCMPG)
+ else emit(Opcodes.DCMPL)
+ }
+ if (nextBlock == success) {
+ jcode.emitIF(cond.negate, labels(failure))
+ } else {
+ jcode.emitIF(cond, labels(success))
+ if (nextBlock != failure) { jcode goTo labels(failure) }
+ }
+ }
}
+ genJumpInstr
+ case icodes.retCat =>
+ def genRetInstr = (instr: @unchecked) match {
+ case RETURN(kind) => jcode emitRETURN kind
+ case THROW(_) => emit(Opcodes.ATHROW)
+ }
+ genRetInstr
}
-
- } // end of genCode()'s genBlock()
+ }
/**
* Emits one or more conversion instructions based on the types given as arguments.
@@ -2759,6 +2785,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
case Negation(kind) => jcode.neg(kind)
case Arithmetic(op, kind) =>
+ def genArith = {
op match {
case ADD => jcode.add(kind)
@@ -2781,57 +2808,89 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
case _ =>
abort("Unknown arithmetic primitive " + primitive)
}
+ }
+ genArith
// TODO Logical's 2nd elem should be declared ValueTypeKind, to better approximate its allowed values (isIntSized, its comments appears to convey)
// TODO GenICode uses `toTypeKind` to define that elem, `toValueTypeKind` would be needed instead.
// TODO How about adding some asserts to Logical and similar ones to capture the remaining constraint (UNIT not allowed).
- case Logical(op, kind) => ((op, kind): @unchecked) match {
- case (AND, LONG) => emit(Opcodes.LAND)
- case (AND, INT) => emit(Opcodes.IAND)
- case (AND, _) =>
- emit(Opcodes.IAND)
- if (kind != BOOL) { emitT2T(INT, kind) }
-
- case (OR, LONG) => emit(Opcodes.LOR)
- case (OR, INT) => emit(Opcodes.IOR)
- case (OR, _) =>
- emit(Opcodes.IOR)
- if (kind != BOOL) { emitT2T(INT, kind) }
-
- case (XOR, LONG) => emit(Opcodes.LXOR)
- case (XOR, INT) => emit(Opcodes.IXOR)
- case (XOR, _) =>
- emit(Opcodes.IXOR)
- if (kind != BOOL) { emitT2T(INT, kind) }
- }
-
- case Shift(op, kind) => ((op, kind): @unchecked) match {
- case (LSL, LONG) => emit(Opcodes.LSHL)
- case (LSL, INT) => emit(Opcodes.ISHL)
- case (LSL, _) =>
- emit(Opcodes.ISHL)
- emitT2T(INT, kind)
-
- case (ASR, LONG) => emit(Opcodes.LSHR)
- case (ASR, INT) => emit(Opcodes.ISHR)
- case (ASR, _) =>
- emit(Opcodes.ISHR)
- emitT2T(INT, kind)
-
- case (LSR, LONG) => emit(Opcodes.LUSHR)
- case (LSR, INT) => emit(Opcodes.IUSHR)
- case (LSR, _) =>
- emit(Opcodes.IUSHR)
- emitT2T(INT, kind)
- }
+ case Logical(op, kind) =>
+ def genLogical = op match {
+ case AND =>
+ kind match {
+ case LONG => emit(Opcodes.LAND)
+ case INT => emit(Opcodes.IAND)
+ case _ =>
+ emit(Opcodes.IAND)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ case OR =>
+ kind match {
+ case LONG => emit(Opcodes.LOR)
+ case INT => emit(Opcodes.IOR)
+ case _ =>
+ emit(Opcodes.IOR)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ case XOR =>
+ kind match {
+ case LONG => emit(Opcodes.LXOR)
+ case INT => emit(Opcodes.IXOR)
+ case _ =>
+ emit(Opcodes.IXOR)
+ if (kind != BOOL) { emitT2T(INT, kind) }
+ }
+ }
+ genLogical
+
+ case Shift(op, kind) =>
+ def genShift = op match {
+ case LSL =>
+ kind match {
+ case LONG => emit(Opcodes.LSHL)
+ case INT => emit(Opcodes.ISHL)
+ case _ =>
+ emit(Opcodes.ISHL)
+ emitT2T(INT, kind)
+ }
+ case ASR =>
+ kind match {
+ case LONG => emit(Opcodes.LSHR)
+ case INT => emit(Opcodes.ISHR)
+ case _ =>
+ emit(Opcodes.ISHR)
+ emitT2T(INT, kind)
+ }
+ case LSR =>
+ kind match {
+ case LONG => emit(Opcodes.LUSHR)
+ case INT => emit(Opcodes.IUSHR)
+ case _ =>
+ emit(Opcodes.IUSHR)
+ emitT2T(INT, kind)
+ }
+ }
+ genShift
- case Comparison(op, kind) => ((op, kind): @unchecked) match {
- case (CMP, LONG) => emit(Opcodes.LCMP)
- case (CMPL, FLOAT) => emit(Opcodes.FCMPL)
- case (CMPG, FLOAT) => emit(Opcodes.FCMPG)
- case (CMPL, DOUBLE) => emit(Opcodes.DCMPL)
- case (CMPG, DOUBLE) => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc3.html
- }
+ case Comparison(op, kind) =>
+ def genCompare = op match {
+ case CMP =>
+ (kind: @unchecked) match {
+ case LONG => emit(Opcodes.LCMP)
+ }
+ case CMPL =>
+ (kind: @unchecked) match {
+ case FLOAT => emit(Opcodes.FCMPL)
+ case DOUBLE => emit(Opcodes.DCMPL)
+ }
+ case CMPG =>
+ (kind: @unchecked) match {
+ case FLOAT => emit(Opcodes.FCMPG)
+ case DOUBLE => emit(Opcodes.DCMPL) // TODO bug? why not DCMPG? http://docs.oracle.com/javase/specs/jvms/se5.0/html/Instructions2.doc3.html
+
+ }
+ }
+ genCompare
case Conversion(src, dst) =>
debuglog("Converting from: " + src + " to: " + dst)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 11b0c40be7..930791d88d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -1960,7 +1960,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
// Nested objects won't receive ACC_FINAL in order to allow for their overriding.
val finalFlag = (
- (sym.hasFlag(Flags.FINAL) || isTopLevelModule(sym))
+ (((sym.rawflags & Flags.FINAL) != 0) || isTopLevelModule(sym))
&& !sym.enclClass.isInterface
&& !sym.isClassConstructor
&& !sym.isMutable // lazy vals and vars both
diff --git a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
index 1f68781777..24a26b2ad3 100644
--- a/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
+++ b/src/compiler/scala/tools/nsc/doc/html/page/Template.scala
@@ -49,7 +49,11 @@ class Template(universe: doc.Universe, generator: DiagramGenerator, tpl: DocTemp
if(top === self) {{
var url = '{ val p = templateToPath(tpl); "../" * (p.size - 1) + "index.html" }';
var hash = '{ val p = templateToPath(tpl); (p.tail.reverse ::: List(p.head.replace(".html", ""))).mkString(".") }';
- window.location.href = url + '#' + hash;
+ var anchor = window.location.hash;
+ var anchor_opt = '';
+ if (anchor.length { scala.xml.Unparsed(">=") /* unless we use Unparsed, it gets escaped and crashes the script */ } 1)
+ anchor_opt = '@' + anchor.substring(1);
+ window.location.href = url + '#' + hash + anchor_opt;
}}
</script>
</xml:group>
diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
index 2c16a754cb..4a4a900e2b 100644
--- a/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/ILoopInit.scala
@@ -8,6 +8,7 @@ package interpreter
import scala.reflect.internal.util.Position
import scala.util.control.Exception.ignoring
+import scala.tools.nsc.util.stackTraceString
/**
* Machinery for the asynchronous initialization of the repl.
@@ -94,9 +95,7 @@ trait ILoopInit {
runThunks()
} catch {
case ex: Throwable =>
- val message = new java.io.StringWriter()
- ex.printStackTrace(new java.io.PrintWriter(message))
- initError = message.toString
+ initError = stackTraceString(ex)
throw ex
} finally {
initIsComplete = true
diff --git a/src/compiler/scala/tools/nsc/interpreter/Imports.scala b/src/compiler/scala/tools/nsc/interpreter/Imports.scala
index 5193166889..14d43bc6d5 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Imports.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Imports.scala
@@ -23,7 +23,7 @@ trait Imports {
val hd :: tl = sym.fullName.split('.').toList map newTermName
val tree = Import(
tl.foldLeft(Ident(hd): Tree)((x, y) => Select(x, y)),
- List(ImportSelector(nme.WILDCARD, -1, null, -1))
+ ImportSelector.wildList
)
tree setSymbol sym
new ImportHandler(tree)
@@ -192,4 +192,4 @@ trait Imports {
private def membersAtPickler(sym: Symbol): List[Symbol] =
beforePickler(sym.info.nonPrivateMembers.toList)
-} \ No newline at end of file
+}
diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
index d1c404b3e3..c5da8822d5 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala
@@ -551,7 +551,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
if (parentToken == AT && in.token == DEFAULT) {
val annot =
atPos(pos) {
- New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), List(List()))
+ New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), ListOfNil)
}
mods1 = mods1 withAnnotations List(annot)
skipTo(SEMI)
@@ -640,7 +640,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
def importCompanionObject(cdef: ClassDef): Tree =
atPos(cdef.pos) {
- Import(Ident(cdef.name.toTermName), List(ImportSelector(nme.WILDCARD, -1, null, -1)))
+ Import(Ident(cdef.name.toTermName), ImportSelector.wildList)
}
// Importing the companion object members cannot be done uncritically: see
@@ -841,7 +841,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners {
val predefs = List(
DefDef(
Modifiers(Flags.JAVA | Flags.STATIC), nme.values, List(),
- List(List()),
+ ListOfNil,
arrayOf(enumType),
blankExpr),
DefDef(
diff --git a/src/compiler/scala/tools/nsc/package.scala b/src/compiler/scala/tools/nsc/package.scala
index 9ad0d9ba1f..9d593e5acc 100644
--- a/src/compiler/scala/tools/nsc/package.scala
+++ b/src/compiler/scala/tools/nsc/package.scala
@@ -14,4 +14,6 @@ package object nsc {
type MissingRequirementError = scala.reflect.internal.MissingRequirementError
val MissingRequirementError = scala.reflect.internal.MissingRequirementError
+
+ val ListOfNil = List(Nil)
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 213a995e96..8e77f8b6f4 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -250,7 +250,7 @@ abstract class SymbolLoaders {
protected def description = "class file "+ classfile.toString
protected def doComplete(root: Symbol) {
- val start = Statistics.startTimer(classReadNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(classReadNanos) else null
classfileParser.parse(classfile, root)
if (root.associatedFile eq null) {
root match {
@@ -262,7 +262,7 @@ abstract class SymbolLoaders {
debuglog("Not setting associatedFile to %s because %s is a %s".format(classfile, root.name, root.shortSymbolClass))
}
}
- Statistics.stopTimer(classReadNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(classReadNanos, start)
}
override def sourcefile: Option[AbstractFile] = classfileParser.srcfile
}
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index 436867257a..570704f049 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -50,14 +50,14 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
private def transformTemplate(tree: Tree) = {
val t @ Template(parents, self, body) = tree
clearStatics()
-
+
val newBody = transformTrees(body)
val templ = deriveTemplate(tree)(_ => transformTrees(newStaticMembers.toList) ::: newBody)
try addStaticInits(templ) // postprocess to include static ctors
finally clearStatics()
}
private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix)
-
+
//private val classConstantMeth = new HashMap[String, Symbol]
//private val symbolStaticFields = new HashMap[String, (Symbol, Tree, Tree)]
@@ -91,40 +91,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
*/
def toBoxedType(tp: Type) = if (isJavaValueType(tp)) boxedClass(tp.typeSymbol).tpe else tp
- override def transform(tree: Tree): Tree = tree match {
-
- /* Transforms dynamic calls (i.e. calls to methods that are undefined
- * in the erased type space) to -- dynamically -- unsafe calls using
- * reflection. This is used for structural sub-typing of refinement
- * types, but may be used for other dynamic calls in the future.
- * For 'a.f(b)' it will generate something like:
- * 'a.getClass().
- * ' getMethod("f", Array(classOf[b.type])).
- * ' invoke(a, Array(b))
- * plus all the necessary casting/boxing/etc. machinery required
- * for type-compatibility (see fixResult).
- *
- * USAGE CONTRACT:
- * There are a number of assumptions made on the way a dynamic apply
- * is used. Assumptions relative to type are handled by the erasure
- * phase.
- * - The applied arguments are compatible with AnyRef, which means
- * that an argument tree typed as AnyVal has already been extended
- * with the necessary boxing calls. This implies that passed
- * arguments might not be strictly compatible with the method's
- * parameter types (a boxed integer while int is expected).
- * - The expected return type is an AnyRef, even when the method's
- * return type is an AnyVal. This means that the tree containing the
- * call has already been extended with the necessary unboxing calls
- * (or is happy with the boxed type).
- * - The type-checker has prevented dynamic applies on methods which
- * parameter's erased types are not statically known at the call site.
- * This is necessary to allow dispatching the call to the correct
- * method (dispatching on parameters is static in Scala). In practice,
- * this limitation only arises when the called method is defined as a
- * refinement, where the refinement defines a parameter based on a
- * type variable. */
- case ad@ApplyDynamic(qual0, params) =>
+ def transformApplyDynamic(ad: ApplyDynamic) = {
+ val qual0 = ad.qual
+ val params = ad.args
if (settings.logReflectiveCalls.value)
unit.echo(ad.pos, "method invocation uses reflection")
@@ -516,6 +485,44 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
transform(t)
}
/* ### END OF DYNAMIC APPLY TRANSFORM ### */
+ }
+
+ override def transform(tree: Tree): Tree = tree match {
+
+ /* Transforms dynamic calls (i.e. calls to methods that are undefined
+ * in the erased type space) to -- dynamically -- unsafe calls using
+ * reflection. This is used for structural sub-typing of refinement
+ * types, but may be used for other dynamic calls in the future.
+ * For 'a.f(b)' it will generate something like:
+ * 'a.getClass().
+ * ' getMethod("f", Array(classOf[b.type])).
+ * ' invoke(a, Array(b))
+ * plus all the necessary casting/boxing/etc. machinery required
+ * for type-compatibility (see fixResult).
+ *
+ * USAGE CONTRACT:
+ * There are a number of assumptions made on the way a dynamic apply
+ * is used. Assumptions relative to type are handled by the erasure
+ * phase.
+ * - The applied arguments are compatible with AnyRef, which means
+ * that an argument tree typed as AnyVal has already been extended
+ * with the necessary boxing calls. This implies that passed
+ * arguments might not be strictly compatible with the method's
+ * parameter types (a boxed integer while int is expected).
+ * - The expected return type is an AnyRef, even when the method's
+ * return type is an AnyVal. This means that the tree containing the
+ * call has already been extended with the necessary unboxing calls
+ * (or is happy with the boxed type).
+ * - The type-checker has prevented dynamic applies on methods which
+ * parameter's erased types are not statically known at the call site.
+ * This is necessary to allow dispatching the call to the correct
+ * method (dispatching on parameters is static in Scala). In practice,
+ * this limitation only arises when the called method is defined as a
+ * refinement, where the refinement defines a parameter based on a
+ * type variable. */
+
+ case tree: ApplyDynamic =>
+ transformApplyDynamic(tree)
/* Some cleanup transformations add members to templates (classes, traits, etc).
* When inside a template (i.e. the body of one of its members), two maps
@@ -542,12 +549,13 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
else tree
}
-
+
case ValDef(mods, name, tpt, rhs) if tree.symbol.hasStaticAnnotation =>
+ def transformStaticValDef = {
log("moving @static valdef field: " + name + ", in: " + tree.symbol.owner)
val sym = tree.symbol
val owner = sym.owner
-
+
val staticBeforeLifting = atPhase(currentRun.erasurePhase) { owner.isStatic }
val isPrivate = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PRIVATE) }
val isProtected = atPhase(currentRun.typerPhase) { sym.getter(owner).hasFlag(PROTECTED) }
@@ -574,19 +582,19 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val compclass = enclosing.newClass(newTypeName(owner.name.toString))
compclass setInfo ClassInfoType(List(ObjectClass.tpe), newScope, compclass)
enclosing.info.decls enter compclass
-
- val compclstree = ClassDef(compclass, NoMods, List(List()), List(List()), List(), tree.pos)
-
+
+ val compclstree = ClassDef(compclass, NoMods, ListOfNil, ListOfNil, List(), tree.pos)
+
syntheticClasses.getOrElseUpdate(enclosing, mutable.Set()) += compclstree
-
+
compclass
case comp => comp
}
-
+
// create a static field in the companion class for this @static field
val stfieldSym = linkedClass.newVariable(newTermName(name), tree.pos, STATIC | SYNTHETIC | FINAL) setInfo sym.tpe
stfieldSym.addAnnotation(StaticClass)
-
+
val names = classNames.getOrElseUpdate(linkedClass, linkedClass.info.decls.collect {
case sym if sym.name.isTermName => sym.name
} toSet)
@@ -597,9 +605,9 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
)
} else {
linkedClass.info.decls enter stfieldSym
-
+
val initializerBody = rhs
-
+
// static field was previously initialized in the companion object itself, like this:
// staticBodies((linkedClass, stfieldSym)) = Select(This(owner), sym.getter(owner))
// instead, we move the initializer to the static ctor of the companion class
@@ -608,12 +616,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
}
}
super.transform(tree)
-
+ }
+ transformStaticValDef
+
/* MSIL requires that the stack is empty at the end of a try-block.
* Hence, we here rewrite all try blocks with a result != {Unit, All} such that they
* store their result in a local variable. The catch blocks are adjusted as well.
* The try tree is subsituted by a block whose result expression is read of that variable. */
case theTry @ Try(block, catches, finalizer) if shouldRewriteTry(theTry) =>
+ def transformTry = {
val tpe = theTry.tpe.widen
val tempVar = currentOwner.newVariable(mkTerm(nme.EXCEPTION_RESULT_PREFIX), theTry.pos).setInfo(tpe)
def assignBlock(rhs: Tree) = super.transform(BLOCK(Ident(tempVar) === transform(rhs)))
@@ -624,7 +635,8 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val newTry = Try(newBlock, newCatches, super.transform(finalizer))
typedWithPos(theTry.pos)(BLOCK(VAL(tempVar) === EmptyTree, newTry, Ident(tempVar)))
-
+ }
+ transformTry
/*
* This transformation should identify Scala symbol invocations in the tree and replace them
* with references to a static member. Also, whenever a class has at least a single symbol invocation
@@ -657,12 +669,15 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
* have little in common.
*/
case Apply(fn, (arg @ Literal(Constant(symname: String))) :: Nil) if fn.symbol == Symbol_apply =>
+ def transformApply = {
// add the symbol name to a map if it's not there already
val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil)
val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree)
// create a reference to a static field
val ntree = typedWithPos(tree.pos)(REF(staticFieldSym))
super.transform(ntree)
+ }
+ transformApply
// This transform replaces Array(Predef.wrapArray(Array(...)), <tag>)
// with just Array(...)
@@ -722,7 +737,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
case Block(stats, expr) => stats :+ expr
case t => List(t)
}
-
+
val newCtor = findStaticCtor(template) match {
// in case there already were static ctors - augment existing ones
// currently, however, static ctors aren't being generated anywhere else
@@ -746,7 +761,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
deriveTemplate(template)(newCtor :: _)
}
}
-
+
private def addStaticDeclarations(tree: Template, clazz: Symbol) {
// add static field initializer statements for each static field in clazz
if (!clazz.isModuleClass) for {
@@ -757,22 +772,23 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val valdef = staticBodies((clazz, stfieldSym))
val ValDef(_, _, _, rhs) = valdef
val fixedrhs = rhs.changeOwner((valdef.symbol, clazz.info.decl(nme.CONSTRUCTOR)))
-
+
val stfieldDef = localTyper.typedPos(tree.pos)(VAL(stfieldSym) === EmptyTree)
val flattenedInit = fixedrhs match {
case Block(stats, expr) => Block(stats, REF(stfieldSym) === expr)
case rhs => REF(stfieldSym) === rhs
}
val stfieldInit = localTyper.typedPos(tree.pos)(flattenedInit)
-
+
// add field definition to new defs
newStaticMembers append stfieldDef
newStaticInits append stfieldInit
+ case _ => // ignore @static on other members
}
}
-
-
-
+
+
+
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
super.transformStats(stats, exprOwner) ++ {
// flush pending synthetic classes created in this owner
@@ -785,22 +801,22 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
case clsdef @ ClassDef(mods, name, tparams, t @ Template(parent, self, body)) =>
// process all classes in the package again to add static initializers
clearStatics()
-
+
addStaticDeclarations(t, clsdef.symbol)
-
+
val templ = deriveTemplate(t)(_ => transformTrees(newStaticMembers.toList) ::: body)
val ntempl =
try addStaticInits(templ)
finally clearStatics()
-
+
val derived = deriveClassDef(clsdef)(_ => ntempl)
classNames.remove(clsdef.symbol)
derived
-
+
case stat => stat
}
}
-
+
} // CleanUpTransformer
}
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index f2f4a44b02..afc109c47a 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -506,14 +506,14 @@ abstract class Constructors extends Transform with ast.TreeDSL {
val applyMethodDef = DefDef(
sym = applyMethod,
- vparamss = List(List()),
+ vparamss = ListOfNil,
rhs = Block(applyMethodStats, gen.mkAttributedRef(BoxedUnit_UNIT)))
ClassDef(
sym = closureClass,
constrMods = Modifiers(0),
vparamss = List(List(outerFieldDef)),
- argss = List(List()),
+ argss = ListOfNil,
body = List(applyMethodDef),
superPos = impl.pos)
}
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index eb3c965d7f..d97fbf5daa 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -271,8 +271,11 @@ abstract class Erasure extends AddInterfaces
poly + jsig(restpe)
case MethodType(params, restpe) =>
- "("+(params map (_.tpe) map (jsig(_))).mkString+")"+
- (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
+ val buf = new StringBuffer("(")
+ params foreach (p => buf append jsig(p.tpe))
+ buf append ")"
+ buf append (if (restpe.typeSymbol == UnitClass || sym0.isConstructor) VOID_TAG.toString else jsig(restpe))
+ buf.toString
case RefinedType(parent :: _, decls) =>
boxedSig(parent)
@@ -485,7 +488,7 @@ abstract class Erasure extends AddInterfaces
private def isPrimitiveValueMember(sym: Symbol) =
sym != NoSymbol && isPrimitiveValueClass(sym.owner)
- private def box(tree: Tree, target: => String): Tree = {
+ @inline private def box(tree: Tree, target: => String): Tree = {
val result = box1(tree)
log("boxing "+tree+":"+tree.tpe+" to "+target+" = "+result+":"+result.tpe)
result
@@ -928,152 +931,175 @@ abstract class Erasure extends AddInterfaces
* - Reset all other type attributes to null, thus enforcing a retyping.
*/
private val preTransformer = new TypingTransformer(unit) {
- def preErase(tree: Tree): Tree = tree match {
- case ClassDef(_,_,_,_) =>
- debuglog("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
- copyClassDef(tree)(tparams = Nil)
- case DefDef(_,_,_,_,_,_) =>
- copyDefDef(tree)(tparams = Nil)
- case TypeDef(_, _, _, _) =>
- EmptyTree
- case Apply(instanceOf @ TypeApply(fun @ Select(qual, name), args @ List(arg)), List()) // !!! todo: simplify by having GenericArray also extract trees
- if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
- unboundedGenericArrayLevel(arg.tpe) > 0) =>
- val level = unboundedGenericArrayLevel(arg.tpe)
- def isArrayTest(arg: Tree) =
- gen.mkRuntimeCall(nme.isArray, List(arg, Literal(Constant(level))))
-
- global.typer.typedPos(tree.pos) {
- if (level == 1) isArrayTest(qual)
- else gen.evalOnce(qual, currentOwner, unit) { qual1 =>
- gen.mkAnd(
- gen.mkMethodCall(
- qual1(),
- fun.symbol,
- List(specialErasure(fun.symbol)(arg.tpe)),
- Nil
- ),
- isArrayTest(qual1())
- )
- }
+
+ private def preEraseNormalApply(tree: Apply) = {
+ val fn = tree.fun
+ val args = tree.args
+
+ def qualifier = fn match {
+ case Select(qual, _) => qual
+ case TypeApply(Select(qual, _), _) => qual
+ }
+
+ def preEraseAsInstanceOf = {
+ (fn: @unchecked) match {
+ case TypeApply(Select(qual, _), List(targ)) =>
+ if (qual.tpe <:< targ.tpe)
+ atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
+ else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
+ atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
+ else
+ tree
}
- case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
- fun.symbol != Object_asInstanceOf &&
- fun.symbol != Object_isInstanceOf) =>
- // leave all other type tests/type casts, remove all other type applications
- preErase(fun)
- case Apply(fn @ Select(qual, name), args) if fn.symbol.owner == ArrayClass =>
- // Have to also catch calls to abstract types which are bounded by Array.
- if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) {
- // convert calls to apply/update/length on generic arrays to
- // calls of ScalaRunTime.array_xxx method calls
- global.typer.typedPos(tree.pos)({
- val arrayMethodName = name match {
- case nme.apply => nme.array_apply
- case nme.length => nme.array_length
- case nme.update => nme.array_update
- case nme.clone_ => nme.array_clone
- case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
+ // todo: also handle the case where the singleton type is buried in a compound
+ }
+
+ def preEraseIsInstanceOf = {
+ fn match {
+ case TypeApply(sel @ Select(qual, name), List(targ)) =>
+ if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
+ unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
+
+ def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
+ Apply(
+ TypeApply(
+ Select(q(), Object_isInstanceOf) setPos sel.pos,
+ List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
+ List()) setPos tree.pos
+ targ.tpe match {
+ case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
+ val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
+ atPos(tree.pos) {
+ Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
+ }
+ case RefinedType(parents, decls) if (parents.length >= 2) =>
+ // Optimization: don't generate isInstanceOf tests if the static type
+ // conforms, because it always succeeds. (Or at least it had better.)
+ // At this writing the pattern matcher generates some instance tests
+ // involving intersections where at least one parent is statically known true.
+ // That needs fixing, but filtering the parents here adds an additional
+ // level of robustness (in addition to the short term fix.)
+ val parentTests = parents filterNot (qual.tpe <:< _)
+
+ if (parentTests.isEmpty) Literal(Constant(true))
+ else gen.evalOnce(qual, currentOwner, unit) { q =>
+ atPos(tree.pos) {
+ parentTests map mkIsInstanceOf(q) reduceRight gen.mkAnd
+ }
+ }
+ case _ =>
+ tree
}
- gen.mkRuntimeCall(arrayMethodName, qual :: args)
- })
+ case _ => tree
}
- else {
- // store exact array erasure in map to be retrieved later when we might
- // need to do the cast in adaptMember
- treeCopy.Apply(
- tree,
- SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
- args)
- }
- case Apply(fn @ Select(qual, _), Nil) if interceptedMethods(fn.symbol) =>
- if (fn.symbol == Any_## || fn.symbol == Object_##) {
- // This is unattractive, but without it we crash here on ().## because after
- // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
- // This must be because some earlier transformation is being skipped on ##, but so
- // far I don't know what. For null we now define null.## == 0.
- qual.tpe.typeSymbol match {
- case UnitClass | NullClass => LIT(0)
- case IntClass => qual
- case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
- case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
- case _ =>
- global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual)))
- }
- }
- // Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
- else if (isPrimitiveValueClass(qual.tpe.typeSymbol))
- global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
- else
- tree
+ }
+ if (fn.symbol == Any_asInstanceOf) {
+ preEraseAsInstanceOf
+ } else if (fn.symbol == Any_isInstanceOf) {
+ preEraseIsInstanceOf
+ } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
+ ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
+ } else if (fn.symbol.isMethodWithExtension) {
+ Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
+ } else {
+ tree
+ }
+ }
- case Apply(Select(New(tpt), nme.CONSTRUCTOR), List(arg)) if (tpt.tpe.typeSymbol.isDerivedValueClass) =>
-// println("inject derived: "+arg+" "+tpt.tpe)
- InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol
- new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef])
- case Apply(fn, args) =>
- def qualifier = fn match {
- case Select(qual, _) => qual
- case TypeApply(Select(qual, _), _) => qual
- }
- if (fn.symbol == Any_asInstanceOf)
- (fn: @unchecked) match {
- case TypeApply(Select(qual, _), List(targ)) =>
- if (qual.tpe <:< targ.tpe)
- atPos(tree.pos) { Typed(qual, TypeTree(targ.tpe)) }
- else if (isNumericValueClass(qual.tpe.typeSymbol) && isNumericValueClass(targ.tpe.typeSymbol))
- atPos(tree.pos)(numericConversion(qual, targ.tpe.typeSymbol))
- else
- tree
+ private def preEraseApply(tree: Apply) = {
+ tree.fun match {
+ case TypeApply(fun @ Select(qual, name), args @ List(arg))
+ if ((fun.symbol == Any_isInstanceOf || fun.symbol == Object_isInstanceOf) &&
+ unboundedGenericArrayLevel(arg.tpe) > 0) => // !!! todo: simplify by having GenericArray also extract trees
+ val level = unboundedGenericArrayLevel(arg.tpe)
+ def isArrayTest(arg: Tree) =
+ gen.mkRuntimeCall(nme.isArray, List(arg, Literal(Constant(level))))
+
+ global.typer.typedPos(tree.pos) {
+ if (level == 1) isArrayTest(qual)
+ else gen.evalOnce(qual, currentOwner, unit) { qual1 =>
+ gen.mkAnd(
+ gen.mkMethodCall(
+ qual1(),
+ fun.symbol,
+ List(specialErasure(fun.symbol)(arg.tpe)),
+ Nil
+ ),
+ isArrayTest(qual1())
+ )
+ }
}
- // todo: also handle the case where the singleton type is buried in a compound
- else if (fn.symbol == Any_isInstanceOf) {
- fn match {
- case TypeApply(sel @ Select(qual, name), List(targ)) =>
- if (qual.tpe != null && isPrimitiveValueClass(qual.tpe.typeSymbol) && targ.tpe != null && targ.tpe <:< AnyRefClass.tpe)
- unit.error(sel.pos, "isInstanceOf cannot test if value types are references.")
-
- def mkIsInstanceOf(q: () => Tree)(tp: Type): Tree =
- Apply(
- TypeApply(
- Select(q(), Object_isInstanceOf) setPos sel.pos,
- List(TypeTree(tp) setPos targ.pos)) setPos fn.pos,
- List()) setPos tree.pos
- targ.tpe match {
- case SingleType(_, _) | ThisType(_) | SuperType(_, _) =>
- val cmpOp = if (targ.tpe <:< AnyValClass.tpe) Any_equals else Object_eq
- atPos(tree.pos) {
- Apply(Select(qual, cmpOp), List(gen.mkAttributedQualifier(targ.tpe)))
- }
- case RefinedType(parents, decls) if (parents.length >= 2) =>
- // Optimization: don't generate isInstanceOf tests if the static type
- // conforms, because it always succeeds. (Or at least it had better.)
- // At this writing the pattern matcher generates some instance tests
- // involving intersections where at least one parent is statically known true.
- // That needs fixing, but filtering the parents here adds an additional
- // level of robustness (in addition to the short term fix.)
- val parentTests = parents filterNot (qual.tpe <:< _)
-
- if (parentTests.isEmpty) Literal(Constant(true))
- else gen.evalOnce(qual, currentOwner, unit) { q =>
- atPos(tree.pos) {
- parentTests map mkIsInstanceOf(q) reduceRight gen.mkAnd
- }
- }
- case _ =>
- tree
+ case fn @ Select(qual, name) =>
+ val args = tree.args
+ if (fn.symbol.owner == ArrayClass) {
+ // Have to also catch calls to abstract types which are bounded by Array.
+ if (unboundedGenericArrayLevel(qual.tpe.widen) == 1 || qual.tpe.typeSymbol.isAbstractType) {
+ // convert calls to apply/update/length on generic arrays to
+ // calls of ScalaRunTime.array_xxx method calls
+ global.typer.typedPos(tree.pos) {
+ val arrayMethodName = name match {
+ case nme.apply => nme.array_apply
+ case nme.length => nme.array_length
+ case nme.update => nme.array_update
+ case nme.clone_ => nme.array_clone
+ case _ => unit.error(tree.pos, "Unexpected array member, no translation exists.") ; nme.NO_NAME
+ }
+ gen.mkRuntimeCall(arrayMethodName, qual :: args)
}
- case _ => tree
- }
- } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) {
- ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos
- } else if (fn.symbol.isMethodWithExtension) {
- Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args)
- } else {
+ } else {
+ // store exact array erasure in map to be retrieved later when we might
+ // need to do the cast in adaptMember
+ treeCopy.Apply(
+ tree,
+ SelectFromArray(qual, name, erasure(tree.symbol)(qual.tpe)).copyAttrs(fn),
+ args)
+ }
+ } else if (args.isEmpty && interceptedMethods(fn.symbol)) {
+ if (fn.symbol == Any_## || fn.symbol == Object_##) {
+ // This is unattractive, but without it we crash here on ().## because after
+ // erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
+ // This must be because some earlier transformation is being skipped on ##, but so
+ // far I don't know what. For null we now define null.## == 0.
+ qual.tpe.typeSymbol match {
+ case UnitClass | NullClass => LIT(0)
+ case IntClass => qual
+ case s @ (ShortClass | ByteClass | CharClass) => numericConversion(qual, s)
+ case BooleanClass => If(qual, LIT(true.##), LIT(false.##))
+ case _ =>
+ global.typer.typed(gen.mkRuntimeCall(nme.hash_, List(qual)))
+ }
+ } else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
+ // Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
+ global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
+ } else {
tree
+ }
+ } else qual match {
+ case New(tpt) if name == nme.CONSTRUCTOR && tpt.tpe.typeSymbol.isDerivedValueClass =>
+ // println("inject derived: "+arg+" "+tpt.tpe)
+ val List(arg) = args
+ InjectDerivedValue(arg) addAttachment //@@@ setSymbol tpt.tpe.typeSymbol
+ new TypeRefAttachment(tree.tpe.asInstanceOf[TypeRef])
+ case _ =>
+ preEraseNormalApply(tree)
}
+ case _ =>
+ preEraseNormalApply(tree)
+ }
+ }
+
+ def preErase(tree: Tree): Tree = tree match {
+ case tree: Apply =>
+ preEraseApply(tree)
+
+ case TypeApply(fun, args) if (fun.symbol.owner != AnyClass &&
+ fun.symbol != Object_asInstanceOf &&
+ fun.symbol != Object_isInstanceOf) =>
+ // leave all other type tests/type casts, remove all other type applications
+ preErase(fun)
+
case Select(qual, name) =>
val owner = tree.symbol.owner
// println("preXform: "+ (tree, tree.symbol, tree.symbol.owner, tree.symbol.owner.isRefinementClass))
@@ -1120,6 +1146,14 @@ abstract class Erasure extends AddInterfaces
}
treeCopy.Literal(tree, Constant(erased))
+ case ClassDef(_,_,_,_) =>
+ debuglog("defs of " + tree.symbol + " = " + tree.symbol.info.decls)
+ copyClassDef(tree)(tparams = Nil)
+ case DefDef(_,_,_,_,_,_) =>
+ copyDefDef(tree)(tparams = Nil)
+ case TypeDef(_, _, _, _) =>
+ EmptyTree
+
case _ =>
tree
}
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index e8387c80f5..12e2433e0d 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -111,7 +111,7 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
var added = false
val stats =
for (stat <- body1) yield stat match {
- case Block(_, _) | Apply(_, _) | If(_, _, _) if !added =>
+ case Block(_, _) | Apply(_, _) | If(_, _, _) | Try(_, _, _) if !added =>
// Avoid adding bitmaps when they are fully overshadowed by those
// that are added inside loops
if (LocalLazyValFinder.find(stat)) {
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 3c828db7f3..79b24e826d 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -492,19 +492,19 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* fields count as fields defined by the class itself.
*/
private val fieldOffset = perRunCaches.newMap[Symbol, Int]()
-
+
private val bitmapKindForCategory = perRunCaches.newMap[Name, ClassSymbol]()
-
+
// ByteClass, IntClass, LongClass
private def bitmapKind(field: Symbol): ClassSymbol = bitmapKindForCategory(bitmapCategory(field))
-
+
private def flagsPerBitmap(field: Symbol): Int = bitmapKind(field) match {
case BooleanClass => 1
case ByteClass => 8
case IntClass => 32
case LongClass => 64
}
-
+
/** The first transform; called in a pre-order traversal at phase mixin
* (that is, every node is processed before its children).
@@ -718,7 +718,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val sym = clazz0.info.decl(bitmapName)
assert(!sym.isOverloaded, sym)
-
+
def createBitmap: Symbol = {
val bitmapKind = bitmapKindForCategory(category)
val sym = clazz0.newVariable(bitmapName, clazz0.pos) setInfo bitmapKind.tpe
@@ -732,7 +732,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
case BooleanClass => VAL(sym) === FALSE
case _ => VAL(sym) === ZERO
}
-
+
sym setFlag PrivateLocal
clazz0.info.decls.enter(sym)
addDef(clazz0.pos, init)
@@ -744,7 +744,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else
createBitmap
}
-
+
def maskForOffset(offset: Int, sym: Symbol, kind: ClassSymbol): Tree = {
def realOffset = offset % flagsPerBitmap(sym)
if (kind == LongClass ) LIT(1L << realOffset) else LIT(1 << realOffset)
@@ -755,9 +755,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val bmp = bitmapFor(clazz, offset, valSym)
def mask = maskForOffset(offset, valSym, kind)
def x = This(clazz) DOT bmp
- def newValue = if (kind == BooleanClass) TRUE else (x GEN_| (mask, kind))
+ def newValue = if (kind == BooleanClass) TRUE else (x GEN_| (mask, kind))
- x === newValue
+ x === newValue
}
/** Return an (untyped) tree of the form 'clazz.this.bitmapSym & mask (==|!=) 0', the
@@ -775,7 +775,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
else lhs GEN_!= (ZERO, kind)
}
}
-
+
def mkSlowPathDef(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
stats: List[Tree], retVal: Tree, attrThis: Tree, args: List[Tree]): Symbol = {
val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name), lzyVal.pos, PRIVATE)
@@ -791,14 +791,14 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
stats: List[Tree], retVal: Tree): Tree = {
mkFastPathBody(clazz, lzyVal, cond, syncBody, stats, retVal, gen.mkAttributedThis(clazz), List())
}
-
+
def mkFastPathBody(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
stats: List[Tree], retVal: Tree, attrThis: Tree, args: List[Tree]): Tree = {
val slowPathSym: Symbol = mkSlowPathDef(clazz, lzyVal, cond, syncBody, stats, retVal, attrThis, args)
If(cond, fn (This(clazz), slowPathSym, args.map(arg => Ident(arg.symbol)): _*), retVal)
}
-
-
+
+
/** Always copy the tree if we are going to perform sym substitution,
* otherwise we will side-effect on the tree that is used in the fast path
*/
@@ -807,7 +807,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
if (tree.hasSymbol && from.contains(tree.symbol))
super.transform(tree.duplicate)
else super.transform(tree.duplicate)
-
+
override def apply[T <: Tree](tree: T): T = if (from.isEmpty) tree else super.apply(tree)
}
@@ -827,8 +827,8 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* The result will be a tree of the form
* { if ((bitmap&n & MASK) == 0) this.l$compute()
* else l$
- *
- * ...
+ *
+ * ...
* def l$compute() = { synchronized(this) {
* if ((bitmap$n & MASK) == 0) {
* init // l$ = <rhs>
@@ -836,7 +836,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* }}
* l$
* }
- *
+ *
* ...
* this.f1 = null
* ... this.fn = null
@@ -846,7 +846,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
* For Int bitmap it is 32 and then 'n' in the above code is: (offset / 32),
* the MASK is (1 << (offset % 32)).
* If the class contains only a single lazy val then the bitmap is represented
- * as a Boolean and the condition checking is a simple bool test.
+ * as a Boolean and the condition checking is a simple bool test.
*/
def mkLazyDef(clazz: Symbol, lzyVal: Symbol, init: List[Tree], retVal: Tree, offset: Int): Tree = {
def nullify(sym: Symbol) = Select(This(clazz), sym.accessedOrSelf) === LIT(null)
@@ -878,7 +878,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
def mkCheckedAccessor(clazz: Symbol, retVal: Tree, offset: Int, pos: Position, fieldSym: Symbol): Tree = {
val sym = fieldSym.getter(fieldSym.owner)
val bitmapSym = bitmapFor(clazz, offset, sym)
- val kind = bitmapKind(sym)
+ val kind = bitmapKind(sym)
val mask = maskForOffset(offset, sym, kind)
val msg = "Uninitialized field: " + unit.source + ": " + pos.line
val result =
@@ -966,7 +966,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
stats flatMap {
case stat @ Assign(lhs @ Select(This(_), _), rhs) => stat :: checkedGetter(lhs)
// remove initialization for default values
- case Apply(lhs @ Select(Ident(self), _), List(EmptyTree)) if lhs.symbol.isSetter => Nil
+ case Apply(lhs @ Select(Ident(self), _), EmptyTree.asList) if lhs.symbol.isSetter => Nil
case stat => List(stat)
},
exprOwner
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index 049157dcf1..fc9e611d20 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -111,7 +111,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case TypeRef(_, GroupOfSpecializable, arg :: Nil) =>
arg.typeArgs map (_.typeSymbol)
case _ =>
- List(tp.typeSymbol)
+ tp.typeSymbol :: Nil
}
}
}
@@ -362,7 +362,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// creating each permutation of concrete types
def loop(ctypes: List[List[Type]]): List[List[Type]] = ctypes match {
case Nil => Nil
- case set :: Nil => set map (x => List(x))
+ case set :: Nil => set map (_ :: Nil)
case set :: sets => for (x <- set ; xs <- loop(sets)) yield x :: xs
}
// zip the keys with each permutation to create a TypeEnv.
@@ -424,7 +424,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case MethodType(argSyms, resTpe) => specializedTypeVars(resTpe :: argSyms.map(_.tpe))
case ExistentialType(_, res) => specializedTypeVars(res)
case AnnotatedType(_, tp, _) => specializedTypeVars(tp)
- case TypeBounds(lo, hi) => specializedTypeVars(List(lo, hi))
+ case TypeBounds(lo, hi) => specializedTypeVars(lo :: hi :: Nil)
case RefinedType(parents, _) => parents flatMap specializedTypeVars toSet
case _ => Set()
}
@@ -1399,6 +1399,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
curTree = tree
tree match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
+ def transformNew = {
debuglog("Attempting to specialize new %s(%s)".format(tpt, args.mkString(", ")))
val found = findSpec(tpt.tpe)
if (found.typeSymbol ne tpt.tpe.typeSymbol) {
@@ -1410,9 +1411,26 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
_ => super.transform(tree)
}
} else super.transform(tree)
+ }
+ transformNew
+
+ case Apply(sel @ Select(sup @ Super(qual, name), name1), args)
+ if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) =>
+ def transformSuperApply = {
+
+ def parents = sup.symbol.info.parents
+ debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents)
+
+ val res = localTyper.typed(
+ Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos)
+ debuglog("retyping call to super, from: " + symbol + " to " + res.symbol)
+ res
+ }
+ transformSuperApply
case TypeApply(sel @ Select(qual, name), targs)
if (!specializedTypeVars(symbol.info).isEmpty && name != nme.CONSTRUCTOR) =>
+ def transformTypeApply = {
debuglog("checking typeapp for rerouting: " + tree + " with sym.tpe: " + symbol.tpe + " tree.tpe: " + tree.tpe)
val qual1 = transform(qual)
// log(">>> TypeApply: " + tree + ", qual1: " + qual1)
@@ -1445,14 +1463,19 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// See pos/exponential-spec.scala - can't call transform on the whole tree again.
// super.transform(tree)
}
-
- case Select(Super(_, _), name) if illegalSpecializedInheritance(currentClass) =>
- val pos = tree.pos
- debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.")
- debuglog(pos.lineContent)
- tree
+ }
+ transformTypeApply
case Select(qual, name) =>
+ def transformSelect = {
+ qual match {
+ case _: Super if illegalSpecializedInheritance(currentClass) =>
+ val pos = tree.pos
+ debuglog(pos.source.file.name+":"+pos.line+": not specializing call to super inside illegal specialized inheritance class.")
+ debuglog(pos.lineContent)
+ tree
+ case _ =>
+
debuglog("specializing Select %s [tree.tpe: %s]".format(symbol.defString, tree.tpe))
//log("!!! select " + tree + " -> " + symbol.info + " specTypeVars: " + specializedTypeVars(symbol.info))
@@ -1488,6 +1511,9 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
case None =>
super.transform(tree)
}
+ }
+ }
+ transformSelect
case PackageDef(pid, stats) =>
tree.symbol.info // make sure specializations have been performed
@@ -1497,6 +1523,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
}
case Template(parents, self, body) =>
+ def transformTemplate = {
val specMembers = makeSpecializedMembers(tree.symbol.enclClass) ::: (implSpecClasses(body) map localTyper.typed)
if (!symbol.isPackageClass)
(new CollectMethodBodies)(tree)
@@ -1507,8 +1534,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ ,
self,
atOwner(currentOwner)(transformTrees(body ::: specMembers)))
+ }
+ transformTemplate
case ddef @ DefDef(_, _, _, vparamss, _, _) if info.isDefinedAt(symbol) =>
+ def transformDefDef = {
// log("--> method: " + ddef + " in " + ddef.symbol.owner + ", " + info(symbol))
def reportTypeError(body: =>Tree) = reportError(body)(_ => ddef)
@@ -1597,8 +1627,11 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
debuglog("abstract: " + targ)
localTyper.typed(deriveDefDef(tree)(rhs => rhs))
}
+ }
+ transformDefDef
case ValDef(_, _, _, _) if symbol.hasFlag(SPECIALIZED) && !symbol.isParamAccessor =>
+ def transformValDef = {
assert(body.isDefinedAt(symbol.alias), body)
val tree1 = deriveValDef(tree)(_ => body(symbol.alias).duplicate)
debuglog("now typing: " + tree1 + " in " + tree.symbol.owner.fullName)
@@ -1612,17 +1645,8 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
typeEnv(symbol.alias) ++ typeEnv(tree.symbol)
)
deriveValDef(newValDef)(transform)
-
- case Apply(sel @ Select(sup @ Super(qual, name), name1), args)
- if (sup.symbol.info.parents != beforePrevPhase(sup.symbol.info.parents)) =>
-
- def parents = sup.symbol.info.parents
- debuglog(tree + " parents changed from: " + beforePrevPhase(parents) + " to: " + parents)
-
- val res = localTyper.typed(
- Apply(Select(Super(qual, name) setPos sup.pos, name1) setPos sel.pos, transformTrees(args)) setPos tree.pos)
- debuglog("retyping call to super, from: " + symbol + " to " + res.symbol)
- res
+ }
+ transformValDef
case _ =>
super.transform(tree)
diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
index 9e681b321c..82e95523d9 100644
--- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
@@ -25,19 +25,14 @@ trait TypingTransformers {
protected var curTree: Tree = _
protected def typedPos(pos: Position)(tree: Tree) = localTyper typed { atPos(pos)(tree) }
- /** a typer for each enclosing class */
- val typers: mutable.Map[Symbol, analyzer.Typer] = new mutable.HashMap
-
- override def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
+ override final def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = {
val savedLocalTyper = localTyper
// println("transformer atOwner: " + owner + " isPackage? " + owner.isPackage)
localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner)
- typers += Pair(owner, localTyper)
val result = super.atOwner(owner)(trans)
localTyper = savedLocalTyper
- typers -= owner
result
}
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index e98bf519fe..181463657b 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -35,8 +35,8 @@ import language.postfixOps
* - convert non-local returns to throws with enclosing try statements.
* - convert try-catch expressions in contexts where there might be values on the stack to
* a local method and a call to it (since an exception empties the evaluation stack):
- *
- * meth(x_1,..., try { x_i } catch { ..}, .. x_b0) ==>
+ *
+ * meth(x_1,..., try { x_i } catch { ..}, .. x_b0) ==>
* {
* def liftedTry$1 = try { x_i } catch { .. }
* meth(x_1, .., liftedTry$1(), .. )
@@ -271,7 +271,7 @@ abstract class UnCurry extends InfoTransform
localTyper.typedPos(fun.pos) {
Block(
- List(ClassDef(anonClass, NoMods, List(List()), List(List()), List(applyMethodDef), fun.pos)),
+ List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
}
@@ -396,7 +396,7 @@ abstract class UnCurry extends InfoTransform
localTyper.typedPos(fun.pos) {
Block(
- List(ClassDef(anonClass, NoMods, List(List()), List(List()), List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)),
+ List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)),
Typed(New(anonClass.tpe), TypeTree(fun.tpe)))
}
}
@@ -558,7 +558,7 @@ abstract class UnCurry extends InfoTransform
sym.setInfo(MethodType(List(), tree.tpe))
tree.changeOwner(currentOwner -> sym)
localTyper.typedPos(tree.pos)(Block(
- List(DefDef(sym, List(Nil), tree)),
+ List(DefDef(sym, ListOfNil, tree)),
Apply(Ident(sym), Nil)
))
}
@@ -641,7 +641,7 @@ abstract class UnCurry extends InfoTransform
case ret @ Return(_) if (isNonLocalReturn(ret)) =>
withNeedLift(true) { super.transform(ret) }
- case Try(_, Nil, _) =>
+ case Try(_, Nil, _) =>
// try-finally does not need lifting: lifting is needed only for try-catch
// expressions that are evaluated in a context where the stack might not be empty.
// `finally` does not attempt to continue evaluation after an exception, so the fact
@@ -693,6 +693,46 @@ abstract class UnCurry extends InfoTransform
else
tree
}
+
+ def isThrowable(pat: Tree): Boolean = pat match {
+ case Typed(Ident(nme.WILDCARD), tpt) =>
+ tpt.tpe =:= ThrowableClass.tpe
+ case Bind(_, pat) =>
+ isThrowable(pat)
+ case _ =>
+ false
+ }
+
+ def isDefaultCatch(cdef: CaseDef) = isThrowable(cdef.pat) && cdef.guard.isEmpty
+
+ def postTransformTry(tree: Try) = {
+ val body = tree.block
+ val catches = tree.catches
+ val finalizer = tree.finalizer
+ if (opt.virtPatmat) {
+ if (catches exists (cd => !treeInfo.isCatchCase(cd)))
+ debugwarn("VPM BUG! illegal try/catch " + catches)
+ tree
+ } else if (catches forall treeInfo.isCatchCase) {
+ tree
+ } else {
+ val exname = unit.freshTermName("ex$")
+ val cases =
+ if ((catches exists treeInfo.isDefaultCase) || isDefaultCatch(catches.last)) catches
+ else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
+ val catchall =
+ atPos(tree.pos) {
+ CaseDef(
+ Bind(exname, Ident(nme.WILDCARD)),
+ EmptyTree,
+ Match(Ident(exname), cases))
+ }
+ debuglog("rewrote try: " + catches + " ==> " + catchall);
+ val catches1 = localTyper.typedCases(
+ List(catchall), ThrowableClass.tpe, WildcardType)
+ treeCopy.Try(tree, body, catches1, finalizer)
+ }
+ }
tree match {
/* Some uncurry post transformations add members to templates.
@@ -711,8 +751,12 @@ abstract class UnCurry extends InfoTransform
}
case dd @ DefDef(_, _, _, vparamss0, _, rhs0) =>
+ val vparamss1 = vparamss0 match {
+ case _ :: Nil => vparamss0
+ case _ => vparamss0.flatten :: Nil
+ }
val flatdd = copyDefDef(dd)(
- vparamss = List(vparamss0.flatten),
+ vparamss = vparamss1,
rhs = nonLocalReturnKeys get dd.symbol match {
case Some(k) => atPos(rhs0.pos)(nonLocalReturnTry(rhs0, k, dd.symbol))
case None => rhs0
@@ -720,35 +764,12 @@ abstract class UnCurry extends InfoTransform
)
addJavaVarargsForwarders(dd, flatdd)
- case Try(body, catches, finalizer) =>
- if (opt.virtPatmat) { if(catches exists (cd => !treeInfo.isCatchCase(cd))) debugwarn("VPM BUG! illegal try/catch "+ catches); tree }
- else if (catches forall treeInfo.isCatchCase) tree
- else {
- val exname = unit.freshTermName("ex$")
- val cases =
- if ((catches exists treeInfo.isDefaultCase) || (catches.last match { // bq: handle try { } catch { ... case ex:Throwable => ...}
- case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
- true
- case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) if (tpt.tpe =:= ThrowableClass.tpe) =>
- true
- case _ =>
- false
- })) catches
- else catches :+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Throw(Ident(exname)))
- val catchall =
- atPos(tree.pos) {
- CaseDef(
- Bind(exname, Ident(nme.WILDCARD)),
- EmptyTree,
- Match(Ident(exname), cases))
- }
- debuglog("rewrote try: " + catches + " ==> " + catchall);
- val catches1 = localTyper.typedCases(
- List(catchall), ThrowableClass.tpe, WildcardType)
- treeCopy.Try(tree, body, catches1, finalizer)
- }
+ case tree: Try =>
+ postTransformTry(tree)
+
case Apply(Apply(fn, args), args1) =>
treeCopy.Apply(tree, fn, args ::: args1)
+
case Ident(name) =>
assert(name != tpnme.WILDCARD_STAR, tree)
applyUnary()
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 7f4f61bf80..ab8836f339 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -85,13 +85,13 @@ trait Analyzer extends AnyRef
// compiler run). This is good enough for the resident compiler, which was the most affected.
undoLog.clear()
override def run() {
- val start = Statistics.startTimer(typerNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(typerNanos) else null
global.echoPhaseSummary(this)
currentRun.units foreach applyPhase
undoLog.clear()
// need to clear it after as well or 10K+ accumulated entries are
// uncollectable the rest of the way.
- Statistics.stopTimer(typerNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(typerNanos, start)
}
def apply(unit: CompilationUnit) {
try {
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index c7728ce389..773d9a6f50 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -8,12 +8,19 @@ package typechecker
import scala.collection.{ mutable, immutable }
import scala.reflect.internal.util.StringOps.{ countElementsAsString, countAsString }
-import symtab.Flags.{ PRIVATE, PROTECTED }
+import symtab.Flags.{ PRIVATE, PROTECTED, IS_ERROR }
+import scala.compat.Platform.EOL
+import scala.reflect.runtime.ReflectionUtils
+import scala.reflect.macros.runtime.AbortMacroException
+import scala.util.control.NonFatal
+import scala.tools.nsc.util.stackTraceString
trait ContextErrors {
self: Analyzer =>
import global._
+ import definitions._
+ import treeInfo._
object ErrorKinds extends Enumeration {
type ErrorKind = Value
@@ -320,16 +327,6 @@ trait ContextErrors {
setError(tree)
}
- def MacroEtaError(tree: Tree) = {
- issueNormalTypeError(tree, "macros cannot be eta-expanded")
- setError(tree)
- }
-
- def MacroPartialApplicationError(tree: Tree) = {
- issueNormalTypeError(tree, "macros cannot be partially applied")
- setError(tree)
- }
-
//typedReturn
def ReturnOutsideOfDefError(tree: Tree) = {
issueNormalTypeError(tree, "return outside method definition")
@@ -427,8 +424,11 @@ trait ContextErrors {
def AbstractionFromVolatileTypeError(vd: ValDef) =
issueNormalTypeError(vd, "illegal abstraction from value with volatile type "+vd.symbol.tpe)
+ private[ContextErrors] def TypedApplyWrongNumberOfTpeParametersErrorMessage(fun: Tree) =
+ "wrong number of type parameters for "+treeSymTypeMsg(fun)
+
def TypedApplyWrongNumberOfTpeParametersError(tree: Tree, fun: Tree) = {
- issueNormalTypeError(tree, "wrong number of type parameters for "+treeSymTypeMsg(fun))
+ issueNormalTypeError(tree, TypedApplyWrongNumberOfTpeParametersErrorMessage(fun))
setError(tree)
}
@@ -625,11 +625,111 @@ trait ContextErrors {
}
// cyclic errors
- def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) =
- issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0))
+ def CyclicAliasingOrSubtypingError(errPos: Position, sym0: Symbol) =
+ issueTypeError(PosAndMsgTypeError(errPos, "cyclic aliasing or subtyping involving "+sym0))
+
+ def CyclicReferenceError(errPos: Position, lockedSym: Symbol) =
+ issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym))
+
+ // macro-related errors (also see MacroErrors below)
+
+ def MacroEtaError(tree: Tree) = {
+ issueNormalTypeError(tree, "macros cannot be eta-expanded")
+ setError(tree)
+ }
+
+ // same reason as for MacroBodyTypecheckException
+ case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable
+
+ private def macroExpansionError(expandee: Tree, msg: String = null, pos: Position = NoPosition) = {
+ def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg
+ macroLogLite("macro expansion has failed: %s".format(msgForLog))
+ val errorPos = if (pos != NoPosition) pos else (if (expandee.pos != NoPosition) expandee.pos else enclosingMacroPosition)
+ if (msg != null) context.error(pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions
+ setError(expandee)
+ throw MacroExpansionException
+ }
+
+ def MacroPartialApplicationError(expandee: Tree) = {
+ // macroExpansionError won't work => swallows positions, hence needed to do issueTypeError
+ // kinda contradictory to the comment in `macroExpansionError`, but this is how it works
+ issueNormalTypeError(expandee, "macros cannot be partially applied")
+ setError(expandee)
+ throw MacroExpansionException
+ }
+
+ def MacroGeneratedAbort(expandee: Tree, ex: AbortMacroException) = {
+ // errors have been reported by the macro itself, so we do nothing here
+ macroLogVerbose("macro expansion has been aborted")
+ macroExpansionError(expandee, ex.msg, ex.pos)
+ }
- def CyclicReferenceError(errPos: Position, lockedSym: Symbol) =
- issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym))
+ def MacroGeneratedTypeError(expandee: Tree, err: TypeError = null) =
+ if (err == null) {
+ // errors have been reported by the macro itself, so we do nothing here
+ macroExpansionError(expandee, null)
+ } else {
+ macroLogLite("macro expansion has failed: %s at %s".format(err.msg, err.pos))
+ throw err // this error must be propagated, don't report
+ }
+
+ def MacroGeneratedException(expandee: Tree, ex: Throwable) = {
+ val realex = ReflectionUtils.unwrapThrowable(ex)
+ val message = {
+ try {
+ // [Eugene] is there a better way?
+ // [Paul] See Exceptional.scala and Origins.scala.
+ val relevancyThreshold = realex.getStackTrace().indexWhere(_.getMethodName endsWith "macroExpand1")
+ if (relevancyThreshold == -1) None
+ else {
+ var relevantElements = realex.getStackTrace().take(relevancyThreshold + 1)
+ def isMacroInvoker(este: StackTraceElement) = este.isNativeMethod || (este.getClassName != null && (este.getClassName contains "fastTrack"))
+ var threshold = relevantElements.reverse.indexWhere(isMacroInvoker) + 1
+ while (threshold != relevantElements.length && isMacroInvoker(relevantElements(relevantElements.length - threshold - 1))) threshold += 1
+ relevantElements = relevantElements dropRight threshold
+
+ realex.setStackTrace(relevantElements)
+ Some(EOL + stackTraceString(realex))
+ }
+ } catch {
+ // if the magic above goes boom, just fall back to uninformative, but better than nothing, getMessage
+ case NonFatal(ex) =>
+ macroLogVerbose("got an exception when processing a macro generated exception\n" +
+ "offender = " + stackTraceString(realex) + "\n" +
+ "error = " + stackTraceString(ex))
+ None
+ }
+ } getOrElse {
+ val msg = realex.getMessage
+ if (msg != null) msg else realex.getClass.getName
+ }
+ macroExpansionError(expandee, "exception during macro expansion: " + message)
+ }
+
+ def MacroFreeSymbolError(expandee: Tree, sym: FreeSymbol) = {
+ def template(kind: String) = (
+ s"Macro expansion contains free $kind variable %s. Have you forgotten to use %s? "
+ + s"If you have troubles tracking free $kind variables, consider using -Xlog-free-${kind}s"
+ )
+ val forgotten = (
+ if (sym.isTerm) "splice when splicing this variable into a reifee"
+ else "c.AbsTypeTag annotation for this type parameter"
+ )
+ macroExpansionError(expandee, template(sym.name.nameKind).format(sym.name + " " + sym.origin, forgotten))
+ }
+
+ def MacroExpansionIsNotExprError(expandee: Tree, expanded: Any) =
+ macroExpansionError(expandee,
+ "macro must return a compiler-specific expr; returned value is " + (
+ if (expanded == null) "null"
+ else if (expanded.isInstanceOf[Expr[_]]) " Expr, but it doesn't belong to this compiler's universe"
+ else " of " + expanded.getClass
+ ))
+
+ def MacroImplementationNotFoundError(expandee: Tree) =
+ macroExpansionError(expandee,
+ "macro implementation not found: " + expandee.symbol.name + " " +
+ "(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)")
}
}
@@ -706,7 +806,7 @@ trait ContextErrors {
// side-effect on the tree, break the overloaded type cycle in infer
@inline
private def setErrorOnLastTry(lastTry: Boolean, tree: Tree) = if (lastTry) setError(tree)
-
+
def NoBestMethodAlternativeError(tree: Tree, argtpes: List[Type], pt: Type, lastTry: Boolean) = {
issueNormalTypeError(tree,
applyErrorMsg(tree, " cannot be applied to ", argtpes, pt))
@@ -719,7 +819,7 @@ trait ContextErrors {
def AmbiguousMethodAlternativeError(tree: Tree, pre: Type, best: Symbol,
firstCompeting: Symbol, argtpes: List[Type], pt: Type, lastTry: Boolean) = {
-
+
if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) {
val msg0 =
"argument types " + argtpes.mkString("(", ",", ")") +
@@ -729,7 +829,7 @@ trait ContextErrors {
setErrorOnLastTry(lastTry, tree)
} else setError(tree) // do not even try further attempts because they should all fail
// even if this is not the last attempt (because of the SO's possibility on the horizon)
-
+
}
def NoBestExprAlternativeError(tree: Tree, pt: Type, lastTry: Boolean) = {
@@ -753,21 +853,24 @@ trait ContextErrors {
kindErrors.toList.mkString("\n", ", ", ""))
}
- def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type],
- tparams: List[Symbol], kindErrors: List[String]) = {
- if (settings.explaintypes.value) {
+ private[ContextErrors] def NotWithinBoundsErrorMessage(prefix: String, targs: List[Type], tparams: List[Symbol], explaintypes: Boolean) = {
+ if (explaintypes) {
val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
(targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ))
(targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi))
()
}
- issueNormalTypeError(tree,
- prefix + "type arguments " + targs.mkString("[", ",", "]") +
- " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
- (tparams map (_.defString)).mkString("[", ",", "]"))
+ prefix + "type arguments " + targs.mkString("[", ",", "]") +
+ " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
+ (tparams map (_.defString)).mkString("[", ",", "]")
}
+ def NotWithinBounds(tree: Tree, prefix: String, targs: List[Type],
+ tparams: List[Symbol], kindErrors: List[String]) =
+ issueNormalTypeError(tree,
+ NotWithinBoundsErrorMessage(prefix, targs, tparams, settings.explaintypes.value))
+
//substExpr
def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) =
issueNormalTypeError(tree,
@@ -1061,7 +1164,7 @@ trait ContextErrors {
setError(arg)
} else arg
}
-
+
def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = {
val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+
"in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"."
@@ -1087,4 +1190,133 @@ trait ContextErrors {
setError(arg)
}
}
+
+ // using an exception here is actually a good idea
+ // because the lifespan of this exception is extremely small and controlled
+ // moreover exceptions let us avoid an avalanche of "if (!hasError) do stuff" checks
+ case object MacroBodyTypecheckException extends Exception with scala.util.control.ControlThrowable
+
+ trait MacroErrors {
+ self: MacroTyper =>
+
+ private implicit val context0 = typer.context
+ val context = typer.context
+
+ // helpers
+
+ private def lengthMsg(flavor: String, violation: String, extra: Symbol) = {
+ val noun = if (flavor == "value") "parameter" else "type parameter"
+ val message = noun + " lists have different length, " + violation + " extra " + noun
+ val suffix = if (extra ne NoSymbol) " " + extra.defString else ""
+ message + suffix
+ }
+
+ private def abbreviateCoreAliases(s: String): String = List("AbsTypeTag", "Expr").foldLeft(s)((res, x) => res.replace("c.universe." + x, "c." + x))
+
+ private def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = {
+ var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString
+ if (abbreviate) argsPart = abbreviateCoreAliases(argsPart)
+ var retPart = restpe.toString
+ if (abbreviate || macroDdef.tpt.tpe == null) retPart = abbreviateCoreAliases(retPart)
+ argsPart + ": " + retPart
+ }
+
+ // not exactly an error generator, but very related
+ // and I dearly wanted to push it away from Macros.scala
+ private def checkSubType(slot: String, rtpe: Type, atpe: Type) = {
+ val ok = if (macroDebugVerbose || settings.explaintypes.value) {
+ if (rtpe eq atpe) println(rtpe + " <: " + atpe + "?" + EOL + "true")
+ withTypesExplained(rtpe <:< atpe)
+ } else rtpe <:< atpe
+ if (!ok) {
+ compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, abbreviateCoreAliases(rtpe.toString), abbreviateCoreAliases(atpe.toString)))
+ }
+ }
+
+ // errors
+
+ private def fail() = {
+ // need to set the IS_ERROR flag to prohibit spurious expansions
+ if (macroDef != null) macroDef setFlag IS_ERROR
+ // not setting ErrorSymbol as in `infer.setError`, because we still need to know that it's a macro
+ // otherwise assignTypeToTree in Namers might fail if macroDdef.tpt == EmptyTree
+ macroDdef setType ErrorType
+ throw MacroBodyTypecheckException
+ }
+
+ private def genericError(tree: Tree, message: String) = {
+ issueNormalTypeError(tree, message)
+ fail()
+ }
+
+ private def implRefError(message: String) = genericError(methPart(macroDdef.rhs), message)
+
+ private def compatibilityError(message: String) =
+ implRefError(
+ "macro implementation has wrong shape:"+
+ "\n required: " + showMeth(rparamss, rret, abbreviate = true) +
+ "\n found : " + showMeth(aparamss, aret, abbreviate = false) +
+ "\n" + message)
+
+ // Phase I: sanity checks
+
+ def MacroDefIsFastTrack() = {
+ macroLogVerbose("typecheck terminated unexpectedly: macro is fast track")
+ assert(!macroDdef.tpt.isEmpty, "fast track macros must provide result type")
+ throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR
+ }
+
+ def MacroFeatureNotEnabled() = {
+ macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
+ fail()
+ }
+
+ // Phase II: typecheck the right-hand side of the macro def
+
+ // do nothing, just fail. relevant typecheck errors have already been reported
+ def MacroDefUntypeableBodyError() = fail()
+
+ def MacroDefInvalidBodyError() = genericError(macroDdef, "macro body has wrong shape:\n required: macro [<implementation object>].<method name>[[<type args>]]")
+
+ def MacroImplNotPublicError() = implRefError("macro implementation must be public")
+
+ def MacroImplOverloadedError() = implRefError("macro implementation cannot be overloaded")
+
+ def MacroImplWrongNumberOfTypeArgumentsError(macroImplRef: Tree) = implRefError(typer.TyperErrorGen.TypedApplyWrongNumberOfTpeParametersErrorMessage(macroImplRef))
+
+ def MacroImplNotStaticError() = implRefError("macro implementation must be in statically accessible object")
+
+ // Phase III: check compatibility between the macro def and its macro impl
+ // aXXX (e.g. aparams) => characteristics of the macro impl ("a" stands for "actual")
+ // rXXX (e.g. rparams) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference")
+
+ def MacroImplNonTagImplicitParameters(params: List[Symbol]) = compatibilityError("macro implementations cannot have implicit parameters other than AbsTypeTag evidences")
+
+ def MacroImplParamssMismatchError() = compatibilityError("number of parameter sections differ")
+
+ def MacroImplExtraParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(lengthMsg("value", "found", aparams(rparams.length)))
+
+ def MacroImplMissingParamsError(aparams: List[Symbol], rparams: List[Symbol]) = compatibilityError(abbreviateCoreAliases(lengthMsg("value", "required", rparams(aparams.length))))
+
+ def checkMacroImplParamTypeMismatch(atpe: Type, rparam: Symbol) = checkSubType("parameter " + rparam.name, rparam.tpe, atpe)
+
+ def checkMacroImplResultTypeMismatch(atpe: Type, rret: Type) = checkSubType("return type", atpe, rret)
+
+ def MacroImplParamNameMismatchError(aparam: Symbol, rparam: Symbol) = compatibilityError("parameter names differ: " + rparam.name + " != " + aparam.name)
+
+ def MacroImplVarargMismatchError(aparam: Symbol, rparam: Symbol) = {
+ if (isRepeated(rparam) && !isRepeated(aparam))
+ compatibilityError("types incompatible for parameter " + rparam.name + ": corresponding is not a vararg parameter")
+ if (!isRepeated(rparam) && isRepeated(aparam))
+ compatibilityError("types incompatible for parameter " + aparam.name + ": corresponding is not a vararg parameter")
+ }
+
+ def MacroImplTargMismatchError(atargs: List[Type], atparams: List[Symbol]) =
+ compatibilityError(typer.infer.InferErrorGen.NotWithinBoundsErrorMessage("", atargs, atparams, macroDebugVerbose || settings.explaintypes.value))
+
+ def MacroImplTparamInstantiationError(atparams: List[Symbol], ex: NoInstance) =
+ compatibilityError(
+ "type parameters "+(atparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+
+ ex.getMessage)
+ }
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index dd5588e9a6..6a908c6c65 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -27,6 +27,13 @@ trait Contexts { self: Analyzer =>
override def implicitss: List[List[ImplicitInfo]] = Nil
override def toString = "NoContext"
}
+ private object RootImports {
+ import definitions._
+ // Possible lists of root imports
+ val javaList = JavaLangPackage :: Nil
+ val javaAndScalaList = JavaLangPackage :: ScalaPackage :: Nil
+ val completeList = JavaLangPackage :: ScalaPackage :: PredefModule :: Nil
+ }
private val startContext = {
NoContext.make(
@@ -46,13 +53,12 @@ trait Contexts { self: Analyzer =>
* among its leading imports, or if the tree is [[scala.Predef]], `Predef` is not imported.
*/
protected def rootImports(unit: CompilationUnit): List[Symbol] = {
- import definitions._
- assert(isDefinitionsInitialized, "definitions uninitialized")
+ assert(definitions.isDefinitionsInitialized, "definitions uninitialized")
if (settings.noimports.value) Nil
- else if (unit.isJava) List(JavaLangPackage)
- else if (settings.nopredef.value || treeInfo.noPredefImportForUnit(unit.body)) List(JavaLangPackage, ScalaPackage)
- else List(JavaLangPackage, ScalaPackage, PredefModule)
+ else if (unit.isJava) RootImports.javaList
+ else if (settings.nopredef.value || treeInfo.noPredefImportForUnit(unit.body)) RootImports.javaAndScalaList
+ else RootImports.completeList
}
def rootContext(unit: CompilationUnit): Context = rootContext(unit, EmptyTree, false)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
index e590e7aa30..070f083a89 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Duplicators.scala
@@ -283,14 +283,15 @@ abstract class Duplicators extends Analyzer {
// the typer does not create the symbols for a LabelDef's params, so unless they were created before we need
// to do it manually here -- but for the tailcalls-generated labels, ValDefs are created before the LabelDef,
- // so we just need to plug in the name
+ // so we just need to change the tree to point to the updated symbols
def newParam(p: Tree): Ident =
if (isTailLabel)
- Ident(p.symbol.name) // let the typer pick up the right symbol
+ Ident(updateSym(p.symbol))
else {
val newsym = p.symbol.cloneSymbol //(context.owner) // TODO owner?
Ident(newsym.setInfo(fixType(p.symbol.info)))
}
+
val params1 = params map newParam
val rhs1 = (new TreeSubstituter(params map (_.symbol), params1) transform rhs) // TODO: duplicate?
rhs1.tpe = null
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index a34fc71b8f..226e17f605 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -72,10 +72,10 @@ trait Implicits {
)
indentTyping()
- val rawTypeStart = Statistics.startCounter(rawTypeImpl)
- val findMemberStart = Statistics.startCounter(findMemberImpl)
- val subtypeStart = Statistics.startCounter(subtypeImpl)
- val start = Statistics.startTimer(implicitNanos)
+ val rawTypeStart = if (Statistics.canEnable) Statistics.startCounter(rawTypeImpl) else null
+ val findMemberStart = if (Statistics.canEnable) Statistics.startCounter(findMemberImpl) else null
+ val subtypeStart = if (Statistics.canEnable) Statistics.startCounter(subtypeImpl) else null
+ val start = if (Statistics.canEnable) Statistics.startTimer(implicitNanos) else null
if (printInfers && !tree.isEmpty && !context.undetparams.isEmpty)
printTyping("typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
@@ -87,10 +87,10 @@ trait Implicits {
printInference("[infer implicit] inferred " + result)
context.undetparams = context.undetparams filterNot result.subst.from.contains
- Statistics.stopTimer(implicitNanos, start)
- Statistics.stopCounter(rawTypeImpl, rawTypeStart)
- Statistics.stopCounter(findMemberImpl, findMemberStart)
- Statistics.stopCounter(subtypeImpl, subtypeStart)
+ if (Statistics.canEnable) Statistics.stopTimer(implicitNanos, start)
+ if (Statistics.canEnable) Statistics.stopCounter(rawTypeImpl, rawTypeStart)
+ if (Statistics.canEnable) Statistics.stopCounter(findMemberImpl, findMemberStart)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeImpl, subtypeStart)
deindentTyping()
printTyping("Implicit search yielded: "+ result)
result
@@ -181,8 +181,8 @@ trait Implicits {
containsError(restpe)
case NullaryMethodType(restpe) =>
containsError(restpe)
- case MethodType(params, restpe) =>
- params.exists(_.tpe.isError) || containsError(restpe)
+ case mt @ MethodType(_, restpe) =>
+ (mt.paramTypes exists typeIsError) || containsError(restpe)
case _ =>
tp.isError
}
@@ -308,12 +308,12 @@ trait Implicits {
/** Is implicit info `info1` better than implicit info `info2`?
*/
def improves(info1: ImplicitInfo, info2: ImplicitInfo) = {
- Statistics.incCounter(improvesCount)
+ if (Statistics.canEnable) Statistics.incCounter(improvesCount)
(info2 == NoImplicitInfo) ||
(info1 != NoImplicitInfo) && {
if (info1.sym.isStatic && info2.sym.isStatic) {
improvesCache get (info1, info2) match {
- case Some(b) => Statistics.incCounter(improvesCachedCount); b
+ case Some(b) => if (Statistics.canEnable) Statistics.incCounter(improvesCachedCount); b
case None =>
val result = isStrictlyMoreSpecific(info1.tpe, info2.tpe, info1.sym, info2.sym)
improvesCache((info1, info2)) = result
@@ -377,7 +377,7 @@ trait Implicits {
overlaps(dtor1, dted1) && (dtor1 =:= dted1 || complexity(dtor1) > complexity(dted1))
}
- Statistics.incCounter(implicitSearchCount)
+ if (Statistics.canEnable) Statistics.incCounter(implicitSearchCount)
/** The type parameters to instantiate */
val undetParams = if (isView) List() else context.outer.undetparams
@@ -429,7 +429,7 @@ trait Implicits {
* This method is performance critical: 5-8% of typechecking time.
*/
private def matchesPt(tp: Type, pt: Type, undet: List[Symbol]): Boolean = {
- val start = Statistics.startTimer(matchesPtNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(matchesPtNanos) else null
val result = normSubType(tp, pt) || isView && {
pt match {
case TypeRef(_, Function1.Sym, args) =>
@@ -438,7 +438,7 @@ trait Implicits {
false
}
}
- Statistics.stopTimer(matchesPtNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(matchesPtNanos, start)
result
}
private def matchesPt(info: ImplicitInfo): Boolean = (
@@ -537,7 +537,7 @@ trait Implicits {
}
private def typedImplicit0(info: ImplicitInfo, ptChecked: Boolean, isLocal: Boolean): SearchResult = {
- Statistics.incCounter(plausiblyCompatibleImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(plausiblyCompatibleImplicits)
printTyping (
ptBlock("typedImplicit0",
"info.name" -> info.name,
@@ -557,7 +557,7 @@ trait Implicits {
}
private def typedImplicit1(info: ImplicitInfo, isLocal: Boolean): SearchResult = {
- Statistics.incCounter(matchingImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(matchingImplicits)
val itree = atPos(pos.focus) {
// workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
@@ -595,7 +595,7 @@ trait Implicits {
if (context.hasErrors)
return fail("typed implicit %s has errors".format(info.sym.fullLocationString))
- Statistics.incCounter(typedImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(typedImplicits)
printTyping("typed implicit %s:%s, pt=%s".format(itree1, itree1.tpe, wildPt))
val itree2 = if (isView) (itree1: @unchecked) match { case Apply(fun, _) => fun }
@@ -678,7 +678,7 @@ trait Implicits {
fail("typing TypeApply reported errors for the implicit tree")
else {
val result = new SearchResult(itree2, subst)
- Statistics.incCounter(foundImplicits)
+ if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
result
}
@@ -905,11 +905,11 @@ trait Implicits {
* @return map from infos to search results
*/
def applicableInfos(iss: Infoss, isLocal: Boolean): Map[ImplicitInfo, SearchResult] = {
- val start = Statistics.startCounter(subtypeAppInfos)
+ val start = if (Statistics.canEnable) Statistics.startCounter(subtypeAppInfos) else null
val computation = new ImplicitComputation(iss, isLocal) { }
val applicable = computation.findAll()
- Statistics.stopCounter(subtypeAppInfos, start)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeAppInfos, start)
applicable
}
@@ -1125,13 +1125,13 @@ trait Implicits {
* such that some part of `tp` has C as one of its superclasses.
*/
private def implicitsOfExpectedType: Infoss = {
- Statistics.incCounter(implicitCacheAccs)
+ if (Statistics.canEnable) Statistics.incCounter(implicitCacheAccs)
implicitsCache get pt match {
case Some(implicitInfoss) =>
- Statistics.incCounter(implicitCacheHits)
+ if (Statistics.canEnable) Statistics.incCounter(implicitCacheHits)
implicitInfoss
case None =>
- val start = Statistics.startTimer(subtypeETNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(subtypeETNanos) else null
// val implicitInfoss = companionImplicits(pt)
val implicitInfoss1 = companionImplicitMap(pt).valuesIterator.toList
// val is1 = implicitInfoss.flatten.toSet
@@ -1140,7 +1140,7 @@ trait Implicits {
// if (!(is2 contains i)) println("!!! implicit infos of "+pt+" differ, new does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
// for (i <- is2)
// if (!(is1 contains i)) println("!!! implicit infos of "+pt+" differ, old does not contain "+i+",\nold: "+implicitInfoss+",\nnew: "+implicitInfoss1)
- Statistics.stopTimer(subtypeETNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(subtypeETNanos, start)
implicitsCache(pt) = implicitInfoss1
if (implicitsCache.size >= sizeLimit)
implicitsCache -= implicitsCache.keysIterator.next
@@ -1372,21 +1372,21 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = Statistics.startTimer(inscopeFailNanos)
- val succstart = Statistics.startTimer(inscopeSucceedNanos)
+ val failstart = if (Statistics.canEnable) Statistics.startTimer(inscopeFailNanos) else null
+ val succstart = if (Statistics.canEnable) Statistics.startTimer(inscopeSucceedNanos) else null
var result = searchImplicit(context.implicitss, true)
if (result == SearchFailure) {
- Statistics.stopTimer(inscopeFailNanos, failstart)
+ if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart)
} else {
- Statistics.stopTimer(inscopeSucceedNanos, succstart)
- Statistics.incCounter(inscopeImplicitHits)
+ if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits)
}
if (result == SearchFailure) {
val previousErrs = context.flushAndReturnBuffer()
- val failstart = Statistics.startTimer(oftypeFailNanos)
- val succstart = Statistics.startTimer(oftypeSucceedNanos)
+ val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null
+ val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null
result = materializeImplicit(pt)
@@ -1396,10 +1396,10 @@ trait Implicits {
if (result == SearchFailure) {
context.updateBuffer(previousErrs)
- Statistics.stopTimer(oftypeFailNanos, failstart)
+ if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart)
} else {
- Statistics.stopTimer(oftypeSucceedNanos, succstart)
- Statistics.incCounter(oftypeImplicitHits)
+ if (Statistics.canEnable) Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index d724164715..28636fc76e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -240,8 +240,8 @@ trait Infer {
def normalize(tp: Type): Type = tp match {
case mt @ MethodType(params, restpe) if mt.isImplicit =>
normalize(restpe)
- case mt @ MethodType(params, restpe) if !restpe.isDependent =>
- functionType(params map (_.tpe), normalize(restpe))
+ case mt @ MethodType(_, restpe) if !mt.isDependentMethodType =>
+ functionType(mt.paramTypes, normalize(restpe))
case NullaryMethodType(restpe) =>
normalize(restpe)
case ExistentialType(tparams, qtpe) =>
@@ -661,7 +661,13 @@ trait Infer {
val restp1 = followApply(restp)
if (restp1 eq restp) tp else restp1
case _ =>
- val appmeth = tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val appmeth = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: tp.nonPrivateMember(nme.apply) filter (_.isPublic)
+ val result = tp.nonPrivateMember(nme.apply)
+ if ((result eq NoSymbol) || !result.isOverloaded && result.isPublic) result
+ else result filter (_.isPublic)
+ }
if (appmeth == NoSymbol) tp
else OverloadedType(tp, appmeth.alternatives)
}
@@ -747,8 +753,8 @@ trait Infer {
alts exists (alt => isApplicable(undetparams, pre.memberType(alt), argtpes0, pt))
case ExistentialType(tparams, qtpe) =>
isApplicable(undetparams, qtpe, argtpes0, pt)
- case MethodType(params, _) =>
- val formals = formalTypes(params map { _.tpe }, argtpes0.length, removeByName = false)
+ case mt @ MethodType(params, _) =>
+ val formals = formalTypes(mt.paramTypes, argtpes0.length, removeByName = false)
def tryTupleApply: Boolean = {
// if 1 formal, 1 argtpe (a tuple), otherwise unmodified argtpes0
@@ -854,8 +860,8 @@ trait Infer {
isAsSpecific(res, ftpe2)
case mt: MethodType if mt.isImplicit =>
isAsSpecific(ftpe1.resultType, ftpe2)
- case MethodType(params, _) if params.nonEmpty =>
- var argtpes = params map (_.tpe)
+ case mt @ MethodType(params, _) if params.nonEmpty =>
+ var argtpes = mt.paramTypes
if (isVarArgsList(params) && isVarArgsList(ftpe2.params))
argtpes = argtpes map (argtpe =>
if (isRepeatedParamType(argtpe)) argtpe.typeArgs.head else argtpe)
@@ -864,8 +870,8 @@ trait Infer {
isAsSpecific(PolyType(tparams, res), ftpe2)
case PolyType(tparams, mt: MethodType) if mt.isImplicit =>
isAsSpecific(PolyType(tparams, mt.resultType), ftpe2)
- case PolyType(_, MethodType(params, _)) if params.nonEmpty =>
- isApplicable(List(), ftpe2, params map (_.tpe), WildcardType)
+ case PolyType(_, (mt @ MethodType(params, _))) if params.nonEmpty =>
+ isApplicable(List(), ftpe2, mt.paramTypes, WildcardType)
// case NullaryMethodType(res) =>
// isAsSpecific(res, ftpe2)
case ErrorType =>
@@ -1111,10 +1117,10 @@ trait Infer {
*/
def inferMethodInstance(fn: Tree, undetparams: List[Symbol],
args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match {
- case MethodType(params0, _) =>
+ case mt @ MethodType(params0, _) =>
try {
val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
- val formals = formalTypes(params0 map (_.tpe), args.length)
+ val formals = formalTypes(mt.paramTypes, args.length)
val argtpes = actualTypes(args map (x => elimAnonymousClass(x.tpe.deconst)), formals.length)
val restpe = fn.tpe.resultType(argtpes)
@@ -1367,14 +1373,17 @@ trait Infer {
else =:=
)
(arg hasAnnotation UncheckedClass) || {
- val TypeRef(_, sym, args) = arg.withoutAnnotations
-
- ( isLocalBinding(sym)
- || arg.typeSymbol.isTypeParameterOrSkolem
- || (sym.name == tpnme.WILDCARD) // avoid spurious warnings on HK types
- || check(arg, param.tpe, conforms)
- || warn("non-variable type argument " + arg)
- )
+ arg.withoutAnnotations match {
+ case TypeRef(_, sym, args) =>
+ ( isLocalBinding(sym)
+ || arg.typeSymbol.isTypeParameterOrSkolem
+ || (sym.name == tpnme.WILDCARD) // avoid spurious warnings on HK types
+ || check(arg, param.tpeHK, conforms)
+ || warn("non-variable type argument " + arg)
+ )
+ case _ =>
+ warn("non-variable type argument " + arg)
+ }
}
}
@@ -1641,7 +1650,7 @@ trait Infer {
// for functional values, the `apply` method might be overloaded
val mtypes = followApply(alt.tpe) match {
case OverloadedType(_, alts) => alts map (_.tpe)
- case t => List(t)
+ case t => t :: Nil
}
// Drop those that use a default; keep those that use vararg/tupling conversion.
mtypes exists (t =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 4765bbabc9..01e773e528 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -12,6 +12,8 @@ import scala.reflect.macros.util._
import java.lang.{Class => jClass}
import java.lang.reflect.{Array => jArray, Method => jMethod}
import scala.reflect.internal.util.Collections._
+import scala.util.control.ControlThrowable
+import scala.reflect.macros.runtime.AbortMacroException
/**
* Code to deal with macros, namely with:
@@ -24,7 +26,7 @@ import scala.reflect.internal.util.Collections._
*
* Then fooBar needs to point to a static method of the following form:
*
- * def fooBar[T: c.AbsTypeTag]
+ * def fooBar[T: c.AbsTypeTag] // type tag annotation is optional
* (c: scala.reflect.macros.Context)
* (xs: c.Expr[List[T]])
* : c.Expr[T] = {
@@ -32,7 +34,7 @@ import scala.reflect.internal.util.Collections._
* }
*
* Then, if foo is called in qual.foo[Int](elems), where qual: D,
- * the macro application is expanded to a reflective invocation of fooBar with parameters
+ * the macro application is expanded to a reflective invocation of fooBar with parameters:
*
* (simpleMacroContext{ type PrefixType = D; val prefix = qual })
* (Expr(elems))
@@ -43,6 +45,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
import global._
import definitions._
+ import treeInfo.{isRepeatedParamType => _, _}
import MacrosStats._
def globalSettings = global.settings
@@ -212,11 +215,86 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
MacroImplBinding.unpickle(pickle)
}
+ /** Transforms parameters lists of a macro impl.
+ * The `transform` function is invoked only for AbsTypeTag evidence parameters.
+ *
+ * The transformer takes two arguments: a value parameter from the parameter list
+ * and a type parameter that is witnesses by the value parameter.
+ *
+ * If the transformer returns a NoSymbol, the value parameter is not included from the result.
+ * If the transformer returns something else, this something else is included in the result instead of the value parameter.
+ *
+ * Despite of being highly esoteric, this function significantly simplifies signature analysis.
+ * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence)
+ * or to streamline creation of the list of macro arguments.
+ */
+ private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = {
+ if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do
+ if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do
+ def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
+ case TypeRef(SingleType(SingleType(NoPrefix, c), universe), AbsTypeTagClass, targ :: Nil)
+ if c == paramss.head.head && universe == MacroContextUniverse =>
+ transform(param, targ.typeSymbol)
+ case _ =>
+ param
+ }
+ val transformed = paramss.last map transformTag filter (_ ne NoSymbol)
+ if (transformed.isEmpty) paramss.init else paramss.init :+ transformed
+ }
+
+ def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroImpl: Symbol): Type = {
+ // Step I. Transform c.Expr[T] to T
+ var runtimeType = macroImpl.tpe.finalResultType.dealias match {
+ case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType
+ case _ => AnyTpe // so that macro impls with rhs = ??? don't screw up our inference
+ }
+
+ // Step II. Transform type parameters of a macro implementation into type arguments in a macro definition's body
+ runtimeType = runtimeType.substituteTypes(macroImpl.typeParams, loadMacroImplBinding(macroDdef.symbol).targs.map(_.tpe))
+
+ // Step III. Transform c.prefix.value.XXX to this.XXX and implParam.value.YYY to defParam.YYY
+ def unsigma(tpe: Type): Type =
+ transformTypeTagEvidenceParams(macroImpl.paramss, (param, tparam) => NoSymbol) match {
+ case (implCtxParam :: Nil) :: implParamss =>
+ val implToDef = flatMap2(implParamss, macroDdef.vparamss)(map2(_, _)((_, _))).toMap
+ object UnsigmaTypeMap extends TypeMap {
+ def apply(tp: Type): Type = tp match {
+ case TypeRef(pre, sym, args) =>
+ val pre1 = pre match {
+ case SingleType(SingleType(SingleType(NoPrefix, c), prefix), value) if c == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
+ ThisType(macroDdef.symbol.owner)
+ case SingleType(SingleType(NoPrefix, implParam), value) if value == ExprValue =>
+ implToDef get implParam map (defParam => SingleType(NoPrefix, defParam.symbol)) getOrElse pre
+ case _ =>
+ pre
+ }
+ val args1 = args map mapOver
+ TypeRef(pre1, sym, args1)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
+ UnsigmaTypeMap(tpe)
+ case _ =>
+ tpe
+ }
+
+ unsigma(runtimeType)
+ }
+
/** A reference macro implementation signature compatible with a given macro definition.
*
- * In the example above:
+ * In the example above for the following macro def:
+ * def foo[T](xs: List[T]): T = macro fooBar
+ *
+ * This function will return:
* (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]]): c.Expr[T]
*
+ * Note that type tag evidence parameters are not included into the result.
+ * Type tag context bounds for macro impl tparams are optional.
+ * Therefore compatibility checks ignore such parameters, and we don't need to bother about them here.
+ *
* @param macroDef The macro definition symbol
* @param tparams The type parameters of the macro definition
* @param vparamss The value parameters of the macro definition
@@ -225,33 +303,22 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
private def macroImplSig(macroDef: Symbol, tparams: List[TypeDef], vparamss: List[List[ValDef]], retTpe: Type): (List[List[Symbol]], Type) = {
// had to move method's body to an object because of the recursive dependencies between sigma and param
object SigGenerator {
- val hasThis = macroDef.owner.isClass
- val ownerTpe = macroDef.owner match {
- case owner if owner.isModuleClass => new UniqueThisType(macroDef.owner)
- case owner if owner.isClass => macroDef.owner.tpe
- case _ => NoType
- }
- val hasTparams = !tparams.isEmpty
-
def sigma(tpe: Type): Type = {
class SigmaTypeMap extends TypeMap {
def apply(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) =>
val pre1 = pre match {
case ThisType(sym) if sym == macroDef.owner =>
- SingleType(SingleType(SingleType(NoPrefix, paramsCtx(0)), MacroContextPrefix), ExprValue)
+ SingleType(SingleType(SingleType(NoPrefix, ctxParam), MacroContextPrefix), ExprValue)
case SingleType(NoPrefix, sym) =>
mfind(vparamss)(_.symbol == sym) match {
- case Some(macroDefParam) =>
- SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue)
- case _ =>
- pre
+ case Some(macroDefParam) => SingleType(SingleType(NoPrefix, param(macroDefParam)), ExprValue)
+ case _ => pre
}
case _ =>
pre
}
- val args1 = args map mapOver
- TypeRef(pre1, sym, args1)
+ TypeRef(pre1, sym, args map mapOver)
case _ =>
mapOver(tp)
}
@@ -281,11 +348,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
sigParam
})
- val paramsCtx = List(ctxParam)
- val paramsThis = List(makeParam(nme.macroThis, macroDef.pos, implType(false, ownerTpe), SYNTHETIC))
- val paramsTparams = tparams map param
- val paramssParams = mmap(vparamss)(param)
- val paramss = paramsCtx :: paramssParams
+ val paramss = List(ctxParam) :: mmap(vparamss)(param)
val implRetTpe = typeRef(singleType(NoPrefix, ctxParam), getMember(MacroContextClass, tpnme.Expr), List(sigma(retTpe)))
}
@@ -297,142 +360,23 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
macroTraceVerbose("macroImplSig is: ")(paramss, implRetTpe)
}
- /** Transforms parameters lists of a macro impl.
- * The `transform` function is invoked only for AbsTypeTag evidence parameters.
- *
- * The transformer takes two arguments: a value parameter from the parameter list
- * and a type parameter that is witnesses by the value parameter.
- *
- * If the transformer returns a NoSymbol, the value parameter is not included from the result.
- * If the transformer returns something else, this something else is included in the result instead of the value parameter.
- *
- * Despite of being highly esoteric, this function significantly simplifies signature analysis.
- * For example, it can be used to strip macroImpl.paramss from the evidences (necessary when checking def <-> impl correspondence)
- * or to streamline creation of the list of macro arguments.
- */
- private def transformTypeTagEvidenceParams(paramss: List[List[Symbol]], transform: (Symbol, Symbol) => Symbol): List[List[Symbol]] = {
- if (paramss.isEmpty || paramss.last.isEmpty) return paramss // no implicit parameters in the signature => nothing to do
- if (paramss.head.isEmpty || !(paramss.head.head.tpe <:< MacroContextClass.tpe)) return paramss // no context parameter in the signature => nothing to do
- def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
- case TypeRef(SingleType(SingleType(NoPrefix, c), universe), typetag, targ :: Nil)
- if c == paramss.head.head && universe == MacroContextUniverse && typetag == AbsTypeTagClass =>
- transform(param, targ.typeSymbol)
- case _ =>
- param
- }
- val transformed = paramss.last map transformTag filter (_ ne NoSymbol)
- if (transformed.isEmpty) paramss.init else paramss.init :+ transformed
- }
-
- /** As specified above, body of a macro definition must reference its implementation.
- * This function verifies that the body indeed refers to a method, and that
- * the referenced macro implementation is compatible with the given macro definition.
+ /** Verifies that the body of a macro def typechecks to a reference to a static public non-overloaded method,
+ * and that that method is signature-wise compatible with the given macro definition.
*
- * This means that macro implementation (fooBar in example above) must:
- * 1) Refer to a statically accessible, non-overloaded method.
- * 2) Have the right parameter lists as outlined in the SIP / in the doc comment of this class.
- *
- * @return typechecked rhs of the given macro definition
+ * @return Typechecked rhs of the given macro definition if everything is okay.
+ * EmptyTree if an error occurs.
*/
- def typedMacroBody(typer: Typer, ddef: DefDef): Tree = {
- import typer.context
- macroLogVerbose("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos))
-
- val macroDef = ddef.symbol
- val defpos = macroDef.pos
- val implpos = ddef.rhs.pos
- assert(macroDef.isTermMacro, ddef)
-
- if (fastTrack contains ddef.symbol) {
- macroLogVerbose("typecheck terminated unexpectedly: macro is hardwired")
- assert(!ddef.tpt.isEmpty, "hardwired macros must provide result type")
- return EmptyTree
- }
-
- if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) {
- macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
- ddef.symbol setFlag IS_ERROR
- return EmptyTree
- }
-
- implicit class AugmentedString(s: String) {
- def abbreviateCoreAliases: String = { // hack!
- var result = s
- result = result.replace("c.universe.AbsTypeTag", "c.AbsTypeTag")
- result = result.replace("c.universe.Expr", "c.Expr")
- result
- }
- }
-
- var _hasError = false
- def hasError = _hasError
- def setError(): Unit = {
- _hasError = true
- macroDef setFlag IS_ERROR
- }
- def reportError(pos: Position, msg: String) = {
- setError()
- context.error(pos, msg)
- }
-
- def invalidBodyError() =
- reportError(defpos,
- "macro body has wrong shape:" +
- "\n required: macro <reference to implementation object>.<implementation method name>" +
- "\n or : macro <implementation method name>")
- def validatePreTyper(rhs: Tree): Unit = rhs match {
- // we do allow macro invocations inside macro bodies
- // personally I don't mind if pre-typer tree is a macro invocation
- // that later resolves to a valid reference to a macro implementation
- // however, I don't think that invalidBodyError() should hint at that
- // let this be an Easter Egg :)
- case Apply(_, _) => ;
- case TypeApply(_, _) => ;
- case Super(_, _) => ;
- case This(_) => ;
- case Ident(_) => ;
- case Select(_, _) => ;
- case _ => invalidBodyError()
- }
- def validatePostTyper(rhs1: Tree): Unit = {
- def loop(tree: Tree): Unit = {
- def errorNotStatic() =
- reportError(implpos, "macro implementation must be in statically accessible object")
-
- def ensureRoot(sym: Symbol) =
- if (!sym.isModule && !sym.isModuleClass) errorNotStatic()
-
- def ensureModule(sym: Symbol) =
- if (!sym.isModule) errorNotStatic()
-
- tree match {
- case TypeApply(fun, _) =>
- loop(fun)
- case Super(qual, _) =>
- ensureRoot(macroDef.owner)
- loop(qual)
- case This(_) =>
- ensureRoot(tree.symbol)
- case Select(qual, name) if name.isTypeName =>
- loop(qual)
- case Select(qual, name) if name.isTermName =>
- if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol)
- loop(qual)
- case Ident(name) if name.isTypeName =>
- ;
- case Ident(name) if name.isTermName =>
- if (tree.symbol != rhs1.symbol) ensureModule(tree.symbol)
- case _ =>
- invalidBodyError()
- }
- }
-
- loop(rhs1)
- }
-
- val rhs = ddef.rhs
- validatePreTyper(rhs)
- if (hasError) macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef)
+ def typedMacroBody(typer: Typer, macroDdef: DefDef): Tree =
+ try new MacroTyper(typer, macroDdef).typed
+ catch { case MacroBodyTypecheckException => EmptyTree }
+
+ class MacroTyper(val typer: Typer, val macroDdef: DefDef) extends MacroErrors {
+ // Phase I: sanity checks
+ val macroDef = macroDdef.symbol
+ macroLogVerbose("typechecking macro def %s at %s".format(macroDef, macroDdef.pos))
+ assert(macroDef.isTermMacro, macroDdef)
+ if (fastTrack contains macroDef) MacroDefIsFastTrack()
+ if (!typer.checkFeature(macroDdef.pos, MacrosFeature, immediate = true)) MacroFeatureNotEnabled()
// we use typed1 instead of typed, because otherwise adapt is going to mess us up
// if adapt sees <qualifier>.<method>, it will want to perform eta-expansion and will fail
@@ -440,11 +384,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// because it's adapt which is responsible for automatic expansion during typechecking
def typecheckRhs(rhs: Tree): Tree = {
try {
+ // interestingly enough, just checking isErroneous doesn't cut it
+ // e.g. a "type arguments [U] do not conform to method foo's type parameter bounds" error
+ // doesn't manifest itself as an error in the resulting tree
val prevNumErrors = reporter.ERROR.count
- var rhs1 = if (hasError) EmptyTree else typer.typed1(rhs, EXPRmode, WildcardType)
- def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
+ var rhs1 = typer.typed1(rhs, EXPRmode, WildcardType)
def rhsNeedsMacroExpansion = rhs1.symbol != null && rhs1.symbol.isTermMacro && !rhs1.symbol.isErroneous
- while (!typecheckedWithErrors && rhsNeedsMacroExpansion) {
+ while (rhsNeedsMacroExpansion) {
rhs1 = macroExpand1(typer, rhs1) match {
case Success(expanded) =>
try {
@@ -452,7 +398,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked)))
typechecked
} finally {
- openMacros = openMacros.tail
+ popMacroContext()
}
case Fallback(fallback) =>
typer.typed1(fallback, EXPRmode, WildcardType)
@@ -460,233 +406,80 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
result
}
}
+ val typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
+ if (typecheckedWithErrors) MacroDefUntypeableBodyError()
rhs1
} catch {
case ex: TypeError =>
typer.reportTypeError(context, rhs.pos, ex)
- typer.infer.setError(rhs)
+ MacroDefUntypeableBodyError()
}
}
- val prevNumErrors = reporter.ERROR.count // funnily enough, the isErroneous check is not enough
- var rhs1 = typecheckRhs(rhs)
- val macroImpl = rhs1.symbol
- def typecheckedWithErrors = (rhs1 exists (_.isErroneous)) || reporter.ERROR.count != prevNumErrors
- if (typecheckedWithErrors) {
- setError()
- macroTraceVerbose("body of a macro def failed to typecheck: ")(ddef)
- } else {
- if (!hasError) {
- if (macroImpl == null) invalidBodyError()
- else {
- if (!macroImpl.isMethod) invalidBodyError()
- if (!macroImpl.isPublic) reportError(implpos, "macro implementation must be public")
- if (macroImpl.isOverloaded) reportError(implpos, "macro implementation cannot be overloaded")
- if (!macroImpl.typeParams.isEmpty && !rhs1.isInstanceOf[TypeApply]) reportError(implpos, "macro implementation reference needs type arguments")
- if (!hasError) validatePostTyper(rhs1)
- }
- }
- if (!hasError) {
- bindMacroImpl(macroDef, rhs1) // we must bind right over here, because return type inference needs this info
- }
+ // Phase II: typecheck the right-hand side of the macro def
+ val typed = typecheckRhs(macroDdef.rhs)
+ typed match {
+ case MacroImplReference(owner, meth, targs) =>
+ if (!meth.isMethod) MacroDefInvalidBodyError()
+ if (!meth.isPublic) MacroImplNotPublicError()
+ if (meth.isOverloaded) MacroImplOverloadedError()
+ if (!owner.isStaticOwner && !owner.moduleClass.isStaticOwner) MacroImplNotStaticError()
+ if (meth.typeParams.length != targs.length) MacroImplWrongNumberOfTypeArgumentsError(typed)
+ bindMacroImpl(macroDef, typed)
+ case _ =>
+ MacroDefInvalidBodyError()
}
- if (!hasError) {
- def checkCompatibility(reqparamss: List[List[Symbol]], actparamss: List[List[Symbol]], reqres: Type, actres: Type): List[String] = {
- var hasError = false
- var errors = List[String]()
- def compatibilityError(msg: String) {
- hasError = true
- errors :+= msg
- }
-
- val flatreqparams = reqparamss.flatten
- val flatactparams = actparamss.flatten
- val tparams = macroImpl.typeParams
- val tvars = tparams map freshVar
- def lengthMsg(which: String, extra: Symbol) =
- "parameter lists have different length, "+which+" extra parameter "+extra.defString
- if (actparamss.length != reqparamss.length)
- compatibilityError("number of parameter sections differ")
-
- def checkSubType(slot: String, reqtpe: Type, acttpe: Type): Unit = {
- val ok = if (macroDebugVerbose) {
- if (reqtpe eq acttpe) println(reqtpe + " <: " + acttpe + "?" + EOL + "true")
- withTypesExplained(reqtpe <:< acttpe)
- } else reqtpe <:< acttpe
- if (!ok) {
- compatibilityError("type mismatch for %s: %s does not conform to %s".format(slot, reqtpe.toString.abbreviateCoreAliases, acttpe.toString.abbreviateCoreAliases))
- }
- }
+ // Phase III: check compatibility between the macro def and its macro impl
+ // this check ignores type tag evidence parameters, because type tag context bounds are optional
+ // aXXX (e.g. aparamss) => characteristics of the macro impl ("a" stands for "actual")
+ // rXXX (e.g. rparamss) => characteristics of a reference macro impl signature synthesized from the macro def ("r" stands for "reference")
+ val macroImpl = typed.symbol
+ val aparamss = transformTypeTagEvidenceParams(macroImpl.paramss, (param, tparam) => NoSymbol)
+ val aret = macroImpl.tpe.finalResultType
+ val macroDefRet =
+ if (!macroDdef.tpt.isEmpty) typer.typedType(macroDdef.tpt).tpe
+ else computeMacroDefTypeFromMacroImpl(macroDdef, macroImpl)
+ val (rparamss, rret) = macroImplSig(macroDef, macroDdef.tparams, macroDdef.vparamss, macroDefRet)
+
+ val implicitParams = aparamss.flatten filter (_.isImplicit)
+ if (implicitParams.nonEmpty) MacroImplNonTagImplicitParameters(implicitParams)
+ if (aparamss.length != rparamss.length) MacroImplParamssMismatchError()
+
+ val atparams = macroImpl.typeParams
+ val atvars = atparams map freshVar
+ def atpeToRtpe(atpe: Type) = atpe.substSym(aparamss.flatten, rparamss.flatten).instantiateTypeParams(atparams, atvars)
- if (!hasError) {
- try {
- for ((rparams, aparams) <- reqparamss zip actparamss) {
- if (rparams.length < aparams.length)
- compatibilityError(lengthMsg("found", aparams(rparams.length)))
- if (aparams.length < rparams.length)
- compatibilityError(lengthMsg("required", rparams(aparams.length)).abbreviateCoreAliases)
- }
- // if the implementation signature is already deemed to be incompatible, we bail out
- // otherwise, high-order type magic employed below might crash in weird ways
- if (!hasError) {
- for ((rparams, aparams) <- reqparamss zip actparamss) {
- for ((rparam, aparam) <- rparams zip aparams) {
- def isRepeated(param: Symbol) = param.tpe.typeSymbol == RepeatedParamClass
- if (rparam.name != aparam.name && !rparam.isSynthetic) {
- val rparam1 = rparam
- val aparam1 = aparam
- compatibilityError("parameter names differ: "+rparam.name+" != "+aparam.name)
- }
- if (isRepeated(rparam) && !isRepeated(aparam))
- compatibilityError("types incompatible for parameter "+rparam.name+": corresponding is not a vararg parameter")
- if (!isRepeated(rparam) && isRepeated(aparam))
- compatibilityError("types incompatible for parameter "+aparam.name+": corresponding is not a vararg parameter")
- if (!hasError) {
- var atpe = aparam.tpe.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars)
- atpe = atpe.dealias // SI-5706
- // strip the { type PrefixType = ... } refinement off the Context or otherwise we get compatibility errors
- atpe = atpe match {
- case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe
- case _ => atpe
- }
- checkSubType("parameter " + rparam.name, rparam.tpe, atpe)
- }
- }
- }
- }
- if (!hasError) {
- val atpe = actres.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars)
- checkSubType("return type", atpe, reqres)
- }
- if (!hasError) {
- val targs = solvedTypes(tvars, tparams, tparams map varianceInType(actres), false,
- lubDepth(flatactparams map (_.tpe)) max lubDepth(flatreqparams map (_.tpe)))
- val boundsOk = typer.silent(_.infer.checkBounds(ddef, NoPrefix, NoSymbol, tparams, targs, ""))
- boundsOk match {
- case SilentResultValue(true) => ;
- case SilentResultValue(false) | SilentTypeError(_) =>
- val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds)
- compatibilityError("type arguments " + targs.mkString("[", ",", "]") +
- " do not conform to " + tparams.head.owner + "'s type parameter bounds " +
- (tparams map (_.defString)).mkString("[", ",", "]"))
- }
- }
- } catch {
- case ex: NoInstance =>
- compatibilityError(
- "type parameters "+(tparams map (_.defString) mkString ", ")+" cannot be instantiated\n"+
- ex.getMessage)
- }
- }
-
- errors.toList
- }
-
- var actparamss = macroImpl.paramss
- actparamss = transformTypeTagEvidenceParams(actparamss, (param, tparam) => NoSymbol)
- val actres = macroImpl.tpe.finalResultType
- val implicitParams = actparamss.flatten filter (_.isImplicit)
- if (implicitParams.length > 0) {
- // prohibit implicit params on macro implementations
- // we don't have to do this, but it appears to be more clear than allowing them
- reportError(implicitParams.head.pos, "macro implementations cannot have implicit parameters other than AbsTypeTag evidences")
- macroTraceVerbose("macro def failed to satisfy trivial preconditions: ")(macroDef)
- }
-
- if (!hasError) {
- val rettpe = if (!ddef.tpt.isEmpty) typer.typedType(ddef.tpt).tpe else computeMacroDefTypeFromMacroImpl(ddef, macroDef, macroImpl)
- val (reqparamss, reqres) = macroImplSig(macroDef, ddef.tparams, ddef.vparamss, rettpe)
+ try {
+ map2(aparamss, rparamss)((aparams, rparams) => {
+ if (aparams.length < rparams.length) MacroImplMissingParamsError(aparams, rparams)
+ if (rparams.length < aparams.length) MacroImplExtraParamsError(aparams, rparams)
+ })
- def showMeth(pss: List[List[Symbol]], restpe: Type, abbreviate: Boolean) = {
- var argsPart = (pss map (ps => ps map (_.defString) mkString ("(", ", ", ")"))).mkString
- if (abbreviate) argsPart = argsPart.abbreviateCoreAliases
- var retPart = restpe.toString
- if (abbreviate || ddef.tpt.tpe == null) retPart = retPart.abbreviateCoreAliases
- argsPart + ": " + retPart
+ // cannot fuse these loops because if aparamss.flatten != rparamss.flatten
+ // then `atpeToRtpe` is going to fail with an unsound substitution
+ map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => {
+ if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam)
+ if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam)
+ val aparamtpe = aparam.tpe.dealias match {
+ case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe
+ case tpe => tpe
}
- def compatibilityError(addendum: String) =
- reportError(implpos,
- "macro implementation has wrong shape:"+
- "\n required: "+showMeth(reqparamss, reqres, true) +
- "\n found : "+showMeth(actparamss, actres, false)+
- "\n"+addendum)
-
- val errors = checkCompatibility(reqparamss, actparamss, reqres, actres)
- if (errors.nonEmpty) compatibilityError(errors mkString "\n")
- }
- }
-
- rhs1
- }
-
- def computeMacroDefTypeFromMacroImpl(macroDdef: DefDef, macroDef: Symbol, macroImpl: Symbol): Type = {
- // downgrade from metalevel-0 to metalevel-1
- var runtimeType = macroImpl.tpe.finalResultType.dealias match {
- case TypeRef(_, ExprClass, runtimeType :: Nil) => runtimeType
- case _ => AnyTpe
- }
+ checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam)
+ })
- // transform type parameters of a macro implementation into type parameters of a macro definition
- runtimeType = runtimeType map {
- case TypeRef(pre, sym, args) =>
- // sym.paramPos is unreliable (see an example in `macroArgs`)
- val tparams = macroImpl.typeParams map (_.deSkolemize)
- val paramPos = tparams indexOf sym.deSkolemize
- val sym1 =
- if (paramPos == -1) sym
- else loadMacroImplBinding(macroDef).targs(paramPos).tpe.typeSymbol
- TypeRef(pre, sym1, args)
- case tpe =>
- tpe
- }
+ checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret)
- // as stated in the spec, before being matched to macroimpl, type and value parameters of macrodef
- // undergo a special transformation, sigma, that adapts them to the different metalevel macroimpl lives in
- // as a result, we need to reverse this transformation when inferring macrodef ret from macroimpl ret
- def unsigma(tpe: Type): Type = {
- // unfortunately, we cannot dereference ``paramss'', because we're in the middle of inferring a type for ``macroDef''
-// val defParamss = macroDef.paramss
- val defParamss = mmap(macroDdef.vparamss)(_.symbol)
- var implParamss = macroImpl.paramss
- implParamss = transformTypeTagEvidenceParams(implParamss, (param, tparam) => NoSymbol)
-
- val implCtxParam = if (implParamss.length > 0 && implParamss(0).length > 0) implParamss(0)(0) else null
- def implParamToDefParam(implParam: Symbol): Symbol = {
- val indices = (((implParamss drop 1).zipWithIndex) map { case (implParams, index) => (index, implParams indexOf implParam) } filter (_._2 != -1)).headOption
- val defParam = indices flatMap {
- case (plistIndex, pIndex) =>
- if (defParamss.length <= plistIndex) None
- else if (defParamss(plistIndex).length <= pIndex) None
- else Some(defParamss(plistIndex)(pIndex))
- }
- defParam.orNull
+ val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe))
+ val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, depth = maxLubDepth)
+ val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, ""))
+ boundsOk match {
+ case SilentResultValue(true) => // do nothing, success
+ case SilentResultValue(false) | SilentTypeError(_) => MacroImplTargMismatchError(atargs, atparams)
}
-
- class UnsigmaTypeMap extends TypeMap {
- def apply(tp: Type): Type = tp match {
- case TypeRef(pre, sym, args) =>
- val pre1 = pre match {
- case SingleType(SingleType(SingleType(NoPrefix, param), prefix), value) if param == implCtxParam && prefix == MacroContextPrefix && value == ExprValue =>
- ThisType(macroDef.owner)
- case SingleType(SingleType(NoPrefix, param), value) if implParamToDefParam(param) != null && value == ExprValue =>
- val macroDefParam = implParamToDefParam(param)
- SingleType(NoPrefix, macroDefParam)
- case _ =>
- pre
- }
- val args1 = args map mapOver
- TypeRef(pre1, sym, args1)
- case _ =>
- mapOver(tp)
- }
- }
-
- new UnsigmaTypeMap() apply tpe
+ } catch {
+ case ex: NoInstance => MacroImplTparamInstantiationError(atparams, ex)
}
- runtimeType = unsigma(runtimeType)
-
- runtimeType
}
/** Macro classloader that is used to resolve and run macro implementations.
@@ -719,9 +512,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* 4) Resolves macro implementation within the loaded companion.
*
* @return Requested runtime if macro implementation can be loaded successfully from either of the mirrors,
- * null otherwise.
+ * `null` otherwise.
*/
- type MacroRuntime = List[Any] => Any
+ type MacroRuntime = MacroArgs => Any
private val macroRuntimesCache = perRunCaches.newWeakMap[Symbol, MacroRuntime]
private def macroRuntime(macroDef: Symbol): MacroRuntime = {
macroTraceVerbose("looking for macro implementation: ")(macroDef)
@@ -749,7 +542,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName)
val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") }
macroLogVerbose("successfully loaded macro impl as (%s, %s)".format(implObj, implMeth))
- (args: List[Any]) => implMeth.invoke(implObj, (args map (_.asInstanceOf[AnyRef])): _*)
+ args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*)
} catch {
case ex: Exception =>
macroTraceVerbose(s"macro runtime failed to load: ")(ex.toString)
@@ -766,19 +559,14 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
val callsiteTyper: universe.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
val expandee = expandeeTree
} with UnaffiliatedMacroContext {
- // todo. infer precise typetag for this Expr, namely the PrefixType member of the Context refinement
val prefix = Expr[Nothing](prefixTree)(TypeTag.Nothing)
override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, enclosingMacros.length - 1 /* exclude myself */)
}
/** Calculate the arguments to pass to a macro implementation when expanding the provided tree.
- *
- * This includes inferring the exact type and instance of the macro context to pass, and also
- * allowing for missing parameter sections in macro implementation (see ``macroImplParamsss'' for more info).
- *
- * @return list of runtime objects to pass to the implementation obtained by ``macroRuntime''
*/
- private def macroArgs(typer: Typer, expandee: Tree): Option[List[Any]] = {
+ case class MacroArgs(c: MacroContext, others: List[Any])
+ private def macroArgs(typer: Typer, expandee: Tree): MacroArgs = {
val macroDef = expandee.symbol
val prefixTree = expandee.collect{ case Select(qual, name) => qual }.headOption.getOrElse(EmptyTree)
val context = expandee.attachments.get[MacroRuntimeAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee))
@@ -797,28 +585,18 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
collectMacroArgs(expandee)
val argcDoesntMatch = macroDef.paramss.length != exprArgs.length
- val nullaryArgsEmptyParams = exprArgs.isEmpty && macroDef.paramss == List(List())
- if (argcDoesntMatch && !nullaryArgsEmptyParams) { typer.TyperErrorGen.MacroPartialApplicationError(expandee); return None }
+ val nullaryArgsEmptyParams = exprArgs.isEmpty && macroDef.paramss == ListOfNil
+ if (argcDoesntMatch && !nullaryArgsEmptyParams) { typer.TyperErrorGen.MacroPartialApplicationError(expandee) }
- var argss: List[List[Any]] = List(context) :: exprArgs.toList
+ val argss: List[List[Any]] = exprArgs.toList
+ macroTraceVerbose("context: ")(context)
macroTraceVerbose("argss: ")(argss)
- val rawArgss =
+
+ val preparedArgss: List[List[Any]] =
if (fastTrack contains macroDef) {
- if (fastTrack(macroDef) validate argss) argss
- else {
- // if you're getting here, it's not necessarily partial application that is at fault
- // for example, if a signature of a hardwired macro has been changed without updated FastTrack
- // then the corresponding partial function in FastTrack will refuse to process the expandee
- // validation will return false, and control flow will end up here
- // however, for simplicity sake, I didn't introduce the notion of error handling to FastTrack
- // so all kinds of validation errors produce `MacroPartialApplicationError`
- typer.TyperErrorGen.MacroPartialApplicationError(expandee)
- return None
- }
+ if (fastTrack(macroDef) validate context) argss
+ else typer.TyperErrorGen.MacroPartialApplicationError(expandee)
} else {
- val binding = loadMacroImplBinding(macroDef)
- macroTraceVerbose("binding: ")(binding)
-
// if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
// consider the following example:
//
@@ -832,9 +610,11 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// val outer2 = new outer1.C[String]
// outer2.foo[Boolean]
//
- // then T and U need to be inferred from the lexical scope of the call using ``asSeenFrom''
- // whereas V won't be resolved by asSeenFrom and need to be loaded directly from ``expandee'' which needs to contain a TypeApply node
+ // then T and U need to be inferred from the lexical scope of the call using `asSeenFrom`
+ // whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node
// also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
+ val binding = loadMacroImplBinding(macroDef)
+ macroTraceVerbose("binding: ")(binding)
val tags = binding.signature filter (_ != -1) map (paramPos => {
val targ = binding.targs(paramPos).tpe.typeSymbol
val tpe = if (targ.isTypeParameterOrSkolem) {
@@ -852,39 +632,48 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
targ.tpe
if (tpe.isConcrete) context.TypeTag(tpe) else context.AbsTypeTag(tpe)
})
- val hasImplicitParams = macroDef.paramss.flatten.lastOption exists (_.isImplicit)
- argss = if (hasImplicitParams) argss.dropRight(1) :+ (tags ++ argss.last) else argss :+ tags
+ macroTraceVerbose("tags: ")(tags)
// transforms argss taking into account varargness of paramss
- // not all argument lists in argss map to macroDef.paramss, so we need to apply extra care
- // namely:
- // 1) the first argument list represents (c: Context) in macroImpl, so it doesn't have correspondence in macroDef
- // 2) typetag context bounds are only declared on macroImpls, so this optional arglist also doesn't match macroDef
+ // note that typetag context bounds are only declared on macroImpls
+ // so this optional arglist might not match macroDef's paramlist
// nb! varargs can apply to any parameter section, not necessarily to the last one
- mapWithIndex(argss)((as, i_argss) => {
- val i_paramss = i_argss - 1
- val mapsToParamss = 0 <= i_paramss && i_paramss < macroDef.paramss.length
+ mapWithIndex(argss :+ tags)((as, i) => {
+ val mapsToParamss = macroDef.paramss.indices contains i
if (mapsToParamss) {
- val ps = macroDef.paramss(i_paramss)
- if (isVarArgsList(ps)) as.take(ps.length - 1) :+ as.drop(ps.length - 1)
- else as
+ val ps = macroDef.paramss(i)
+ if (isVarArgsList(ps)) {
+ val (normal, varargs) = as splitAt (ps.length - 1)
+ normal :+ varargs // pack all varargs into a single List argument
+ } else as
} else as
})
}
- val rawArgs = rawArgss.flatten
- macroTraceVerbose("rawArgs: ")(rawArgs)
- Some(rawArgs)
+ macroTraceVerbose("preparedArgss: ")(preparedArgss)
+ MacroArgs(context, preparedArgss.flatten)
}
/** Keeps track of macros in-flight.
- * See more informations in comments to ``openMacros'' in ``scala.reflect.macros.Context''.
+ * See more informations in comments to `openMacros` in `scala.reflect.macros.Context`.
*/
- var openMacros = List[MacroContext]()
+ private var _openMacros = List[MacroContext]()
+ def openMacros = _openMacros
+ private def pushMacroContext(c: MacroContext) = _openMacros ::= c
+ private def popMacroContext() = _openMacros = _openMacros.tail
def enclosingMacroPosition = openMacros map (_.macroApplication.pos) find (_ ne NoPosition) getOrElse NoPosition
+ private sealed abstract class MacroExpansionResult
+ private case class Success(expanded: Tree) extends MacroExpansionResult
+ private case class Fallback(fallback: Tree) extends MacroExpansionResult { currentRun.seenMacroExpansionsFallingBack = true }
+ private case class Other(result: Tree) extends MacroExpansionResult
+ private def Delay(expanded: Tree) = Other(expanded)
+ private def Skip(expanded: Tree) = Other(expanded)
+ private def Cancel(expandee: Tree) = Other(expandee)
+ private def Failure(expandee: Tree) = Other(expandee)
+
/** Performs macro expansion:
- * 1) Checks whether the expansion needs to be delayed (see ``mustDelayMacroExpansion'')
- * 2) Loads macro implementation using ``macroMirror''
+ * 1) Checks whether the expansion needs to be delayed (see `mustDelayMacroExpansion`)
+ * 2) Loads macro implementation using `macroMirror`
* 3) Synthesizes invocation arguments for the macro implementation
* 4) Checks that the result is a tree bound to this universe
* 5) Typechecks the result against the return type of the macro definition
@@ -905,51 +694,28 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
* the expandee with an error marker set if there has been an error
*/
def macroExpand(typer: Typer, expandee: Tree, mode: Int = EXPRmode, pt: Type = WildcardType): Tree = {
- def fail(what: String, tree: Tree): Tree = {
- val err = typer.context.errBuffer.head
- this.fail(typer, tree, err.errPos, "failed to %s: %s".format(what, err.errMsg))
- return expandee
- }
- val start = Statistics.startTimer(macroExpandNanos)
- Statistics.incCounter(macroExpandCount)
+ val start = if (Statistics.canEnable) Statistics.startTimer(macroExpandNanos) else null
+ if (Statistics.canEnable) Statistics.incCounter(macroExpandCount)
try {
macroExpand1(typer, expandee) match {
- case Success(expanded0) =>
+ case Success(expanded) =>
try {
- val expanded = expanded0 // virtpatmat swallows the local for expandee from the match
- // so I added this dummy local for the ease of debugging
- var expectedTpe = expandee.tpe
-
- val isNullaryInvocation = expandee match {
- case TypeApply(Select(_, _), _) => true
- case TypeApply(Ident(_), _) => true
- case Select(_, _) => true
- case Ident(_) => true
- case _ => false
- }
- if (isNullaryInvocation) expectedTpe match {
- case NullaryMethodType(restpe) =>
- macroTraceVerbose("nullary invocation of a nullary method. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
- expectedTpe = restpe
- case MethodType(Nil, restpe) =>
- macroTraceVerbose("nullary invocation of a method with an empty parameter list. unwrapping expectedTpe from " + expectedTpe + " to: ")(restpe)
- expectedTpe = restpe
- case _ => ;
+ def typecheck(phase: String, tree: Tree, pt: Type): Tree = {
+ if (tree.isErroneous) return tree
+ macroLogVerbose(s"typechecking against $phase $pt: $expanded")
+ val numErrors = reporter.ERROR.count
+ def hasNewErrors = reporter.ERROR.count > numErrors
+ val result = typer.context.withImplicitsEnabled(typer.typed(tree, EXPRmode, pt))
+ macroTraceVerbose(s"""${if (hasNewErrors) "failed to typecheck" else "successfully typechecked"} against $phase $pt:\n$result\n""")(result)
}
- macroLogVerbose("typechecking1 against %s: %s".format(expectedTpe, expanded))
- var typechecked = typer.context.withImplicitsEnabled(typer.typed(expanded, EXPRmode, expectedTpe))
- if (typer.context.hasErrors) fail("typecheck against macro def return type", expanded)
- macroLogVerbose("typechecked1:%n%s%n%s".format(typechecked, showRaw(typechecked)))
-
- macroLogVerbose("typechecking2 against %s: %s".format(pt, expanded))
- typechecked = typer.context.withImplicitsEnabled(typer.typed(typechecked, EXPRmode, pt))
- if (typer.context.hasErrors) fail("typecheck against expected type", expanded)
- macroLogVerbose("typechecked2:%n%s%n%s".format(typechecked, showRaw(typechecked)))
-
+ var expectedTpe = expandee.tpe
+ if (isNullaryInvocation(expandee)) expectedTpe = expectedTpe.finalResultType
+ var typechecked = typecheck("macro def return type", expanded, expectedTpe)
+ typechecked = typecheck("expected type", typechecked, pt)
typechecked addAttachment MacroExpansionAttachment(expandee)
} finally {
- openMacros = openMacros.tail
+ popMacroContext()
}
case Fallback(fallback) =>
typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt))
@@ -957,234 +723,98 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
result
}
} finally {
- Statistics.stopTimer(macroExpandNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(macroExpandNanos, start)
}
}
- private sealed abstract class MacroExpansionResult extends Product with Serializable
- private case class Success(expanded: Tree) extends MacroExpansionResult
- private case class Fallback(fallback: Tree) extends MacroExpansionResult
- private case class Other(result: Tree) extends MacroExpansionResult
- private def Delay(expanded: Tree) = Other(expanded)
- private def Skip(expanded: Tree) = Other(expanded)
- private def Cancel(expandee: Tree) = Other(expandee)
- private def Failure(expandee: Tree) = Other(expandee)
- private def fail(typer: Typer, expandee: Tree, pos: Position = NoPosition, msg: String = null) = {
- def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg
- macroLogLite("macro expansion has failed: %s".format(msgForLog))
- val errorPos = if (pos != NoPosition) pos else (if (expandee.pos != NoPosition) expandee.pos else enclosingMacroPosition)
- if (msg != null) typer.context.error(errorPos, msg)
- typer.infer.setError(expandee)
- Failure(expandee)
- }
-
- /** Does the same as ``macroExpand'', but without typechecking the expansion
+ /** Does the same as `macroExpand`, but without typechecking the expansion
* Meant for internal use within the macro infrastructure, don't use it elsewhere.
*/
private def macroExpand1(typer: Typer, expandee: Tree): MacroExpansionResult =
- // InfoLevel.Verbose examines and prints out infos of symbols
- // by the means of this'es these symbols can climb up the lexical scope
- // when these symbols will be examined by a node printer
- // they will enumerate and analyze their children (ask for infos and tpes)
- // if one of those children involves macro expansion, things might get nasty
- // that's why I'm temporarily turning this behavior off
+ // verbose printing might cause recursive macro expansions, so I'm shutting it down here
withInfoLevel(nodePrinters.InfoLevel.Quiet) {
- // if a macro implementation is incompatible or any of the arguments are erroneous
- // there is no sense to expand the macro itself => it will only make matters worse
if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) {
val reason = if (expandee.symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments"
macroTraceVerbose("cancelled macro expansion because of %s: ".format(reason))(expandee)
return Cancel(typer.infer.setError(expandee))
}
- val runtime = macroRuntime(expandee.symbol)
- if (runtime != null) macroExpandWithRuntime(typer, expandee, runtime)
- else macroExpandWithoutRuntime(typer, expandee)
+ try {
+ val runtime = macroRuntime(expandee.symbol)
+ if (runtime != null) macroExpandWithRuntime(typer, expandee, runtime)
+ else macroExpandWithoutRuntime(typer, expandee)
+ } catch {
+ case typer.TyperErrorGen.MacroExpansionException => Failure(expandee)
+ }
}
/** Expands a macro when a runtime (i.e. the macro implementation) can be successfully loaded
* Meant for internal use within the macro infrastructure, don't use it elsewhere.
*/
private def macroExpandWithRuntime(typer: Typer, expandee: Tree, runtime: MacroRuntime): MacroExpansionResult = {
- def issueFreeError(sym: FreeSymbol) = {
- val template = (
- "Macro expansion contains free @kind@ variable %s. Have you forgotten to use %s? "
- + "If you have troubles tracking free @kind@ variables, consider using -Xlog-free-@kind@s"
- )
- val forgotten = (
- if (sym.isTerm) "splice when splicing this variable into a reifee"
- else "c.AbsTypeTag annotation for this type parameter"
- )
- typer.context.error(expandee.pos,
- template.replaceAllLiterally("@kind@", sym.name.nameKind).format(
- sym.name + " " + sym.origin, forgotten)
- )
- }
- def macroExpandInternal = {
- val wasDelayed = isDelayed(expandee)
- val undetparams = calculateUndetparams(expandee)
- val nowDelayed = !typer.context.macrosEnabled || undetparams.nonEmpty
-
- def failExpansion(msg: String = null) = fail(typer, expandee, msg = msg)
- def performExpansion(args: List[Any]): MacroExpansionResult = {
- val numErrors = reporter.ERROR.count
- def hasNewErrors = reporter.ERROR.count > numErrors
-
- val expanded = runtime(args)
-
- if (hasNewErrors)
- failExpansion() // errors have been reported by the macro itself
- else expanded match {
- case expanded: Expr[_] =>
- macroLogVerbose("original:")
- macroLogLite("" + expanded.tree + "\n" + showRaw(expanded.tree))
-
- expanded.tree.freeTerms foreach issueFreeError
- expanded.tree.freeTypes foreach issueFreeError
- if (hasNewErrors) failExpansion()
-
- // inherit the position from the first position-ful expandee in macro callstack
- // this is essential for sane error messages
- // now macro expansion gets typechecked against the macro definition return type
- // however, this happens in macroExpand, not here in macroExpand1
- else Success(atPos(enclosingMacroPosition.focus)(expanded.tree))
- case _ =>
- failExpansion(
- "macro must return a compiler-specific expr; returned value is " + (
- if (expanded.isInstanceOf[Expr[_]]) " Expr, but it doesn't belong to this compiler's universe"
- else " of " + expanded.getClass
- )
- )
- }
- }
-
- if (wasDelayed) {
- if (nowDelayed) Delay(expandee)
- else Skip(macroExpandAll(typer, expandee))
- }
- else {
- macroLogLite("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
- macroArgs(typer, expandee).fold(failExpansion(): MacroExpansionResult) {
- args => (args: @unchecked) match {
- // crashes virtpatmat:
- // case args @ ((context: MacroContext) :: _) =>
- // todo. extract a minimized test case
- case args @ (context0 :: _) =>
- val context = context0.asInstanceOf[MacroContext]
- if (nowDelayed) {
- macroLogLite("macro expansion is delayed: %s".format(expandee))
- delayed += expandee -> undetparams
- // need to save typer context for `macroExpandAll`
- // need to save macro context to preserve enclosures
- expandee addAttachment MacroRuntimeAttachment(delayed = true, typerContext = typer.context, macroContext = Some(context.asInstanceOf[MacroContext]))
- Delay(expandee)
- }
- else {
- // adding stuff to openMacros is easy, but removing it is a nightmare
- // it needs to be sprinkled over several different code locations
- // why? https://github.com/scala/scala/commit/bd3eacbae21f39b1ac7fe8ade4ed71fa98e1a28d#L2R1137
- // todo. will be improved
- openMacros ::= context
- var isSuccess = false
- try performExpansion(args) match {
- case x: Success => isSuccess = true ; x
- case x => x
- }
- finally {
- expandee.removeAttachment[MacroRuntimeAttachment]
- if (!isSuccess) openMacros = openMacros.tail
- }
- }
+ val wasDelayed = isDelayed(expandee)
+ val undetparams = calculateUndetparams(expandee)
+ val nowDelayed = !typer.context.macrosEnabled || undetparams.nonEmpty
+
+ (wasDelayed, nowDelayed) match {
+ case (true, true) => Delay(expandee)
+ case (true, false) => Skip(macroExpandAll(typer, expandee))
+ case (false, true) =>
+ macroLogLite("macro expansion is delayed: %s".format(expandee))
+ delayed += expandee -> undetparams
+ expandee addAttachment MacroRuntimeAttachment(delayed = true, typerContext = typer.context, macroContext = Some(macroArgs(typer, expandee).c))
+ Delay(expandee)
+ case (false, false) =>
+ import typer.TyperErrorGen._
+ macroLogLite("performing macro expansion %s at %s".format(expandee, expandee.pos))
+ val args = macroArgs(typer, expandee)
+ try {
+ val numErrors = reporter.ERROR.count
+ def hasNewErrors = reporter.ERROR.count > numErrors
+ val expanded = { pushMacroContext(args.c); runtime(args) }
+ if (hasNewErrors) MacroGeneratedTypeError(expandee)
+ expanded match {
+ case expanded: Expr[_] =>
+ macroLogVerbose("original:")
+ 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))
+ case _ =>
+ MacroExpansionIsNotExprError(expandee, expanded)
}
+ } catch {
+ case ex: Throwable =>
+ popMacroContext()
+ val realex = ReflectionUtils.unwrapThrowable(ex)
+ realex match {
+ case ex: AbortMacroException => MacroGeneratedAbort(expandee, ex)
+ case ex: ControlThrowable => throw ex
+ case ex: TypeError => MacroGeneratedTypeError(expandee, ex)
+ case _ => MacroGeneratedException(expandee, realex)
+ }
+ } finally {
+ expandee.removeAttachment[MacroRuntimeAttachment]
}
- }
}
-
- try macroExpandInternal
- catch { case ex: Throwable => handleMacroExpansionException(typer, expandee, ex) }
}
+ /** Expands a macro when a runtime (i.e. the macro implementation) cannot be loaded
+ * Meant for internal use within the macro infrastructure, don't use it elsewhere.
+ */
private def macroExpandWithoutRuntime(typer: Typer, expandee: Tree): MacroExpansionResult = {
- val macroDef = expandee.symbol
- def notFound() = {
- typer.context.error(expandee.pos, "macro implementation not found: " + macroDef.name + " " +
- "(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)")
- None
- }
- def fallBackToOverridden(tree: Tree): Option[Tree] = {
+ import typer.TyperErrorGen._
+ val fallbackSym = expandee.symbol.nextOverriddenSymbol orElse MacroImplementationNotFoundError(expandee)
+ macroTraceLite("falling back to: ")(fallbackSym)
+
+ def mkFallbackTree(tree: Tree): Tree = {
tree match {
- case Select(qual, name) if (macroDef.isTermMacro) =>
- macroDef.allOverriddenSymbols match {
- case first :: _ =>
- Some(Select(qual, name) setPos tree.pos setSymbol first)
- case _ =>
- macroTraceVerbose("macro is not overridden: ")(tree)
- notFound()
- }
- case Apply(fn, args) =>
- fallBackToOverridden(fn) match {
- case Some(fn1) => Some(Apply(fn1, args) setPos tree.pos)
- case _ => None
- }
- case TypeApply(fn, args) =>
- fallBackToOverridden(fn) match {
- case Some(fn1) => Some(TypeApply(fn1, args) setPos tree.pos)
- case _ => None
- }
- case _ =>
- macroTraceVerbose("unexpected tree in fallback: ")(tree)
- notFound()
+ case Select(qual, name) => Select(qual, name) setPos tree.pos setSymbol fallbackSym
+ case Apply(fn, args) => Apply(mkFallbackTree(fn), args) setPos tree.pos
+ case TypeApply(fn, args) => TypeApply(mkFallbackTree(fn), args) setPos tree.pos
}
}
- fallBackToOverridden(expandee) match {
- case Some(tree1) =>
- macroTraceLite("falling back to: ")(tree1)
- currentRun.macroExpansionFailed = true
- Fallback(tree1)
- case None =>
- fail(typer, expandee)
- }
- }
-
- private def handleMacroExpansionException(typer: Typer, expandee: Tree, ex: Throwable): MacroExpansionResult = {
- val realex = ReflectionUtils.unwrapThrowable(ex)
- realex match {
- case realex: reflect.macros.runtime.AbortMacroException =>
- macroLogVerbose("macro expansion has failed: %s".format(realex.msg))
- fail(typer, expandee) // error has been reported by abort
- case err: TypeError =>
- macroLogLite("macro expansion has failed: %s at %s".format(err.msg, err.pos))
- throw err // error should be propagated, don't report
- case _ =>
- val message = {
- try {
- // [Eugene] is there a better way?
- // [Paul] See Exceptional.scala and Origins.scala.
- val relevancyThreshold = realex.getStackTrace().indexWhere(este => este.getMethodName == "macroExpand1")
- if (relevancyThreshold == -1) None
- else {
- var relevantElements = realex.getStackTrace().take(relevancyThreshold + 1)
- def isMacroInvoker(este: StackTraceElement) = este.isNativeMethod || (este.getClassName != null && (este.getClassName contains "fastTrack"))
- var threshold = relevantElements.reverse.indexWhere(isMacroInvoker) + 1
- while (threshold != relevantElements.length && isMacroInvoker(relevantElements(relevantElements.length - threshold - 1))) threshold += 1
- relevantElements = relevantElements dropRight threshold
-
- realex.setStackTrace(relevantElements)
- val message = new java.io.StringWriter()
- realex.printStackTrace(new java.io.PrintWriter(message))
- Some(EOL + message)
- }
- } catch {
- // if the magic above goes boom, just fall back to uninformative, but better than nothing, getMessage
- case ex: Throwable =>
- None
- }
- } getOrElse {
- val msg = realex.getMessage
- if (msg != null) msg else realex.getClass.getName
- }
- fail(typer, expandee, msg = "exception during macro expansion: " + message)
- }
+ Fallback(mkFallbackTree(expandee))
}
/** Without any restrictions on macro expansion, macro applications will expand at will,
@@ -1236,7 +866,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
/** Performs macro expansion on all subtrees of a given tree.
* Innermost macros are expanded first, outermost macros are expanded last.
- * See the documentation for ``macroExpand'' for more information.
+ * See the documentation for `macroExpand` for more information.
*/
def macroExpandAll(typer: Typer, expandee: Tree): Tree =
new Transformer {
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index f7ba189e0f..4f597f97c9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -242,7 +242,7 @@ trait MethodSynthesis {
abort("No synthetics for " + meth + ": synthetics contains " + context.unit.synthetics.keys.mkString(", "))
}
case _ =>
- List(stat)
+ stat :: Nil
}
def standardAccessors(vd: ValDef): List[DerivedFromValDef] = (
@@ -491,7 +491,7 @@ trait MethodSynthesis {
// Derives a tree without attempting to use the original tree's symbol.
override def derivedTree = {
atPos(tree.pos.focus) {
- DefDef(derivedMods, name, Nil, List(Nil), tree.tpt.duplicate,
+ DefDef(derivedMods, name, Nil, ListOfNil, tree.tpt.duplicate,
if (isDeferred) EmptyTree else Select(This(owner), tree.name)
)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 92d0d4e228..adced9d8c9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -192,6 +192,10 @@ trait Namers extends MethodSynthesis {
if (!allowsOverload(sym)) {
val prev = scope.lookupEntry(sym.name)
if ((prev ne null) && prev.owner == scope && conflict(sym, prev.sym)) {
+ if (sym.isSynthetic || prev.sym.isSynthetic) {
+ handleSyntheticNameConflict(sym, prev.sym)
+ handleSyntheticNameConflict(prev.sym, sym)
+ }
DoubleDefError(sym, prev.sym)
sym setInfo ErrorType
scope unlink prev.sym // let them co-exist...
@@ -202,6 +206,14 @@ trait Namers extends MethodSynthesis {
scope enter sym
}
+ /** Logic to handle name conflicts of synthetically generated symbols
+ * We handle right now: t6227
+ */
+ def handleSyntheticNameConflict(sym1: Symbol, sym2: Symbol) = {
+ if (sym1.isImplicit && sym1.isMethod && sym2.isModule && sym2.companionClass.isCaseClass)
+ validate(sym2.companionClass)
+ }
+
def enterSym(tree: Tree): Context = {
def dispatch() = {
var returnContext = this.context
@@ -973,7 +985,7 @@ trait Namers extends MethodSynthesis {
// Add a () parameter section if this overrides some method with () parameters.
if (clazz.isClass && vparamss.isEmpty && overriddenSymbol.alternatives.exists(
_.info.isInstanceOf[MethodType])) {
- vparamSymss = List(List())
+ vparamSymss = ListOfNil
}
mforeach(vparamss) { vparam =>
if (vparam.tpt.isEmpty) {
@@ -1032,7 +1044,7 @@ trait Namers extends MethodSynthesis {
var baseParamss = (vparamss, overridden.tpe.paramss) match {
// match empty and missing parameter list
case (Nil, List(Nil)) => Nil
- case (List(Nil), Nil) => List(Nil)
+ case (List(Nil), Nil) => ListOfNil
case (_, paramss) => paramss
}
assert(
@@ -1390,6 +1402,7 @@ trait Namers extends MethodSynthesis {
fail(ImplicitAtToplevel)
}
if (sym.isClass) {
+ checkNoConflict(IMPLICIT, CASE)
if (sym.isAnyOverride && !sym.hasFlag(TRAIT))
fail(OverrideClass)
} else {
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 6eeba2b4bf..c60118a8b4 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -277,7 +277,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
if(phase.id >= currentRun.uncurryPhase.id) debugwarn("running translateMatch at "+ phase +" on "+ selector +" match "+ cases)
patmatDebug("translating "+ cases.mkString("{", "\n", "}"))
- val start = Statistics.startTimer(patmatNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatNanos) else null
val selectorTp = repeatedToSeq(elimAnonymousClass(selector.tpe.widen.withoutAnnotations))
@@ -305,7 +305,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// pt = Any* occurs when compiling test/files/pos/annotDepMethType.scala with -Xexperimental
val combined = combineCases(selector, selectorSym, cases map translateCase(selectorSym, pt), pt, matchOwner, matchFailGenOverride)
- Statistics.stopTimer(patmatNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatNanos, start)
combined
}
@@ -1954,7 +1954,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// TODO: for V1 representing x1 and V2 standing for x1.head, encode that
// V1 = Nil implies -(V2 = Ci) for all Ci in V2's domain (i.e., it is unassignable)
def removeVarEq(props: List[Prop], modelNull: Boolean = false): (Prop, List[Prop]) = {
- val start = Statistics.startTimer(patmatAnaVarEq)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaVarEq) else null
val vars = new collection.mutable.HashSet[Var]
@@ -2009,7 +2009,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("eqAxioms:\n"+ cnfString(eqFreePropToSolvable(eqAxioms)))
patmatDebug("pure:"+ pure.map(p => cnfString(eqFreePropToSolvable(p))).mkString("\n"))
- Statistics.stopTimer(patmatAnaVarEq, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaVarEq, start)
(eqAxioms, pure)
}
@@ -2040,6 +2040,11 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
trait CNF extends Logic {
// CNF: a formula is a conjunction of clauses
type Formula = Array[Clause]
+ /** Override Array creation for efficiency (to not go through reflection). */
+ private implicit val formulaTag: scala.reflect.ClassTag[Formula] = new scala.reflect.ClassTag[Formula] {
+ def runtimeClass: java.lang.Class[Formula] = classOf[Formula]
+ final override def newArray(len: Int): Array[Formula] = new Array[Formula](len)
+ }
def formula(c: Clause*): Formula = c.toArray
def andFormula(a: Formula, b: Formula): Formula = a ++ b
@@ -2116,13 +2121,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- val start = Statistics.startTimer(patmatCNF)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatCNF) else null
val res = conjunctiveNormalForm(negationNormalForm(p))
- Statistics.stopTimer(patmatCNF, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatCNF, start)
//
- if (Statistics.enabled) patmatCNFSizes(res.size).value += 1
+ if (Statistics.canEnable) patmatCNFSizes(res.size).value += 1
// patmatDebug("cnf for\n"+ p +"\nis:\n"+cnfString(res))
res
@@ -2199,7 +2204,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
patmatDebug("DPLL\n"+ cnfString(f))
- val start = Statistics.startTimer(patmatAnaDPLL)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaDPLL) else null
val satisfiableWithModel: Model =
if (f isEmpty) EmptyModel
@@ -2237,7 +2242,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- Statistics.stopTimer(patmatAnaDPLL, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaDPLL, start)
satisfiableWithModel
}
@@ -2598,7 +2603,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// thus, the case is unreachable if there is no model for -(-P /\ C),
// or, equivalently, P \/ -C, or C => P
def unreachableCase(prevBinder: Symbol, cases: List[List[TreeMaker]], pt: Type): Option[Int] = {
- val start = Statistics.startTimer(patmatAnaReach)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaReach) else null
// use the same approximator so we share variables,
// but need different conditions depending on whether we're conservatively looking for failure or success
@@ -2652,7 +2657,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
}
}
- Statistics.stopTimer(patmatAnaReach, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaReach, start)
if (reachable) None else Some(caseIndex)
} catch {
@@ -2745,7 +2750,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// - back off (to avoid crying exhaustive too often) when:
// - there are guards -->
// - there are extractor calls (that we can't secretly/soundly) rewrite
- val start = Statistics.startTimer(patmatAnaExhaust)
+ val start = if (Statistics.canEnable) Statistics.startTimer(patmatAnaExhaust) else null
var backoff = false
val approx = new TreeMakersToConds(prevBinder)
@@ -2797,7 +2802,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
val pruned = CounterExample.prune(counterExamples).map(_.toString).sorted
- Statistics.stopTimer(patmatAnaExhaust, start)
+ if (Statistics.canEnable) Statistics.stopTimer(patmatAnaExhaust, start)
pruned
} catch {
case ex : AnalysisBudget.Exception =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 41387b7507..166bb2d18c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -124,7 +124,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
defaultMethodNames.toList.distinct foreach { name =>
val methods = clazz.info.findMember(name, 0L, METHOD, false).alternatives
- val haveDefaults = methods filter (sym => sym.hasParamWhich(_.hasDefault) && !nme.isProtectedAccessorName(sym.name))
+ def hasDefaultParam(tpe: Type): Boolean = tpe match {
+ case MethodType(params, restpe) => (params exists (_.hasDefault)) || hasDefaultParam(restpe)
+ case _ => false
+ }
+ val haveDefaults = methods filter (sym => hasDefaultParam(sym.info) && !nme.isProtectedAccessorName(sym.name))
if (haveDefaults.lengthCompare(1) > 0) {
val owners = haveDefaults map (_.owner)
@@ -937,9 +941,9 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
case TypeBounds(lo, hi) =>
validateVariance(lo, -variance)
validateVariance(hi, variance)
- case MethodType(formals, result) =>
+ case mt @ MethodType(formals, result) =>
if (inRefinement)
- validateVariances(formals map (_.tpe), -variance)
+ validateVariances(mt.paramTypes, -variance)
validateVariance(result, variance)
case NullaryMethodType(result) =>
validateVariance(result, variance)
@@ -1298,13 +1302,12 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
def transformStat(tree: Tree, index: Int): List[Tree] = tree match {
case t if treeInfo.isSelfConstrCall(t) =>
assert(index == 0, index)
- val t = transform(tree)
- if (currentLevel.maxindex > 0) {
+ try transform(tree) :: Nil
+ finally if (currentLevel.maxindex > 0) {
// An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717
debuglog("refsym = " + currentLevel.refsym)
unit.error(currentLevel.refpos, "forward reference not allowed from self constructor invocation")
}
- List(t)
case ModuleDef(_, _, _) => eliminateModuleDefs(tree)
case ValDef(_, _, _, _) =>
val tree1 @ ValDef(_, _, _, rhs) = transform(tree) // important to do before forward reference check
@@ -1316,11 +1319,11 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
debuglog("refsym = " + currentLevel.refsym)
unit.error(currentLevel.refpos, "forward reference extends over definition of " + lazySym)
}
- List(tree1)
+ tree1 :: Nil
}
case Import(_, _) => Nil
case DefDef(mods, _, _, _, _, _) if (mods hasFlag MACRO) || (tree.symbol hasFlag MACRO) => Nil
- case _ => List(transform(tree))
+ case _ => transform(tree) :: Nil
}
/* Check whether argument types conform to bounds of type parameters */
@@ -1615,6 +1618,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
if ((clazz isSubClass AnyValClass) && !isPrimitiveValueClass(clazz)) {
if (clazz.isTrait)
unit.error(clazz.pos, "Only classes (not traits) are allowed to extend AnyVal")
+ else if ((clazz != AnyValClass) && clazz.hasFlag(ABSTRACT))
+ unit.error(clazz.pos, "`abstract' modifier cannot be used with value classes")
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index d2a89eb9ff..63050bc032 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -70,7 +70,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
storeAccessorDefinition(clazz, DefDef(acc, EmptyTree))
acc
}
-
+
atPos(sel.pos)(Select(gen.mkAttributedThis(clazz), superAcc) setType sel.tpe)
}
@@ -170,6 +170,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
treeCopy.CaseDef(tree, pat, transform(guard), transform(body))
case ClassDef(_, _, _, _) =>
+ def transformClassDef = {
checkCompanionNameClashes(sym)
val decls = sym.info.decls
for (s <- decls) {
@@ -195,12 +196,15 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
super.transform(tree)
+ }
+ transformClassDef
case ModuleDef(_, _, _) =>
checkCompanionNameClashes(sym)
super.transform(tree)
case Template(_, _, body) =>
+ def transformTemplate = {
val ownAccDefs = new ListBuffer[Tree]
accDefs(currentOwner) = ownAccDefs
@@ -213,6 +217,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
accDefs -= currentOwner
ownAccDefs ++= body1
deriveTemplate(tree)(_ => ownAccDefs.toList)
+ }
+ transformTemplate
case TypeApply(sel @ Select(This(_), name), args) =>
mayNeedProtectedAccessor(sel, args, false)
@@ -227,6 +233,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
typeDef
case sel @ Select(qual, name) =>
+ def transformSelect = {
/** return closest enclosing method, unless shadowed by an enclosing class;
* no use of closures here in the interest of speed.
*/
@@ -290,7 +297,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
log("Ensuring accessor for call to protected " + sym.fullLocationString + " from " + currentClass)
ensureAccessor(sel)
} else
- mayNeedProtectedAccessor(sel, List(EmptyTree), false)
+ mayNeedProtectedAccessor(sel, EmptyTree.asList, false)
}
case Super(_, mix) =>
@@ -303,8 +310,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
transformSuperSelect(sel)
case _ =>
- mayNeedProtectedAccessor(sel, List(EmptyTree), true)
+ mayNeedProtectedAccessor(sel, EmptyTree.asList, true)
+ }
}
+ transformSelect
case DefDef(mods, name, tparams, vparamss, tpt, rhs) if tree.symbol.isMethodWithExtension =>
treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, withInvalidOwner(transform(rhs)))
@@ -313,6 +322,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
mayNeedProtectedAccessor(sel, args, true)
case Assign(lhs @ Select(qual, name), rhs) =>
+ def transformAssign = {
if (lhs.symbol.isVariable &&
lhs.symbol.isJavaDefined &&
needsProtectedAccessor(lhs.symbol, tree.pos)) {
@@ -322,6 +332,8 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
transform(localTyper.typed(Apply(setter, List(qual, rhs))))
} else
super.transform(tree)
+ }
+ transformAssign
case Apply(fn, args) =>
assert(fn.tpe != null, tree)
@@ -345,9 +357,22 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
- override def atOwner[A](owner: Symbol)(trans: => A): A = {
+ /** a typer for each enclosing class */
+ private var typers = immutable.Map[Symbol, analyzer.Typer]()
+
+ /** Specialized here for performance; the previous blanked
+ * introduction of typers in TypingTransformer caused a >5%
+ * performance hit for the compiler as a whole.
+ */
+ override def atOwner[A](tree: Tree, owner: Symbol)(trans: => A): A = {
if (owner.isClass) validCurrentOwner = true
- super.atOwner(owner)(trans)
+ val savedLocalTyper = localTyper
+ localTyper = localTyper.atOwner(tree, if (owner.isModule) owner.moduleClass else owner)
+ typers = typers updated (owner, localTyper)
+ val result = super.atOwner(tree, owner)(trans)
+ localTyper = savedLocalTyper
+ typers -= owner
+ result
}
private def withInvalidOwner[A](trans: => A): A = {
@@ -500,7 +525,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
)
true
}
- isCandidate && !host.isPackageClass && !isSelfType
+ isCandidate && !host.isPackageClass && !isSelfType
}
/** Return the innermost enclosing class C of referencingClass for which either
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9b07eed5d7..f6baf02c3e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -104,7 +104,8 @@ trait Typers extends Modes with Adaptations with Tags {
tp.isError || pt.isError ||
context0.implicitsEnabled && // this condition prevents chains of views
inferView(EmptyTree, tp, pt, false) != EmptyTree
- }}
+ }
+ }
/** Find implicit arguments and pass them to given tree.
*/
@@ -194,16 +195,14 @@ trait Typers extends Modes with Adaptations with Tags {
case PolyType(_, _) => EmptyTree
case _ =>
def wrapImplicit(from: Type): Tree = {
- val result = inferImplicit(tree, functionType(List(from), to), reportAmbiguous, true, context, saveErrors)
+ val result = inferImplicit(tree, functionType(from :: Nil, to), reportAmbiguous, true, context, saveErrors)
if (result.subst != EmptyTreeTypeSubstituter) {
result.subst traverse tree
notifyUndetparamsInferred(result.subst.from, result.subst.to)
}
result.tree
}
- val result = wrapImplicit(from)
- if (result != EmptyTree) result
- else wrapImplicit(byNameType(from))
+ wrapImplicit(from) orElse wrapImplicit(byNameType(from))
}
}
@@ -354,7 +353,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (formals exists (isRepeatedParamType(_)))
error(pos, "methods with `*`-parameters cannot be converted to function values");
*/
- if (restpe.isDependent)
+ if (tpe.isDependentMethodType)
DependentMethodTpeConversionToFunctionError(tree, tpe)
checkParamsConvertible(tree, restpe)
case _ =>
@@ -608,21 +607,23 @@ trait Typers extends Modes with Adaptations with Tags {
/** Is `sym` defined in package object of package `pkg`?
*/
- private def isInPackageObject(sym: Symbol, pkg: Symbol) =
- pkg.isPackageClass && {
- sym.alternatives forall { sym =>
- !sym.owner.isPackage && {
- sym.owner.isPackageObjectClass &&
+ private def isInPackageObject(sym: Symbol, pkg: Symbol) = {
+ def isInPkgObj(sym: Symbol) =
+ !sym.owner.isPackage && {
+ sym.owner.isPackageObjectClass &&
sym.owner.owner == pkg ||
pkg.isInitialized && {
// need to be careful here to not get a cyclic reference during bootstrap
val pkgobj = pkg.info.member(nme.PACKAGEkw)
pkgobj.isInitialized &&
- (pkgobj.info.member(sym.name).alternatives contains sym)
+ (pkgobj.info.member(sym.name).alternatives contains sym)
}
- }
}
+ pkg.isPackageClass && {
+ if (sym.isOverloaded) sym.alternatives forall isInPkgObj
+ else isInPkgObj(sym)
}
+ }
/** Post-process an identifier or selection node, performing the following:
* 1. Check that non-function pattern expressions are stable
@@ -705,15 +706,15 @@ trait Typers extends Modes with Adaptations with Tags {
def silent[T](op: Typer => T,
reportAmbiguousErrors: Boolean = context.ambiguousErrors,
newtree: Tree = context.tree): SilentResult[T] = {
- val rawTypeStart = Statistics.startCounter(rawTypeFailed)
- val findMemberStart = Statistics.startCounter(findMemberFailed)
- val subtypeStart = Statistics.startCounter(subtypeFailed)
- val failedSilentStart = Statistics.startTimer(failedSilentNanos)
+ val rawTypeStart = if (Statistics.canEnable) Statistics.startCounter(rawTypeFailed) else null
+ val findMemberStart = if (Statistics.canEnable) Statistics.startCounter(findMemberFailed) else null
+ val subtypeStart = if (Statistics.canEnable) Statistics.startCounter(subtypeFailed) else null
+ val failedSilentStart = if (Statistics.canEnable) Statistics.startTimer(failedSilentNanos) else null
def stopStats() = {
- Statistics.stopCounter(rawTypeFailed, rawTypeStart)
- Statistics.stopCounter(findMemberFailed, findMemberStart)
- Statistics.stopCounter(subtypeFailed, subtypeStart)
- Statistics.stopTimer(failedSilentNanos, failedSilentStart)
+ if (Statistics.canEnable) Statistics.stopCounter(rawTypeFailed, rawTypeStart)
+ if (Statistics.canEnable) Statistics.stopCounter(findMemberFailed, findMemberStart)
+ if (Statistics.canEnable) Statistics.stopCounter(subtypeFailed, subtypeStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedSilentNanos, failedSilentStart)
}
try {
if (context.reportErrors ||
@@ -1133,109 +1134,112 @@ trait Typers extends Modes with Adaptations with Tags {
} else if (tree.tpe <:< pt) {
tree
} else {
- if (inPatternMode(mode)) {
- if ((tree.symbol ne null) && tree.symbol.isModule)
- inferModulePattern(tree, pt)
- if (isPopulated(tree.tpe, approximateAbstracts(pt)))
- return tree
- }
- val tree1 = constfold(tree, pt) // (10) (11)
- if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
- else {
- if (inExprModeButNot(mode, FUNmode)) {
- pt.normalize match {
- case TypeRef(_, sym, _) =>
- // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
- // infinite expansion if pt is constant type ()
- if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) { // (12)
- if (settings.warnValueDiscard.value)
- context.unit.warning(tree.pos, "discarded non-Unit value")
- return typed(atPos(tree.pos)(Block(List(tree), Literal(Constant()))), mode, pt)
- } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) {
- if (settings.warnNumericWiden.value)
- context.unit.warning(tree.pos, "implicit numeric widening")
- return typed(atPos(tree.pos)(Select(tree, "to" + sym.name)), mode, pt)
- }
- case AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (13)
- return typed(adaptAnnotations(tree, mode, pt), mode, pt)
- case _ =>
- }
- if (!context.undetparams.isEmpty) {
- return instantiate(tree, mode, pt)
- }
- if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
- // (14); the condition prevents chains of views
- debuglog("inferring view from " + tree.tpe + " to " + pt)
- val coercion = inferView(tree, tree.tpe, pt, true)
- // convert forward views of delegate types into closures wrapped around
- // the delegate's apply method (the "Invoke" method, which was translated into apply)
- if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {
- val meth: Symbol = tree.tpe.member(nme.apply)
- debuglog("replacing forward delegate view with: " + meth + ":" + meth.tpe)
- return typed(Select(tree, meth), mode, pt)
+ def fallBack: Tree = {
+ if (inPatternMode(mode)) {
+ if ((tree.symbol ne null) && tree.symbol.isModule)
+ inferModulePattern(tree, pt)
+ if (isPopulated(tree.tpe, approximateAbstracts(pt)))
+ return tree
+ }
+ val tree1 = constfold(tree, pt) // (10) (11)
+ if (tree1.tpe <:< pt) adapt(tree1, mode, pt, original)
+ else {
+ if (inExprModeButNot(mode, FUNmode)) {
+ pt.normalize match {
+ case TypeRef(_, sym, _) =>
+ // note: was if (pt.typeSymbol == UnitClass) but this leads to a potentially
+ // infinite expansion if pt is constant type ()
+ if (sym == UnitClass && tree.tpe <:< AnyClass.tpe) { // (12)
+ if (settings.warnValueDiscard.value)
+ context.unit.warning(tree.pos, "discarded non-Unit value")
+ return typed(atPos(tree.pos)(Block(List(tree), Literal(Constant()))), mode, pt)
+ } else if (isNumericValueClass(sym) && isNumericSubType(tree.tpe, pt)) {
+ if (settings.warnNumericWiden.value)
+ context.unit.warning(tree.pos, "implicit numeric widening")
+ return typed(atPos(tree.pos)(Select(tree, "to" + sym.name)), mode, pt)
+ }
+ case AnnotatedType(_, _, _) if canAdaptAnnotations(tree, mode, pt) => // (13)
+ return typed(adaptAnnotations(tree, mode, pt), mode, pt)
+ case _ =>
}
- if (coercion != EmptyTree) {
- def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe
- if (settings.logImplicitConv.value)
- unit.echo(tree.pos, msg)
-
- debuglog(msg)
- val silentContext = context.makeImplicit(context.ambiguousErrors)
- val res = newTyper(silentContext).typed(
- new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
+ if (!context.undetparams.isEmpty) {
+ return instantiate(tree, mode, pt)
+ }
+ if (context.implicitsEnabled && !pt.isError && !tree.isErrorTyped) {
+ // (14); the condition prevents chains of views
+ debuglog("inferring view from " + tree.tpe + " to " + pt)
+ val coercion = inferView(tree, tree.tpe, pt, true)
+ // convert forward views of delegate types into closures wrapped around
+ // the delegate's apply method (the "Invoke" method, which was translated into apply)
+ if (forMSIL && coercion != null && isCorrespondingDelegate(tree.tpe, pt)) {
+ val meth: Symbol = tree.tpe.member(nme.apply)
+ debuglog("replacing forward delegate view with: " + meth + ":" + meth.tpe)
+ return typed(Select(tree, meth), mode, pt)
+ }
+ if (coercion != EmptyTree) {
+ def msg = "inferred view from " + tree.tpe + " to " + pt + " = " + coercion + ":" + coercion.tpe
+ if (settings.logImplicitConv.value)
+ unit.echo(tree.pos, msg)
+
+ debuglog(msg)
+ val silentContext = context.makeImplicit(context.ambiguousErrors)
+ val res = newTyper(silentContext).typed(
+ new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
+ if (silentContext.hasErrors) context.issue(silentContext.errBuffer.head) else return res
+ }
}
}
- }
- if (settings.debug.value) {
- log("error tree = " + tree)
- if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
- }
+ if (settings.debug.value) {
+ log("error tree = " + tree)
+ if (settings.explaintypes.value) explainTypes(tree.tpe, pt)
+ }
- val found = tree.tpe
- if (!found.isErroneous && !pt.isErroneous) {
- if (!context.reportErrors && isPastTyper) {
- val (bound, req) = pt match {
- case ExistentialType(qs, tpe) => (qs, tpe)
- case _ => (Nil, pt)
- }
- val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams
- if (boundOrSkolems.nonEmpty) {
- // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
- // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
- // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
- //
- // val x: T = expr
- //
- // where T is the type of expr, but T contains existential skolems ts.
- // In that case, this value definition does not typecheck.
- // The value definition
- //
- // val x: T forSome { ts } = expr
- //
- // would typecheck. Or one can simply leave out the type of the `val`:
- //
- // val x = expr
- //
- // SI-6029 shows another case where we also fail (in uncurry), but this time the expected
- // type is an existential type.
- //
- // The reason for both failures have to do with the way we (don't) transform
- // skolem types along with the trees that contain them. We'd need a
- // radically different approach to do it. But before investing a lot of time to
- // to do this (I have already sunk 3 full days with in the end futile attempts
- // to consistently transform skolems and fix 6029), I'd like to
- // investigate ways to avoid skolems completely.
- //
- 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))
+ val found = tree.tpe
+ if (!found.isErroneous && !pt.isErroneous) {
+ if (!context.reportErrors && isPastTyper) {
+ val (bound, req) = pt match {
+ case ExistentialType(qs, tpe) => (qs, tpe)
+ case _ => (Nil, pt)
+ }
+ val boundOrSkolems = bound ++ pt.skolemsExceptMethodTypeParams
+ if (boundOrSkolems.nonEmpty) {
+ // Ignore type errors raised in later phases that are due to mismatching types with existential skolems
+ // We have lift crashing in 2.9 with an adapt failure in the pattern matcher.
+ // Here's my hypothsis why this happens. The pattern matcher defines a variable of type
+ //
+ // val x: T = expr
+ //
+ // where T is the type of expr, but T contains existential skolems ts.
+ // In that case, this value definition does not typecheck.
+ // The value definition
+ //
+ // val x: T forSome { ts } = expr
+ //
+ // would typecheck. Or one can simply leave out the type of the `val`:
+ //
+ // val x = expr
+ //
+ // SI-6029 shows another case where we also fail (in uncurry), but this time the expected
+ // type is an existential type.
+ //
+ // The reason for both failures have to do with the way we (don't) transform
+ // skolem types along with the trees that contain them. We'd need a
+ // radically different approach to do it. But before investing a lot of time to
+ // to do this (I have already sunk 3 full days with in the end futile attempts
+ // to consistently transform skolems and fix 6029), I'd like to
+ // investigate ways to avoid skolems completely.
+ //
+ 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))
+ }
}
+ // create an actual error
+ AdaptTypeError(tree, found, pt)
}
- // create an actual error
- AdaptTypeError(tree, found, pt)
+ setError(tree)
}
- setError(tree)
}
+ fallBack
}
}
}
@@ -2504,7 +2508,7 @@ trait Typers extends Modes with Adaptations with Tags {
def translated =
if (members.head eq EmptyTree) setError(tree)
- else typed(atPos(tree.pos)(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos.focus)), atPos(tree.pos.focus)(New(anonClass.tpe)))), mode, pt)
+ else typed(atPos(tree.pos)(Block(List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus)), atPos(tree.pos.focus)(New(anonClass.tpe)))), mode, pt)
}
// Function(params, Match(sel, cases)) ==> new <Partial>Function { def apply<OrElse>(params) = `translateMatch('sel match { cases }')` }
@@ -2850,73 +2854,79 @@ trait Typers extends Modes with Adaptations with Tags {
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
- var fun = fun0
- if (fun.hasSymbol && fun.symbol.isOverloaded) {
- // remove alternatives with wrong number of parameters without looking at types.
- // less expensive than including them in inferMethodAlternatvie (see below).
- def shapeType(arg: Tree): Type = arg match {
- case Function(vparams, body) =>
- functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
- case AssignOrNamedArg(Ident(name), rhs) =>
- NamedType(name, shapeType(rhs))
- case _ =>
- NothingClass.tpe
- }
- val argtypes = args map shapeType
- val pre = fun.symbol.tpe.prefix
-
- var sym = fun.symbol filter { alt =>
- // must use pt as expected type, not WildcardType (a tempting quick fix to #2665)
- // now fixed by using isWeaklyCompatible in exprTypeArgs
- // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed)
- // (I had expected inferMethodAlternative to pick up the slack introduced by using WildcardType here)
- //
- // @PP responds: I changed it to pass WildcardType instead of pt and only one line in
- // trunk (excluding scalacheck, which had another) failed to compile. It was this line in
- // Types: "refs = Array(Map(), Map())". I determined that inference fails if there are at
- // least two invariant type parameters. See the test case I checked in to help backstop:
- // pos/isApplicableSafe.scala.
- isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
- }
- if (sym.isOverloaded) {
- val sym1 = sym filter (alt => {
- // eliminate functions that would result from tupling transforms
- // keeps alternatives with repeated params
- hasExactlyNumParams(followApply(alt.tpe), argtypes.length) ||
- // also keep alts which define at least one default
- alt.tpe.paramss.exists(_.exists(_.hasDefault))
- })
- if (sym1 != NoSymbol) sym = sym1
- }
- if (sym != NoSymbol)
- fun = adapt(fun setSymbol sym setType pre.memberType(sym), forFunMode(mode), WildcardType)
+ def preSelectOverloaded(fun: Tree): Tree = {
+ if (fun.hasSymbol && fun.symbol.isOverloaded) {
+ // remove alternatives with wrong number of parameters without looking at types.
+ // less expensive than including them in inferMethodAlternatvie (see below).
+ def shapeType(arg: Tree): Type = arg match {
+ case Function(vparams, body) =>
+ functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
+ case AssignOrNamedArg(Ident(name), rhs) =>
+ NamedType(name, shapeType(rhs))
+ case _ =>
+ NothingClass.tpe
+ }
+ val argtypes = args map shapeType
+ val pre = fun.symbol.tpe.prefix
+
+ var sym = fun.symbol filter { alt =>
+ // must use pt as expected type, not WildcardType (a tempting quick fix to #2665)
+ // now fixed by using isWeaklyCompatible in exprTypeArgs
+ // TODO: understand why exactly -- some types were not inferred anymore (`ant clean quick.bin` failed)
+ // (I had expected inferMethodAlternative to pick up the slack introduced by using WildcardType here)
+ //
+ // @PP responds: I changed it to pass WildcardType instead of pt and only one line in
+ // trunk (excluding scalacheck, which had another) failed to compile. It was this line in
+ // Types: "refs = Array(Map(), Map())". I determined that inference fails if there are at
+ // least two invariant type parameters. See the test case I checked in to help backstop:
+ // pos/isApplicableSafe.scala.
+ isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
+ }
+ if (sym.isOverloaded) {
+ val sym1 = sym filter (alt => {
+ // eliminate functions that would result from tupling transforms
+ // keeps alternatives with repeated params
+ hasExactlyNumParams(followApply(alt.tpe), argtypes.length) ||
+ // also keep alts which define at least one default
+ alt.tpe.paramss.exists(_.exists(_.hasDefault))
+ })
+ if (sym1 != NoSymbol) sym = sym1
+ }
+ if (sym == NoSymbol) fun
+ else adapt(fun setSymbol sym setType pre.memberType(sym), forFunMode(mode), WildcardType)
+ } else fun
}
+ val fun = preSelectOverloaded(fun0)
+
fun.tpe match {
case OverloadedType(pre, alts) =>
- val undetparams = context.extractUndetparams()
-
- val argtpes = new ListBuffer[Type]
- val amode = forArgMode(fun, mode)
- val args1 = args map {
- case arg @ AssignOrNamedArg(Ident(name), rhs) =>
- // named args: only type the righthand sides ("unknown identifier" errors otherwise)
- val rhs1 = typedArg(rhs, amode, BYVALmode, WildcardType)
- argtpes += NamedType(name, rhs1.tpe.deconst)
- // the assign is untyped; that's ok because we call doTypedApply
- atPos(arg.pos) { new AssignOrNamedArg(arg.lhs , rhs1) }
- case arg =>
- val arg1 = typedArg(arg, amode, BYVALmode, WildcardType)
- argtpes += arg1.tpe.deconst
- arg1
- }
- context.undetparams = undetparams
- if (context.hasErrors)
- setError(tree)
- else {
- inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
- doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ def handleOverloaded = {
+ val undetparams = context.extractUndetparams()
+
+ val argtpes = new ListBuffer[Type]
+ val amode = forArgMode(fun, mode)
+ val args1 = args map {
+ case arg @ AssignOrNamedArg(Ident(name), rhs) =>
+ // named args: only type the righthand sides ("unknown identifier" errors otherwise)
+ val rhs1 = typedArg(rhs, amode, BYVALmode, WildcardType)
+ argtpes += NamedType(name, rhs1.tpe.deconst)
+ // the assign is untyped; that's ok because we call doTypedApply
+ atPos(arg.pos) { new AssignOrNamedArg(arg.lhs, rhs1) }
+ case arg =>
+ val arg1 = typedArg(arg, amode, BYVALmode, WildcardType)
+ argtpes += arg1.tpe.deconst
+ arg1
+ }
+ context.undetparams = undetparams
+ if (context.hasErrors)
+ setError(tree)
+ else {
+ inferMethodAlternative(fun, undetparams, argtpes.toList, pt, varArgsOnly = treeInfo.isWildcardStarArgList(args))
+ doTypedApply(tree, adapt(fun, forFunMode(mode), WildcardType), args1, mode, pt)
+ }
}
+ handleOverloaded
case mt @ MethodType(params, _) =>
val paramTypes = mt.paramTypes
@@ -3037,101 +3047,107 @@ trait Typers extends Modes with Adaptations with Tags {
} else {
val tparams = context.extractUndetparams()
if (tparams.isEmpty) { // all type params are defined
- // In order for checkDead not to be misled by the unfortunate special
- // case of AnyRef#synchronized (which is implemented with signature T => T
- // but behaves as if it were (=> T) => T) we need to know what is the actual
- // target of a call. Since this information is no longer available from
- // typedArg, it is recorded here.
- checkDead.updateExpr(fun)
-
- val args1 =
- // no expected type when jumping to a match label -- anything goes (this is ok since we're typing the translation of well-typed code)
- // ... except during erasure: we must take the expected type into account as it drives the insertion of casts!
- // I've exhausted all other semi-clean approaches I could think of in balancing GADT magic, SI-6145, CPS type-driven transforms and other existential trickiness
- // (the right thing to do -- packing existential types -- runs into limitations in subtyping existential types,
- // casting breaks SI-6145,
- // not casting breaks GADT typing as it requires sneaking ill-typed trees past typer)
- if (!phase.erasedTypes && fun.symbol.isLabel && treeInfo.isSynthCaseSymbol(fun.symbol))
- typedArgs(args, forArgMode(fun, mode))
- else
- typedArgs(args, forArgMode(fun, mode), paramTypes, formals)
-
- // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
- // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
- // precise(foo) : foo.type => foo.type
- val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
- def ifPatternSkipFormals(tp: Type) = tp match {
- case MethodType(_, rtp) if (inPatternMode(mode)) => rtp
- case _ => tp
- }
+ def handleMonomorphicCall: Tree = {
+ // In order for checkDead not to be misled by the unfortunate special
+ // case of AnyRef#synchronized (which is implemented with signature T => T
+ // but behaves as if it were (=> T) => T) we need to know what is the actual
+ // target of a call. Since this information is no longer available from
+ // typedArg, it is recorded here.
+ checkDead.updateExpr(fun)
+
+ val args1 =
+ // no expected type when jumping to a match label -- anything goes (this is ok since we're typing the translation of well-typed code)
+ // ... except during erasure: we must take the expected type into account as it drives the insertion of casts!
+ // I've exhausted all other semi-clean approaches I could think of in balancing GADT magic, SI-6145, CPS type-driven transforms and other existential trickiness
+ // (the right thing to do -- packing existential types -- runs into limitations in subtyping existential types,
+ // casting breaks SI-6145,
+ // not casting breaks GADT typing as it requires sneaking ill-typed trees past typer)
+ if (!phase.erasedTypes && fun.symbol.isLabel && treeInfo.isSynthCaseSymbol(fun.symbol))
+ typedArgs(args, forArgMode(fun, mode))
+ else
+ typedArgs(args, forArgMode(fun, mode), paramTypes, formals)
+
+ // instantiate dependent method types, must preserve singleton types where possible (stableTypeFor) -- example use case:
+ // val foo = "foo"; def precise(x: String)(y: x.type): x.type = {...}; val bar : foo.type = precise(foo)(foo)
+ // precise(foo) : foo.type => foo.type
+ val restpe = mt.resultType(args1 map (arg => gen.stableTypeFor(arg) getOrElse arg.tpe))
+ def ifPatternSkipFormals(tp: Type) = tp match {
+ case MethodType(_, rtp) if (inPatternMode(mode)) => rtp
+ case _ => tp
+ }
- // Replace the Delegate-Chainer methods += and -= with corresponding
- // + and - calls, which are translated in the code generator into
- // Combine and Remove
- if (forMSIL) {
- fun match {
- case Select(qual, name) =>
- if (isSubType(qual.tpe, DelegateClass.tpe)
- && (name == encode("+=") || name == encode("-=")))
- {
- val n = if (name == encode("+=")) nme.PLUS else nme.MINUS
- val f = Select(qual, n)
- // the compiler thinks, the PLUS method takes only one argument,
- // but he thinks it's an instance method -> still two ref's on the stack
- // -> translated by backend
- val rhs = treeCopy.Apply(tree, f, args)
- return typed(Assign(qual, rhs))
- }
- case _ => ()
+ // Replace the Delegate-Chainer methods += and -= with corresponding
+ // + and - calls, which are translated in the code generator into
+ // Combine and Remove
+ if (forMSIL) {
+ fun match {
+ case Select(qual, name) =>
+ if (isSubType(qual.tpe, DelegateClass.tpe)
+ && (name == encode("+=") || name == encode("-="))) {
+ val n = if (name == encode("+=")) nme.PLUS else nme.MINUS
+ val f = Select(qual, n)
+ // the compiler thinks, the PLUS method takes only one argument,
+ // but he thinks it's an instance method -> still two ref's on the stack
+ // -> translated by backend
+ val rhs = treeCopy.Apply(tree, f, args)
+ return typed(Assign(qual, rhs))
+ }
+ case _ => ()
+ }
}
- }
- /** This is translating uses of List() into Nil. This is less
- * than ideal from a consistency standpoint, but it shouldn't be
- * altered without due caution.
- * ... this also causes bootstrapping cycles if List_apply is
- * forced during kind-arity checking, so it is guarded by additional
- * tests to ensure we're sufficiently far along.
- */
- if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply))
- atPos(tree.pos)(gen.mkNil setType restpe)
- else
- constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe))
+ /**
+ * This is translating uses of List() into Nil. This is less
+ * than ideal from a consistency standpoint, but it shouldn't be
+ * altered without due caution.
+ * ... this also causes bootstrapping cycles if List_apply is
+ * forced during kind-arity checking, so it is guarded by additional
+ * tests to ensure we're sufficiently far along.
+ */
+ if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply))
+ atPos(tree.pos)(gen.mkNil setType restpe)
+ else
+ constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe))
+ }
+ handleMonomorphicCall
} else if (needsInstantiation(tparams, formals, args)) {
//println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
inferExprInstance(fun, tparams)
doTypedApply(tree, fun, args, mode, pt)
} else {
- assert(!inPatternMode(mode), modeString(mode)) // this case cannot arise for patterns
- val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
- val strictTargs = map2(lenientTargs, tparams)((targ, tparam) =>
- if (targ == WildcardType) tparam.tpeHK else targ)
- var remainingParams = paramTypes
- def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup
- val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
- val newmode =
- if (isByNameParamType(remainingParams.head)) POLYmode
- else POLYmode | BYVALmode
- if (remainingParams.tail.nonEmpty) remainingParams = remainingParams.tail
- val arg1 = typedArg(arg, forArgMode(fun, mode), newmode, lenientPt)
- val argtparams = context.extractUndetparams()
- if (!argtparams.isEmpty) {
- val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
- inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
- arg1
- } else arg1
- }
- val args1 = map2(args, formals)(typedArgToPoly)
- if (args1 exists {_.isErrorTyped}) duplErrTree
- else {
- debuglog("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(_.tpe)+", pt = "+pt+", lobounds = "+tparams.map(_.tpe.bounds.lo)+", parambounds = "+tparams.map(_.info)) //debug
- // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
- // returns those undetparams which have not been instantiated.
- val undetparams = inferMethodInstance(fun, tparams, args1, pt)
- val result = doTypedApply(tree, fun, args1, mode, pt)
- context.undetparams = undetparams
- result
+ def handlePolymorphicCall = {
+ assert(!inPatternMode(mode), modeString(mode)) // this case cannot arise for patterns
+ val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
+ val strictTargs = map2(lenientTargs, tparams)((targ, tparam) =>
+ if (targ == WildcardType) tparam.tpeHK else targ)
+ var remainingParams = paramTypes
+ def typedArgToPoly(arg: Tree, formal: Type): Tree = { //TR TODO: cleanup
+ val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs)
+ val newmode =
+ if (isByNameParamType(remainingParams.head)) POLYmode
+ else POLYmode | BYVALmode
+ if (remainingParams.tail.nonEmpty) remainingParams = remainingParams.tail
+ val arg1 = typedArg(arg, forArgMode(fun, mode), newmode, lenientPt)
+ val argtparams = context.extractUndetparams()
+ if (!argtparams.isEmpty) {
+ val strictPt = formal.instantiateTypeParams(tparams, strictTargs)
+ inferArgumentInstance(arg1, argtparams, strictPt, lenientPt)
+ arg1
+ } else arg1
+ }
+ val args1 = map2(args, formals)(typedArgToPoly)
+ if (args1 exists { _.isErrorTyped }) duplErrTree
+ else {
+ debuglog("infer method inst " + fun + ", tparams = " + tparams + ", args = " + args1.map(_.tpe) + ", pt = " + pt + ", lobounds = " + tparams.map(_.tpe.bounds.lo) + ", parambounds = " + tparams.map(_.info)) //debug
+ // define the undetparams which have been fixed by this param list, replace the corresponding symbols in "fun"
+ // returns those undetparams which have not been instantiated.
+ val undetparams = inferMethodInstance(fun, tparams, args1, pt)
+ val result = doTypedApply(tree, fun, args1, mode, pt)
+ context.undetparams = undetparams
+ result
+ }
}
+ handlePolymorphicCall
}
}
@@ -3572,9 +3588,9 @@ trait Typers extends Modes with Adaptations with Tags {
def isCapturedExistential(sym: Symbol) =
(sym hasAllFlags (EXISTENTIAL | CAPTURED)) && {
- val start = Statistics.startTimer(isReferencedNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(isReferencedNanos) else null
try !isReferencedFrom(context, sym)
- finally Statistics.stopTimer(isReferencedNanos, start)
+ finally if (Statistics.canEnable) Statistics.stopTimer(isReferencedNanos, start)
}
def packCaptured(tpe: Type): Type = {
@@ -3854,7 +3870,9 @@ trait Typers extends Modes with Adaptations with Tags {
case _ => NoType
}
- def typedAnnotated(ann: Tree, arg1: Tree): Tree = {
+ def typedAnnotated(atd: Annotated): Tree = {
+ val ann = atd.annot
+ val arg1 = typed(atd.arg, mode, pt)
/** mode for typing the annotation itself */
val annotMode = mode & ~TYPEmode | EXPRmode
@@ -3933,7 +3951,9 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedBind(name: Name, body: Tree) =
+ def typedBind(tree: Bind) = {
+ val name = tree.name
+ val body = tree.body
name match {
case name: TypeName => assert(body == EmptyTree, context.unit + " typedBind: " + name.debugString + " " + body + " " + body.getClass)
val sym =
@@ -3977,11 +3997,11 @@ trait Typers extends Modes with Adaptations with Tags {
tree setSymbol sym
treeCopy.Bind(tree, name, body1) setSymbol sym setType body1.tpe
}
+ }
-
- def typedArrayValue(elemtpt: Tree, elems: List[Tree]) = {
- val elemtpt1 = typedType(elemtpt, mode)
- val elems1 = elems mapConserve (elem => typed(elem, mode, elemtpt1.tpe))
+ def typedArrayValue(tree: ArrayValue) = {
+ val elemtpt1 = typedType(tree.elemtpt, mode)
+ val elems1 = tree.elems mapConserve (elem => typed(elem, mode, elemtpt1.tpe))
treeCopy.ArrayValue(tree, elemtpt1, elems1)
.setType(
(if (isFullyDefined(pt) && !phase.erasedTypes) pt
@@ -4024,17 +4044,19 @@ trait Typers extends Modes with Adaptations with Tags {
else fail()
}
- def typedIf(cond: Tree, thenp: Tree, elsep: Tree) = {
- val cond1 = checkDead(typed(cond, EXPRmode | BYVALmode, BooleanClass.tpe))
+ def typedIf(tree: If) = {
+ val cond1 = checkDead(typed(tree.cond, EXPRmode | BYVALmode, BooleanClass.tpe))
+ val thenp = tree.thenp
+ val elsep = tree.elsep
if (elsep.isEmpty) { // in the future, should be unnecessary
val thenp1 = typed(thenp, UnitClass.tpe)
treeCopy.If(tree, cond1, thenp1, elsep) setType thenp1.tpe
} else {
var thenp1 = typed(thenp, pt)
var elsep1 = typed(elsep, pt)
+ def thenTp = packedType(thenp1, context.owner)
+ def elseTp = packedType(elsep1, context.owner)
- lazy val thenTp = packedType(thenp1, context.owner)
- lazy val elseTp = packedType(elsep1, context.owner)
// println("typedIf: "+(thenp1.tpe, elsep1.tpe, ptOrLub(List(thenp1.tpe, elsep1.tpe)),"\n", thenTp, elseTp, thenTp =:= elseTp))
val (owntype, needAdapt) =
// in principle we should pack the types of each branch before lubbing, but lub doesn't really work for existentials anyway
@@ -4046,7 +4068,7 @@ trait Typers extends Modes with Adaptations with Tags {
&& thenTp =:= elseTp
) (thenp1.tpe, false) // use unpacked type
// TODO: skolemize (lub of packed types) when that no longer crashes on files/pos/t4070b.scala
- else ptOrLub(List(thenp1.tpe, elsep1.tpe), pt)
+ else ptOrLub(thenp1.tpe :: elsep1.tpe :: Nil, pt)
if (needAdapt) { //isNumericValueType(owntype)) {
thenp1 = adapt(thenp1, mode, owntype)
@@ -4059,7 +4081,9 @@ trait Typers extends Modes with Adaptations with Tags {
// under -Xexperimental (and not -Xoldpatmat), and when there's a suitable __match in scope, virtualize the pattern match
// otherwise, type the Match and leave it until phase `patmat` (immediately after typer)
// empty-selector matches are transformed into synthetic PartialFunction implementations when the expected type demands it
- def typedVirtualizedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree =
+ def typedVirtualizedMatch(tree: Match): Tree = {
+ val selector = tree.selector
+ val cases = tree.cases
if (selector == EmptyTree) {
if (newPatternMatching && (pt.typeSymbol == PartialFunctionClass)) (new MatchFunTyper(tree, cases, mode, pt)).translated
else {
@@ -4076,8 +4100,10 @@ trait Typers extends Modes with Adaptations with Tags {
}
} else
virtualizedMatch(typedMatch(selector, cases, mode, pt, tree), mode, pt)
+ }
- def typedReturn(expr: Tree) = {
+ def typedReturn(tree: Return) = {
+ val expr = tree.expr
val enclMethod = context.enclMethod
if (enclMethod == NoContext ||
enclMethod.owner.isConstructor ||
@@ -4104,7 +4130,8 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedNew(tpt: Tree) = {
+ def typedNew(tree: New) = {
+ val tpt = tree.tpt
val tpt1 = {
val tpt0 = typedTypeConstructor(tpt)
if (checkStablePrefixClassType(tpt0))
@@ -4212,10 +4239,10 @@ trait Typers extends Modes with Adaptations with Tags {
* insert an implicit conversion.
*/
def tryTypedApply(fun: Tree, args: List[Tree]): Tree = {
- val start = Statistics.startTimer(failedApplyNanos)
+ val start = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null
def onError(typeError: AbsTypeError): Tree = {
- Statistics.stopTimer(failedApplyNanos, start)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, start)
// If the problem is with raw types, copnvert to existentials and try again.
// See #4712 for a case where this situation arises,
@@ -4271,15 +4298,15 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedApply(fun: Tree, args: List[Tree]) = {
+ def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = {
val stableApplication = (fun.symbol ne null) && fun.symbol.isMethod && fun.symbol.isStable
if (stableApplication && isPatternMode) {
// treat stable function applications f() as expressions.
typed1(tree, mode & ~PATTERNmode | EXPRmode, pt)
} else {
val funpt = if (isPatternMode) pt else WildcardType
- val appStart = Statistics.startTimer(failedApplyNanos)
- val opeqStart = Statistics.startTimer(failedOpEqNanos)
+ val appStart = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null
+ val opeqStart = if (Statistics.canEnable) Statistics.startTimer(failedOpEqNanos) else null
def onError(reportError: => Tree): Tree = {
fun match {
@@ -4287,14 +4314,14 @@ trait Typers extends Modes with Adaptations with Tags {
if !isPatternMode && nme.isOpAssignmentName(newTermName(name.decode)) =>
val qual1 = typedQualifier(qual)
if (treeInfo.isVariableOrGetter(qual1)) {
- Statistics.stopTimer(failedOpEqNanos, opeqStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedOpEqNanos, opeqStart)
convertToAssignment(fun, qual1, name, args)
} else {
- Statistics.stopTimer(failedApplyNanos, appStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
case _ =>
- Statistics.stopTimer(failedApplyNanos, appStart)
+ if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, appStart)
reportError
}
}
@@ -4303,7 +4330,7 @@ trait Typers extends Modes with Adaptations with Tags {
if ((mode & EXPRmode) != 0) tree else context.tree) match {
case SilentResultValue(fun1) =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
- Statistics.incCounter(typedApplyCount)
+ if (Statistics.canEnable) Statistics.incCounter(typedApplyCount)
def isImplicitMethod(tpe: Type) = tpe match {
case mt: MethodType => mt.isImplicit
case _ => false
@@ -4342,6 +4369,38 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
+ def typedApply(tree: Apply) = {
+ val fun = tree.fun
+ val args = tree.args
+ fun match {
+ case Block(stats, expr) =>
+ typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
+ case _ =>
+ normalTypedApply(tree, fun, args) match {
+ case Apply(Select(New(tpt), name), args)
+ if (tpt.tpe != null &&
+ tpt.tpe.typeSymbol == ArrayClass &&
+ args.length == 1 &&
+ erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor
+ // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len)
+ // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times
+ // [Eugene] no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions)
+ val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
+ val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last
+ val newArrayApp = atPos(tree.pos) {
+ val tag = resolveClassTag(tree.pos, tagType)
+ if (tag.isEmpty) MissingClassTagError(tree, tagType)
+ else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
+ }
+ typed(newArrayApp, mode, pt)
+ case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696
+ TooManyArgumentListsForConstructor(tree)
+ case tree1 =>
+ tree1
+ }
+ }
+ }
+
def convertToAssignment(fun: Tree, qual: Tree, name: Name, args: List[Tree]): Tree = {
val prefix = name.toTermName stripSuffix nme.EQL
def mkAssign(vble: Tree): Tree =
@@ -4387,8 +4446,9 @@ trait Typers extends Modes with Adaptations with Tags {
typed1(tree1, mode, pt)
}
- def typedSuper(qual: Tree, mix: TypeName) = {
- val qual1 = typed(qual)
+ def typedSuper(tree: Super) = {
+ val mix = tree.mix
+ val qual1 = typed(tree.qual)
val clazz = qual1 match {
case This(_) => qual1.symbol
@@ -4431,12 +4491,13 @@ trait Typers extends Modes with Adaptations with Tags {
treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype)
}
- def typedThis(qual: Name) = tree.symbol orElse qualifyingClass(tree, qual, packageOK = false) match {
- case NoSymbol => tree
- case clazz =>
- tree setSymbol clazz setType clazz.thisType.underlying
- if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree
- }
+ def typedThis(tree: This) =
+ tree.symbol orElse qualifyingClass(tree, tree.qual, packageOK = false) match {
+ case NoSymbol => tree
+ case clazz =>
+ tree setSymbol clazz setType clazz.thisType.underlying
+ if (isStableContext(tree, mode, pt)) tree setType clazz.thisType else tree
+ }
/** Attribute a selection where <code>tree</code> is <code>qual.name</code>.
* <code>qual</code> is already attributed.
@@ -4445,7 +4506,7 @@ trait Typers extends Modes with Adaptations with Tags {
* @param name ...
* @return ...
*/
- def typedSelect(qual: Tree, name: Name): Tree = {
+ def typedSelect(tree: Tree, qual: Tree, name: Name): Tree = {
def asDynamicCall = dyna.mkInvoke(context.tree, tree, qual, name) map (typed1(_, mode, pt))
val sym = tree.symbol orElse member(qual, name) orElse {
@@ -4463,41 +4524,43 @@ trait Typers extends Modes with Adaptations with Tags {
qual.tpe = tree.symbol.owner.tpe
if (!reallyExists(sym)) {
- if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
- val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
- if (tree1 != EmptyTree) return typed1(tree1, mode, pt)
- }
+ def handleMissing: Tree = {
+ if (context.owner.enclosingTopLevelClass.isJavaDefined && name.isTypeName) {
+ val tree1 = atPos(tree.pos) { gen.convertToSelectFromType(qual, name) }
+ if (tree1 != EmptyTree) return typed1(tree1, mode, pt)
+ }
- // try to expand according to Dynamic rules.
- asDynamicCall foreach (x => return x)
+ // try to expand according to Dynamic rules.
+ asDynamicCall foreach (x => return x)
- debuglog(
- "qual = "+qual+":"+qual.tpe+
- "\nSymbol="+qual.tpe.termSymbol+"\nsymbol-info = "+qual.tpe.termSymbol.info+
- "\nscope-id = "+qual.tpe.termSymbol.info.decls.hashCode()+"\nmembers = "+qual.tpe.members+
- "\nname = "+name+"\nfound = "+sym+"\nowner = "+context.enclClass.owner
- )
+ debuglog(
+ "qual = " + qual + ":" + qual.tpe +
+ "\nSymbol=" + qual.tpe.termSymbol + "\nsymbol-info = " + qual.tpe.termSymbol.info +
+ "\nscope-id = " + qual.tpe.termSymbol.info.decls.hashCode() + "\nmembers = " + qual.tpe.members +
+ "\nname = " + name + "\nfound = " + sym + "\nowner = " + context.enclClass.owner)
- def makeInteractiveErrorTree = {
- val tree1 = tree match {
- case Select(_, _) => treeCopy.Select(tree, qual, name)
- case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
+ def makeInteractiveErrorTree = {
+ val tree1 = tree match {
+ case Select(_, _) => treeCopy.Select(tree, qual, name)
+ case SelectFromTypeTree(_, _) => treeCopy.SelectFromTypeTree(tree, qual, name)
+ }
+ setError(tree1)
}
- setError(tree1)
- }
- if (name == nme.ERROR && forInteractive)
- return makeInteractiveErrorTree
+ if (name == nme.ERROR && forInteractive)
+ return makeInteractiveErrorTree
- if (!qual.tpe.widen.isErroneous) {
- if ((mode & QUALmode) != 0) {
- val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name)
- if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
+ if (!qual.tpe.widen.isErroneous) {
+ if ((mode & QUALmode) != 0) {
+ val lastTry = rootMirror.missingHook(qual.tpe.typeSymbol, name)
+ if (lastTry != NoSymbol) return typed1(tree setSymbol lastTry, mode, pt)
+ }
+ NotAMemberError(tree, qual, name)
}
- NotAMemberError(tree, qual, name)
- }
- if (forInteractive) makeInteractiveErrorTree else setError(tree)
+ if (forInteractive) makeInteractiveErrorTree else setError(tree)
+ }
+ handleMissing
} else {
val tree1 = tree match {
case Select(_, _) => treeCopy.Select(tree, qual, name)
@@ -4553,6 +4616,49 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
+ def typedSelectOrSuperCall(tree: Select) = {
+ val qual = tree.qualifier
+ val name = tree.name
+ qual match {
+ case _: Super if name == nme.CONSTRUCTOR =>
+ val qual1 =
+ typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType)
+ // the qualifier type of a supercall constructor is its first parent class
+ typedSelect(tree, qual1, nme.CONSTRUCTOR)
+ case _ =>
+ if (Statistics.canEnable) Statistics.incCounter(typedSelectCount)
+ var qual1 = checkDead(typedQualifier(qual, mode))
+ if (name.isTypeName) qual1 = checkStable(qual1)
+
+ val tree1 = // temporarily use `filter` and an alternative for `withFilter`
+ if (name == nme.withFilter)
+ silent(_ => typedSelect(tree, qual1, name)) match {
+ case SilentResultValue(result) =>
+ result
+ case _ =>
+ silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
+ case SilentResultValue(result2) =>
+ unit.deprecationWarning(
+ tree.pos, "`withFilter' method does not yet exist on " + qual1.tpe.widen +
+ ", using `filter' method instead")
+ result2
+ case SilentTypeError(err) =>
+ WithFilterError(tree, err)
+ }
+ }
+ else
+ typedSelect(tree, qual1, name)
+
+ if (tree.isInstanceOf[PostfixSelect])
+ checkFeature(tree.pos, PostfixOpsFeature, name.decode)
+ if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
+ checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
+
+ if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
+ else tree1
+ }
+ }
+
/** Attribute an identifier consisting of a simple name or an outer reference.
*
* @param tree The tree representing the identifier.
@@ -4560,7 +4666,7 @@ trait Typers extends Modes with Adaptations with Tags {
* Transformations: (1) Prefix class members with this.
* (2) Change imported symbols to selections
*/
- def typedIdent(name: Name): Tree = {
+ def typedIdent(tree: Tree, name: Name): Tree = {
var errorContainer: AbsTypeError = null
@inline
def ambiguousError(msg: String) = {
@@ -4573,8 +4679,6 @@ trait Typers extends Modes with Adaptations with Tags {
errorContainer = tree
}
- val fingerPrint: Long = name.fingerPrint
-
var defSym: Symbol = tree.symbol // the directly found symbol
var pre: Type = NoPrefix // the prefix type of defSym, if a class member
var qual: Tree = EmptyTree // the qualifier tree if transformed tree is a select
@@ -4612,10 +4716,7 @@ trait Typers extends Modes with Adaptations with Tags {
var cx = startingIdentContext
while (defSym == NoSymbol && cx != NoContext && (cx.scope ne null)) { // cx.scope eq null arises during FixInvalidSyms in Duplicators
pre = cx.enclClass.prefix
- defEntry = {
- val scope = cx.scope
- if ((fingerPrint & scope.fingerPrints) != 0) scope.lookupEntry(name) else null
- }
+ defEntry = cx.scope.lookupEntry(name)
if ((defEntry ne null) && qualifies(defEntry.sym)) {
// Right here is where SI-1987, overloading in package objects, can be
// seen to go wrong. There is an overloaded symbol, but when referring
@@ -4629,8 +4730,13 @@ trait Typers extends Modes with Adaptations with Tags {
if (isInPackageObject(defEntry.sym, pre.typeSymbol)) {
defSym = pre.member(defEntry.sym.name)
if (defSym ne defEntry.sym) {
- log("!!! Overloaded package object member resolved incorrectly.\n Discarded: " +
- defEntry.sym.defString + "\n Using: " + defSym.defString)
+ qual = gen.mkAttributedQualifier(pre)
+ log(s"""
+ | !!! Overloaded package object member resolved incorrectly.
+ | prefix: $pre
+ | Discarded: ${defEntry.sym.defString}
+ | Using: ${defSym.defString}
+ """.stripMargin)
}
}
else
@@ -4803,7 +4909,18 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedCompoundTypeTree(templ: Template) = {
+ def typedIdentOrWildcard(tree: Ident) = {
+ val name = tree.name
+ if (Statistics.canEnable) Statistics.incCounter(typedIdentCount)
+ if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
+ (name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
+ tree setType makeFullyDefined(pt)
+ else
+ typedIdent(tree, name)
+ }
+
+ def typedCompoundTypeTree(tree: CompoundTypeTree) = {
+ val templ = tree.templ
val parents1 = templ.parents mapConserve (typedType(_, mode))
if (parents1 exists (_.isErrorTyped)) tree setType ErrorType
else {
@@ -4816,7 +4933,9 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- def typedAppliedTypeTree(tpt: Tree, args: List[Tree]) = {
+ def typedAppliedTypeTree(tree: AppliedTypeTree) = {
+ val tpt = tree.tpt
+ val args = tree.args
val tpt1 = typed1(tpt, mode | FUNmode | TAPPmode, WildcardType)
if (tpt1.isErrorTyped) {
tpt1
@@ -4867,367 +4986,395 @@ trait Typers extends Modes with Adaptations with Tags {
}
}
- // begin typed1
val sym: Symbol = tree.symbol
if ((sym ne null) && (sym ne NoSymbol)) sym.initialize
- //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG
- tree match {
- case PackageDef(pid, stats) =>
- val pid1 = typedQualifier(pid).asInstanceOf[RefTree]
- assert(sym.moduleClass ne NoSymbol, sym)
- // complete lazy annotations
- val annots = sym.annotations
- val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
- .typedStats(stats, NoSymbol)
- treeCopy.PackageDef(tree, pid1, stats1) setType NoType
-
- case tree @ ClassDef(_, _, _, _) =>
- newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree)
- case tree @ ModuleDef(_, _, _) =>
- newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree)
+ def typedPackageDef(pdef: PackageDef) = {
+ val pid1 = typedQualifier(pdef.pid).asInstanceOf[RefTree]
+ assert(sym.moduleClass ne NoSymbol, sym)
+ // complete lazy annotations
+ val annots = sym.annotations
+ val stats1 = newTyper(context.make(tree, sym.moduleClass, sym.info.decls))
+ .typedStats(pdef.stats, NoSymbol)
+ treeCopy.PackageDef(tree, pid1, stats1) setType NoType
+ }
- case vdef @ ValDef(_, _, _, _) =>
- typedValDef(vdef)
+ def typedDocDef(docdef: DocDef) = {
+ val comment = docdef.comment
+ if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) {
+ docComments(sym) = comment
+ comment.defineVariables(sym)
+ val typer1 = newTyper(context.makeNewScope(tree, context.owner))
+ for (useCase <- comment.useCases) {
+ typer1.silent(_.typedUseCase(useCase)) match {
+ case SilentTypeError(err) =>
+ unit.warning(useCase.pos, err.errMsg)
+ case _ =>
+ }
+ for (useCaseSym <- useCase.defined) {
+ if (sym.name != useCaseSym.name)
+ unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
+ }
+ }
+ }
+ typed(docdef.definition, mode, pt)
+ }
- case ddef @ DefDef(_, _, _, _, _, _) =>
- // flag default getters for constructors. An actual flag would be nice. See SI-5543.
- //val flag = ddef.mods.hasDefaultFlag && ddef.mods.hasFlag(PRESUPER)
- val flag = ddef.mods.hasDefaultFlag && sym.owner.isModuleClass &&
- nme.defaultGetterToMethod(sym.name) == nme.CONSTRUCTOR
- newTyper(context.makeNewScope(tree, sym)).constrTyperIf(flag).typedDefDef(ddef)
+ def defDefTyper(ddef: DefDef) = {
+ val flag = ddef.mods.hasDefaultFlag && sym.owner.isModuleClass &&
+ nme.defaultGetterToMethod(sym.name) == nme.CONSTRUCTOR
+ newTyper(context.makeNewScope(ddef, sym)).constrTyperIf(flag)
+ }
- case tdef @ TypeDef(_, _, _, _) =>
- typedTypeDef(tdef)
+ def typedAlternative(alt: Alternative) = {
+ val alts1 = alt.trees mapConserve (alt => typed(alt, mode | ALTmode, pt))
+ treeCopy.Alternative(tree, alts1) setType pt
+ }
- case ldef @ LabelDef(_, _, _) =>
- labelTyper(ldef).typedLabelDef(ldef)
-
- case ddef @ DocDef(comment, defn) =>
- if (forScaladoc && (sym ne null) && (sym ne NoSymbol)) {
- docComments(sym) = comment
- comment.defineVariables(sym)
- val typer1 = newTyper(context.makeNewScope(tree, context.owner))
- for (useCase <- comment.useCases) {
- typer1.silent(_.typedUseCase(useCase)) match {
- case SilentTypeError(err) =>
- unit.warning(useCase.pos, err.errMsg)
- case _ =>
- }
- for (useCaseSym <- useCase.defined) {
- if (sym.name != useCaseSym.name)
- unit.warning(useCase.pos, "@usecase " + useCaseSym.name.decode + " does not match commented symbol: " + sym.name.decode)
+ def typedStar(tree: Star) = {
+ if ((mode & STARmode) == 0 && !isPastTyper)
+ StarPatternWithVarargParametersError(tree)
+ treeCopy.Star(tree, typed(tree.elem, mode, pt)) setType makeFullyDefined(pt)
+ }
+
+ def typedUnApply(tree: UnApply) = {
+ val fun1 = typed(tree.fun)
+ val tpes = formalTypes(unapplyTypeList(tree.fun.symbol, fun1.tpe, tree.args.length), tree.args.length)
+ val args1 = map2(tree.args, tpes)(typedPattern)
+ treeCopy.UnApply(tree, fun1, args1) setType pt
+ }
+
+ def typedTry(tree: Try) = {
+ var block1 = typed(tree.block, pt)
+ var catches1 = typedCases(tree.catches, ThrowableClass.tpe, pt)
+
+ for (cdef <- catches1 if cdef.guard.isEmpty) {
+ def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.")
+ def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol
+ cdef.pat match {
+ case Bind(name, i @ Ident(_)) if unbound(i) => warn(name)
+ case i @ Ident(name) if unbound(i) => warn(name)
+ case _ =>
+ }
+ }
+
+ val finalizer1 =
+ if (tree.finalizer.isEmpty) tree.finalizer
+ else typed(tree.finalizer, UnitClass.tpe)
+ val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
+ if (needAdapt) {
+ block1 = adapt(block1, mode, owntype)
+ catches1 = catches1 map (adaptCase(_, mode, owntype))
+ }
+
+ treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
+ }
+
+ def typedThrow(tree: Throw) = {
+ val expr1 = typed(tree.expr, EXPRmode | BYVALmode, ThrowableClass.tpe)
+ treeCopy.Throw(tree, expr1) setType NothingClass.tpe
+ }
+
+ def typedTyped(tree: Typed) = {
+ val expr = tree.expr
+ val tpt = tree.tpt
+ tpt match {
+ case Function(List(), EmptyTree) =>
+ // find out whether the programmer is trying to eta-expand a macro def
+ // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee)
+ // that typecheck must not trigger macro expansions, so we explicitly prohibit them
+ // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?"
+ // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code
+ val exprTyped = context.withMacrosDisabled(typed1(expr, mode, pt))
+ exprTyped match {
+ case macroDef if macroDef.symbol != null && macroDef.symbol.isTermMacro && !macroDef.symbol.isErroneous =>
+ MacroEtaError(exprTyped)
+ case _ =>
+ typedEta(checkDead(exprTyped))
+ }
+
+ case Ident(tpnme.WILDCARD_STAR) =>
+ val exprTyped = typed(expr, onlyStickyModes(mode), WildcardType)
+ def subArrayType(pt: Type) =
+ if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
+ else {
+ val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
+ newExistentialType(List(tparam), arrayType(tparam.tpe))
}
+
+ val (exprAdapted, baseClass) = exprTyped.tpe.typeSymbol match {
+ case ArrayClass => (adapt(exprTyped, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
+ case _ => (adapt(exprTyped, onlyStickyModes(mode), seqType(pt)), SeqClass)
}
- }
- typed(defn, mode, pt)
+ exprAdapted.tpe.baseType(baseClass) match {
+ case TypeRef(_, _, List(elemtp)) =>
+ treeCopy.Typed(tree, exprAdapted, tpt setType elemtp) setType elemtp
+ case _ =>
+ setError(tree)
+ }
+
+ case _ =>
+ val tptTyped = typedType(tpt, mode)
+ val exprTyped = typed(expr, onlyStickyModes(mode), tptTyped.tpe.deconst)
+ val treeTyped = treeCopy.Typed(tree, exprTyped, tptTyped)
- case Annotated(constr, arg) =>
- typedAnnotated(constr, typed(arg, mode, pt))
+ if (isPatternMode) {
+ val uncheckedTypeExtractor = extractorForUncheckedType(tpt.pos, tptTyped.tpe)
- case tree @ Block(_, _) =>
+ // make fully defined to avoid bounded wildcard types that may be in pt from calling dropExistential (SI-2038)
+ val ptDefined = if (isFullyDefined(pt)) pt else makeFullyDefined(pt)
+ val ownType = inferTypedPattern(tptTyped, tptTyped.tpe, ptDefined, canRemedy = uncheckedTypeExtractor.nonEmpty)
+ treeTyped setType ownType
+
+ uncheckedTypeExtractor match {
+ case None => treeTyped
+ case Some(extractor) => wrapClassTagUnapply(treeTyped, extractor, tptTyped.tpe)
+ }
+ } else
+ treeTyped setType tptTyped.tpe
+ }
+ }
+
+ def typedTypeApply(tree: TypeApply) = {
+ val fun = tree.fun
+ val args = tree.args
+ // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
+ //@M! we must type fun in order to type the args, as that requires the kinds of fun's type parameters.
+ // However, args should apparently be done first, to save context.undetparams. Unfortunately, the args
+ // *really* have to be typed *after* fun. We escape from this classic Catch-22 by simply saving&restoring undetparams.
+
+ // @M TODO: the compiler still bootstraps&all tests pass when this is commented out..
+ //val undets = context.undetparams
+
+ // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters
+ val fun1 = typed(fun, forFunMode(mode) | TAPPmode, WildcardType)
+ val tparams = fun1.symbol.typeParams
+
+ //@M TODO: val undets_fun = context.undetparams ?
+ // "do args first" (by restoring the context.undetparams) in order to maintain context.undetparams on the function side.
+
+ // @M TODO: the compiler still bootstraps when this is commented out.. TODO: run tests
+ //context.undetparams = undets
+
+ // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds?
+ val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) {
+ //@M! the polytype denotes the expected kind
+ (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe))
+ }
+ else {
+ //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases.
+ // Until the right alternative for an overloaded method is known, be very liberal,
+ // typedTypeApply will find the right alternative and then do the same check as
+ // in the then-branch above. (see pos/tcpoly_overloaded.scala)
+ // this assert is too strict: be tolerant for errors like trait A { def foo[m[x], g]=error(""); def x[g] = foo[g/*ERR: missing argument type*/] }
+ //assert(fun1.symbol.info.isInstanceOf[OverloadedType] || fun1.symbol.isError) //, (fun1.symbol,fun1.symbol.info,fun1.symbol.info.getClass,args,tparams))
+ args mapConserve (typedHigherKindedType(_, mode))
+ }
+
+ //@M TODO: context.undetparams = undets_fun ?
+ Typer.this.typedTypeApply(tree, mode, fun1, args1)
+ }
+
+ def typedApplyDynamic(tree: ApplyDynamic) = {
+ assert(phase.erasedTypes)
+ val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic")
+ val qual1 = typed(tree.qual, AnyRefClass.tpe)
+ val args1 = tree.args mapConserve (arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg))
+ treeCopy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType)
+ }
+
+ def typedReferenceToBoxed(tree: ReferenceToBoxed) = {
+ val id = tree.ident
+ val id1 = typed1(id, mode, pt) match { case id: Ident => id }
+ // [Eugene] am I doing it right?
+ val erasedTypes = phaseId(currentPeriod) >= currentRun.erasurePhase.id
+ val tpe = capturedVariableType(id.symbol, erasedTypes = erasedTypes)
+ treeCopy.ReferenceToBoxed(tree, id1) setType tpe
+ }
+
+ def typedLiteral(tree: Literal) = {
+ val value = tree.value
+ tree setType (
+ if (value.tag == UnitTag) UnitClass.tpe
+ else ConstantType(value))
+ }
+
+ def typedSingletonTypeTree(tree: SingletonTypeTree) = {
+ val ref1 = checkStable(
+ typed(tree.ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
+ tree setType ref1.tpe.resultType
+ }
+
+ def typedSelectFromTypeTree(tree: SelectFromTypeTree) = {
+ val qual1 = typedType(tree.qualifier, mode)
+ if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1)
+ else typedSelect(tree, qual1, tree.name)
+ }
+
+ def typedTypeBoundsTree(tree: TypeBoundsTree) = {
+ val lo1 = typedType(tree.lo, mode)
+ val hi1 = typedType(tree.hi, mode)
+ treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
+ }
+
+ def typedExistentialTypeTree(tree: ExistentialTypeTree) = {
+ val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){
+ _.typedExistentialTypeTree(tree, mode)
+ }
+ checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type")
+ tree1
+ }
+
+ def typedTypeTree(tree: TypeTree) = {
+ if (tree.original != null)
+ tree setType typedType(tree.original, mode).tpe
+ else
+ // we should get here only when something before failed
+ // and we try again (@see tryTypedApply). In that case we can assign
+ // whatever type to tree; we just have to survive until a real error message is issued.
+ tree setType AnyClass.tpe
+ }
+
+ // begin typed1
+ //if (settings.debug.value && tree.isDef) log("typing definition of "+sym);//DEBUG
+
+ tree match {
+ case tree: Ident =>
+ typedIdentOrWildcard(tree)
+
+ case tree: Select =>
+ typedSelectOrSuperCall(tree)
+
+ case tree: Apply =>
+ typedApply(tree)
+
+ case tree: TypeTree =>
+ typedTypeTree(tree)
+
+ case tree: Literal =>
+ typedLiteral(tree)
+
+ case tree: This =>
+ typedThis(tree)
+
+ case tree: ValDef =>
+ typedValDef(tree)
+
+ case tree: DefDef =>
+ // flag default getters for constructors. An actual flag would be nice. See SI-5543.
+ //val flag = ddef.mods.hasDefaultFlag && ddef.mods.hasFlag(PRESUPER)
+ defDefTyper(tree).typedDefDef(tree)
+
+ case tree: Block =>
typerWithLocalContext(context.makeNewScope(tree, context.owner)){
_.typedBlock(tree, mode, pt)
}
- case Alternative(alts) =>
- val alts1 = alts mapConserve (alt => typed(alt, mode | ALTmode, pt))
- treeCopy.Alternative(tree, alts1) setType pt
-
- case Star(elem) =>
- if ((mode & STARmode) == 0 && !isPastTyper)
- StarPatternWithVarargParametersError(tree)
- treeCopy.Star(tree, typed(elem, mode, pt)) setType makeFullyDefined(pt)
+ case tree: If =>
+ typedIf(tree)
- case Bind(name, body) =>
- typedBind(name, body)
+ case tree: TypeApply =>
+ typedTypeApply(tree)
- case UnApply(fun, args) =>
- val fun1 = typed(fun)
- val tpes = formalTypes(unapplyTypeList(fun.symbol, fun1.tpe, args.length), args.length)
- val args1 = map2(args, tpes)(typedPattern)
- treeCopy.UnApply(tree, fun1, args1) setType pt
+ case tree: AppliedTypeTree =>
+ typedAppliedTypeTree(tree)
- case ArrayValue(elemtpt, elems) =>
- typedArrayValue(elemtpt, elems)
+ case tree: Bind =>
+ typedBind(tree)
- case tree @ Function(_, _) =>
+ case tree: Function =>
if (tree.symbol == NoSymbol)
tree.symbol = context.owner.newAnonymousFunctionValue(tree.pos)
typerWithLocalContext(context.makeNewScope(tree, tree.symbol))(_.typedFunction(tree, mode, pt))
+ case tree: Match =>
+ typedVirtualizedMatch(tree)
+
+ case tree: New =>
+ typedNew(tree)
+
case Assign(lhs, rhs) =>
typedAssign(lhs, rhs)
case AssignOrNamedArg(lhs, rhs) => // called by NamesDefaults in silent typecheck
typedAssign(lhs, rhs)
- case If(cond, thenp, elsep) =>
- typedIf(cond, thenp, elsep)
+ case tree: Super =>
+ typedSuper(tree)
- case tree @ Match(selector, cases) =>
- typedVirtualizedMatch(tree, selector, cases)
+ case tree: TypeBoundsTree =>
+ typedTypeBoundsTree(tree)
- case Return(expr) =>
- typedReturn(expr)
+ case tree: Typed =>
+ typedTyped(tree)
- case Try(block, catches, finalizer) =>
- var block1 = typed(block, pt)
- var catches1 = typedCases(catches, ThrowableClass.tpe, pt)
+ case tree: ClassDef =>
+ newTyper(context.makeNewScope(tree, sym)).typedClassDef(tree)
- for (cdef <- catches1 if cdef.guard.isEmpty) {
- def warn(name: Name) = context.warning(cdef.pat.pos, s"This catches all Throwables. If this is really intended, use `case ${name.decoded} : Throwable` to clear this warning.")
- def unbound(t: Tree) = t.symbol == null || t.symbol == NoSymbol
- cdef.pat match {
- case Bind(name, i@Ident(_)) if unbound(i) => warn(name)
- case i@Ident(name) if unbound(i) => warn(name)
- case _ =>
- }
- }
+ case tree: ModuleDef =>
+ newTyper(context.makeNewScope(tree, sym.moduleClass)).typedModuleDef(tree)
- val finalizer1 = if (finalizer.isEmpty) finalizer
- else typed(finalizer, UnitClass.tpe)
- val (owntype, needAdapt) = ptOrLub(block1.tpe :: (catches1 map (_.tpe)), pt)
- if (needAdapt) {
- block1 = adapt(block1, mode, owntype)
- catches1 = catches1 map (adaptCase(_, mode, owntype))
- }
+ case tree: TypeDef =>
+ typedTypeDef(tree)
- treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
-
- case Throw(expr) =>
- val expr1 = typed(expr, EXPRmode | BYVALmode, ThrowableClass.tpe)
- treeCopy.Throw(tree, expr1) setType NothingClass.tpe
-
- case New(tpt: Tree) =>
- typedNew(tpt)
-
- case Typed(expr, Function(List(), EmptyTree)) =>
- // find out whether the programmer is trying to eta-expand a macro def
- // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee)
- // that typecheck must not trigger macro expansions, so we explicitly prohibit them
- // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?"
- // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code
- val expr1 = context.withMacrosDisabled(typed1(expr, mode, pt))
- expr1 match {
- case macroDef if macroDef.symbol != null && macroDef.symbol.isTermMacro && !macroDef.symbol.isErroneous =>
- MacroEtaError(expr1)
- case _ =>
- typedEta(checkDead(expr1))
- }
+ case tree: LabelDef =>
+ labelTyper(tree).typedLabelDef(tree)
- case Typed(expr0, tpt @ Ident(tpnme.WILDCARD_STAR)) =>
- val expr = typed(expr0, onlyStickyModes(mode), WildcardType)
- def subArrayType(pt: Type) =
- if (isPrimitiveValueClass(pt.typeSymbol) || !isFullyDefined(pt)) arrayType(pt)
- else {
- val tparam = context.owner freshExistential "" setInfo TypeBounds.upper(pt)
- newExistentialType(List(tparam), arrayType(tparam.tpe))
- }
+ case tree: PackageDef =>
+ typedPackageDef(tree)
- val (expr1, baseClass) = expr.tpe.typeSymbol match {
- case ArrayClass => (adapt(expr, onlyStickyModes(mode), subArrayType(pt)), ArrayClass)
- case _ => (adapt(expr, onlyStickyModes(mode), seqType(pt)), SeqClass)
- }
- expr1.tpe.baseType(baseClass) match {
- case TypeRef(_, _, List(elemtp)) =>
- treeCopy.Typed(tree, expr1, tpt setType elemtp) setType elemtp
- case _ =>
- setError(tree)
- }
+ case tree: DocDef =>
+ typedDocDef(tree)
- case Typed(expr, tpt) =>
- val tptTyped = typedType(tpt, mode)
- val exprTyped = typed(expr, onlyStickyModes(mode), tptTyped.tpe.deconst)
- val treeTyped = treeCopy.Typed(tree, exprTyped, tptTyped)
+ case tree: Annotated =>
+ typedAnnotated(tree)
- if (isPatternMode) {
- val uncheckedTypeExtractor = extractorForUncheckedType(tpt.pos, tptTyped.tpe)
+ case tree: SingletonTypeTree =>
+ typedSingletonTypeTree(tree)
- // make fully defined to avoid bounded wildcard types that may be in pt from calling dropExistential (SI-2038)
- val ptDefined = if (isFullyDefined(pt)) pt else makeFullyDefined(pt)
- val ownType = inferTypedPattern(tptTyped, tptTyped.tpe, ptDefined, canRemedy = uncheckedTypeExtractor.nonEmpty)
- treeTyped setType ownType
+ case tree: SelectFromTypeTree =>
+ typedSelectFromTypeTree(tree)
- uncheckedTypeExtractor match {
- case None => treeTyped
- case Some(extractor) => wrapClassTagUnapply(treeTyped, extractor, tptTyped.tpe)
- }
- } else
- treeTyped setType tptTyped.tpe
-
- case TypeApply(fun, args) =>
- // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer)
- //@M! we must type fun in order to type the args, as that requires the kinds of fun's type parameters.
- // However, args should apparently be done first, to save context.undetparams. Unfortunately, the args
- // *really* have to be typed *after* fun. We escape from this classic Catch-22 by simply saving&restoring undetparams.
-
- // @M TODO: the compiler still bootstraps&all tests pass when this is commented out..
- //val undets = context.undetparams
-
- // @M: fun is typed in TAPPmode because it is being applied to its actual type parameters
- val fun1 = typed(fun, forFunMode(mode) | TAPPmode, WildcardType)
- val tparams = fun1.symbol.typeParams
-
- //@M TODO: val undets_fun = context.undetparams ?
- // "do args first" (by restoring the context.undetparams) in order to maintain context.undetparams on the function side.
-
- // @M TODO: the compiler still bootstraps when this is commented out.. TODO: run tests
- //context.undetparams = undets
-
- // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds?
- val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) {
- //@M! the polytype denotes the expected kind
- (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe))
- } else {
- //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases.
- // Until the right alternative for an overloaded method is known, be very liberal,
- // typedTypeApply will find the right alternative and then do the same check as
- // in the then-branch above. (see pos/tcpoly_overloaded.scala)
- // this assert is too strict: be tolerant for errors like trait A { def foo[m[x], g]=error(""); def x[g] = foo[g/*ERR: missing argument type*/] }
- //assert(fun1.symbol.info.isInstanceOf[OverloadedType] || fun1.symbol.isError) //, (fun1.symbol,fun1.symbol.info,fun1.symbol.info.getClass,args,tparams))
- args mapConserve (typedHigherKindedType(_, mode))
- }
+ case tree: CompoundTypeTree =>
+ typedCompoundTypeTree(tree)
- //@M TODO: context.undetparams = undets_fun ?
- typedTypeApply(tree, mode, fun1, args1)
+ case tree: ExistentialTypeTree =>
+ typedExistentialTypeTree(tree)
- case Apply(Block(stats, expr), args) =>
- typed1(atPos(tree.pos)(Block(stats, Apply(expr, args) setPos tree.pos.makeTransparent)), mode, pt)
+ case tree: Return =>
+ typedReturn(tree)
- case Apply(fun, args) =>
- typedApply(fun, args) match {
- case Apply(Select(New(tpt), name), args)
- if (tpt.tpe != null &&
- tpt.tpe.typeSymbol == ArrayClass &&
- args.length == 1 &&
- erasure.GenericArray.unapply(tpt.tpe).isDefined) => // !!! todo simplify by using extractor
- // convert new Array[T](len) to evidence[ClassTag[T]].newArray(len)
- // convert new Array^N[T](len) for N > 1 to evidence[ClassTag[Array[...Array[T]...]]].newArray(len), where Array HK gets applied (N-1) times
- // no more MaxArrayDims. ClassTags are flexible enough to allow creation of arrays of arbitrary dimensionality (w.r.t JVM restrictions)
- val Some((level, componentType)) = erasure.GenericArray.unapply(tpt.tpe)
- val tagType = List.iterate(componentType, level)(tpe => appliedType(ArrayClass.toTypeConstructor, List(tpe))).last
- val newArrayApp = atPos(tree.pos) {
- val tag = resolveClassTag(tree.pos, tagType)
- if (tag.isEmpty) MissingClassTagError(tree, tagType)
- else new ApplyToImplicitArgs(Select(tag, nme.newArray), args)
- }
- typed(newArrayApp, mode, pt)
- case Apply(Select(fun, nme.apply), _) if treeInfo.isSuperConstrCall(fun) => //SI-5696
- TooManyArgumentListsForConstructor(tree)
- case tree1 =>
- tree1
- }
+ case tree: Try =>
+ typedTry(tree)
- case ApplyDynamic(qual, args) =>
- assert(phase.erasedTypes)
- val reflectiveCalls = !(settings.refinementMethodDispatch.value == "invoke-dynamic")
- val qual1 = typed(qual, AnyRefClass.tpe)
- val args1 = args mapConserve (arg => if (reflectiveCalls) typed(arg, AnyRefClass.tpe) else typed(arg))
- treeCopy.ApplyDynamic(tree, qual1, args1) setType (if (reflectiveCalls) AnyRefClass.tpe else tree.symbol.info.resultType)
-
- case Super(qual, mix) =>
- typedSuper(qual, mix)
-
- case This(qual) =>
- typedThis(qual)
-
- case Select(qual @ Super(_, _), nme.CONSTRUCTOR) =>
- val qual1 =
- typed(qual, EXPRmode | QUALmode | POLYmode | SUPERCONSTRmode, WildcardType)
- // the qualifier type of a supercall constructor is its first parent class
- typedSelect(qual1, nme.CONSTRUCTOR)
-
- case Select(qual, name) =>
- Statistics.incCounter(typedSelectCount)
- var qual1 = checkDead(typedQualifier(qual, mode))
- if (name.isTypeName) qual1 = checkStable(qual1)
-
- val tree1 = // temporarily use `filter` and an alternative for `withFilter`
- if (name == nme.withFilter)
- silent(_ => typedSelect(qual1, name)) match {
- case SilentResultValue(result) =>
- result
- case _ =>
- silent(_ => typed1(Select(qual1, nme.filter) setPos tree.pos, mode, pt)) match {
- case SilentResultValue(result2) =>
- unit.deprecationWarning(
- tree.pos, "`withFilter' method does not yet exist on "+qual1.tpe.widen+
- ", using `filter' method instead")
- result2
- case SilentTypeError(err) =>
- WithFilterError(tree, err)
- }
- }
- else
- typedSelect(qual1, name)
+ case tree: Throw =>
+ typedThrow(tree)
- if (tree.isInstanceOf[PostfixSelect])
- checkFeature(tree.pos, PostfixOpsFeature, name.decode)
- if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
- checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
+ case tree: Alternative =>
+ typedAlternative(tree)
- if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
- else tree1
+ case tree: Star =>
+ typedStar(tree)
- case Ident(name) =>
- Statistics.incCounter(typedIdentCount)
- if ((name == nme.WILDCARD && (mode & (PATTERNmode | FUNmode)) == PATTERNmode) ||
- (name == tpnme.WILDCARD && (mode & TYPEmode) != 0))
- tree setType makeFullyDefined(pt)
- else
- typedIdent(name)
-
- case ReferenceToBoxed(idt @ Ident(_)) =>
- val id1 = typed1(idt, mode, pt) match { case id: Ident => id }
- val tpe = capturedVariableType(idt.symbol, erasedTypes = phase.erasedTypes)
- treeCopy.ReferenceToBoxed(tree, id1) setType tpe
-
- case Literal(value) =>
- tree setType (
- if (value.tag == UnitTag) UnitClass.tpe
- else ConstantType(value))
-
- case SingletonTypeTree(ref) =>
- val ref1 = checkStable(
- typed(ref, EXPRmode | QUALmode | (mode & TYPEPATmode), AnyRefClass.tpe))
- tree setType ref1.tpe.resultType
-
- case SelectFromTypeTree(qual, selector) =>
- val qual1 = typedType(qual, mode)
- if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1)
- else typedSelect(qual1, selector)
-
- case CompoundTypeTree(templ) =>
- typedCompoundTypeTree(templ)
-
- case AppliedTypeTree(tpt, args) =>
- typedAppliedTypeTree(tpt, args)
-
- case TypeBoundsTree(lo, hi) =>
- val lo1 = typedType(lo, mode)
- val hi1 = typedType(hi, mode)
- treeCopy.TypeBoundsTree(tree, lo1, hi1) setType TypeBounds(lo1.tpe, hi1.tpe)
-
- case etpt @ ExistentialTypeTree(_, _) =>
- val tree1 = typerWithLocalContext(context.makeNewScope(tree, context.owner)){
- _.typedExistentialTypeTree(etpt, mode)
- }
- checkExistentialsFeature(tree1.pos, tree1.tpe, "the existential type")
- tree1
+ case tree: UnApply =>
+ typedUnApply(tree)
- case dc@TypeTreeWithDeferredRefCheck() => dc // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
- case tpt @ TypeTree() =>
- if (tpt.original != null)
- tree setType typedType(tpt.original, mode).tpe
- else
- // we should get here only when something before failed
- // and we try again (@see tryTypedApply). In that case we can assign
- // whatever type to tree; we just have to survive until a real error message is issued.
- tree setType AnyClass.tpe
- case Import(expr, selectors) =>
+ case tree: ArrayValue =>
+ typedArrayValue(tree)
+
+ case tree: ApplyDynamic =>
+ typedApplyDynamic(tree)
+
+ case tree: ReferenceToBoxed =>
+ typedReferenceToBoxed(tree)
+
+ case tree: TypeTreeWithDeferredRefCheck =>
+ tree // TODO: should we re-type the wrapped tree? then we need to change TypeTreeWithDeferredRefCheck's representation to include the wrapped tree explicitly (instead of in its closure)
+
+ case tree: Import =>
assert(forInteractive, "!forInteractive") // should not happen in normal circumstances.
tree setType tree.symbol.tpe
+
case _ =>
abort("unexpected tree: " + tree.getClass + "\n" + tree)//debug
}
@@ -5244,8 +5391,8 @@ trait Typers extends Modes with Adaptations with Tags {
indentTyping()
var alreadyTyped = false
- val startByType = Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass))
- Statistics.incCounter(visitsByType, tree.getClass)
+ val startByType = if (Statistics.canEnable) Statistics.pushTimer(byTypeStack, byTypeNanos(tree.getClass)) else null
+ if (Statistics.canEnable) Statistics.incCounter(visitsByType, tree.getClass)
try {
if (context.retyping &&
(tree.tpe ne null) && (tree.tpe.isErroneous || !(tree.tpe <:< pt))) {
@@ -5300,7 +5447,7 @@ trait Typers extends Modes with Adaptations with Tags {
}
finally {
deindentTyping()
- Statistics.popTimer(byTypeStack, startByType)
+ if (Statistics.canEnable) Statistics.popTimer(byTypeStack, startByType)
}
}
@@ -5454,7 +5601,7 @@ trait Typers extends Modes with Adaptations with Tags {
val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous))
val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty
- if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree.symbol, tree1.symbol) else AnyClass.tpe
+ if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree1.symbol) else AnyClass.tpe
}
def transformedOr(tree: Tree, op: => Tree): Tree = transformed.get(tree) match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index 4871ef199c..5db1863f67 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -115,7 +115,7 @@ trait Unapplies extends ast.TreeDSL
Modifiers(OVERRIDE | FINAL),
nme.toString_,
Nil,
- List(Nil),
+ ListOfNil,
TypeTree(),
Literal(Constant(cdef.name.decode)))
@@ -126,7 +126,7 @@ trait Unapplies extends ast.TreeDSL
ModuleDef(
Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin),
cdef.name.toTermName,
- Template(parents, emptyValDef, NoMods, Nil, List(Nil), body, cdef.impl.pos.focus))
+ Template(parents, emptyValDef, NoMods, Nil, ListOfNil, body, cdef.impl.pos.focus))
}
private val caseMods = Modifiers(SYNTHETIC | CASE)
diff --git a/src/compiler/scala/tools/reflect/FastTrack.scala b/src/compiler/scala/tools/reflect/FastTrack.scala
index f84877cccb..07c972899e 100644
--- a/src/compiler/scala/tools/reflect/FastTrack.scala
+++ b/src/compiler/scala/tools/reflect/FastTrack.scala
@@ -17,16 +17,11 @@ trait FastTrack {
private implicit def context2taggers(c0: MacroContext): Taggers { val c: c0.type } = new { val c: c0.type = c0 } with Taggers
private implicit def context2macroimplementations(c0: MacroContext): MacroImplementations { val c: c0.type } = new { val c: c0.type = c0 } with MacroImplementations
- implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args)
+ implicit def fastTrackEntry2MacroRuntime(entry: FastTrackEntry): MacroRuntime = args => entry.run(args.c)
type FastTrackExpander = PartialFunction[(MacroContext, Tree), Tree]
case class FastTrackEntry(sym: Symbol, expander: FastTrackExpander) {
- def validate(argss: List[List[Any]]): Boolean = {
- val c = argss.flatten.apply(0).asInstanceOf[MacroContext]
- val isValid = expander isDefinedAt (c, c.expandee)
- isValid
- }
- def run(args: List[Any]): Any = {
- val c = args(0).asInstanceOf[MacroContext]
+ def validate(c: MacroContext): Boolean = expander.isDefinedAt((c, c.expandee))
+ def run(c: MacroContext): Any = {
val result = expander((c, c.expandee))
c.Expr[Nothing](result)(c.AbsTypeTag.Nothing)
}
diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala
index 270581a3aa..d470f4c966 100644
--- a/src/library/scala/Function.scala
+++ b/src/library/scala/Function.scala
@@ -28,11 +28,11 @@ 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
+ * may be called 2 or more times on each logical invocation, because the
* only way to supply an implementation of `isDefinedAt` is to call the
* function and examine the return value.
+ * See also [[scala.PartialFunction]], method `applyOrElse`.
*
* @param f a function `T => Option[R]`
* @return a partial function defined for those inputs where
diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala
index f651461fe6..b7420f4447 100644
--- a/src/library/scala/Option.scala
+++ b/src/library/scala/Option.scala
@@ -266,7 +266,7 @@ sealed abstract class Option[+A] extends Product with Serializable {
* if it is nonempty, or the empty list if the $option is empty.
*/
def toList: List[A] =
- if (isEmpty) List() else List(this.get)
+ if (isEmpty) List() else new ::(this.get, Nil)
/** Returns a [[scala.util.Left]] containing the given
* argument `left` if this $option is empty, or
diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala
index 7154b8da34..d0a339bdd5 100644
--- a/src/library/scala/PartialFunction.scala
+++ b/src/library/scala/PartialFunction.scala
@@ -67,7 +67,7 @@ trait PartialFunction[-A, +B] extends (A => B) { self =>
* of this partial function and `that`. The resulting partial function
* 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] =
+ def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] =
new OrElse[A1, B1] (this, that)
//TODO: why not overload it with orElse(that: F1): F1?
@@ -78,10 +78,8 @@ trait PartialFunction[-A, +B] extends (A => B) { self =>
* @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 PartialFunction[A, C] {
- def isDefinedAt(x: A): Boolean = self isDefinedAt x
- def apply(x: A): C = k(self(x))
- }
+ override def andThen[C](k: B => C): PartialFunction[A, C] =
+ new AndThen[A, B, C] (this, k)
/** Turns this partial function into an plain function returning an `Option` result.
* @see Function.unlift
@@ -90,28 +88,54 @@ trait PartialFunction[-A, +B] extends (A => B) { self =>
*/
def lift: A => Option[B] = new Lifted(this)
- /**
- * TODO: comment
+ /** Applies this partial function to the given argument when it is contained in the function domain.
+ * Applies fallback function where this partial function is not defined.
+ *
+ * Note that expression `pf.applyOrElse(x, default)` is equivalent to
+ * {{{ if(pf isDefinedAt x) pf(x) else default(x) }}}
+ * except that `applyOrElse` method can be implemented more efficiently.
+ * For all partial function literals compiler generates `applyOrElse` implementation which
+ * avoids double evaluation of pattern matchers and guards.
+ * This makes `applyOrElse` the basis for the efficient implementation for many operations and scenarios, such as:
+ *
+ * - combining partial functions into `orElse`/`andThen` chains does not lead to
+ * excessive `apply`/`isDefinedAt` evaluation
+ * - `lift` and `unlift` do not evaluate source functions twice on each invocation
+ * - `runWith` allows efficient imperative-style combining of partial functions
+ * with conditionally applied actions
+ *
+ * For non-literal partial function classes with nontrivial `isDefinedAt` method
+ * it is recommended to override `applyOrElse` with custom implementation that avoids
+ * double `isDefinedAt` evaluation. This may result in better performance
+ * and more predictable behavior w.r.t. side effects.
+ *
+ * @param x the function argument
+ * @param default the fallback function
+ * @return the result of this function or fallback function application.
* @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
+ /** Composes this partial function with an action function which
+ * gets applied to results of this partial function.
+ * The action function is invoked only for its side effects; its result is ignored.
+ *
+ * Note that expression `pf.runWith(action)(x)` is equivalent to
+ * {{{ if(pf isDefinedAt x) { action(pf(x)); true } else false }}}
+ * except that `runWith` is implemented via `applyOrElse` and thus potentially more efficient.
+ * Using `runWith` avoids double evaluation of pattern matchers and guards for partial function literals.
+ * @see `applyOrElse`.
+ *
+ * @param action the action function
+ * @return a function which maps arguments `x` to `isDefinedAt(x)`. The resulting function
+ * runs `action(this(x))` where `this` is defined.
* @since 2.10
*/
- def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) }
+ def runWith[U](action: B => U): A => Boolean = { x =>
+ val z = applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) { action(z); true } else false
+ }
}
/** A few handy operations which leverage the extra bit of information
@@ -137,11 +161,10 @@ object PartialFunction {
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 applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = {
+ val z = f1.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) z else f2.applyOrElse(x, default)
+ }
override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) =
new OrElse[A1, B1] (f1, f2 orElse that)
@@ -150,23 +173,61 @@ object PartialFunction {
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
+ /** Composite function produced by `PartialFunction#andThen` method
+ */
+ private final class AndThen[-A, B, +C] (pf: PartialFunction[A, B], k: B => C) extends PartialFunction[A, C] {
+ def isDefinedAt(x: A) = pf.isDefinedAt(x)
+
+ def apply(x: A): C = k(pf(x))
+
+ override def applyOrElse[A1 <: A, C1 >: C](x: A1, default: A1 => C1): C1 = {
+ val z = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) k(z) else default(x)
+ }
+ }
+
+ /** To implement patterns like {{{ if(pf isDefinedAt x) f1(pf(x)) else f2(x) }}} efficiently
+ * the following trick is used:
+ *
+ * To avoid double evaluation of pattern matchers & guards `applyOrElse` method is used here
+ * instead of `isDefinedAt`/`apply` pair.
+ *
+ * After call to `applyOrElse` we need both the function result it returned and
+ * the fact if the function's argument was contained in its domain. The only degree of freedom we have here
+ * to achieve this goal is tweaking with the continuation argument (`default`) of `applyOrElse` method.
+ * The obvious way is to throw an exception from `default` function and to catch it after
+ * calling `applyOrElse` but I consider this somewhat inefficient.
+ *
+ * I know only one way how you can do this task efficiently: `default` function should return unique marker object
+ * which never may be returned by any other (regular/partial) function. This way after calling `applyOrElse` you need
+ * just one reference comparison to distinguish if `pf isDefined x` or not.
+ *
+ * This correctly interacts with specialization as return type of `applyOrElse`
+ * (which is parameterized upper bound) can never be specialized.
+ *
+ * Here `fallback_pf` is used as both unique marker object and special fallback function that returns it.
+ */
+ private[this] final val fallback_pf: PartialFunction[Any, Any] = { case _ => fallback_pf }
+ @inline private final def checkFallback[B] = fallback_pf.asInstanceOf[PartialFunction[Any, B]]
+ @inline private final def fallbackOccurred[B](x: B) = (fallback_pf eq x.asInstanceOf[AnyRef])
- private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B])
+ private 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)
+ def apply(x: A): Option[B] = {
+ val z = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) Some(z) else None
}
}
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 applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = {
+ val z = f(x)
+ if (!z.isEmpty) z.get else default(x)
+ }
+
override def lift = f
}
@@ -178,7 +239,6 @@ object PartialFunction {
/** 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}
@@ -189,12 +249,11 @@ object PartialFunction {
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
+ /** The partial function with empty domain.
+ * Any attempt to invoke empty partial function leads to throwing [[scala.MatchError]] exception.
* @since 2.10
*/
def empty[A, B] : PartialFunction[A, B] = empty_pf
diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala
index 903de4a247..9b04256c8d 100644
--- a/src/library/scala/collection/GenTraversableLike.scala
+++ b/src/library/scala/collection/GenTraversableLike.scala
@@ -65,14 +65,14 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* @throws `NoSuchElementException` if the $coll is empty.
*/
def head: A
-
+
/** Optionally selects the first element.
* $orderDependent
* @return the first element of this $coll if it is nonempty,
* `None` if it is empty.
*/
def headOption: Option[A]
-
+
/** Tests whether this $coll can be repeatedly traversed.
* @return `true`
*/
@@ -92,14 +92,14 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* @throws NoSuchElementException If the $coll is empty.
*/
def last: A
-
+
/** Optionally selects the last element.
* $orderDependent
* @return the last element of this $coll$ if it is nonempty,
* `None` if it is empty.
*/
def lastOption: Option[A]
-
+
/** Selects all elements except the last.
* $orderDependent
* @return a $coll consisting of all elements of this $coll
@@ -107,7 +107,7 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
* @throws `UnsupportedOperationException` if the $coll is empty.
*/
def init: Repr
-
+
/** Computes a prefix scan of the elements of the collection.
*
* Note: The neutral element `z` may be applied more than once.
@@ -210,7 +210,7 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That
/** Builds a new collection by applying a function to all elements of this $coll
- * and using the elements of the resulting collections.
+ * and using the elements of the resulting collections.
*
* @param f the function to apply to each element.
* @tparam B the element type of the returned collection.
diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala
index a978a9a783..8e4fdf537d 100644
--- a/src/library/scala/collection/JavaConversions.scala
+++ b/src/library/scala/collection/JavaConversions.scala
@@ -22,7 +22,8 @@ import convert._
* scala.collection.mutable.Buffer <=> java.util.List
* scala.collection.mutable.Set <=> java.util.Set
* scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
- * scala.collection.mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap
+ * scala.collection.mutable.ConcurrentMap (deprecated since 2.10) <=> java.util.concurrent.ConcurrentMap
+ * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
*}}}
* In all cases, converting from a source type to a target type and back
* again will return the original source object, eg.
diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala
index 5e0bd010a6..188e0e8afd 100755
--- a/src/library/scala/collection/LinearSeqOptimized.scala
+++ b/src/library/scala/collection/LinearSeqOptimized.scala
@@ -82,17 +82,16 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
false
}
- override /*TraversableLike*/
- def count(p: A => Boolean): Int = {
+ override /*SeqLike*/
+ def contains(elem: Any): Boolean = {
var these = this
- var cnt = 0
while (!these.isEmpty) {
- if (p(these.head)) cnt += 1
+ if (these.head == elem) return true
these = these.tail
}
- cnt
+ false
}
-
+
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
@@ -113,7 +112,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea
}
acc
}
-
+
override /*IterableLike*/
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 0345f05355..b2051bf209 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -235,14 +235,19 @@ trait TraversableLike[+A, +Repr] extends Any
(that ++ seq)(breakOut)
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
- val b = bf(repr)
- b.sizeHint(this)
+ def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
+ val b = bf(repr)
+ b.sizeHint(this)
+ b
+ }
+ val b = builder
for (x <- this) b += f(x)
b.result
}
def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
- val b = bf(repr)
+ def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
+ val b = builder
for (x <- this) b ++= f(x).seq
b.result
}
@@ -266,7 +271,12 @@ trait TraversableLike[+A, +Repr] extends Any
* @return a new $coll consisting of all elements of this $coll that do not satisfy the given
* predicate `p`. The order of the elements is preserved.
*/
- def filterNot(p: A => Boolean): Repr = filter(!p(_))
+ def filterNot(p: A => Boolean): Repr = {
+ val b = newBuilder
+ for (x <- this)
+ if (!p(x)) b += x
+ b.result
+ }
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala
index 49f4d7cd99..c2994a0986 100644
--- a/src/library/scala/collection/convert/WrapAsScala.scala
+++ b/src/library/scala/collection/convert/WrapAsScala.scala
@@ -13,7 +13,27 @@ import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
import Wrappers._
import language.implicitConversions
-trait WrapAsScala {
+trait LowPriorityWrapAsScala {
+ this: WrapAsScala =>
+ /**
+ * 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.
+ */
+ @deprecated("Use `mapAsScalaConcurrentMap` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0")
+ implicit def mapAsScalaDeprecatedConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] =
+ asScalaConcurrentMap(m)
+}
+
+trait WrapAsScala extends LowPriorityWrapAsScala {
/**
* Implicitly converts a Java `Iterator` to a Scala `Iterator`.
*
diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala
index 0b297aeb45..b41327ed95 100644
--- a/src/library/scala/collection/immutable/HashMap.scala
+++ b/src/library/scala/collection/immutable/HashMap.scala
@@ -146,6 +146,29 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
private object EmptyHashMap extends HashMap[Any, Nothing] { }
+ // utility method to create a HashTrieMap from two leaf HashMaps (HashMap1 or HashMapCollision1) with non-colliding hash code)
+ private def makeHashTrieMap[A, B](hash0:Int, elem0:HashMap[A, B], hash1:Int, elem1:HashMap[A, B], level:Int, size:Int) : HashTrieMap[A, B] = {
+ val index0 = (hash0 >>> level) & 0x1f
+ val index1 = (hash1 >>> level) & 0x1f
+ if(index0 != index1) {
+ val bitmap = (1 << index0) | (1 << index1)
+ val elems = new Array[HashMap[A,B]](2)
+ if(index0 < index1) {
+ elems(0) = elem0
+ elems(1) = elem1
+ } else {
+ elems(0) = elem1
+ elems(1) = elem0
+ }
+ new HashTrieMap[A, B](bitmap, elems, size)
+ } else {
+ val elems = new Array[HashMap[A,B]](1)
+ val bitmap = (1 << index0)
+ elems(0) = makeHashTrieMap(hash0, elem0, hash1, elem1, level + 5, size)
+ new HashTrieMap[A, B](bitmap, elems, size)
+ }
+ }
+
// TODO: add HashMap2, HashMap3, ...
class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] {
@@ -183,30 +206,10 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
new HashMap1(nkv._1, hash, nkv._2, nkv)
}
} else {
- var thatindex = (hash >>> level) & 0x1f
- var thisindex = (this.hash >>> level) & 0x1f
if (hash != this.hash) {
// they have different hashes, but may collide at this level - find a level at which they don't
- var lvl = level
- var top: HashTrieMap[A, B1] = null
- var prev: HashTrieMap[A, B1] = null
- while (thisindex == thatindex) {
- val newlevel = new HashTrieMap[A, B1](1 << thisindex, new Array[HashMap[A, B1]](1), 2)
- if (prev ne null) prev.elems(0) = newlevel else top = newlevel
- prev = newlevel
- lvl += 5
- thatindex = (hash >>> lvl) & 0x1f
- thisindex = (this.hash >>> lvl) & 0x1f
- }
- val bottelems = new Array[HashMap[A,B1]](2)
- val ind = if (thisindex < thatindex) 1 else 0
- bottelems(1 - ind) = this
- bottelems(ind) = new HashMap1[A, B1](key, hash, value, kv)
- val bottom = new HashTrieMap[A,B1]((1 << thisindex) | (1 << thatindex), bottelems, 2)
- if (prev ne null) {
- prev.elems(0) = bottom
- top
- } else bottom
+ val that = new HashMap1[A, B1](key, hash, value, kv)
+ makeHashTrieMap[A,B1](this.hash, this, hash, that, level, 2)
} else {
// 32-bit hash collision (rare, but not impossible)
new HashMapCollision1(hash, ListMap.empty.updated(this.key,this.value).updated(key,value))
@@ -221,12 +224,13 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
// this method may be called multiple times in a multithreaded environment, but that's ok
private[HashMap] def ensurePair: (A,B) = if (kv ne null) kv else { kv = (key, value); kv }
protected override def merge0[B1 >: B](that: HashMap[A, B1], level: Int, merger: Merger[A, B1]): HashMap[A, B1] = {
- that.updated0(key, hash, level, value, kv, if (merger ne null) merger.invert else null)
+ that.updated0(key, hash, level, value, kv, merger.invert)
}
}
private[collection] class HashMapCollision1[A, +B](private[collection] val hash: Int, val kvs: ListMap[A, B @uV])
extends HashMap[A, B @uV] {
+ // assert(kvs.size > 1)
override def size = kvs.size
@@ -238,20 +242,20 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value))
else new HashMapCollision1(hash, kvs + merger((key, kvs(key)), kv))
} else {
- var m: HashMap[A,B1] = new HashTrieMap[A,B1](0,new Array[HashMap[A,B1]](0),0)
- // might be able to save some ops here, but it doesn't seem to be worth it
- for ((k,v) <- kvs)
- m = m.updated0(k, this.hash, level, v, null, merger)
- m.updated0(key, hash, level, value, kv, merger)
+ val that = new HashMap1(key, hash, value, kv)
+ makeHashTrieMap(this.hash, this, hash, that, level, size + 1)
}
override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] =
if (hash == this.hash) {
val kvs1 = kvs - key
- if (!kvs1.isEmpty)
- new HashMapCollision1(hash, kvs1)
- else
+ if (kvs1.isEmpty)
HashMap.empty[A,B]
+ else if(kvs1.tail.isEmpty) {
+ val kv = kvs1.head
+ new HashMap1[A,B](kv._1,hash,kv._2,kv)
+ } else
+ new HashMapCollision1(hash, kvs1)
} else this
override def iterator: Iterator[(A,B)] = kvs.iterator
@@ -275,6 +279,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
private[collection] val size0: Int
) extends HashMap[A, B @uV] {
+ // assert(Integer.bitCount(bitmap) == elems.length)
+ // assert(elems.length > 1 || (elems.length == 1 && elems(0).isInstanceOf[HashTrieMap[_,_]]))
+
/*
def this (level: Int, m1: HashMap1[A,B], m2: HashMap1[A,B]) = {
this(((m1.hash >>> level) & 0x1f) | ((m2.hash >>> level) & 0x1f), {
@@ -347,9 +354,14 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
Array.copy(elems, 0, elemsNew, 0, offset)
Array.copy(elems, offset + 1, elemsNew, offset, elems.length - offset - 1)
val sizeNew = size - sub.size
- new HashTrieMap(bitmapNew, elemsNew, sizeNew)
+ if (elemsNew.length == 1 && !elemsNew(0).isInstanceOf[HashTrieMap[_,_]])
+ elemsNew(0)
+ else
+ new HashTrieMap(bitmapNew, elemsNew, sizeNew)
} else
HashMap.empty[A,B]
+ } else if(elems.length == 1 && !subNew.isInstanceOf[HashTrieMap[_,_]]) {
+ subNew
} else {
val elemsNew = new Array[HashMap[A,B]](elems.length)
Array.copy(elems, 0, elemsNew, 0, elems.length)
@@ -480,7 +492,7 @@ time { mNew.iterator.foreach( p => ()) }
}
new HashTrieMap[A, B1](this.bitmap | that.bitmap, merged, totalelems)
- case hm: HashMapCollision1[_, _] => that.merge0(this, level, if (merger ne null) merger.invert else null)
+ case hm: HashMapCollision1[_, _] => that.merge0(this, level, merger.invert)
case hm: HashMap[_, _] => this
case _ => sys.error("section supposed to be unreachable.")
}
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 74dc385f99..87b58005cf 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -302,6 +302,15 @@ sealed abstract class List[+A] extends AbstractSeq[A]
if (isEmpty) Stream.Empty
else new Stream.Cons(head, tail.toStream)
+ @inline override final
+ def foreach[B](f: A => B) {
+ var these = this
+ while (!these.isEmpty) {
+ f(these.head)
+ these = these.tail
+ }
+ }
+
@deprecated("use `distinct` instead", "2.8.0")
def removeDuplicates: List[A] = distinct
}
@@ -378,7 +387,6 @@ final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extend
while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
out.writeObject(ListSerializeEnd)
}
-
}
/** $factoryInfo
diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala
index 091443f909..c21032603f 100644
--- a/src/library/scala/collection/immutable/ListMap.scala
+++ b/src/library/scala/collection/immutable/ListMap.scala
@@ -121,12 +121,12 @@ extends AbstractMap[A, B]
def hasNext = !self.isEmpty
def next(): (A,B) =
if (!hasNext) throw new NoSuchElementException("next on empty iterator")
- else { val res = (self.key, self.value); self = self.next; res }
+ else { val res = (self.key, self.value); self = self.tail; res }
}.toList.reverseIterator
protected def key: A = throw new NoSuchElementException("empty map")
protected def value: B = throw new NoSuchElementException("empty map")
- protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map")
+ override def tail: ListMap[A, B] = throw new NoSuchElementException("empty map")
/** This class represents an entry in the `ListMap`.
*/
@@ -140,7 +140,7 @@ extends AbstractMap[A, B]
override def size: Int = size0(this, 0)
// to allow tail recursion and prevent stack overflows
- @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1)
+ @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.tail, acc + 1)
/** Is this an empty map?
*
@@ -157,7 +157,7 @@ extends AbstractMap[A, B]
*/
override def apply(k: A): B1 = apply0(this, k)
- @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (k == cur.key) cur.value else apply0(cur.next, k)
+ @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = if (k == cur.key) cur.value else apply0(cur.tail, k)
/** Checks if this map maps `key` to a value and return the
* value if it exists.
@@ -169,7 +169,7 @@ extends AbstractMap[A, B]
@tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] =
if (k == cur.key) Some(cur.value)
- else if (cur.next.nonEmpty) get0(cur.next, k) else None
+ else if (cur.tail.nonEmpty) get0(cur.tail, k) else None
/** This method allows one to create a new map with an additional mapping
* from `key` to `value`. If the map contains already a mapping for `key`,
@@ -198,7 +198,7 @@ extends AbstractMap[A, B]
var lst: List[(A, B1)] = Nil
while (cur.nonEmpty) {
if (k != cur.key) lst ::= ((cur.key, cur.value))
- cur = cur.next
+ cur = cur.tail
}
var acc = ListMap[A, B1]()
while (lst != Nil) {
@@ -211,6 +211,6 @@ extends AbstractMap[A, B]
}
- override protected def next: ListMap[A, B1] = ListMap.this
+ override def tail: ListMap[A, B1] = ListMap.this
}
}
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 1bf1e20694..97707d4f7c 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -479,22 +479,40 @@ self =>
final class StreamWithFilter(p: A => Boolean) extends WithFilter(p) {
override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = {
- def tailMap = asStream[B](tail withFilter p map f)
- if (isStreamBuilder(bf)) asThat(
- if (isEmpty) Stream.Empty
- else if (p(head)) cons(f(head), tailMap)
- else tailMap
- )
+ def tailMap(coll: Stream[A]): Stream[B] = {
+ var head: A = null.asInstanceOf[A]
+ var tail: Stream[A] = coll
+ while (true) {
+ if (tail.isEmpty)
+ return Stream.Empty
+ head = tail.head
+ tail = tail.tail
+ if (p(head))
+ return cons(f(head), tailMap(tail))
+ }
+ throw new RuntimeException()
+ }
+
+ if (isStreamBuilder(bf)) asThat(tailMap(Stream.this))
else super.map(f)(bf)
}
override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = {
- def tailFlatMap = asStream[B](tail withFilter p flatMap f)
- if (isStreamBuilder(bf)) asThat(
- if (isEmpty) Stream.Empty
- else if (p(head)) f(head).toStream append tailFlatMap
- else tailFlatMap
- )
+ def tailFlatMap(coll: Stream[A]): Stream[B] = {
+ var head: A = null.asInstanceOf[A]
+ var tail: Stream[A] = coll
+ while (true) {
+ if (tail.isEmpty)
+ return Stream.Empty
+ head = tail.head
+ tail = tail.tail
+ if (p(head))
+ return f(head).toStream append tailFlatMap(tail)
+ }
+ throw new RuntimeException()
+ }
+
+ if (isStreamBuilder(bf)) asThat(tailFlatMap(Stream.this))
else super.flatMap(f)(bf)
}
diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala
index bbf4f5889d..b6887df61e 100644
--- a/src/library/scala/collection/mutable/Builder.scala
+++ b/src/library/scala/collection/mutable/Builder.scala
@@ -62,9 +62,27 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* wrong, i.e. a different number of elements is added.
*
* @param coll the collection which serves as a hint for the result's size.
+ */
+ def sizeHint(coll: TraversableLike[_, _]) {
+ if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
+ sizeHint(coll.size)
+ }
+ }
+
+ /** Gives a hint that one expects the `result` of this builder
+ * to have the same size as the given collection, plus some delta. This will
+ * provide a hint only if the collection is known to have a cheap
+ * `size` method. Currently this is assumed to be the case if and only if
+ * the collection is of type `IndexedSeqLike`.
+ * Some builder classes
+ * will optimize their representation based on the hint. However,
+ * builder implementations are still required to work correctly even if the hint is
+ * wrong, i.e. a different number of elements is added.
+ *
+ * @param coll the collection which serves as a hint for the result's size.
* @param delta a correction to add to the `coll.size` to produce the size hint.
*/
- def sizeHint(coll: TraversableLike[_, _], delta: Int = 0) {
+ def sizeHint(coll: TraversableLike[_, _], delta: Int) {
if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) {
sizeHint(coll.size + delta)
}
diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala
index cba4e9725e..b7c5f07502 100644
--- a/src/library/scala/collection/mutable/DoubleLinkedList.scala
+++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala
@@ -63,6 +63,13 @@ class DoubleLinkedList[A]() extends AbstractSeq[A]
}
override def companion: GenericCompanion[DoubleLinkedList] = DoubleLinkedList
+
+ // Accurately clone this collection. See SI-6296
+ override def clone(): DoubleLinkedList[A] = {
+ val builder = newBuilder
+ builder ++= this
+ builder.result
+ }
}
/** $factoryInfo
diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala
index 2aa19d6cb0..21c3a84699 100644
--- a/src/library/scala/collection/mutable/Queue.scala
+++ b/src/library/scala/collection/mutable/Queue.scala
@@ -32,6 +32,7 @@ import generic._
*/
class Queue[A]
extends MutableList[A]
+ with LinearSeqOptimized[A, Queue[A]]
with GenericTraversableTemplate[A, Queue]
with Cloneable[Queue[A]]
with Serializable
@@ -165,6 +166,17 @@ extends MutableList[A]
* @return the first element.
*/
def front: A = head
+
+
+ // TODO - Don't override this just for new to create appropriate type....
+ override def tail: Queue[A] = {
+ require(nonEmpty, "tail of empty list")
+ val tl = new Queue[A]
+ tl.first0 = first0.tail
+ tl.last0 = last0
+ tl.len = len - 1
+ tl
+ }
}
diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala
index ad882390c8..c9876c4d74 100644
--- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala
+++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala
@@ -202,7 +202,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has
def groupByKey[Repr](cbf: () => Combiner[V, Repr]): ParHashMap[K, Repr] = {
val bucks = buckets.filter(_ != null).map(_.headPtr)
val root = new Array[HashMap[K, AnyRef]](bucks.length)
-
+
combinerTaskSupport.executeAndWaitResult(new CreateGroupedTrie(cbf, bucks, root, 0, bucks.length))
var bitmap = 0
@@ -306,8 +306,7 @@ extends collection.parallel.BucketCombiner[(K, V), ParHashMap[K, V], (K, V), Has
unrolled = unrolled.next
}
- evaluateCombiners(trie)
- trie.asInstanceOf[HashMap[K, Repr]]
+ evaluateCombiners(trie).asInstanceOf[HashMap[K, Repr]]
}
private def evaluateCombiners(trie: HashMap[K, Combiner[V, Repr]]): HashMap[K, Repr] = trie match {
case hm1: HashMap.HashMap1[_, _] =>
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 7b6df6e31c..5255c44f10 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -64,6 +64,7 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial
}
object ClassTag {
+ private val NothingTYPE = classOf[scala.runtime.Nothing$]
private val NullTYPE = classOf[scala.runtime.Null$]
private val ObjectTYPE = classOf[java.lang.Object]
@@ -80,13 +81,7 @@ object ClassTag {
val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object]{ def runtimeClass = ObjectTYPE; private def readResolve() = ClassTag.Object }
val AnyVal : ClassTag[scala.AnyVal] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyVal]]
val AnyRef : ClassTag[scala.AnyRef] = ClassTag.Object.asInstanceOf[ClassTag[scala.AnyRef]]
- val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{
- def runtimeClass = throw new Exception("Nothing is a bottom type, therefore its erasure does not return a value")
- private def readResolve() = ClassTag.Nothing
- override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && (x.asInstanceOf[AnyRef] eq ClassTag.Nothing)
- override def hashCode = System.identityHashCode(this)
- override def toString = "ClassTag[Nothing]"
- }
+ val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{ def runtimeClass = NothingTYPE; private def readResolve() = ClassTag.Nothing }
val Null : ClassTag[scala.Null] = new ClassTag[scala.Null]{ def runtimeClass = NullTYPE; private def readResolve() = ClassTag.Null }
def apply[T](runtimeClass1: jClass[_]): ClassTag[T] =
diff --git a/src/library/scala/reflect/base/Base.scala b/src/library/scala/reflect/base/Base.scala
index 798e257d1e..28ebdf4377 100644
--- a/src/library/scala/reflect/base/Base.scala
+++ b/src/library/scala/reflect/base/Base.scala
@@ -487,6 +487,7 @@ class Base extends Universe { self =>
}
case object EmptyTree extends TermTree {
+ val asList = List(this)
override def isEmpty = true
}
diff --git a/src/library/scala/reflect/base/Symbols.scala b/src/library/scala/reflect/base/Symbols.scala
index 294fa19d62..3830264425 100644
--- a/src/library/scala/reflect/base/Symbols.scala
+++ b/src/library/scala/reflect/base/Symbols.scala
@@ -107,8 +107,8 @@ trait Symbols { self: Universe =>
/** Does this symbol represent the definition of a type?
* Note that every symbol is either a term or a type.
- * So for every symbol `sym`, either `sym.isTerm` is true
- * or `sym.isType` is true.
+ * So for every symbol `sym` (except for `NoSymbol`),
+ * either `sym.isTerm` is true or `sym.isType` is true.
*/
def isType: Boolean = false
@@ -118,9 +118,9 @@ trait Symbols { self: Universe =>
def asType: TypeSymbol = throw new ScalaReflectionException(s"$this is not a type")
/** Does this symbol represent the definition of a term?
- * Note that every symbol is either a term or a term.
- * So for every symbol `sym`, either `sym.isTerm` is true
- * or `sym.isTerm` is true.
+ * Note that every symbol is either a term or a type.
+ * So for every symbol `sym` (except for `NoSymbol`),
+ * either `sym.isTerm` is true or `sym.isTerm` is true.
*/
def isTerm: Boolean = false
@@ -234,10 +234,10 @@ trait Symbols { self: Universe =>
* `PolyType(ClassInfoType(...))` that describes type parameters, value
* parameters, parent types, and members of `C`.
*/
- def toType: Type
+ def toType: Type
- override def isType = true
- override def asType = this
+ final override def isType = true
+ final override def asType = this
}
/** The base API that all term symbols support */
diff --git a/src/library/scala/reflect/base/TypeTags.scala b/src/library/scala/reflect/base/TypeTags.scala
index c9d1ccf5bc..b7e0c37a4b 100644
--- a/src/library/scala/reflect/base/TypeTags.scala
+++ b/src/library/scala/reflect/base/TypeTags.scala
@@ -250,9 +250,11 @@ trait TypeTags { self: Universe =>
}
// incantations
+ def absTypeTag[T](implicit attag: AbsTypeTag[T]) = attag
def typeTag[T](implicit ttag: TypeTag[T]) = ttag
// big thanks to Viktor Klang for this brilliant idea!
+ def absTypeOf[T](implicit attag: AbsTypeTag[T]): Type = attag.tpe
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
}
diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala
index f499350ce9..c1f245590b 100644
--- a/src/library/scala/runtime/AbstractPartialFunction.scala
+++ b/src/library/scala/runtime/AbstractPartialFunction.scala
@@ -8,7 +8,8 @@
package scala.runtime
-/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`.
+/** `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,
@@ -16,12 +17,7 @@ package scala.runtime
* - 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.
+ * This trait is used as a basis for implementation of all partial function literals.
*
* @author Pavel Pavlov
* @since 2.10
@@ -35,34 +31,4 @@ abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala
// 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)
-
- @annotation.unspecialized 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)
- }
- }
-
- // 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
- @annotation.unspecialized override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x)
- @annotation.unspecialized override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this
- //TODO: check generated code for PF literal here
- @annotation.unspecialized 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 2ee053c92b..1567e06c22 100644
--- a/src/library/scala/util/control/Exception.scala
+++ b/src/library/scala/util/control/Exception.scala
@@ -6,7 +6,8 @@
** |/ **
\* */
-package scala.util.control
+package scala.util
+package control
import collection.immutable.List
import reflect.{ ClassTag, classTag }
@@ -25,6 +26,10 @@ import language.implicitConversions
* val x2 = catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s)
* }}}
*
+ * This class differs from `scala.util.Try` in that it focuses on composing exception handlers rather than
+ * composing behavior. All behavior should be composed first and fed to a `Catch` object using one of the
+ * `opt` or `either` methods.
+ *
* @author Paul Phillips
*/
@@ -118,6 +123,11 @@ object Exception {
*/
def either[U >: T](body: => U): Either[Throwable, U] = toEither(Right(body))
+ /** Apply this catch logic to the supplied body, mapping the result
+ * into Try[T] - Failure if an exception was caught, Success(T) otherwise.
+ */
+ def withTry[U >: T](body: => U): scala.util.Try[U] = toTry(Success(body))
+
/** Create a `Catch` object with the same `isDefinedAt` logic as this one,
* but with the supplied `apply` method replacing the current one. */
def withApply[U](f: Throwable => U): Catch[U] = {
@@ -131,35 +141,11 @@ object Exception {
/** Convenience methods. */
def toOption: Catch[Option[T]] = withApply(_ => None)
def toEither: Catch[Either[Throwable, T]] = withApply(Left(_))
- }
-
- /** A container class for Try logic */
- class Try[+T] private[Exception](body: => T, val catcher: Catch[T]) {
- /** Execute "body" using catch/finally logic "catcher" */
- def apply(): T = catcher(body)
- def apply[U >: T](other: => U): U = catcher(other)
-
- /** As apply, but map caught exceptions to `None` and success to `Some(T)`. */
- def opt(): Option[T] = catcher opt body
- def opt[U >: T](other: => U): Option[U] = catcher opt other
-
- /** As apply, but map caught exceptions to `Left(ex)` and success to Right(x) */
- def either(): Either[Throwable, T] = catcher either body
- def either[U >: T](other: => U): Either[Throwable, U] = catcher either other
-
- /** Create a `Try` object with the supplied body replacing the current body. */
- def tryInstead[U >: T](other: => U) = new Try(other, catcher)
-
- /** Create a `Try` object with the supplied logic appended to the existing Catch logic. */
- def or[U >: T](pf: Catcher[U]) = new Try(body, catcher or pf)
-
- /** Create a `Try`object with the supplied code appended to the existing `Finally`. */
- def andFinally(fin: => Unit) = new Try(body, catcher andFinally fin)
-
- override def toString() = List("Try(<body>)", catcher.toString) mkString " "
+ def toTry: Catch[scala.util.Try[T]] = withApply(x => Failure(x))
}
final val nothingCatcher: Catcher[Nothing] = mkThrowableCatcher(_ => false, throw _)
+ final def nonFatalCatcher[T]: Catcher[T] = mkThrowableCatcher({ case NonFatal(_) => true; case _ => false }, throw _)
final def allCatcher[T]: Catcher[T] = mkThrowableCatcher(_ => true, throw _)
/** The empty `Catch` object. */
@@ -168,6 +154,9 @@ object Exception {
/** A `Catch` object which catches everything. */
final def allCatch[T]: Catch[T] = new Catch(allCatcher[T]) withDesc "<everything>"
+ /** A `Catch` object witch catches non-fatal exceptions. */
+ final def nonFatalCatch[T]: Catch[T] = new Catch(nonFatalCatcher[T]) withDesc "<non-fatal>"
+
/** Creates a `Catch` object which will catch any of the supplied exceptions.
* Since the returned `Catch` object has no specific logic defined and will simply
* rethrow the exceptions it catches, you will typically want to call `opt` or
diff --git a/src/library/scala/util/hashing/MurmurHash3.scala b/src/library/scala/util/hashing/MurmurHash3.scala
index 3efd5b5e72..1cfb8276fe 100644
--- a/src/library/scala/util/hashing/MurmurHash3.scala
+++ b/src/library/scala/util/hashing/MurmurHash3.scala
@@ -157,6 +157,20 @@ private[hashing] class MurmurHash3 {
// Finalization
finalizeHash(h, data.length)
}
+
+ final def listHash(xs: collection.immutable.List[_], seed: Int): Int = {
+ var n = 0
+ var h = seed
+ var elems = xs
+ while (!elems.isEmpty) {
+ val head = elems.head
+ val tail = elems.tail
+ h = mix(h, head.##)
+ n += 1
+ elems = tail
+ }
+ finalizeHash(h, n)
+ }
}
/**
@@ -199,7 +213,11 @@ object MurmurHash3 extends MurmurHash3 {
/** To offer some potential for optimization.
*/
- def seqHash(xs: collection.Seq[_]): Int = orderedHash(xs, seqSeed)
+ def seqHash(xs: collection.Seq[_]): Int = xs match {
+ case xs: List[_] => listHash(xs, seqSeed)
+ case xs => orderedHash(xs, seqSeed)
+ }
+
def mapHash(xs: collection.Map[_, _]): Int = unorderedHash(xs, mapSeed)
def setHash(xs: collection.Set[_]): Int = unorderedHash(xs, setSeed)
diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala
index 66e0a496d8..eaaea583ce 100644
--- a/src/library/scala/util/parsing/combinator/Parsers.scala
+++ b/src/library/scala/util/parsing/combinator/Parsers.scala
@@ -155,14 +155,20 @@ trait Parsers {
val successful = true
}
- private lazy val lastNoSuccess = new DynamicVariable[Option[NoSuccess]](None)
+ private lazy val lastNoSuccessVar = new DynamicVariable[Option[NoSuccess]](None)
+
+ @deprecated("lastNoSuccess was not thread-safe and will be removed in 2.11.0", "2.10.0")
+ def lastNoSuccess: NoSuccess = lastNoSuccessVar.value.orNull
+
+ @deprecated("lastNoSuccess was not thread-safe and will be removed in 2.11.0", "2.10.0")
+ def lastNoSuccess_=(x: NoSuccess): Unit = lastNoSuccessVar.value = Option(x)
/** A common super-class for unsuccessful parse results. */
sealed abstract class NoSuccess(val msg: String, override val next: Input) extends ParseResult[Nothing] { // when we don't care about the difference between Failure and Error
val successful = false
- if (lastNoSuccess.value map { v => !(next.pos < v.next.pos) } getOrElse true)
- lastNoSuccess.value = Some(this)
+ if (lastNoSuccessVar.value forall (v => !(next.pos < v.next.pos)))
+ lastNoSuccessVar.value = Some(this)
def map[U](f: Nothing => U) = this
def mapPartial[U](f: PartialFunction[Nothing, U], error: Nothing => String): ParseResult[U] = this
@@ -881,14 +887,14 @@ trait Parsers {
* if `p` consumed all the input.
*/
def phrase[T](p: Parser[T]) = new Parser[T] {
- def apply(in: Input) = lastNoSuccess.withValue(None) {
+ def apply(in: Input) = lastNoSuccessVar.withValue(None) {
p(in) match {
case s @ Success(out, in1) =>
if (in1.atEnd)
s
else
- lastNoSuccess.value filterNot { _.next.pos < in1.pos } getOrElse Failure("end of input expected", in1)
- case ns => lastNoSuccess.value.getOrElse(ns)
+ lastNoSuccessVar.value filterNot { _.next.pos < in1.pos } getOrElse Failure("end of input expected", in1)
+ case ns => lastNoSuccessVar.value.getOrElse(ns)
}
}
}
diff --git a/src/reflect/scala/reflect/api/FlagSets.scala b/src/reflect/scala/reflect/api/FlagSets.scala
index 36836e84a9..fdd43f1883 100644
--- a/src/reflect/scala/reflect/api/FlagSets.scala
+++ b/src/reflect/scala/reflect/api/FlagSets.scala
@@ -3,7 +3,7 @@ package api
import scala.language.implicitConversions
-trait FlagSets { self: Universe =>
+trait FlagSets extends base.FlagSets { self: Universe =>
type FlagSet
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
index 7d185d9879..8c4c423221 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -1,7 +1,7 @@
package scala.reflect
package api
-trait Mirrors { self: Universe =>
+trait Mirrors extends base.Mirrors { self: Universe =>
type RuntimeClass >: Null
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index 9e7b3c9712..b17377795b 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -59,6 +59,9 @@ trait Symbols extends base.Symbols { self: Universe =>
*/
def typeSignature: Type
+ /** Returns all symbols overriden by this symbol. */
+ def allOverriddenSymbols: List[Symbol]
+
/******************* tests *******************/
/** Does this symbol represent a synthetic (i.e. a compiler-generated) entity?
@@ -197,9 +200,6 @@ trait Symbols extends base.Symbols { self: Universe =>
/** ...
*/
def suchThat(cond: Symbol => Boolean): Symbol
-
- /** The string discriminator of this symbol; useful for debugging */
- def kind: String
}
/** The API of term symbols */
diff --git a/src/reflect/scala/reflect/api/Types.scala b/src/reflect/scala/reflect/api/Types.scala
index ebaedd7ac3..f22f8d3e75 100644
--- a/src/reflect/scala/reflect/api/Types.scala
+++ b/src/reflect/scala/reflect/api/Types.scala
@@ -66,6 +66,10 @@ trait Types extends base.Types { self: Universe =>
/** Does this type conform to given type argument `that`? */
def <:< (that: Type): Boolean
+ /** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
+ */
+ def weak_<:<(that: Type): Boolean
+
/** Is this type equivalent to given type argument `that`? */
def =:= (that: Type): Boolean
@@ -155,9 +159,6 @@ trait Types extends base.Types { self: Universe =>
/** Does this type contain a reference to given symbol? */
def contains(sym: Symbol): Boolean
-
- /** The string discriminator of this type; useful for debugging */
- def kind: String
}
/** .. */
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 229570dafd..a444c786f7 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -8,6 +8,7 @@ package internal
import util._
import pickling.ByteCodecs
+import scala.annotation.tailrec
/** AnnotationInfo and its helpers */
trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
@@ -31,11 +32,27 @@ trait AnnotationInfos extends api.AnnotationInfos { self: SymbolTable =>
case AnnotationInfo(tp, Literal(Constant(tpe: Type)) :: Nil, _) if tp.typeSymbol == ThrowsClass => tpe.typeSymbol
}
- /** Test for, get, or remove an annotation */
- def hasAnnotation(cls: Symbol) = annotations exists (_ matches cls)
- def getAnnotation(cls: Symbol) = annotations find (_ matches cls)
+ /** Tests for, get, or remove an annotation */
+ def hasAnnotation(cls: Symbol): Boolean =
+ //OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls)
+ dropOtherAnnotations(annotations, cls).nonEmpty
+
+ def getAnnotation(cls: Symbol): Option[AnnotationInfo] =
+ //OPT inlined from exists to save on #closures; was: annotations find (_ matches cls)
+ dropOtherAnnotations(annotations, cls) match {
+ case ann :: _ => Some(ann)
+ case _ => None
+ }
+
def removeAnnotation(cls: Symbol): Self = filterAnnotations(ann => !(ann matches cls))
+
final def withAnnotation(annot: AnnotationInfo): Self = withAnnotations(List(annot))
+
+ @tailrec private
+ def dropOtherAnnotations(anns: List[AnnotationInfo], cls: Symbol): List[AnnotationInfo] = anns match {
+ case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls)
+ case Nil => Nil
+ }
}
/** Arguments to classfile annotations (which are written to
diff --git a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
index fbee906b7b..554b3bfca6 100644
--- a/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
+++ b/src/reflect/scala/reflect/internal/BaseTypeSeqs.scala
@@ -39,8 +39,8 @@ trait BaseTypeSeqs {
*/
class BaseTypeSeq protected[BaseTypeSeqs] (private[BaseTypeSeqs] val parents: List[Type], private[BaseTypeSeqs] val elems: Array[Type]) {
self =>
- Statistics.incCounter(baseTypeSeqCount)
- Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
+ if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqCount)
+ if (Statistics.canEnable) Statistics.incCounter(baseTypeSeqLenTotal, elems.length)
/** The number of types in the sequence */
def length: Int = elems.length
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index fcbe7d0ed9..98d42b724c 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -137,9 +137,8 @@ trait Definitions extends api.StandardDefinitions {
lazy val BooleanTpe = BooleanClass.toTypeConstructor
lazy val ScalaNumericValueClasses = ScalaValueClasses filterNot Set[Symbol](UnitClass, BooleanClass)
-
- def ScalaValueClassesNoUnit = ScalaValueClasses filterNot (_ eq UnitClass)
- def ScalaValueClasses: List[ClassSymbol] = List(
+ lazy val ScalaValueClassesNoUnit = ScalaValueClasses filterNot (_ eq UnitClass)
+ lazy val ScalaValueClasses: List[ClassSymbol] = List(
UnitClass,
BooleanClass,
ByteClass,
@@ -381,6 +380,7 @@ trait Definitions extends api.StandardDefinitions {
def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass
def isRepeatedParamType(tp: Type) = isScalaRepeatedParamType(tp) || isJavaRepeatedParamType(tp)
+ def isRepeated(param: Symbol) = isRepeatedParamType(param.tpe)
def isCastSymbol(sym: Symbol) = sym == Any_asInstanceOf || sym == Object_asInstanceOf
def isJavaVarArgsMethod(m: Symbol) = m.isMethod && isJavaVarArgs(m.info.params)
@@ -462,7 +462,7 @@ trait Definitions extends api.StandardDefinitions {
def ReflectRuntimeUniverse = if (ReflectRuntimePackage != NoSymbol) getMemberValue(ReflectRuntimePackage, nme.universe) else NoSymbol
def ReflectRuntimeCurrentMirror = if (ReflectRuntimePackage != NoSymbol) getMemberMethod(ReflectRuntimePackage, nme.currentMirror) else NoSymbol
- lazy val PartialManifestClass = getMemberType(ReflectPackage, tpnme.ClassManifest)
+ lazy val PartialManifestClass = getTypeMember(ReflectPackage, tpnme.ClassManifest)
lazy val PartialManifestModule = requiredModule[scala.reflect.ClassManifestFactory.type]
lazy val FullManifestClass = requiredClass[scala.reflect.Manifest[_]]
lazy val FullManifestModule = requiredModule[scala.reflect.ManifestFactory.type]
@@ -494,7 +494,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.Context") // defined in scala-reflect.jar, so we need to be careful
def MacroContextPrefix = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.prefix) else NoSymbol
- def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getMemberType(MacroContextClass, tpnme.PrefixType) else NoSymbol
+ def MacroContextPrefixType = if (MacroContextClass != NoSymbol) getTypeMember(MacroContextClass, tpnme.PrefixType) else NoSymbol
def MacroContextUniverse = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.universe) else NoSymbol
def MacroContextMirror = if (MacroContextClass != NoSymbol) getMemberMethod(MacroContextClass, nme.mirror) else NoSymbol
lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl]
@@ -1012,10 +1012,10 @@ trait Definitions extends api.StandardDefinitions {
case _ => fatalMissingSymbol(owner, name, "member object")
}
}
- def getMemberType(owner: Symbol, name: Name): TypeSymbol = {
+ def getTypeMember(owner: Symbol, name: Name): TypeSymbol = {
getMember(owner, name.toTypeName) match {
case x: TypeSymbol => x
- case _ => fatalMissingSymbol(owner, name, "member type")
+ case _ => fatalMissingSymbol(owner, name, "type member")
}
}
def getMemberClass(owner: Symbol, name: Name): ClassSymbol = {
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
index 25441f9812..4b3eb0cdc4 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -3,7 +3,7 @@ package internal
import scala.collection.mutable.WeakHashMap
// SI-6241: move importers to a mirror
-trait Importers { self: SymbolTable =>
+trait Importers extends api.Importers { self: SymbolTable =>
def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
if (self eq from0) {
@@ -238,7 +238,7 @@ trait Importers { self: SymbolTable =>
case from.AntiPolyType(pre, targs) =>
AntiPolyType(importType(pre), targs map importType)
case x: from.TypeVar =>
- TypeVar(importType(x.origin), importTypeConstraint(x.constr0), x.typeArgs map importType, x.params map importSymbol)
+ TypeVar(importType(x.origin), importTypeConstraint(x.constr), x.typeArgs map importType, x.params map importSymbol)
case from.NotNullType(tpe) =>
NotNullType(importType(tpe))
case from.AnnotatedType(annots, tpe, selfsym) =>
@@ -448,4 +448,4 @@ trait Importers { self: SymbolTable =>
case _ => constant.value
})
}
-} \ No newline at end of file
+}
diff --git a/src/reflect/scala/reflect/internal/Names.scala b/src/reflect/scala/reflect/internal/Names.scala
index 835a46f05d..2fdf27d847 100644
--- a/src/reflect/scala/reflect/internal/Names.scala
+++ b/src/reflect/scala/reflect/internal/Names.scala
@@ -415,9 +415,6 @@ trait Names extends api.Names with LowPriorityNames {
}
else toString
}
-
- @inline
- final def fingerPrint: Long = (1L << start)
/** TODO - find some efficiency. */
def append(ch: Char) = newName("" + this + ch)
diff --git a/src/reflect/scala/reflect/internal/Scopes.scala b/src/reflect/scala/reflect/internal/Scopes.scala
index ed75b5d855..385e45997b 100644
--- a/src/reflect/scala/reflect/internal/Scopes.scala
+++ b/src/reflect/scala/reflect/internal/Scopes.scala
@@ -43,13 +43,8 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
*/
class Scope protected[Scopes] (initElems: ScopeEntry = null, initFingerPrints: Long = 0L) extends ScopeBase with MemberScopeBase {
- /** A bitset containing the last 6 bits of the start value of every name
- * stored in this scope.
- */
- var fingerPrints: Long = initFingerPrints
-
protected[Scopes] def this(base: Scope) = {
- this(base.elems, base.fingerPrints)
+ this(base.elems)
nestinglevel = base.nestinglevel + 1
}
@@ -119,7 +114,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
* @param sym ...
*/
def enter[T <: Symbol](sym: T): T = {
- fingerPrints |= sym.name.fingerPrint
enterEntry(newScopeEntry(sym, this))
sym
}
@@ -156,7 +150,6 @@ trait Scopes extends api.Scopes { self: SymbolTable =>
}
def rehash(sym: Symbol, newname: Name) {
- fingerPrints |= newname.fingerPrint
if (hashtable ne null) {
val index = sym.name.start & HASHMASK
var e1 = hashtable(index)
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 761dcc0534..4100e97cdd 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -72,11 +72,13 @@ abstract class SymbolTable extends macros.Universe
Console.err.println(msg + ": " + result)
result
}
- private[scala] def logResult[T](msg: String)(result: T): T = {
+ @inline
+ final private[scala] def logResult[T](msg: => String)(result: T): T = {
log(msg + ": " + result)
result
}
- private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
+ @inline
+ final private[scala] def logResultIf[T](msg: => String, cond: T => Boolean)(result: T): T = {
if (cond(result))
log(msg + ": " + result)
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index d52afed28a..37f41e2868 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -11,6 +11,7 @@ import scala.collection.mutable.ListBuffer
import util.Statistics
import Flags._
import base.Attachments
+import scala.annotation.tailrec
trait Symbols extends api.Symbols { self: SymbolTable =>
import definitions._
@@ -62,7 +63,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
abstract class SymbolContextApiImpl extends SymbolContextApi {
this: Symbol =>
- def kind: String = kindString
def isExistential: Boolean = this.isExistentiallyBound
def isParamWithDefault: Boolean = this.hasDefault
def isByNameParam: Boolean = this.isValueParameter && (this hasFlag BYNAMEPARAM)
@@ -294,14 +294,31 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def newExistential(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): TypeSymbol =
newAbstractType(name, pos, EXISTENTIAL | newFlags)
- /** Synthetic value parameters when parameter symbols are not available
- */
- final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[TermSymbol]] = {
+ private def freshNamer: () => TermName = {
var cnt = 0
- def freshName() = { cnt += 1; nme.syntheticParamName(cnt) }
- mmap(argtypess)(tp => newValueParameter(freshName(), owner.pos.focus, SYNTHETIC) setInfo tp)
+ () => { cnt += 1; nme.syntheticParamName(cnt) }
}
+ /** Synthetic value parameters when parameter symbols are not available
+ */
+ final def newSyntheticValueParamss(argtypess: List[List[Type]]): List[List[TermSymbol]] =
+ argtypess map (xs => newSyntheticValueParams(xs, freshNamer))
+
+ /** Synthetic value parameters when parameter symbols are not available.
+ * Calling this method multiple times will re-use the same parameter names.
+ */
+ final def newSyntheticValueParams(argtypes: List[Type]): List[TermSymbol] =
+ newSyntheticValueParams(argtypes, freshNamer)
+
+ final def newSyntheticValueParams(argtypes: List[Type], freshName: () => TermName): List[TermSymbol] =
+ argtypes map (tp => newSyntheticValueParam(tp, freshName()))
+
+ /** Synthetic value parameter when parameter symbol is not available.
+ * Calling this method multiple times will re-use the same parameter name.
+ */
+ final def newSyntheticValueParam(argtype: Type, name: TermName = nme.syntheticParamName(1)): TermSymbol =
+ newValueParameter(name, owner.pos.focus, SYNTHETIC) setInfo argtype
+
def newSyntheticTypeParam(): TypeSymbol = newSyntheticTypeParam("T0", 0L)
def newSyntheticTypeParam(name: String, newFlags: Long): TypeSymbol = newTypeParameter(newTypeName(name), NoPosition, newFlags) setInfo TypeBounds.empty
def newSyntheticTypeParams(num: Int): List[TypeSymbol] = (0 until num).toList map (n => newSyntheticTypeParam("T" + n, 0L))
@@ -328,18 +345,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def freshExistential(suffix: String): TypeSymbol =
newExistential(freshExistentialName(suffix), pos)
- /** Synthetic value parameters when parameter symbols are not available.
- * Calling this method multiple times will re-use the same parameter names.
- */
- final def newSyntheticValueParams(argtypes: List[Type]): List[TermSymbol] =
- newSyntheticValueParamss(List(argtypes)).head
-
- /** Synthetic value parameter when parameter symbol is not available.
- * Calling this method multiple times will re-use the same parameter name.
- */
- final def newSyntheticValueParam(argtype: Type): Symbol =
- newSyntheticValueParams(List(argtype)).head
-
/** Type skolems are type parameters ''seen from the inside''
* Assuming a polymorphic method m[T], its type is a PolyType which has a TypeParameter
* with name `T` in its typeParams list. While type checking the parameters, result type and
@@ -1373,7 +1378,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
/** The value parameter sections of this symbol.
*/
def paramss: List[List[Symbol]] = info.paramss
- def hasParamWhich(cond: Symbol => Boolean) = mexists(paramss)(cond)
/** The least proper supertype of a class; includes all parent types
* and refinement where needed. You need to compute that in a situation like this:
@@ -1522,7 +1526,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def alternatives: List[Symbol] =
if (isOverloaded) info.asInstanceOf[OverloadedType].alternatives
- else List(this)
+ else this :: Nil
def filter(cond: Symbol => Boolean): Symbol =
if (isOverloaded) {
@@ -1626,7 +1630,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
(info.decls filter (_.isCaseAccessorMethod)).toList
final def constrParamAccessors: List[Symbol] =
- info.decls.toList filter (sym => !sym.isMethod && sym.isParamAccessor)
+ info.decls.filter(sym => !sym.isMethod && sym.isParamAccessor).toList
/** The symbol accessed by this accessor (getter or setter) function. */
final def accessed: Symbol = accessed(owner.info)
@@ -1892,9 +1896,15 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* @param ofclazz The class containing the symbol's definition
* @param site The base type from which member types are computed
*/
- final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol =
- ofclazz.info.nonPrivateDecl(name).filter(sym =>
- !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+ final def matchingSymbol(ofclazz: Symbol, site: Type): Symbol = {
+ //OPT cut down on #closures by special casing non-overloaded case
+ // was: ofclazz.info.nonPrivateDecl(name) filter (sym =>
+ // !sym.isTerm || (site.memberType(this) matches site.memberType(sym)))
+ val result = ofclazz.info.nonPrivateDecl(name)
+ def qualifies(sym: Symbol) = !sym.isTerm || (site.memberType(this) matches site.memberType(sym))
+ if ((result eq NoSymbol) || !result.isOverloaded && qualifies(result)) result
+ else result filter qualifies
+ }
/** The non-private member of `site` whose type and name match the type of this symbol. */
final def matchingSymbol(site: Type, admit: Long = 0L): Symbol =
@@ -2873,7 +2883,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
override def name: TypeName = {
- Statistics.incCounter(nameCount)
+ if (Statistics.canEnable) Statistics.incCounter(nameCount)
if (needsFlatClasses) {
if (flatname eq null)
flatname = nme.flattenedName(rawowner.name, rawname).toTypeName
@@ -3202,7 +3212,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def toList: List[TypeHistory] = this :: ( if (prev eq null) Nil else prev.toList )
}
+// ----- Hoisted closures and convenience methods, for compile time reductions -------
+
+ private[scala] final val symbolIsPossibleInRefinement = (sym: Symbol) => sym.isPossibleInRefinement
+ private[scala] final val symbolIsNonVariant = (sym: Symbol) => sym.variance == 0
+
+ @tailrec private[scala] final
+ def allSymbolsHaveOwner(syms: List[Symbol], owner: Symbol): Boolean = syms match {
+ case sym :: rest => sym.owner == owner && allSymbolsHaveOwner(rest, owner)
+ case _ => true
+ }
+
+
+// -------------- Statistics --------------------------------------------------------
+
Statistics.newView("#symbols")(ids)
+
}
object SymbolsStats {
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index d160695e67..f953e9b757 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -194,7 +194,7 @@ abstract class TreeGen extends macros.TreeBuilder {
mkTypeApply(mkAttributedSelect(target, method), targs map TypeTree)
private def mkSingleTypeApply(value: Tree, tpe: Type, what: Symbol, wrapInApply: Boolean) = {
- val tapp = mkAttributedTypeApply(value, what, List(tpe.normalize))
+ val tapp = mkAttributedTypeApply(value, what, tpe.normalize :: Nil)
if (wrapInApply) Apply(tapp, Nil) else tapp
}
private def typeTestSymbol(any: Boolean) = if (any) Any_isInstanceOf else Object_isInstanceOf
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 19f264f60e..3a930a195b 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -17,7 +17,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass }
+ import definitions.{ isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, MacroContextClass, MacroContextPrefixType }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -521,20 +521,18 @@ abstract class TreeInfo {
*/
def noPredefImportForUnit(body: Tree) = {
// Top-level definition whose leading imports include Predef.
- def containsLeadingPredefImport(defs: List[Tree]): Boolean = defs match {
- case PackageDef(_, defs1) :: _ => containsLeadingPredefImport(defs1)
- case Import(expr, _) :: rest => isReferenceToPredef(expr) || containsLeadingPredefImport(rest)
- case _ => false
+ def isLeadingPredefImport(defn: Tree): Boolean = defn match {
+ case PackageDef(_, defs1) => defs1 exists isLeadingPredefImport
+ case Import(expr, _) => isReferenceToPredef(expr)
+ case _ => false
}
-
// Compilation unit is class or object 'name' in package 'scala'
def isUnitInScala(tree: Tree, name: Name) = tree match {
case PackageDef(Ident(nme.scala_), defs) => firstDefinesClassOrObject(defs, name)
case _ => false
}
- ( isUnitInScala(body, nme.Predef)
- || containsLeadingPredefImport(List(body)))
+ isUnitInScala(body, nme.Predef) || isLeadingPredefImport(body)
}
def isAbsTypeDef(tree: Tree) = tree match {
@@ -591,4 +589,24 @@ abstract class TreeInfo {
object DynamicUpdate extends DynamicApplicationExtractor(_ == nme.updateDynamic)
object DynamicApplication extends DynamicApplicationExtractor(isApplyDynamicName)
object DynamicApplicationNamed extends DynamicApplicationExtractor(_ == nme.applyDynamicNamed)
+
+ object MacroImplReference {
+ private def refPart(tree: Tree): Tree = tree match {
+ case TypeApply(fun, _) => refPart(fun)
+ case ref: RefTree => ref
+ case _ => EmptyTree
+ }
+
+ def unapply(tree: Tree) = refPart(tree) match {
+ case ref: RefTree => Some((ref.qualifier.symbol, ref.symbol, typeArguments(tree)))
+ case _ => None
+ }
+ }
+
+ def isNullaryInvocation(tree: Tree): Boolean =
+ tree.symbol != null && tree.symbol.isMethod && (tree match {
+ case TypeApply(fun, _) => isNullaryInvocation(fun)
+ case tree: RefTree => true
+ case _ => false
+ })
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 3894870252..0180ed4c4f 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -19,7 +19,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
val id = nodeCount // TODO: add to attachment?
nodeCount += 1
- Statistics.incCounter(TreesStats.nodeByType, getClass)
+ if (Statistics.canEnable) Statistics.incCounter(TreesStats.nodeByType, getClass)
@inline final override def pos: Position = rawatt.pos
@@ -29,7 +29,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def setType(tp: Type): this.type = { rawtpe = tp; this }
def defineType(tp: Type): this.type = setType(tp)
- def symbol: Symbol = null
+ def symbol: Symbol = null //!!!OPT!!! symbol is about 3% of hot compile times -- megamorphic dispatch?
def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) }
def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
def hasSymbol = false
@@ -210,7 +210,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
trait TypTree extends Tree with TypTreeApi
- trait SymTree extends Tree with SymTreeContextApi {
+ abstract class SymTree extends Tree with SymTreeContextApi {
override def hasSymbol = true
override var symbol: Symbol = NoSymbol
}
@@ -230,6 +230,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
case object EmptyTree extends TermTree {
+ val asList = List(this)
super.tpe_=(NoType)
override def tpe_=(t: Type) =
if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
@@ -290,7 +291,10 @@ trait Trees extends api.Trees { self: SymbolTable =>
object LabelDef extends LabelDefExtractor
case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) extends ImportSelectorApi
- object ImportSelector extends ImportSelectorExtractor
+ object ImportSelector extends ImportSelectorExtractor {
+ val wild = ImportSelector(nme.WILDCARD, -1, null, -1)
+ val wildList = List(wild)
+ }
case class Import(expr: Tree, selectors: List[ImportSelector])
extends SymTree with ImportApi
@@ -329,7 +333,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object ArrayValue extends ArrayValueExtractor
case class Function(vparams: List[ValDef], body: Tree)
- extends TermTree with SymTree with FunctionApi
+ extends SymTree with TermTree with FunctionApi
object Function extends FunctionExtractor
case class Assign(lhs: Tree, rhs: Tree)
@@ -349,7 +353,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object Match extends MatchExtractor
case class Return(expr: Tree)
- extends TermTree with SymTree with ReturnApi
+ extends SymTree with TermTree with ReturnApi
object Return extends ReturnExtractor
case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree)
@@ -397,7 +401,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ApplyConstructor(tpt: Tree, args: List[Tree]) = Apply(Select(New(tpt), nme.CONSTRUCTOR), args)
case class ApplyDynamic(qual: Tree, args: List[Tree])
- extends TermTree with SymTree with ApplyDynamicApi
+ extends SymTree with TermTree with ApplyDynamicApi
object ApplyDynamic extends ApplyDynamicExtractor
case class Super(qual: Tree, mix: TypeName) extends TermTree with SuperApi {
@@ -407,7 +411,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object Super extends SuperExtractor
case class This(qual: TypeName)
- extends TermTree with SymTree with ThisApi
+ extends SymTree with TermTree with ThisApi
object This extends ThisExtractor
case class Select(qualifier: Tree, name: Name)
@@ -443,7 +447,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
object SingletonTypeTree extends SingletonTypeTreeExtractor
case class SelectFromTypeTree(qualifier: Tree, name: TypeName)
- extends TypTree with RefTree with SelectFromTypeTreeApi
+ extends RefTree with TypTree with SelectFromTypeTreeApi
object SelectFromTypeTree extends SelectFromTypeTreeExtractor
case class CompoundTypeTree(templ: Template)
@@ -1141,29 +1145,25 @@ trait Trees extends api.Trees { self: SymbolTable =>
}
}
+ //OPT ordered according to frequency to speed it up.
override protected def itransform(transformer: Transformer, tree: Tree): Tree = {
import transformer._
val treeCopy = transformer.treeCopy
+
+ // begin itransform
tree match {
- case EmptyTree =>
- tree
- case PackageDef(pid, stats) =>
- treeCopy.PackageDef(
- tree, transform(pid).asInstanceOf[RefTree],
- atOwner(mclass(tree.symbol)) {
- transformStats(stats, currentOwner)
- }
- )
- case ClassDef(mods, name, tparams, impl) =>
- atOwner(tree.symbol) {
- treeCopy.ClassDef(tree, transformModifiers(mods), name,
- transformTypeDefs(tparams), transformTemplate(impl))
- }
- case ModuleDef(mods, name, impl) =>
- atOwner(mclass(tree.symbol)) {
- treeCopy.ModuleDef(tree, transformModifiers(mods),
- name, transformTemplate(impl))
- }
+ case Ident(name) =>
+ treeCopy.Ident(tree, name)
+ case Select(qualifier, selector) =>
+ treeCopy.Select(tree, transform(qualifier), selector)
+ case Apply(fun, args) =>
+ treeCopy.Apply(tree, transform(fun), transformTrees(args))
+ case TypeTree() =>
+ treeCopy.TypeTree(tree)
+ case Literal(value) =>
+ treeCopy.Literal(tree, value)
+ case This(qual) =>
+ treeCopy.This(tree, qual)
case ValDef(mods, name, tpt, rhs) =>
atOwner(tree.symbol) {
treeCopy.ValDef(tree, transformModifiers(mods),
@@ -1175,73 +1175,70 @@ trait Trees extends api.Trees { self: SymbolTable =>
transformTypeDefs(tparams), transformValDefss(vparamss),
transform(tpt), transform(rhs))
}
- case TypeDef(mods, name, tparams, rhs) =>
- atOwner(tree.symbol) {
- treeCopy.TypeDef(tree, transformModifiers(mods), name,
- transformTypeDefs(tparams), transform(rhs))
- }
- case LabelDef(name, params, rhs) =>
- treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
- case Import(expr, selectors) =>
- treeCopy.Import(tree, transform(expr), selectors)
- case Template(parents, self, body) =>
- treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
case Block(stats, expr) =>
treeCopy.Block(tree, transformStats(stats, currentOwner), transform(expr))
+ case If(cond, thenp, elsep) =>
+ treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep))
case CaseDef(pat, guard, body) =>
treeCopy.CaseDef(tree, transform(pat), transform(guard), transform(body))
- case Alternative(trees) =>
- treeCopy.Alternative(tree, transformTrees(trees))
- case Star(elem) =>
- treeCopy.Star(tree, transform(elem))
+ case TypeApply(fun, args) =>
+ treeCopy.TypeApply(tree, transform(fun), transformTrees(args))
+ case AppliedTypeTree(tpt, args) =>
+ treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
case Bind(name, body) =>
treeCopy.Bind(tree, name, transform(body))
- case UnApply(fun, args) =>
- treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
- case ArrayValue(elemtpt, trees) =>
- treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
case Function(vparams, body) =>
atOwner(tree.symbol) {
treeCopy.Function(tree, transformValDefs(vparams), transform(body))
}
+ case Match(selector, cases) =>
+ treeCopy.Match(tree, transform(selector), transformCaseDefs(cases))
+ case New(tpt) =>
+ treeCopy.New(tree, transform(tpt))
case Assign(lhs, rhs) =>
treeCopy.Assign(tree, transform(lhs), transform(rhs))
case AssignOrNamedArg(lhs, rhs) =>
treeCopy.AssignOrNamedArg(tree, transform(lhs), transform(rhs))
- case If(cond, thenp, elsep) =>
- treeCopy.If(tree, transform(cond), transform(thenp), transform(elsep))
- case Match(selector, cases) =>
- treeCopy.Match(tree, transform(selector), transformCaseDefs(cases))
- case Return(expr) =>
- treeCopy.Return(tree, transform(expr))
case Try(block, catches, finalizer) =>
treeCopy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer))
+ case EmptyTree =>
+ tree
case Throw(expr) =>
treeCopy.Throw(tree, transform(expr))
- case New(tpt) =>
- treeCopy.New(tree, transform(tpt))
- case Typed(expr, tpt) =>
- treeCopy.Typed(tree, transform(expr), transform(tpt))
- case TypeApply(fun, args) =>
- treeCopy.TypeApply(tree, transform(fun), transformTrees(args))
- case Apply(fun, args) =>
- treeCopy.Apply(tree, transform(fun), transformTrees(args))
- case ApplyDynamic(qual, args) =>
- treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args))
case Super(qual, mix) =>
treeCopy.Super(tree, transform(qual), mix)
- case This(qual) =>
- treeCopy.This(tree, qual)
- case Select(qualifier, selector) =>
- treeCopy.Select(tree, transform(qualifier), selector)
- case Ident(name) =>
- treeCopy.Ident(tree, name)
- case ReferenceToBoxed(idt) =>
- treeCopy.ReferenceToBoxed(tree, transform(idt) match { case idt1: Ident => idt1 })
- case Literal(value) =>
- treeCopy.Literal(tree, value)
- case TypeTree() =>
- treeCopy.TypeTree(tree)
+ case TypeBoundsTree(lo, hi) =>
+ treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi))
+ case Typed(expr, tpt) =>
+ treeCopy.Typed(tree, transform(expr), transform(tpt))
+ case Import(expr, selectors) =>
+ treeCopy.Import(tree, transform(expr), selectors)
+ case Template(parents, self, body) =>
+ treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
+ case ClassDef(mods, name, tparams, impl) =>
+ atOwner(tree.symbol) {
+ treeCopy.ClassDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transformTemplate(impl))
+ }
+ case ModuleDef(mods, name, impl) =>
+ atOwner(mclass(tree.symbol)) {
+ treeCopy.ModuleDef(tree, transformModifiers(mods),
+ name, transformTemplate(impl))
+ }
+ case TypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree.symbol) {
+ treeCopy.TypeDef(tree, transformModifiers(mods), name,
+ transformTypeDefs(tparams), transform(rhs))
+ }
+ case LabelDef(name, params, rhs) =>
+ treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
+ case PackageDef(pid, stats) =>
+ treeCopy.PackageDef(
+ tree, transform(pid).asInstanceOf[RefTree],
+ atOwner(mclass(tree.symbol)) {
+ transformStats(stats, currentOwner)
+ }
+ )
case Annotated(annot, arg) =>
treeCopy.Annotated(tree, transform(annot), transform(arg))
case SingletonTypeTree(ref) =>
@@ -1250,12 +1247,22 @@ trait Trees extends api.Trees { self: SymbolTable =>
treeCopy.SelectFromTypeTree(tree, transform(qualifier), selector)
case CompoundTypeTree(templ) =>
treeCopy.CompoundTypeTree(tree, transformTemplate(templ))
- case AppliedTypeTree(tpt, args) =>
- treeCopy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
- case TypeBoundsTree(lo, hi) =>
- treeCopy.TypeBoundsTree(tree, transform(lo), transform(hi))
case ExistentialTypeTree(tpt, whereClauses) =>
treeCopy.ExistentialTypeTree(tree, transform(tpt), transformTrees(whereClauses))
+ case Return(expr) =>
+ treeCopy.Return(tree, transform(expr))
+ case Alternative(trees) =>
+ treeCopy.Alternative(tree, transformTrees(trees))
+ case Star(elem) =>
+ treeCopy.Star(tree, transform(elem))
+ case UnApply(fun, args) =>
+ treeCopy.UnApply(tree, fun, transformTrees(args)) // bq: see test/.../unapplyContexts2.scala
+ case ArrayValue(elemtpt, trees) =>
+ treeCopy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
+ case ApplyDynamic(qual, args) =>
+ treeCopy.ApplyDynamic(tree, transform(qual), transformTrees(args))
+ case ReferenceToBoxed(idt) =>
+ treeCopy.ReferenceToBoxed(tree, transform(idt) match { case idt1: Ident => idt1 })
case _ =>
xtransform(transformer, tree)
}
@@ -1536,6 +1543,8 @@ trait Trees extends api.Trees { self: SymbolTable =>
sys.error("Not a LabelDef: " + t + "/" + t.getClass)
}
+// -------------- Classtags --------------------------------------------------------
+
implicit val TreeTag = ClassTag[Tree](classOf[Tree])
implicit val TermTreeTag = ClassTag[TermTree](classOf[TermTree])
implicit val TypTreeTag = ClassTag[TypTree](classOf[TypTree])
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 56506246ca..01f615c5cc 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -15,6 +15,7 @@ import scala.util.control.ControlThrowable
import scala.annotation.tailrec
import util.Statistics
import scala.runtime.ObjectRef
+import util.ThreeValues._
/* A standard type pattern match:
case ErrorType =>
@@ -117,13 +118,34 @@ trait Types extends api.Types { self: SymbolTable =>
class UndoLog extends Clearable {
private type UndoPairs = List[(TypeVar, TypeConstraint)]
- private var log: UndoPairs = List()
+ //OPT this method is public so we can do `manual inlining`
+ var log: UndoPairs = List()
+
+ /*
+ * These two methods provide explicit locking mechanism that is overridden in SynchronizedUndoLog.
+ *
+ * The idea behind explicit locking mechanism is that all public methods that access mutable state
+ * will have to obtain the lock for their entire execution so both reads and writes can be kept in
+ * right order. Originally, that was achieved by overriding those public methods in
+ * `SynchronizedUndoLog` which was fine but expensive. The reason is that those public methods take
+ * thunk as argument and if we keep them non-final there's no way to make them inlined so thunks
+ * can go away.
+ *
+ * By using explicit locking we can achieve inlining.
+ *
+ * NOTE: They are made public for now so we can apply 'manual inlining' (copy&pasting into hot
+ * places implementation of `undo` or `undoUnless`). This should be changed back to protected
+ * once inliner is fixed.
+ */
+ def lock(): Unit = ()
+ def unlock(): Unit = ()
// register with the auto-clearing cache manager
perRunCaches.recordCache(this)
/** Undo all changes to constraints to type variables upto `limit`. */
- private def undoTo(limit: UndoPairs) {
+ //OPT this method is public so we can do `manual inlining`
+ def undoTo(limit: UndoPairs) {
while ((log ne limit) && log.nonEmpty) {
val (tv, constr) = log.head
tv.constr = constr
@@ -140,30 +162,41 @@ trait Types extends api.Types { self: SymbolTable =>
}
def clear() {
- if (settings.debug.value)
- self.log("Clearing " + log.size + " entries from the undoLog.")
-
- log = Nil
+ lock()
+ try {
+ if (settings.debug.value)
+ self.log("Clearing " + log.size + " entries from the undoLog.")
+ log = Nil
+ } finally unlock()
+ }
+ def size = {
+ lock()
+ try log.size finally unlock()
}
- def size = log.size
// `block` should not affect constraints on typevars
def undo[T](block: => T): T = {
- val before = log
+ lock()
+ try {
+ val before = log
- try block
- finally undoTo(before)
+ try block
+ finally undoTo(before)
+ } finally unlock()
}
// if `block` evaluates to false, it should not affect constraints on typevars
def undoUnless(block: => Boolean): Boolean = {
- val before = log
- var result = false
+ lock()
+ try {
+ val before = log
+ var result = false
- try result = block
- finally if (!result) undoTo(before)
+ try result = block
+ finally if (!result) undoTo(before)
- result
+ result
+ } finally unlock()
}
}
@@ -293,7 +326,7 @@ trait Types extends api.Types { self: SymbolTable =>
case SuperType(_, _) => false
case SingleType(pre, sym) => notConcreteSym(sym)
case ConstantType(_) => false
- case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists (arg => notConcreteTpe(arg)))
+ case TypeRef(_, sym, args) => notConcreteSym(sym) || (args exists notConcreteTpe)
case RefinedType(_, _) => false
case ExistentialType(_, _) => false
case AnnotatedType(_, tp, _) => notConcreteTpe(tp)
@@ -343,8 +376,8 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def isImmediatelyDependent: Boolean = false
- /** Does this depend on an enclosing method parameter? */
- def isDependent: Boolean = IsDependentCollector.collect(this)
+ /** Is this type a dependent method type? */
+ def isDependentMethodType: Boolean = false
/** True for WildcardType or BoundedWildcardType. */
def isWildcard = false
@@ -363,7 +396,7 @@ trait Types extends api.Types { self: SymbolTable =>
* and all type parameters (if any) are invariant.
*/
def isFinalType =
- typeSymbol.isFinal && (typeSymbol.typeParams forall (_.variance == 0))
+ typeSymbol.isFinal && (typeSymbol.typeParams forall symbolIsNonVariant)
/** Is this type completed (i.e. not a lazy type)? */
def isComplete: Boolean = true
@@ -442,7 +475,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (phase.erasedTypes) this
else {
val cowner = commonOwner(this)
- refinedType(List(this), cowner, EmptyScope, cowner.pos).narrow
+ refinedType(this :: Nil, cowner, EmptyScope, cowner.pos).narrow
}
/** For a TypeBounds type, itself;
@@ -692,7 +725,8 @@ trait Types extends api.Types { self: SymbolTable =>
* = Int
*/
def asSeenFrom(pre: Type, clazz: Symbol): Type = {
- TypesStats.timedTypeOp(asSeenFromNanos) {
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, asSeenFromNanos) else null
+ try {
val trivial = (
this.isTrivial
|| phase.erasedTypes && pre.typeSymbol != ArrayClass
@@ -707,7 +741,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (m.capturedSkolems.isEmpty) tp1
else deriveType(m.capturedSkolems, _.cloneSymbol setFlag CAPTURED)(tp1)
}
- }
+ } finally if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
/** The info of `sym`, seen as a member of this type.
@@ -815,7 +849,7 @@ trait Types extends api.Types { self: SymbolTable =>
/** Is this type a subtype of that type? */
def <:<(that: Type): Boolean = {
- if (util.Statistics.enabled) stat_<:<(that)
+ if (Statistics.canEnable) stat_<:<(that)
else {
(this eq that) ||
(if (explainSwitch) explain("<:", isSubType, this, that)
@@ -843,26 +877,26 @@ trait Types extends api.Types { self: SymbolTable =>
}
def stat_<:<(that: Type): Boolean = {
- Statistics.incCounter(subtypeCount)
- val start = Statistics.pushTimer(typeOpsStack, subtypeNanos)
+ if (Statistics.canEnable) Statistics.incCounter(subtypeCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
(this eq that) ||
(if (explainSwitch) explain("<:", isSubType, this, that)
else isSubType(this, that, AnyDepth))
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
result
}
/** Is this type a weak subtype of that type? True also for numeric types, i.e. Int weak_<:< Long.
*/
def weak_<:<(that: Type): Boolean = {
- Statistics.incCounter(subtypeCount)
- val start = Statistics.pushTimer(typeOpsStack, subtypeNanos)
+ if (Statistics.canEnable) Statistics.incCounter(subtypeCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, subtypeNanos) else null
val result =
((this eq that) ||
(if (explainSwitch) explain("weak_<:", isWeakSubType, this, that)
else isWeakSubType(this, that)))
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
result
}
@@ -1007,7 +1041,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (!e.sym.hasFlag(excludedFlags)) {
if (sym == NoSymbol) sym = e.sym
else {
- if (alts.isEmpty) alts = List(sym)
+ if (alts.isEmpty) alts = sym :: Nil
alts = e.sym :: alts
}
}
@@ -1025,8 +1059,8 @@ trait Types extends api.Types { self: SymbolTable =>
// See (t0851) for a situation where this happens.
val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
- Statistics.incCounter(findMembersCount)
- val start = Statistics.pushTimer(typeOpsStack, findMembersNanos)
+ if (Statistics.canEnable) Statistics.incCounter(findMembersCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMembersNanos) else null
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var members: Scope = null
@@ -1078,7 +1112,7 @@ trait Types extends api.Types { self: SymbolTable =>
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
} // while (continue)
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (suspension ne null) suspension foreach (_.suspended = false)
if (members eq null) EmptyScope else members
}
@@ -1101,8 +1135,8 @@ trait Types extends api.Types { self: SymbolTable =>
// See (t0851) for a situation where this happens.
val suspension: List[TypeVar] = if (this.isGround) null else suspendTypeVarsInType(this)
- Statistics.incCounter(findMemberCount)
- val start = Statistics.pushTimer(typeOpsStack, findMemberNanos)
+ if (Statistics.canEnable) Statistics.incCounter(findMemberCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, findMemberNanos) else null
//Console.println("find member " + name.decode + " in " + this + ":" + this.baseClasses)//DEBUG
var member: Symbol = NoSymbol
@@ -1113,7 +1147,6 @@ trait Types extends api.Types { self: SymbolTable =>
var excluded = excludedFlags | DEFERRED
var continue = true
var self: Type = null
- val fingerPrint: Long = name.fingerPrint
while (continue) {
continue = false
@@ -1121,75 +1154,73 @@ trait Types extends api.Types { self: SymbolTable =>
var bcs = bcs0
while (!bcs.isEmpty) {
val decls = bcs.head.info.decls
- if ((fingerPrint & decls.fingerPrints) != 0) {
- var entry = decls.lookupEntry(name)
- while (entry ne null) {
- val sym = entry.sym
- val flags = sym.flags
- if ((flags & required) == required) {
- val excl = flags & excluded
- if (excl == 0L &&
+ var entry = decls.lookupEntry(name)
+ while (entry ne null) {
+ val sym = entry.sym
+ val flags = sym.flags
+ if ((flags & required) == required) {
+ val excl = flags & excluded
+ if (excl == 0L &&
(// omit PRIVATE LOCALS unless selector class is contained in class owning the def.
- (bcs eq bcs0) ||
- (flags & PrivateLocal) != PrivateLocal ||
- (bcs0.head.hasTransOwner(bcs.head)))) {
- if (name.isTypeName || stableOnly && sym.isStable) {
- Statistics.popTimer(typeOpsStack, start)
- if (suspension ne null) suspension foreach (_.suspended = false)
- return sym
- } else if (member eq NoSymbol) {
- member = sym
- } else if (members eq null) {
- if ((member ne sym) &&
- ((member.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = this.narrow
- if (membertpe eq null) membertpe = self.memberType(member)
- !(membertpe matches self.memberType(sym))
- })) {
- lastM = new ::(sym, null)
- members = member :: lastM
- }
- } else {
- var others: List[Symbol] = members
- var symtpe: Type = null
- while ((others ne null) && {
- val other = others.head
- (other ne sym) &&
- ((other.owner eq sym.owner) ||
- (flags & PRIVATE) != 0 || {
- if (self eq null) self = this.narrow
- if (symtpe eq null) symtpe = self.memberType(sym)
- !(self.memberType(other) matches symtpe)
+ (bcs eq bcs0) ||
+ (flags & PrivateLocal) != PrivateLocal ||
+ (bcs0.head.hasTransOwner(bcs.head)))) {
+ if (name.isTypeName || stableOnly && sym.isStable) {
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
+ if (suspension ne null) suspension foreach (_.suspended = false)
+ return sym
+ } else if (member eq NoSymbol) {
+ member = sym
+ } else if (members eq null) {
+ if ((member ne sym) &&
+ ((member.owner eq sym.owner) ||
+ (flags & PRIVATE) != 0 || {
+ if (self eq null) self = this.narrow
+ if (membertpe eq null) membertpe = self.memberType(member)
+ !(membertpe matches self.memberType(sym))
+ })) {
+ lastM = new ::(sym, null)
+ members = member :: lastM
+ }
+ } else {
+ var others: List[Symbol] = members
+ var symtpe: Type = null
+ while ((others ne null) && {
+ val other = others.head
+ (other ne sym) &&
+ ((other.owner eq sym.owner) ||
+ (flags & PRIVATE) != 0 || {
+ if (self eq null) self = this.narrow
+ if (symtpe eq null) symtpe = self.memberType(sym)
+ !(self.memberType(other) matches symtpe)
})}) {
- others = others.tail
- }
- if (others eq null) {
- val lastM1 = new ::(sym, null)
- lastM.tl = lastM1
- lastM = lastM1
- }
+ others = others.tail
+ }
+ if (others eq null) {
+ val lastM1 = new ::(sym, null)
+ lastM.tl = lastM1
+ lastM = lastM1
}
- } else if (excl == DEFERRED) {
- continue = true
}
+ } else if (excl == DEFERRED) {
+ continue = true
}
- entry = decls lookupNextEntry entry
- } // while (entry ne null)
- } // if (fingerPrint matches)
+ }
+ entry = decls lookupNextEntry entry
+ } // while (entry ne null)
// excluded = excluded | LOCAL
bcs = if (name == nme.CONSTRUCTOR) Nil else bcs.tail
} // while (!bcs.isEmpty)
required |= DEFERRED
excluded &= ~(DEFERRED.toLong)
} // while (continue)
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
if (suspension ne null) suspension foreach (_.suspended = false)
if (members eq null) {
- if (member == NoSymbol) Statistics.incCounter(noMemberCount)
+ if (member == NoSymbol) if (Statistics.canEnable) Statistics.incCounter(noMemberCount)
member
} else {
- Statistics.incCounter(multMemberCount)
+ if (Statistics.canEnable) Statistics.incCounter(multMemberCount)
lastM.tl = Nil
baseClasses.head.newOverloaded(this, members)
}
@@ -1238,14 +1269,18 @@ trait Types extends api.Types { self: SymbolTable =>
// Subclasses ------------------------------------------------------------
- trait UniqueType extends Product {
- final override val hashCode = scala.runtime.ScalaRunTime._hashCode(this)
+ /**
+ * A type that can be passed to unique(..) and be stored in the uniques map.
+ */
+ abstract class UniqueType extends Type with Product {
+ final override val hashCode = computeHashCode
+ protected def computeHashCode = scala.runtime.ScalaRunTime._hashCode(this)
}
/** A base class for types that defer some operations
* to their immediate supertype.
*/
- abstract class SubType extends Type {
+ abstract class SubType extends UniqueType {
def supertype: Type
override def parents: List[Type] = supertype.parents
override def decls: Scope = supertype.decls
@@ -1276,7 +1311,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isVolatile = underlying.isVolatile
override def widen: Type = underlying.widen
override def baseTypeSeq: BaseTypeSeq = {
- Statistics.incCounter(singletonBaseTypeSeqCount)
+ if (Statistics.canEnable) Statistics.incCounter(singletonBaseTypeSeqCount)
underlying.baseTypeSeq prepend this
}
override def isHigherKinded = false // singleton type classifies objects, thus must be kind *
@@ -1386,7 +1421,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "ThisType"
}
- final class UniqueThisType(sym: Symbol) extends ThisType(sym) with UniqueType { }
+ final class UniqueThisType(sym: Symbol) extends ThisType(sym) { }
object ThisType extends ThisTypeExtractor {
def apply(sym: Symbol): Type =
@@ -1398,7 +1433,11 @@ trait Types extends api.Types { self: SymbolTable =>
* Cannot be created directly; one should always use `singleType` for creation.
*/
abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType with SingleTypeApi {
- override val isTrivial: Boolean = pre.isTrivial
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(pre.isTrivial)
+ toBoolean(trivial)
+ }
override def isGround = sym.isPackageClass || pre.isGround
// override def isNullable = underlying.isNullable
@@ -1443,7 +1482,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "SingleType"
}
- final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym) with UniqueType { }
+ final class UniqueSingleType(pre: Type, sym: Symbol) extends SingleType(pre, sym)
object SingleType extends SingleTypeExtractor {
def apply(pre: Type, sym: Symbol): Type = {
@@ -1464,7 +1503,11 @@ trait Types extends api.Types { self: SymbolTable =>
}
abstract case class SuperType(thistpe: Type, supertpe: Type) extends SingletonType with SuperTypeApi {
- override val isTrivial: Boolean = thistpe.isTrivial && supertpe.isTrivial
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(thistpe.isTrivial && supertpe.isTrivial)
+ toBoolean(trivial)
+ }
override def isNotNull = true;
override def typeSymbol = thistpe.typeSymbol
override def underlying = supertpe
@@ -1474,7 +1517,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "SuperType"
}
- final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp) with UniqueType { }
+ final class UniqueSuperType(thistp: Type, supertp: Type) extends SuperType(thistp, supertp)
object SuperType extends SuperTypeExtractor {
def apply(thistp: Type, supertp: Type): Type = {
@@ -1487,7 +1530,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
abstract case class TypeBounds(lo: Type, hi: Type) extends SubType with TypeBoundsApi {
def supertype = hi
- override val isTrivial: Boolean = lo.isTrivial && hi.isTrivial
+ override def isTrivial: Boolean = lo.isTrivial && hi.isTrivial
override def bounds: TypeBounds = this
def containsType(that: Type) = that match {
case TypeBounds(_, _) => that <:< this
@@ -1495,8 +1538,8 @@ trait Types extends api.Types { self: SymbolTable =>
}
private def lowerString = if (emptyLowerBound) "" else " >: " + lo
private def upperString = if (emptyUpperBound) "" else " <: " + hi
- private def emptyLowerBound = lo.typeSymbolDirect eq NothingClass
- private def emptyUpperBound = hi.typeSymbolDirect eq AnyClass
+ private def emptyLowerBound = typeIsNothing(lo)
+ private def emptyUpperBound = typeIsAny(hi)
def isEmptyBounds = emptyLowerBound && emptyUpperBound
// override def isNullable: Boolean = NullClass.tpe <:< lo;
@@ -1504,7 +1547,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "TypeBoundsType"
}
- final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi) with UniqueType { }
+ final class UniqueTypeBounds(lo: Type, hi: Type) extends TypeBounds(lo, hi)
object TypeBounds extends TypeBoundsExtractor {
def empty: TypeBounds = apply(NothingClass.tpe, AnyClass.tpe)
@@ -1579,10 +1622,10 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def narrow: Type = typeSymbol.thisType
- override def isNotNull: Boolean = parents exists (_.isNotNull)
+ override def isNotNull: Boolean = parents exists typeIsNotNull
override def isStructuralRefinement: Boolean =
- typeSymbol.isAnonOrRefinementClass && decls.exists(_.isPossibleInRefinement)
+ typeSymbol.isAnonOrRefinementClass && (decls exists symbolIsPossibleInRefinement)
// override def isNullable: Boolean =
// parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType);
@@ -1598,7 +1641,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- if (tpe.parents.exists(_.exists(_.isInstanceOf[TypeVar]))) {
+ if (tpe.parents exists typeContainsTypeVar) {
// rename type vars to fresh type params, take base type sequence of
// resulting type, and rename back all the entries in that sequence
var tvs = Set[TypeVar]()
@@ -1625,8 +1668,8 @@ trait Types extends api.Types { self: SymbolTable =>
val bts = copyRefinedType(tpe.asInstanceOf[RefinedType], tpe.parents map varToParam, varToParam mapOver tpe.decls).baseTypeSeq
tpe.baseTypeSeqCache = bts lateMap paramToVar
} else {
- Statistics.incCounter(compoundBaseTypeSeqCount)
- val start = Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos)
+ if (Statistics.canEnable) Statistics.incCounter(compoundBaseTypeSeqCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos) else null
try {
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache =
@@ -1635,7 +1678,7 @@ trait Types extends api.Types { self: SymbolTable =>
else
compoundBaseTypeSeq(tpe)
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
// [Martin] suppressing memo-ization solves the problem with "same type after erasure" errors
// when compiling with
@@ -1683,12 +1726,12 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseClassesPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- val start = Statistics.pushTimer(typeOpsStack, baseClassesNanos)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseClassesNanos) else null
try {
tpe.baseClassesCache = null
tpe.baseClassesCache = tpe.memo(computeBaseClasses)(tpe.typeSymbol :: _.baseClasses.tail)
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
}
@@ -1706,7 +1749,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def isHigherKinded = (
parents.nonEmpty &&
- (parents forall (_.isHigherKinded)) &&
+ (parents forall typeIsHigherKinded) &&
!phase.erasedTypes
)
@@ -1989,7 +2032,7 @@ trait Types extends api.Types { self: SymbolTable =>
override def kind = "ConstantType"
}
- final class UniqueConstantType(value: Constant) extends ConstantType(value) with UniqueType {
+ final class UniqueConstantType(value: Constant) extends ConstantType(value) {
/** Save the type of `value`. For Java enums, it depends on finding the linked class,
* which might not be found after `flatten`. */
private lazy val _tpe: Type = value.tpe
@@ -2037,7 +2080,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var volatileRecursions: Int = 0
private val pendingVolatiles = new mutable.HashSet[Symbol]
- class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType {
+ class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) {
require(args0.nonEmpty, this)
/** No unapplied type params size it has (should have) equally as many args. */
@@ -2090,7 +2133,7 @@ trait Types extends api.Types { self: SymbolTable =>
override protected def finishPrefix(rest: String) = "" + thisInfo
}
- class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) with UniqueType {
+ class NoArgsTypeRef(pre0: Type, sym0: Symbol) extends TypeRef(pre0, sym0, Nil) {
// 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
// to a java or scala symbol, but it does matter whether it occurs in java or scala code.
@@ -2294,15 +2337,32 @@ trait Types extends api.Types { self: SymbolTable =>
*
* @M: a higher-kinded type is represented as a TypeRef with sym.typeParams.nonEmpty, but args.isEmpty
*/
- abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type with TypeRefApi {
- override val isTrivial: Boolean = !sym.isTypeParameter && pre.isTrivial && args.forall(_.isTrivial)
-
+ abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends UniqueType with TypeRefApi {
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN)
+ trivial = fromBoolean(!sym.isTypeParameter && pre.isTrivial && areTrivialTypes(args))
+ toBoolean(trivial)
+ }
private[reflect] var parentsCache: List[Type] = _
private[reflect] var parentsPeriod = NoPeriod
private[reflect] var baseTypeSeqCache: BaseTypeSeq = _
private[reflect] var baseTypeSeqPeriod = NoPeriod
private var normalized: Type = _
+ //OPT specialize hashCode
+ override final def computeHashCode = {
+ import scala.util.hashing.MurmurHash3._
+ val hasArgs = args.nonEmpty
+ var h = productSeed
+ h = mix(h, pre.hashCode)
+ h = mix(h, sym.hashCode)
+ if (hasArgs)
+ finalizeHash(mix(h, args.hashCode), 3)
+ else
+ finalizeHash(h, 2)
+ }
+
// @M: propagate actual type params (args) to `tp`, by replacing
// formal type parameters with actual ones. If tp is higher kinded,
// the "actual" type arguments are types that simply reference the
@@ -2399,7 +2459,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def needsPreString = (
settings.debug.value
|| !shorthands(sym.fullName)
- || sym.ownerChain.exists(s => !s.isClass)
+ || (sym.ownersIterator exists (s => !s.isClass))
)
private def preString = if (needsPreString) pre.prefixString else ""
private def argsString = if (args.isEmpty) "" else args.mkString("[", ",", "]")
@@ -2500,13 +2560,13 @@ trait Types extends api.Types { self: SymbolTable =>
if (period != currentPeriod) {
tpe.baseTypeSeqPeriod = currentPeriod
if (!isValidForBaseClasses(period)) {
- Statistics.incCounter(typerefBaseTypeSeqCount)
- val start = Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos)
+ if (Statistics.canEnable) Statistics.incCounter(typerefBaseTypeSeqCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, baseTypeSeqNanos) else null
try {
tpe.baseTypeSeqCache = undetBaseTypeSeq
tpe.baseTypeSeqCache = tpe.baseTypeSeqImpl
} finally {
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
}
@@ -2523,14 +2583,22 @@ trait Types extends api.Types { self: SymbolTable =>
case class MethodType(override val params: List[Symbol],
override val resultType: Type) extends Type with MethodTypeApi {
- override lazy val isTrivial: Boolean =
- isTrivialResult && (params forall isTrivialParam)
+ private var trivial: ThreeValue = UNKNOWN
+ override def isTrivial: Boolean = {
+ if (trivial == UNKNOWN) trivial = fromBoolean(isTrivialResult && areTrivialParams(params))
+ toBoolean(trivial)
+ }
private def isTrivialResult =
resultType.isTrivial && (resultType eq resultType.withoutAnnotations)
- private def isTrivialParam(p: Symbol) =
- p.tpe.isTrivial && !(params.exists(_.tpe contains p) || (resultType contains p))
+ private def areTrivialParams(ps: List[Symbol]): Boolean = ps match {
+ case p :: rest =>
+ p.tpe.isTrivial && !typesContain(paramTypes, p) && !(resultType contains p) &&
+ areTrivialParams(rest)
+ case _ =>
+ true
+ }
def isImplicit = params.nonEmpty && params.head.isImplicit
def isJava = false // can we do something like for implicits? I.e. do Java methods without parameters need to be recognized?
@@ -2546,13 +2614,19 @@ trait Types extends api.Types { self: SymbolTable =>
override def resultType(actuals: List[Type]) =
if (isTrivial || phase.erasedTypes) resultType
- else if (sameLength(actuals, params)) {
+ else if (/*isDependentMethodType &&*/ sameLength(actuals, params)) {
val idm = new InstantiateDependentMap(params, actuals)
val res = idm(resultType)
existentialAbstraction(idm.existentialsNeeded, res)
}
else existentialAbstraction(params, resultType)
+ private var isdepmeth: ThreeValue = UNKNOWN
+ override def isDependentMethodType: Boolean = {
+ if (isdepmeth == UNKNOWN) isdepmeth = fromBoolean(IsDependentCollector.collect(resultType))
+ toBoolean(isdepmeth)
+ }
+
// implicit args can only be depended on in result type:
//TODO this may be generalised so that the only constraint is dependencies are acyclic
def approximate: MethodType = MethodType(params, resultApprox)
@@ -2567,7 +2641,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def atOwner(owner: Symbol) =
- if ((params exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ if (!allSymbolsHaveOwner(params, owner) || (resultType.atOwner(owner) ne resultType))
cloneInfo(owner)
else
this
@@ -2655,7 +2729,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
override def atOwner(owner: Symbol) =
- if ((typeParams exists (_.owner != owner)) || (resultType.atOwner(owner) ne resultType))
+ if (!allSymbolsHaveOwner(typeParams, owner) || (resultType.atOwner(owner) ne resultType))
cloneInfo(owner)
else
this
@@ -2759,7 +2833,7 @@ trait Types extends api.Types { self: SymbolTable =>
createFromClonedSymbolsAtOwner(quantified, owner, underlying)(newExistentialType)
override def atOwner(owner: Symbol) =
- if (quantified exists (_.owner != owner)) cloneInfo(owner) else this
+ if (!allSymbolsHaveOwner(quantified, owner)) cloneInfo(owner) else this
override def kind = "ExistentialType"
@@ -2870,14 +2944,13 @@ trait Types extends api.Types { self: SymbolTable =>
* any results.
*/
if (propagateParameterBoundsToTypeVars) {
- val exclude = bounds.isEmptyBounds || bounds.exists(_.typeSymbolDirect.isNonClassType)
+ val exclude = bounds.isEmptyBounds || (bounds exists typeIsNonClassType)
if (exclude) new TypeConstraint
else TypeVar.trace("constraint", "For " + tparam.fullLocationString)(new TypeConstraint(bounds))
}
else new TypeConstraint
}
- def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr))
def untouchable(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = true)
def apply(tparam: Symbol): TypeVar = createTypeVar(tparam, untouchable = false)
def apply(origin: Type, constr: TypeConstraint): TypeVar = apply(origin, constr, Nil, Nil)
@@ -2890,7 +2963,7 @@ trait Types extends api.Types { self: SymbolTable =>
val tv = (
if (args.isEmpty && params.isEmpty) {
if (untouchable) new TypeVar(origin, constr) with UntouchableTypeVar
- else new TypeVar(origin, constr)
+ else new TypeVar(origin, constr) {}
}
else if (args.size == params.size) {
if (untouchable) new AppliedTypeVar(origin, constr, params zip args) with UntouchableTypeVar
@@ -2916,13 +2989,12 @@ trait Types extends api.Types { self: SymbolTable =>
if (tp == NoType) tp
else existentialAbstraction(existentialsInType(tp), tp)
)
+
def containsExistential(tpe: Type) =
- tpe exists (_.typeSymbol.isExistentiallyBound)
+ tpe exists typeIsExistentiallyBound
- def existentialsInType(tpe: Type) = (
- for (tp <- tpe ; if tp.typeSymbol.isExistentiallyBound) yield
- tp.typeSymbol
- )
+ def existentialsInType(tpe: Type) =
+ tpe withFilter typeIsExistentiallyBound map (_.typeSymbol)
/** Precondition: params.nonEmpty. (args.nonEmpty enforced structurally.)
*/
@@ -2981,9 +3053,9 @@ trait Types extends api.Types { self: SymbolTable =>
*
* Precondition for this class, enforced structurally: args.isEmpty && params.isEmpty.
*/
- class TypeVar(
+ abstract case class TypeVar(
val origin: Type,
- val constr0: TypeConstraint
+ var constr: TypeConstraint
) extends Type {
def untouchable = false // by other typevars
override def params: List[Symbol] = Nil
@@ -2996,7 +3068,7 @@ trait Types extends api.Types { self: SymbolTable =>
* in operations that are exposed from types. Hence, no syncing of `constr`
* or `encounteredHigherLevel` or `suspended` accesses should be necessary.
*/
- var constr = constr0
+// var constr = constr0
def instValid = constr.instValid
override def isGround = instValid && constr.inst.isGround
@@ -3395,16 +3467,16 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
- /** A temporary type representing the reasure of a user-defined value type.
- * Created during phase reasure, elimintaed again in posterasure.
+ /** A temporary type representing the erasure of a user-defined value type.
+ * Created during phase reasure, eliminated again in posterasure.
* @param sym The value class symbol
* @param underlying The underlying type before erasure
*/
- abstract case class ErasedValueType(original: TypeRef) extends Type {
+ abstract case class ErasedValueType(original: TypeRef) extends UniqueType {
override def safeToString = "ErasedValueType("+original+")"
}
- final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original) with UniqueType
+ final class UniqueErasedValueType(original: TypeRef) extends ErasedValueType(original)
object ErasedValueType {
def apply(original: TypeRef): Type = {
@@ -3715,10 +3787,11 @@ trait Types extends api.Types { self: SymbolTable =>
case TypeRef(_, SingletonClass, _) =>
AnyClass.tpe
case tp1 @ RefinedType(parents, decls) =>
- var parents1 = parents filter (_.typeSymbol != SingletonClass)
- if (parents1.isEmpty) parents1 = List(AnyClass.tpe)
- if (parents1.tail.isEmpty && decls.isEmpty) mapOver(parents1.head)
- else mapOver(copyRefinedType(tp1, parents1, decls))
+ parents filter (_.typeSymbol != SingletonClass) match {
+ case Nil => AnyClass.tpe
+ case p :: Nil if decls.isEmpty => mapOver(p)
+ case ps => mapOver(copyRefinedType(tp1, ps, decls))
+ }
case tp1 =>
mapOver(tp1)
}
@@ -3823,7 +3896,7 @@ trait Types extends api.Types { self: SymbolTable =>
private var uniqueRunId = NoRunId
protected def unique[T <: Type](tp: T): T = {
- Statistics.incCounter(rawTypeCount)
+ if (Statistics.canEnable) Statistics.incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.HashSet[Type]("uniques", initialUniquesCapacity)
perRunCaches.recordCache(uniques)
@@ -3860,8 +3933,8 @@ trait Types extends api.Types { self: SymbolTable =>
* guarding addLoBound/addHiBound somehow broke raw types so it
* only guards against being created with them.]
*/
- private var lobounds = lo0 filterNot (_.typeSymbolDirect eq NothingClass)
- private var hibounds = hi0 filterNot (_.typeSymbolDirect eq AnyClass)
+ private var lobounds = lo0 filterNot typeIsNothing
+ private var hibounds = hi0 filterNot typeIsAny
private var numlo = numlo0
private var numhi = numhi0
private var avoidWidening = avoidWidening0
@@ -3917,8 +3990,8 @@ trait Types extends api.Types { self: SymbolTable =>
override def toString = {
val boundsStr = {
- val lo = loBounds filterNot (_.typeSymbolDirect eq NothingClass)
- val hi = hiBounds filterNot (_.typeSymbolDirect eq AnyClass)
+ val lo = loBounds filterNot typeIsNothing
+ val hi = hiBounds filterNot typeIsAny
val lostr = if (lo.isEmpty) Nil else List(lo.mkString(" >: (", ", ", ")"))
val histr = if (hi.isEmpty) Nil else List(hi.mkString(" <: (", ", ", ")"))
@@ -3965,15 +4038,18 @@ trait Types extends api.Types { self: SymbolTable =>
override def variance = _variance
def variance_=(x: Int) = _variance = x
- override protected def noChangeToSymbols(origSyms: List[Symbol]) = {
- origSyms forall { sym =>
- val v = variance
- if (sym.isAliasType) variance = 0
- val result = this(sym.info)
- variance = v
- result eq sym.info
+ override protected def noChangeToSymbols(origSyms: List[Symbol]) =
+ //OPT inline from forall to save on #closures
+ origSyms match {
+ case sym :: rest =>
+ val v = variance
+ if (sym.isAliasType) variance = 0
+ val result = this(sym.info)
+ variance = v
+ (result eq sym.info) && noChangeToSymbols(rest)
+ case _ =>
+ true
}
- }
override protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] =
map2Conserve(args, tparams) { (arg, tparam) =>
@@ -4478,7 +4554,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (sameLength(basesym.typeParams, baseargs))
instParam(basesym.typeParams, baseargs)
else
- if (symclazz.tpe.parents.exists(_.isErroneous))
+ if (symclazz.tpe.parents exists typeIsErroneous)
ErrorType // don't be to overzealous with throwing exceptions, see #2641
else
throw new Error(
@@ -4529,7 +4605,7 @@ trait Types extends api.Types { self: SymbolTable =>
else subst(tp, sym, from.tail, to.tail)
val boundSyms = tp0.boundSyms
- val tp1 = if (boundSyms exists from.contains) renameBoundSyms(tp0) else tp0
+ val tp1 = if (boundSyms.nonEmpty && (boundSyms exists from.contains)) renameBoundSyms(tp0) else tp0
val tp = mapOver(tp1)
tp match {
@@ -4569,10 +4645,12 @@ trait Types extends api.Types { self: SymbolTable =>
tp match {
case TypeRef(pre, sym, args) if pre ne NoPrefix =>
val newSym = subst(sym, from, to)
+ // mapOver takes care of subst'ing in args
+ mapOver ( if (sym eq newSym) tp else copyTypeRef(tp, pre, newSym, args) )
// assert(newSym.typeParams.length == sym.typeParams.length, "typars mismatch in SubstSymMap: "+(sym, sym.typeParams, newSym, newSym.typeParams))
- mapOver(copyTypeRef(tp, pre, newSym, args)) // mapOver takes care of subst'ing in args
case SingleType(pre, sym) if pre ne NoPrefix =>
- mapOver(singleType(pre, subst(sym, from, to)))
+ val newSym = subst(sym, from, to)
+ mapOver( if (sym eq newSym) tp else singleType(pre, newSym) )
case _ =>
super.apply(tp)
}
@@ -4668,6 +4746,8 @@ trait Types extends api.Types { self: SymbolTable =>
else mapOver(tp)
}
+ /** Note: This map is needed even for non-dependent method types, despite what the name might imply.
+ */
class InstantiateDependentMap(params: List[Symbol], actuals0: List[Type]) extends TypeMap with KeepOnlyTypeConstraints {
private val actuals = actuals0.toIndexedSeq
private val existentials = new Array[Symbol](actuals.size)
@@ -5101,14 +5181,21 @@ trait Types extends api.Types { self: SymbolTable =>
1
}
- private def maxDepth(tps: Seq[Type], by: Type => Int): Int = {
- var d = 0
- for (tp <- tps) d = d max by(tp)
- d
+ private def maxDepth(tps: List[Type], by: Type => Int): Int = {
+ //OPT replaced with tailrecursive function to save on #closures
+ // was:
+ // var d = 0
+ // for (tp <- tps) d = d max by(tp) //!!!OPT!!!
+ // d
+ def loop(tps: List[Type], acc: Int): Int = tps match {
+ case tp :: rest => loop(rest, acc max by(tp))
+ case _ => acc
+ }
+ loop(tps, 0)
}
- private def typeDepth(tps: Seq[Type]): Int = maxDepth(tps, typeDepth)
- private def baseTypeSeqDepth(tps: Seq[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
+ private def typeDepth(tps: List[Type]): Int = maxDepth(tps, typeDepth)
+ private def baseTypeSeqDepth(tps: List[Type]): Int = maxDepth(tps, _.baseTypeSeqDepth)
/** Is intersection of given types populated? That is,
* for all types tp1, tp2 in intersection
@@ -5217,11 +5304,24 @@ trait Types extends api.Types { self: SymbolTable =>
/** Do `tp1` and `tp2` denote equivalent types? */
def isSameType(tp1: Type, tp2: Type): Boolean = try {
- Statistics.incCounter(sametypeCount)
+ if (Statistics.canEnable) Statistics.incCounter(sametypeCount)
subsametypeRecursions += 1
- undoLog undoUnless {
- isSameType1(tp1, tp2)
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless {
+// isSameType1(tp1, tp2)
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = {
+ isSameType1(tp1, tp2)
+ } finally if (!result) undoLog.undoTo(before)
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
@@ -5572,22 +5672,49 @@ trait Types extends api.Types { self: SymbolTable =>
def isSubType(tp1: Type, tp2: Type, depth: Int): Boolean = try {
subsametypeRecursions += 1
- undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
- if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
- val p = new SubTypePair(tp1, tp2)
- if (pendingSubTypes(p))
- false
- else
- try {
- pendingSubTypes += p
- isSubType2(tp1, tp2, depth)
- } finally {
- pendingSubTypes -= p
- }
- } else {
- isSubType2(tp1, tp2, depth)
- }
- }
+ //OPT cutdown on Function0 allocation
+ //was:
+// undoLog undoUnless { // if subtype test fails, it should not affect constraints on typevars
+// if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+// val p = new SubTypePair(tp1, tp2)
+// if (pendingSubTypes(p))
+// false
+// else
+// try {
+// pendingSubTypes += p
+// isSubType2(tp1, tp2, depth)
+// } finally {
+// pendingSubTypes -= p
+// }
+// } else {
+// isSubType2(tp1, tp2, depth)
+// }
+// }
+
+ undoLog.lock()
+ try {
+ val before = undoLog.log
+ var result = false
+
+ try result = { // if subtype test fails, it should not affect constraints on typevars
+ if (subsametypeRecursions >= LogPendingSubTypesThreshold) {
+ val p = new SubTypePair(tp1, tp2)
+ if (pendingSubTypes(p))
+ false
+ else
+ try {
+ pendingSubTypes += p
+ isSubType2(tp1, tp2, depth)
+ } finally {
+ pendingSubTypes -= p
+ }
+ } else {
+ isSubType2(tp1, tp2, depth)
+ }
+ } finally if (!result) undoLog.undoTo(before)
+
+ result
+ } finally undoLog.unlock()
} finally {
subsametypeRecursions -= 1
// XXX AM TODO: figure out when it is safe and needed to clear the log -- the commented approach below is too eager (it breaks #3281, #3866)
@@ -5611,6 +5738,7 @@ trait Types extends api.Types { self: SymbolTable =>
false
}
+ @deprecated("The compiler doesn't use this so you shouldn't either - it will be removed", "2.10.0")
def instTypeVar(tp: Type): Type = tp match {
case TypeRef(pre, sym, args) =>
copyTypeRef(tp, instTypeVar(pre), sym, args)
@@ -5893,9 +6021,17 @@ trait Types extends api.Types { self: SymbolTable =>
def specializesSym(tp: Type, sym: Symbol, depth: Int): Boolean =
tp.typeSymbol == NothingClass ||
- tp.typeSymbol == NullClass && containsNull(sym.owner) ||
- (tp.nonPrivateMember(sym.name).alternatives exists
- (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
+ tp.typeSymbol == NullClass && containsNull(sym.owner) || {
+ def specializedBy(membr: Symbol): Boolean =
+ membr == sym || specializesSym(tp.narrow, membr, sym.owner.thisType, sym, depth)
+ val member = tp.nonPrivateMember(sym.name)
+ if (member eq NoSymbol) false
+ else if (member.isOverloaded) member.alternatives exists specializedBy
+ else specializedBy(member)
+ // was
+ // (tp.nonPrivateMember(sym.name).alternatives exists
+ // (alt => sym == alt || specializesSym(tp.narrow, alt, sym.owner.thisType, sym, depth)))
+ }
/** Does member `sym1` of `tp1` have a stronger type
* than member `sym2` of `tp2`?
@@ -6141,9 +6277,9 @@ trait Types extends api.Types { self: SymbolTable =>
*/
def isWithinBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): Boolean = {
var bounds = instantiatedBounds(pre, owner, tparams, targs)
- if (targs.exists(_.annotations.nonEmpty))
+ if (targs exists typeHasAnnotations)
bounds = adaptBoundsToAnnotations(bounds, tparams, targs)
- (bounds corresponds targs)(_ containsType _)
+ (bounds corresponds targs)(boundsContainType)
}
def instantiatedBounds(pre: Type, owner: Symbol, tparams: List[Symbol], targs: List[Type]): List[TypeBounds] =
@@ -6211,7 +6347,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def lubList(ts: List[Type], depth: Int): List[Type] = {
// Matching the type params of one of the initial types means dummies.
val initialTypeParams = ts map (_.typeParams)
- def isHotForTs(xs: List[Type]) = initialTypeParams contains xs.map(_.typeSymbol)
+ def isHotForTs(xs: List[Type]) = initialTypeParams contains (xs map (_.typeSymbol))
def elimHigherOrderTypeParam(tp: Type) = tp match {
case TypeRef(pre, sym, args) if args.nonEmpty && isHotForTs(args) => tp.typeConstructor
@@ -6221,7 +6357,7 @@ trait Types extends api.Types { self: SymbolTable =>
def loop(tsBts: List[List[Type]]): List[Type] = {
lubListDepth += 1
- if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) Nil
+ if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) Nil
else if (tsBts.tail.isEmpty) tsBts.head
else {
// ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
@@ -6303,10 +6439,12 @@ trait Types extends api.Types { self: SymbolTable =>
* of some other element of the list. */
private def elimSuper(ts: List[Type]): List[Type] = ts match {
case List() => List()
+ case List(t) => List(t)
case t :: ts1 =>
val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
if (rest exists (t1 => t1 <:< t)) rest else t :: rest
}
+
def elimAnonymousClass(t: Type) = t match {
case TypeRef(pre, clazz, Nil) if clazz.isAnonymousClass =>
clazz.classBound.asSeenFrom(pre, clazz.owner)
@@ -6323,6 +6461,7 @@ trait Types extends api.Types { self: SymbolTable =>
private def elimSub(ts: List[Type], depth: Int): List[Type] = {
def elimSub0(ts: List[Type]): List[Type] = ts match {
case List() => List()
+ case List(t) => List(t)
case t :: ts1 =>
val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, decr(depth))))
if (rest exists (t1 => isSubType(t, t1, decr(depth)))) rest else t :: rest
@@ -6356,7 +6495,7 @@ trait Types extends api.Types { self: SymbolTable =>
def weakLub(ts: List[Type]) =
if (ts.nonEmpty && (ts forall isNumericValueType)) (numericLub(ts), true)
- else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty)))
+ else if (ts exists typeHasAnnotations)
(annotationsLub(lub(ts map (_.withoutAnnotations)), ts), true)
else (lub(ts), false)
@@ -6365,7 +6504,7 @@ trait Types extends api.Types { self: SymbolTable =>
val nglb = numericGlb(ts)
if (nglb != NoType) (nglb, true)
else (glb(ts), false)
- } else if (ts.nonEmpty && (ts exists (_.annotations.nonEmpty))) {
+ } else if (ts exists typeHasAnnotations) {
(annotationsGlb(glb(ts map (_.withoutAnnotations)), ts), true)
} else (glb(ts), false)
}
@@ -6421,14 +6560,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => NothingClass.tpe
case List(t) => t
case _ =>
- Statistics.incCounter(lubCount)
- val start = Statistics.pushTimer(typeOpsStack, lubNanos)
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
lub(ts, lubDepth(ts))
} finally {
lubResults.clear()
glbResults.clear()
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
@@ -6441,8 +6580,8 @@ trait Types extends api.Types { self: SymbolTable =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(glb(bounds, depth)))
PolyType(tparams1, lub0(matchingInstTypes(ts, tparams1)))
- case ts @ MethodType(params, _) :: rest =>
- MethodType(params, lub0(matchingRestypes(ts, params map (_.tpe))))
+ case ts @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, lub0(matchingRestypes(ts, mt.paramTypes)))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(lub0(matchingRestypes(ts, Nil)))
case ts @ TypeBounds(_, _) :: rest =>
@@ -6544,13 +6683,13 @@ trait Types extends api.Types { self: SymbolTable =>
indent = indent + " "
assert(indent.length <= 100)
}
- Statistics.incCounter(nestedLubCount)
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
val res = lub0(ts)
if (printLubs) {
indent = indent stripSuffix " "
println(indent + "lub of " + ts + " is " + res)//debug
}
- if (ts forall (_.isNotNull)) res.notNull else res
+ if (ts forall typeIsNotNull) res.notNull else res
}
val GlbFailure = new Throwable
@@ -6569,14 +6708,14 @@ trait Types extends api.Types { self: SymbolTable =>
case List() => AnyClass.tpe
case List(t) => t
case ts0 =>
- Statistics.incCounter(lubCount)
- val start = Statistics.pushTimer(typeOpsStack, lubNanos)
+ if (Statistics.canEnable) Statistics.incCounter(lubCount)
+ val start = if (Statistics.canEnable) Statistics.pushTimer(typeOpsStack, lubNanos) else null
try {
glbNorm(ts0, lubDepth(ts0))
} finally {
lubResults.clear()
glbResults.clear()
- Statistics.popTimer(typeOpsStack, start)
+ if (Statistics.canEnable) Statistics.popTimer(typeOpsStack, start)
}
}
@@ -6596,8 +6735,8 @@ trait Types extends api.Types { self: SymbolTable =>
val tparams1 = map2(tparams, matchingBounds(ts, tparams).transpose)((tparam, bounds) =>
tparam.cloneSymbol.setInfo(lub(bounds, depth)))
PolyType(tparams1, glbNorm(matchingInstTypes(ts, tparams1), depth))
- case ts @ MethodType(params, _) :: rest =>
- MethodType(params, glbNorm(matchingRestypes(ts, params map (_.tpe)), depth))
+ case ts @ (mt @ MethodType(params, _)) :: rest =>
+ MethodType(params, glbNorm(matchingRestypes(ts, mt.paramTypes), depth))
case ts @ NullaryMethodType(_) :: rest =>
NullaryMethodType(glbNorm(matchingRestypes(ts, Nil), depth))
case ts @ TypeBounds(_, _) :: rest =>
@@ -6691,12 +6830,12 @@ trait Types extends api.Types { self: SymbolTable =>
}
// if (settings.debug.value) { println(indent + "glb of " + ts + " at depth "+depth); indent = indent + " " } //DEBUG
- Statistics.incCounter(nestedLubCount)
+ if (Statistics.canEnable) Statistics.incCounter(nestedLubCount)
val res = glb0(ts)
// if (settings.debug.value) { indent = indent.substring(0, indent.length() - 2); log(indent + "glb of " + ts + " is " + res) }//DEBUG
- if (ts exists (_.isNotNull)) res.notNull else res
+ if (ts exists typeIsNotNull) res.notNull else res
}
/** A list of the typevars in a type. */
@@ -6738,7 +6877,7 @@ trait Types extends api.Types { self: SymbolTable =>
// special treatment for lubs of array types after erasure:
// if argss contain one value type and some other type, the lub is Object
// if argss contain several reference types, the lub is an array over lub of argtypes
- if (argss exists (_.isEmpty)) {
+ if (argss exists typeListIsEmpty) {
None // something is wrong: an array without a type arg.
} else {
val args = argss map (_.head)
@@ -6860,7 +6999,7 @@ trait Types extends api.Types { self: SymbolTable =>
*/
private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] =
tps map {
- case MethodType(params1, res) if (isSameTypes(params1 map (_.tpe), pts)) =>
+ case mt @ MethodType(params1, res) if isSameTypes(mt.paramTypes, pts) =>
res
case NullaryMethodType(res) if pts.isEmpty =>
res
@@ -6931,7 +7070,7 @@ trait Types extends api.Types { self: SymbolTable =>
}
// Add serializable to a list of parents, unless one of them already is
def addSerializable(ps: Type*): List[Type] = (
- if (ps exists (_ <:< SerializableClass.tpe)) ps.toList
+ if (ps exists typeIsSubTypeOfSerializable) ps.toList
else (ps :+ SerializableClass.tpe).toList
)
@@ -6972,6 +7111,35 @@ trait Types extends api.Types { self: SymbolTable =>
tostringRecursions -= 1
}
+// ----- Hoisted closures and convenience methods, for compile time reductions -------
+
+ private[scala] val typeIsNotNull = (tp: Type) => tp.isNotNull
+ private[scala] val isTypeVar = (tp: Type) => tp.isInstanceOf[TypeVar]
+ private[scala] val typeContainsTypeVar = (tp: Type) => tp exists isTypeVar
+ private[scala] val typeIsNonClassType = (tp: Type) => tp.typeSymbolDirect.isNonClassType
+ private[scala] val typeIsExistentiallyBound = (tp: Type) => tp.typeSymbol.isExistentiallyBound
+ private[scala] val typeIsErroneous = (tp: Type) => tp.isErroneous
+ private[scala] val typeIsError = (tp: Type) => tp.isError
+ private[scala] val typeHasAnnotations = (tp: Type) => tp.annotations.nonEmpty
+ private[scala] val boundsContainType = (bounds: TypeBounds, tp: Type) => bounds containsType tp
+ private[scala] val typeListIsEmpty = (ts: List[Type]) => ts.isEmpty
+ private[scala] val typeIsSubTypeOfSerializable = (tp: Type) => tp <:< SerializableClass.tpe
+ private[scala] val typeIsNothing = (tp: Type) => tp.typeSymbolDirect eq NothingClass
+ private[scala] val typeIsAny = (tp: Type) => tp.typeSymbolDirect eq AnyClass
+ private[scala] val typeIsHigherKinded = (tp: Type) => tp.isHigherKinded
+
+ @tailrec private def typesContain(tps: List[Type], sym: Symbol): Boolean = tps match {
+ case tp :: rest => (tp contains sym) || typesContain(rest, sym)
+ case _ => false
+ }
+
+ @tailrec private def areTrivialTypes(tps: List[Type]): Boolean = tps match {
+ case tp :: rest => tp.isTrivial && areTrivialTypes(rest)
+ case _ => true
+ }
+
+// -------------- Classtags --------------------------------------------------------
+
implicit val AnnotatedTypeTag = ClassTag[AnnotatedType](classOf[AnnotatedType])
implicit val BoundedWildcardTypeTag = ClassTag[BoundedWildcardType](classOf[BoundedWildcardType])
implicit val ClassInfoTypeTag = ClassTag[ClassInfoType](classOf[ClassInfoType])
@@ -6990,7 +7158,10 @@ trait Types extends api.Types { self: SymbolTable =>
implicit val TypeRefTag = ClassTag[TypeRef](classOf[TypeRef])
implicit val TypeTagg = ClassTag[Type](classOf[Type])
+// -------------- Statistics --------------------------------------------------------
+
Statistics.newView("#unique types") { if (uniques == null) 0 else uniques.size }
+
}
object TypesStats {
@@ -7018,9 +7189,11 @@ object TypesStats {
val singletonBaseTypeSeqCount = Statistics.newSubCounter(" of which for singletons", baseTypeSeqCount)
val typeOpsStack = Statistics.newTimerStack()
+ /** Commented out, because right now this does not inline, so creates a closure which will distort statistics
@inline final def timedTypeOp[T](c: Statistics.StackableTimer)(op: => T): T = {
val start = Statistics.pushTimer(typeOpsStack, c)
try op
- finally Statistics.popTimer(typeOpsStack, start)
+ finally
}
+ */
}
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index 9234ccca7b..2e00316d5b 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -769,8 +769,21 @@ abstract class UnPickler /*extends reflect.generic.UnPickler*/ {
}
/* Read a reference to a pickled item */
+ protected def readSymbolRef(): Symbol = {//OPT inlined from: at(readNat(), readSymbol) to save on closure creation
+ val i = readNat()
+ var r = entries(i)
+ if (r eq null) {
+ val savedIndex = readIndex
+ readIndex = index(i)
+ r = readSymbol()
+ assert(entries(i) eq null, entries(i))
+ entries(i) = r
+ readIndex = savedIndex
+ }
+ r.asInstanceOf[Symbol]
+ }
+
protected def readNameRef(): Name = at(readNat(), readName)
- protected def readSymbolRef(): Symbol = at(readNat(), readSymbol)
protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... ()
protected def readConstantRef(): Constant = at(readNat(), readConstant)
protected def readAnnotationRef(): AnnotationInfo = at(readNat(), readAnnotation)
diff --git a/src/reflect/scala/reflect/internal/transform/Erasure.scala b/src/reflect/scala/reflect/internal/transform/Erasure.scala
index 368d55a59c..cc5b5bb406 100644
--- a/src/reflect/scala/reflect/internal/transform/Erasure.scala
+++ b/src/reflect/scala/reflect/internal/transform/Erasure.scala
@@ -141,7 +141,7 @@ trait Erasure {
if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
// this replaces each typeref that refers to an argument
// by the type `p.tpe` of the actual argument p (p in params)
- else apply(mt.resultType(params map (_.tpe))))
+ else apply(mt.resultType(mt.paramTypes)))
case RefinedType(parents, decls) =>
apply(mergeParents(parents))
case AnnotatedType(_, atp, _) =>
@@ -220,7 +220,7 @@ trait Erasure {
MethodType(
cloneSymbolsAndModify(params, specialErasureAvoiding(clazz, _)),
if (restpe.typeSymbol == UnitClass) erasedTypeRef(UnitClass)
- else specialErasureAvoiding(clazz, (mt.resultType(params map (_.tpe)))))
+ else specialErasureAvoiding(clazz, (mt.resultType(mt.paramTypes))))
case TypeRef(pre, `clazz`, args) =>
typeRef(pre, clazz, List())
case _ =>
diff --git a/src/reflect/scala/reflect/internal/util/Collections.scala b/src/reflect/scala/reflect/internal/util/Collections.scala
index 2ac0e64edd..14b5d3003d 100644
--- a/src/reflect/scala/reflect/internal/util/Collections.scala
+++ b/src/reflect/scala/reflect/internal/util/Collections.scala
@@ -69,7 +69,7 @@ trait Collections {
}
lb.toList
}
-
+
final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = {
val lb = new ListBuffer[B]
for (x <- elems ; if pf isDefinedAt x)
@@ -104,7 +104,7 @@ trait Collections {
index += 1
}
}
-
+
// @inline
final def findOrElse[A](xs: TraversableOnce[A])(p: A => Boolean)(orElse: => A): A = {
xs find p getOrElse orElse
diff --git a/src/reflect/scala/reflect/internal/util/Statistics.scala b/src/reflect/scala/reflect/internal/util/Statistics.scala
index e503d812e6..f7b81ca252 100644
--- a/src/reflect/scala/reflect/internal/util/Statistics.scala
+++ b/src/reflect/scala/reflect/internal/util/Statistics.scala
@@ -237,6 +237,23 @@ quant)
private var _enabled = false
private val qs = new mutable.HashMap[String, Quantity]
+ /** replace with
+ *
+ * final val canEnable = false
+ *
+ * to remove all Statistics code from build
+ */
+ final val canEnable = _enabled
+
+ /** replace with
+ *
+ * final def hotEnabled = _enabled
+ *
+ * and rebuild, to also count tiny but super-hot methods
+ * such as phase, flags, owner, name.
+ */
+ final val hotEnabled = false
+
def enabled = _enabled
def enabled_=(cond: Boolean) = {
if (cond && !_enabled) {
@@ -253,9 +270,4 @@ quant)
_enabled = true
}
}
-
- /** replace rhs with enabled and rebuild to also count tiny but super-hot methods
- * such as phase, flags, owner, name.
- */
- final val hotEnabled = false
}
diff --git a/src/reflect/scala/reflect/internal/util/ThreeValues.scala b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
new file mode 100644
index 0000000000..d89f11c407
--- /dev/null
+++ b/src/reflect/scala/reflect/internal/util/ThreeValues.scala
@@ -0,0 +1,14 @@
+package scala.reflect.internal.util
+
+/** A simple three value type for booleans with an unknown value */
+object ThreeValues {
+
+ type ThreeValue = Byte
+
+ final val YES = 1
+ final val NO = -1
+ final val UNKNOWN = 0
+
+ @inline def fromBoolean(b: Boolean): ThreeValue = if (b) YES else NO
+ @inline def toBoolean(x: ThreeValue): Boolean = x == YES
+}
diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala
index 46b7066902..ad100d7e89 100644
--- a/src/reflect/scala/reflect/macros/Aliases.scala
+++ b/src/reflect/scala/reflect/macros/Aliases.scala
@@ -21,6 +21,8 @@ trait Aliases {
type TypeTag[T] = universe.TypeTag[T]
val AbsTypeTag = universe.AbsTypeTag
val TypeTag = universe.TypeTag
+ def absTypeTag[T](implicit attag: AbsTypeTag[T]) = attag
def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+ def absTypeOf[T](implicit attag: AbsTypeTag[T]): Type = attag.tpe
def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 967ac69148..9f2c3fc79c 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -124,7 +124,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
private def ErrorInnerModule(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is an inner module, use reflectModule on an InstanceMirror to obtain its ModuleMirror")
private def ErrorStaticClass(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is a static class, use reflectClass on a RuntimeMirror to obtain its ClassMirror")
private def ErrorStaticModule(wannabe: Symbol) = throw new ScalaReflectionException(s"$wannabe is a static module, use reflectModule on a RuntimeMirror to obtain its ModuleMirror")
- private def ErrorNotMember(wannabe: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${wannabe.kind} ${wannabe.fullName}")
+ private def ErrorNotMember(wannabe: Symbol, owner: Symbol) = throw new ScalaReflectionException(s"expected a member of $owner, you provided ${wannabe.kindString} ${wannabe.fullName}")
private def ErrorNotField(wannabe: Symbol) = throw new ScalaReflectionException(s"expected a field or an accessor method symbol, you provided $wannabe")
private def ErrorNonExistentField(wannabe: Symbol) = throw new ScalaReflectionException(s"""
|Scala field ${wannabe.name} isn't represented as a Java field, neither it has a Java accessor method
diff --git a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
index e1eb7a57fe..de029ca658 100644
--- a/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
+++ b/src/reflect/scala/reflect/runtime/SynchronizedTypes.scala
@@ -14,15 +14,10 @@ trait SynchronizedTypes extends internal.Types { self: SymbolTable =>
override def unique[T <: Type](tp: T): T = uniqueLock.synchronized { super.unique(tp) }
class SynchronizedUndoLog extends UndoLog {
+ private val actualLock = new java.util.concurrent.locks.ReentrantLock
- override def clear() =
- synchronized { super.clear() }
-
- override def undo[T](block: => T): T =
- synchronized { super.undo(block) }
-
- override def undoUnless(block: => Boolean): Boolean =
- synchronized { super.undoUnless(block) }
+ final override def lock(): Unit = actualLock.lock()
+ final override def unlock(): Unit = actualLock.unlock()
}
override protected def newUndoLog = new SynchronizedUndoLog
diff --git a/src/reflect/scala/tools/nsc/io/ZipArchive.scala b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
index 852dba9ec8..d1a91294a5 100644
--- a/src/reflect/scala/tools/nsc/io/ZipArchive.scala
+++ b/src/reflect/scala/tools/nsc/io/ZipArchive.scala
@@ -96,14 +96,25 @@ abstract class ZipArchive(override val file: JFile) extends AbstractFile with Eq
}
}
- private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry = {
- dirs.getOrElseUpdate(path, {
- val parent = ensureDir(dirs, dirName(path), null)
- val dir = new DirEntry(path)
- parent.entries(baseName(path)) = dir
- dir
- })
- }
+ private def ensureDir(dirs: mutable.Map[String, DirEntry], path: String, zipEntry: ZipEntry): DirEntry =
+ //OPT inlined from getOrElseUpdate; saves ~50K closures on test run.
+ // was:
+ // dirs.getOrElseUpdate(path, {
+ // val parent = ensureDir(dirs, dirName(path), null)
+ // val dir = new DirEntry(path)
+ // parent.entries(baseName(path)) = dir
+ // dir
+ // })
+ dirs get path match {
+ case Some(v) => v
+ case None =>
+ val parent = ensureDir(dirs, dirName(path), null)
+ val dir = new DirEntry(path)
+ parent.entries(baseName(path)) = dir
+ dirs(path) = dir
+ dir
+ }
+
protected def getDir(dirs: mutable.Map[String, DirEntry], entry: ZipEntry): DirEntry = {
if (entry.isDirectory) ensureDir(dirs, entry.getName, entry)
else ensureDir(dirs, dirName(entry.getName), null)
diff --git a/src/scalap/scala/tools/scalap/Main.scala b/src/scalap/scala/tools/scalap/Main.scala
index a8a9c65f63..49c272cc28 100644
--- a/src/scalap/scala/tools/scalap/Main.scala
+++ b/src/scalap/scala/tools/scalap/Main.scala
@@ -10,10 +10,10 @@ package scala.tools.scalap
import java.io.{ PrintStream, OutputStreamWriter, ByteArrayOutputStream }
import scala.reflect.NameTransformer
import scalax.rules.scalasig._
-import tools.nsc.util.{ ClassPath, JavaClassPath }
-import tools.util.PathResolver
+import scala.tools.nsc.util.{ ClassPath, JavaClassPath }
+import scala.tools.util.PathResolver
import ClassPath.DefaultJavaContext
-import tools.nsc.io.{ PlainFile, AbstractFile }
+import scala.tools.nsc.io.{ PlainFile, AbstractFile }
/**The main object used to execute scalap on the command-line.
*
diff --git a/test/files/jvm/future-spec/TryTests.scala b/test/files/jvm/future-spec/TryTests.scala
index 82ca12276f..5d1b9b84b4 100644
--- a/test/files/jvm/future-spec/TryTests.scala
+++ b/test/files/jvm/future-spec/TryTests.scala
@@ -46,6 +46,12 @@ object TryTests extends MinimalScalaTest {
val e2 = new Exception
Failure[Int](e) map(_ => throw e2) mustEqual Failure(e)
}
+ "when there is a fatal exception" in {
+ val e3 = new ThreadDeath
+ intercept[ThreadDeath] {
+ Success(1) map (_ => throw e3)
+ }
+ }
}
"flatMap" in {
@@ -60,6 +66,12 @@ object TryTests extends MinimalScalaTest {
val e2 = new Exception
Failure[Int](e).flatMap[Int](_ => throw e2) mustEqual Failure(e)
}
+ "when there is a fatal exception" in {
+ val e3 = new ThreadDeath
+ intercept[ThreadDeath] {
+ Success(1).flatMap[Int](_ => throw e3)
+ }
+ }
}
"flatten" in {
@@ -115,4 +127,4 @@ object TryTests extends MinimalScalaTest {
}
}
}
-} \ No newline at end of file
+}
diff --git a/test/files/jvm/manifests-new.scala b/test/files/jvm/manifests-new.scala
index 8706881640..f730be67bb 100644
--- a/test/files/jvm/manifests-new.scala
+++ b/test/files/jvm/manifests-new.scala
@@ -106,6 +106,6 @@ trait TestUtil {
// val t1: TypeTag[T] = read(write(t))
val t1: TypeTag[T] = t
val x1 = x.toString.replaceAll("@[0-9a-z]+$", "")
- println("x="+x1+", t="+t1+", k="+t1.tpe.kind+", s="+t1.tpe.typeSymbol.toString)
+ println("x="+x1+", t="+t1+", k="+t1.tpe.asInstanceOf[Product].productPrefix+", s="+t1.tpe.typeSymbol.toString)
}
} \ No newline at end of file
diff --git a/test/files/neg/javaConversions-2.10-ambiguity.check b/test/files/neg/javaConversions-2.10-ambiguity.check
new file mode 100644
index 0000000000..c064a22964
--- /dev/null
+++ b/test/files/neg/javaConversions-2.10-ambiguity.check
@@ -0,0 +1,6 @@
+javaConversions-2.10-ambiguity.scala:8: error: type mismatch;
+ found : scala.collection.concurrent.Map[String,String]
+ required: scala.collection.mutable.ConcurrentMap[String,String]
+ assertType[mutable.ConcurrentMap[String, String]](a)
+ ^
+one error found
diff --git a/test/files/neg/javaConversions-2.10-ambiguity.scala b/test/files/neg/javaConversions-2.10-ambiguity.scala
new file mode 100644
index 0000000000..e856846a29
--- /dev/null
+++ b/test/files/neg/javaConversions-2.10-ambiguity.scala
@@ -0,0 +1,10 @@
+import collection.{JavaConversions, mutable, concurrent}
+import JavaConversions._
+import java.util.concurrent.{ConcurrentHashMap => CHM}
+
+object Bar {
+ def assertType[T](t: T) = t
+ val a = new CHM[String, String]() += (("", ""))
+ assertType[mutable.ConcurrentMap[String, String]](a)
+}
+// vim: set et:
diff --git a/test/files/neg/macro-invalidshape-a.check b/test/files/neg/macro-invalidshape-a.check
index 246b5c3226..098ec35a00 100644
--- a/test/files/neg/macro-invalidshape-a.check
+++ b/test/files/neg/macro-invalidshape-a.check
@@ -1,6 +1,5 @@
Macros_Test_2.scala:2: error: macro body has wrong shape:
- required: macro <reference to implementation object>.<implementation method name>
- or : macro <implementation method name>
+ required: macro [<implementation object>].<method name>[[<type args>]]
def foo(x: Any) = macro 2
^
one error found
diff --git a/test/files/neg/macro-invalidshape-b.check b/test/files/neg/macro-invalidshape-b.check
index 59701d023b..297ff69199 100644
--- a/test/files/neg/macro-invalidshape-b.check
+++ b/test/files/neg/macro-invalidshape-b.check
@@ -1,6 +1,5 @@
Macros_Test_2.scala:2: error: macro body has wrong shape:
- required: macro <reference to implementation object>.<implementation method name>
- or : macro <implementation method name>
+ required: macro [<implementation object>].<method name>[[<type args>]]
def foo(x: Any) = macro Impls.foo(null)(null)
^
one error found
diff --git a/test/files/neg/macro-invalidshape-c.check b/test/files/neg/macro-invalidshape-c.check
index 84d8c35222..6513df166e 100644
--- a/test/files/neg/macro-invalidshape-c.check
+++ b/test/files/neg/macro-invalidshape-c.check
@@ -1,6 +1,9 @@
-Macros_Test_2.scala:2: error: macro body has wrong shape:
- required: macro <reference to implementation object>.<implementation method name>
- or : macro <implementation method name>
+Macros_Test_2.scala:2: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
def foo(x: Any) = macro {2; Impls.foo}
- ^
+ ^
+Macros_Test_2.scala:2: error: missing arguments for method foo in object Impls;
+follow this method with `_' if you want to treat it as a partially applied function
+ def foo(x: Any) = macro {2; Impls.foo}
+ ^
+one warning found
one error found
diff --git a/test/files/neg/macro-invalidsig-context-bounds.check b/test/files/neg/macro-invalidsig-context-bounds.check
index 6c9482e537..5d42ebc515 100644
--- a/test/files/neg/macro-invalidsig-context-bounds.check
+++ b/test/files/neg/macro-invalidsig-context-bounds.check
@@ -1,4 +1,7 @@
-Impls_1.scala:5: error: macro implementations cannot have implicit parameters other than AbsTypeTag evidences
- def foo[U: c.AbsTypeTag: Numeric](c: Ctx) = {
- ^
-one error found
+Macros_Test_1.scala:2: error: macro implementation has wrong shape:
+ required: (c: scala.reflect.macros.Context): c.Expr[Any]
+ found : (c: scala.reflect.macros.Context)(implicit evidence$2: Numeric[U]): c.universe.Literal
+macro implementations cannot have implicit parameters other than AbsTypeTag evidences
+ def foo[U] = macro Impls.foo[U]
+ ^
+one error found
diff --git a/test/files/neg/macro-invalidsig-implicit-params.check b/test/files/neg/macro-invalidsig-implicit-params.check
index 98b3167b7a..62156770e4 100644
--- a/test/files/neg/macro-invalidsig-implicit-params.check
+++ b/test/files/neg/macro-invalidsig-implicit-params.check
@@ -1,4 +1,7 @@
-Impls_Macros_1.scala:5: error: macro implementations cannot have implicit parameters other than AbsTypeTag evidences
- def foo_targs[T, U: c.AbsTypeTag](c: Ctx)(implicit x: c.Expr[Int]) = {
- ^
-one error found
+Impls_Macros_1.scala:18: error: macro implementation has wrong shape:
+ required: (c: scala.reflect.macros.Context)(x: c.Expr[Int]): c.Expr[Unit]
+ found : (c: scala.reflect.macros.Context)(implicit x: c.Expr[Int]): c.Expr[Unit]
+macro implementations cannot have implicit parameters other than AbsTypeTag evidences
+ def foo_targs[U](x: Int) = macro Impls.foo_targs[T, U]
+ ^
+one error found
diff --git a/test/files/neg/macro-invalidsig-params-namemismatch.check b/test/files/neg/macro-invalidsig-params-namemismatch.check
index f2639d9350..00d781a2ac 100644
--- a/test/files/neg/macro-invalidsig-params-namemismatch.check
+++ b/test/files/neg/macro-invalidsig-params-namemismatch.check
@@ -2,7 +2,6 @@ Impls_Macros_1.scala:8: error: macro implementation has wrong shape:
required: (c: scala.reflect.macros.Context)(x: c.Expr[Int], y: c.Expr[Int]): c.Expr[Any]
found : (c: scala.reflect.macros.Context)(y: c.Expr[Int], x: c.Expr[Int]): Nothing
parameter names differ: x != y
-parameter names differ: y != x
def foo(x: Int, y: Int) = macro Impls.foo
^
one error found
diff --git a/test/files/neg/macro-invalidsig-tparams-badtype.check b/test/files/neg/macro-invalidsig-tparams-badtype.check
index e5e8366ba4..20c58ff2bb 100644
--- a/test/files/neg/macro-invalidsig-tparams-badtype.check
+++ b/test/files/neg/macro-invalidsig-tparams-badtype.check
@@ -3,5 +3,5 @@ Macros_Test_2.scala:2: error: macro implementation has wrong shape:
found : (c: scala.reflect.macros.Context)(U: c.universe.Type): Nothing
number of parameter sections differ
def foo[U] = macro Impls.foo[U]
- ^
+ ^
one error found
diff --git a/test/files/neg/macro-invalidsig-tparams-notparams-a.check b/test/files/neg/macro-invalidsig-tparams-notparams-a.check
index 5b4ef42ea5..5aee62b9e5 100644
--- a/test/files/neg/macro-invalidsig-tparams-notparams-a.check
+++ b/test/files/neg/macro-invalidsig-tparams-notparams-a.check
@@ -1,4 +1,4 @@
-Macros_Test_2.scala:2: error: macro implementation reference needs type arguments
+Macros_Test_2.scala:2: error: wrong number of type parameters for method foo: [U](c: scala.reflect.macros.Context)(implicit evidence$1: c.AbsTypeTag[U])Nothing
def foo = macro Impls.foo
^
one error found
diff --git a/test/files/neg/macro-invalidsig-tparams-notparams-b.check b/test/files/neg/macro-invalidsig-tparams-notparams-b.check
index 261e3b8293..e8de8a4c6b 100644
--- a/test/files/neg/macro-invalidsig-tparams-notparams-b.check
+++ b/test/files/neg/macro-invalidsig-tparams-notparams-b.check
@@ -1,4 +1,4 @@
-Macros_Test_2.scala:3: error: macro implementation reference needs type arguments
+Macros_Test_2.scala:3: error: wrong number of type parameters for method foo: [T, U, V](c: scala.reflect.macros.Context)(implicit evidence$1: c.AbsTypeTag[T], implicit evidence$2: c.AbsTypeTag[U], implicit V: c.AbsTypeTag[V])c.Expr[Unit]
def foo[V] = macro Impls.foo
^
one error found
diff --git a/test/files/neg/macro-invalidusage-badbounds.check b/test/files/neg/macro-invalidusage-badbounds-a.check
index fd0b64533e..fd0b64533e 100644
--- a/test/files/neg/macro-invalidusage-badbounds.check
+++ b/test/files/neg/macro-invalidusage-badbounds-a.check
diff --git a/test/files/neg/macro-invalidusage-badbounds.flags b/test/files/neg/macro-invalidusage-badbounds-a.flags
index cd66464f2f..cd66464f2f 100644
--- a/test/files/neg/macro-invalidusage-badbounds.flags
+++ b/test/files/neg/macro-invalidusage-badbounds-a.flags
diff --git a/test/files/neg/macro-invalidusage-badbounds-a/Impls_1.scala b/test/files/neg/macro-invalidusage-badbounds-a/Impls_1.scala
new file mode 100644
index 0000000000..6ee71a3628
--- /dev/null
+++ b/test/files/neg/macro-invalidusage-badbounds-a/Impls_1.scala
@@ -0,0 +1,5 @@
+import scala.reflect.macros.{Context => Ctx}
+
+object Impls {
+ def foo[U <: String](c: Ctx) = c.literalUnit
+}
diff --git a/test/files/neg/macro-invalidusage-badbounds/Macros_Test_2.scala b/test/files/neg/macro-invalidusage-badbounds-a/Macros_Test_2.scala
index 3139599108..3139599108 100644
--- a/test/files/neg/macro-invalidusage-badbounds/Macros_Test_2.scala
+++ b/test/files/neg/macro-invalidusage-badbounds-a/Macros_Test_2.scala
diff --git a/test/files/neg/static-annot.scala b/test/files/neg/static-annot.scala
index c6c626d42b..c0b5ed30d8 100644
--- a/test/files/neg/static-annot.scala
+++ b/test/files/neg/static-annot.scala
@@ -45,3 +45,9 @@ class PrivateProtectedLazy {
println(PrivateProtectedLazy.baz)
println(PrivateProtectedLazy.bam)
}
+
+
+class StaticDef {
+ // this should not crash the compiler
+ @static def x = 42
+}
diff --git a/test/files/neg/t6227.check b/test/files/neg/t6227.check
new file mode 100644
index 0000000000..5e3c636712
--- /dev/null
+++ b/test/files/neg/t6227.check
@@ -0,0 +1,4 @@
+t6227.scala:2: error: illegal combination of modifiers: implicit and case for: class IntOps
+ implicit case class IntOps( i: Int ) {
+ ^
+one error found
diff --git a/test/files/neg/t6227.scala b/test/files/neg/t6227.scala
new file mode 100644
index 0000000000..46416839d1
--- /dev/null
+++ b/test/files/neg/t6227.scala
@@ -0,0 +1,6 @@
+object Test {
+ implicit case class IntOps( i: Int ) {
+ def twice = i * 2
+ }
+}
+
diff --git a/test/files/neg/t6264.check b/test/files/neg/t6264.check
new file mode 100644
index 0000000000..438be4c39f
--- /dev/null
+++ b/test/files/neg/t6264.check
@@ -0,0 +1,4 @@
+t6264.scala:3: error: non-variable type argument Tuple1[_] in type Tuple2[_, Tuple1[_]] is unchecked since it is eliminated by erasure
+ x.isInstanceOf[Tuple2[_, Tuple1[_]]]
+ ^
+one error found
diff --git a/test/files/neg/t6264.flags b/test/files/neg/t6264.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t6264.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/t6264.scala b/test/files/neg/t6264.scala
new file mode 100644
index 0000000000..dc3b727934
--- /dev/null
+++ b/test/files/neg/t6264.scala
@@ -0,0 +1,6 @@
+class Foo {
+ def foo(x: AnyRef): Unit = {
+ x.isInstanceOf[Tuple2[_, Tuple1[_]]]
+ ()
+ }
+}
diff --git a/test/files/neg/t6283.check b/test/files/neg/t6283.check
new file mode 100644
index 0000000000..69e417ee93
--- /dev/null
+++ b/test/files/neg/t6283.check
@@ -0,0 +1,4 @@
+t6283.scala:1: error: `abstract' modifier cannot be used with value classes
+abstract class Funky(val i: Int) extends AnyVal
+ ^
+one error found
diff --git a/test/files/neg/t6283.scala b/test/files/neg/t6283.scala
new file mode 100644
index 0000000000..d41eb18a74
--- /dev/null
+++ b/test/files/neg/t6283.scala
@@ -0,0 +1 @@
+abstract class Funky(val i: Int) extends AnyVal
diff --git a/test/files/pos/SI-5788.scala b/test/files/pos/SI-5788.scala
index 93b84bde87..f292461804 100644
--- a/test/files/pos/SI-5788.scala
+++ b/test/files/pos/SI-5788.scala
@@ -1,4 +1,3 @@
-trait Test {
- trait B[T]
- private final def grow[T](): B[T] = grow[T]()
+trait Foo[@specialized(Int) A] {
+ final def bar(a:A):A = bar(a)
}
diff --git a/test/files/pos/hk-match/a.scala b/test/files/pos/hk-match/a.scala
new file mode 100644
index 0000000000..7144068f3c
--- /dev/null
+++ b/test/files/pos/hk-match/a.scala
@@ -0,0 +1,5 @@
+trait A {
+ type HKAlias[X] = List[X]
+
+ (null: Any) match { case f: Bippy[HKAlias] => f }
+}
diff --git a/test/files/pos/hk-match/b.scala b/test/files/pos/hk-match/b.scala
new file mode 100644
index 0000000000..f7d21f6383
--- /dev/null
+++ b/test/files/pos/hk-match/b.scala
@@ -0,0 +1 @@
+trait Bippy[E[X]]
diff --git a/test/files/pos/javaConversions-2.10-regression.scala b/test/files/pos/javaConversions-2.10-regression.scala
new file mode 100644
index 0000000000..e1b81015ba
--- /dev/null
+++ b/test/files/pos/javaConversions-2.10-regression.scala
@@ -0,0 +1,17 @@
+import collection.{JavaConversions, mutable, concurrent}
+import JavaConversions._
+import java.util.concurrent.{ConcurrentHashMap => CHM}
+
+object Foo {
+ def buildCache2_9_simple[K <: AnyRef, V <: AnyRef]: mutable.ConcurrentMap[K, V] =
+ asScalaConcurrentMap(new CHM())
+
+ def buildCache2_9_implicit[K <: AnyRef, V <: AnyRef]: mutable.ConcurrentMap[K, V] =
+ new CHM[K, V]()
+}
+
+object Bar {
+ def assertType[T](t: T) = t
+ val a = new CHM[String, String]() += (("", ""))
+ assertType[concurrent.Map[String, String]](a)
+}
diff --git a/test/files/pos/specializes-sym-crash.scala b/test/files/pos/specializes-sym-crash.scala
new file mode 100644
index 0000000000..c46f435ac4
--- /dev/null
+++ b/test/files/pos/specializes-sym-crash.scala
@@ -0,0 +1,26 @@
+import scala.collection._
+
+trait Foo[+A,
+ +Coll,
+ +This <: GenSeqView[A, Coll] with GenSeqViewLike[A, Coll, This]]
+extends GenSeq[A] with GenSeqLike[A, This] with GenIterableView[A, Coll] with GenIterableViewLike[A, Coll, This] {
+self =>
+
+ trait Transformed[+B] extends GenSeqView[B, Coll] with super.Transformed[B] {
+ def length: Int
+ def apply(idx: Int): B
+ override def toString = viewToString
+ }
+ trait Reversed extends Transformed[A] {
+ override def iterator: Iterator[A] = createReversedIterator
+ def length: Int = self.length
+ def apply(idx: Int): A = self.apply(length - 1 - idx)
+ final override protected[this] def viewIdentifier = "R"
+
+ private def createReversedIterator = {
+ var lst = List[A]()
+ for (elem <- self) lst ::= elem
+ lst.iterator
+ }
+ }
+}
diff --git a/test/files/pos/t5667.scala b/test/files/pos/t5667.scala
index 513de5b663..353eec93d6 100644
--- a/test/files/pos/t5667.scala
+++ b/test/files/pos/t5667.scala
@@ -1,6 +1,4 @@
object Main {
implicit class C(val s: String) extends AnyVal
implicit class C2(val s: String) extends AnyRef
-
- implicit case class Foo(i: Int)
}
diff --git a/test/files/pos/t6208.scala b/test/files/pos/t6208.scala
new file mode 100644
index 0000000000..dac571346d
--- /dev/null
+++ b/test/files/pos/t6208.scala
@@ -0,0 +1,4 @@
+object Test {
+ val col = collection.mutable.Queue(1,2,3)
+ val WORK: collection.mutable.Queue[Int] = col filterNot (_ % 2 == 0)
+}
diff --git a/test/files/run/classtags_core.check b/test/files/run/classtags_core.check
index 2241108ba0..6519db2178 100644
--- a/test/files/run/classtags_core.check
+++ b/test/files/run/classtags_core.check
@@ -1,30 +1,30 @@
-true
-ClassTag[byte]
-true
-ClassTag[short]
-true
-ClassTag[char]
-true
-ClassTag[int]
-true
-ClassTag[long]
-true
-ClassTag[float]
-true
-ClassTag[double]
-true
-ClassTag[boolean]
-true
-ClassTag[void]
-true
-ClassTag[class java.lang.Object]
-true
-ClassTag[class java.lang.Object]
-true
-ClassTag[class java.lang.Object]
-true
-ClassTag[class java.lang.Object]
-true
-ClassTag[class scala.runtime.Null$]
-true
-ClassTag[Nothing]
+true
+ClassTag[byte]
+true
+ClassTag[short]
+true
+ClassTag[char]
+true
+ClassTag[int]
+true
+ClassTag[long]
+true
+ClassTag[float]
+true
+ClassTag[double]
+true
+ClassTag[boolean]
+true
+ClassTag[void]
+true
+ClassTag[class java.lang.Object]
+true
+ClassTag[class java.lang.Object]
+true
+ClassTag[class java.lang.Object]
+true
+ClassTag[class java.lang.Object]
+true
+ClassTag[class scala.runtime.Null$]
+true
+ClassTag[class scala.runtime.Nothing$]
diff --git a/test/files/run/existentials3-new.check b/test/files/run/existentials3-new.check
index 0d6f694a68..a036d92a24 100644
--- a/test/files/run/existentials3-new.check
+++ b/test/files/run/existentials3-new.check
@@ -1,24 +1,24 @@
-Bar.type, t=AbstractTypeRef, s= <: scala.runtime.AbstractFunction0[Bar] with Serializable{case def unapply(x$0: Bar): Boolean} with Singleton
-Bar, t=AbstractTypeRef, s= <: Test.ToS with Product with Serializable{def copy(): Bar}
+Bar.type, t=TypeRef, s= <: scala.runtime.AbstractFunction0[Bar] with Serializable{case def unapply(x$0: Bar): Boolean} with Singleton
+Bar, t=TypeRef, s= <: Test.ToS with Product with Serializable{def copy(): Bar}
Test.ToS, t=RefinedType, s=f3
Test.ToS, t=RefinedType, s=f4
Test.ToS, t=RefinedType, s=f5
() => Test.ToS, t=TypeRef, s=class Function0
() => Test.ToS, t=TypeRef, s=class Function0
-$anon, t=AbstractTypeRef, s= <: B with Test.ToS
-$anon, t=AbstractTypeRef, s= <: B with A with Test.ToS
+$anon, t=TypeRef, s= <: B with Test.ToS
+$anon, t=TypeRef, s= <: B with A with Test.ToS
List[java.lang.Object{type T1}#T1], t=TypeRef, s=class List
List[Seq[Int]], t=TypeRef, s=class List
List[Seq[U forSome { type U <: Int }]], t=TypeRef, s=class List
-Bar.type, t=AbstractTypeRef, s= <: scala.runtime.AbstractFunction0[Bar] with Serializable{case def unapply(x$0: Bar): Boolean} with Singleton
-Bar, t=AbstractTypeRef, s= <: Test.ToS with Product with Serializable{def copy(): Bar}
+Bar.type, t=TypeRef, s= <: scala.runtime.AbstractFunction0[Bar] with Serializable{case def unapply(x$0: Bar): Boolean} with Singleton
+Bar, t=TypeRef, s= <: Test.ToS with Product with Serializable{def copy(): Bar}
Test.ToS, t=RefinedType, s=g3
Test.ToS, t=RefinedType, s=g4
Test.ToS, t=RefinedType, s=g5
() => Test.ToS, t=TypeRef, s=class Function0
() => Test.ToS, t=TypeRef, s=class Function0
-$anon, t=AbstractTypeRef, s= <: B with Test.ToS
-$anon, t=AbstractTypeRef, s= <: B with A with Test.ToS
+$anon, t=TypeRef, s= <: B with Test.ToS
+$anon, t=TypeRef, s= <: B with A with Test.ToS
List[java.lang.Object{type T1}#T1], t=TypeRef, s=class List
List[Seq[Int]], t=TypeRef, s=class List
List[Seq[U forSome { type U <: Int }]], t=TypeRef, s=class List
diff --git a/test/files/run/existentials3-new.scala b/test/files/run/existentials3-new.scala
index 649fac8327..16735eab4f 100644
--- a/test/files/run/existentials3-new.scala
+++ b/test/files/run/existentials3-new.scala
@@ -35,7 +35,7 @@ object Test {
def printTpe(t: Type) = {
val s = if (t.typeSymbol.isFreeType) t.typeSymbol.typeSignature.toString else t.typeSymbol.toString
- println("%s, t=%s, s=%s".format(t, t.kind, s))
+ println("%s, t=%s, s=%s".format(t, t.asInstanceOf[Product].productPrefix, s))
}
def m[T: TypeTag](x: T) = printTpe(typeOf[T])
def m2[T: AbsTypeTag](x: T) = printTpe(implicitly[AbsTypeTag[T]].tpe)
diff --git a/test/files/run/inline-ex-handlers.check b/test/files/run/inline-ex-handlers.check
index a4c9f215e8..2bc72893e7 100644
--- a/test/files/run/inline-ex-handlers.check
+++ b/test/files/run/inline-ex-handlers.check
@@ -61,22 +61,22 @@
> ? LOAD_LOCAL(variable monitor4)
> 305 MONITOR_EXIT
> ? JUMP 12
-550c557,563
+550c557
< ? THROW(Throwable)
---
> ? JUMP 12
+556c563,570
+< ? THROW(Throwable)
+---
+> ? STORE_LOCAL(value t)
+> ? JUMP 13
>
> 12:
> ? LOAD_LOCAL(variable monitor3)
> 304 MONITOR_EXIT
> ? STORE_LOCAL(value t)
> ? JUMP 13
-556c569,582
-< ? THROW(Throwable)
----
-> ? STORE_LOCAL(value t)
-> ? JUMP 13
->
+571a586,597
> 13:
> 310 LOAD_MODULE object Predef
> 310 CALL_PRIMITIVE(StartConcat)
@@ -88,6 +88,7 @@
> 310 CALL_PRIMITIVE(EndConcat)
> 310 CALL_METHOD scala.Predef.println (dynamic)
> 310 JUMP 2
+>
580c606
< catch (Throwable) in ArrayBuffer(7, 8, 9, 10) starting at: 6
---
@@ -110,12 +111,12 @@
> 81 LOAD_LOCAL(value e)
> ? STORE_LOCAL(variable exc1)
> ? JUMP 12
-668c700,714
+668c700,701
< 81 THROW(Exception)
---
> ? STORE_LOCAL(variable exc1)
> ? JUMP 12
->
+684a718,730
> 12:
> 83 LOAD_MODULE object Predef
> 83 CONSTANT("finally")
@@ -128,6 +129,7 @@
> 84 STORE_LOCAL(variable result)
> 84 LOAD_LOCAL(variable exc1)
> 84 THROW(Throwable)
+>
690c736
< catch (<none>) in ArrayBuffer(4, 6, 7, 9) starting at: 3
---
@@ -171,17 +173,18 @@
---
> ? STORE_LOCAL(value ex6)
> ? JUMP 33
-802c854,861
+802c854,855
< 170 THROW(Throwable)
---
> ? STORE_LOCAL(value ex6)
> ? JUMP 33
->
+811a865,870
> 33:
> 169 LOAD_LOCAL(value ex6)
> 169 STORE_LOCAL(value x4)
> 169 SCOPE_ENTER value x4
> 169 JUMP 5
+>
826,829d884
< 180 LOAD_LOCAL(value x5)
< 180 CALL_METHOD MyException.message (dynamic)
@@ -207,7 +210,7 @@
---
> ? STORE_LOCAL(variable exc2)
> ? JUMP 34
-842a902,914
+857a917,929
> 34:
> 184 LOAD_MODULE object Predef
> 184 CONSTANT("finally")
diff --git a/test/files/run/macro-def-path-dependent-d.check b/test/files/run/macro-def-path-dependent-d1.check
index 1ea14b4e20..1ea14b4e20 100644
--- a/test/files/run/macro-def-path-dependent-d.check
+++ b/test/files/run/macro-def-path-dependent-d1.check
diff --git a/test/files/run/macro-def-path-dependent-d.flags b/test/files/run/macro-def-path-dependent-d1.flags
index cd66464f2f..cd66464f2f 100644
--- a/test/files/run/macro-def-path-dependent-d.flags
+++ b/test/files/run/macro-def-path-dependent-d1.flags
diff --git a/test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala b/test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala
index 2daf6fc3fb..2daf6fc3fb 100644
--- a/test/files/run/macro-def-path-dependent-d/Impls_Macros_1.scala
+++ b/test/files/run/macro-def-path-dependent-d1/Impls_Macros_1.scala
diff --git a/test/files/run/macro-def-path-dependent-d/Test_2.scala b/test/files/run/macro-def-path-dependent-d1/Test_2.scala
index 7dffc5107d..7dffc5107d 100644
--- a/test/files/run/macro-def-path-dependent-d/Test_2.scala
+++ b/test/files/run/macro-def-path-dependent-d1/Test_2.scala
diff --git a/test/files/run/macro-def-path-dependent-d2.check b/test/files/run/macro-def-path-dependent-d2.check
new file mode 100644
index 0000000000..1ea14b4e20
--- /dev/null
+++ b/test/files/run/macro-def-path-dependent-d2.check
@@ -0,0 +1 @@
+it works
diff --git a/test/files/run/macro-def-path-dependent-d2.flags b/test/files/run/macro-def-path-dependent-d2.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-def-path-dependent-d2.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-def-path-dependent-d2/Impls_1.scala b/test/files/run/macro-def-path-dependent-d2/Impls_1.scala
new file mode 100644
index 0000000000..1cda64e43e
--- /dev/null
+++ b/test/files/run/macro-def-path-dependent-d2/Impls_1.scala
@@ -0,0 +1,7 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.macros.Context
+import scala.reflect.api.Universe
+
+object Impls {
+ def materializeTypeTag_impl[T: c.AbsTypeTag](c: Context)(u: c.Expr[Universe])(e: c.Expr[T]): c.Expr[u.value.TypeTag[T]] = ???
+} \ No newline at end of file
diff --git a/test/files/run/macro-def-path-dependent-d2/Macros_2.scala b/test/files/run/macro-def-path-dependent-d2/Macros_2.scala
new file mode 100644
index 0000000000..65ce4d8bd2
--- /dev/null
+++ b/test/files/run/macro-def-path-dependent-d2/Macros_2.scala
@@ -0,0 +1,7 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.macros.Context
+import scala.reflect.api.Universe
+
+object Macros {
+ def materializeTypeTag[T](u: Universe)(e: T) = macro Impls.materializeTypeTag_impl[T]
+} \ No newline at end of file
diff --git a/test/files/run/macro-def-path-dependent-d2/Test_3.scala b/test/files/run/macro-def-path-dependent-d2/Test_3.scala
new file mode 100644
index 0000000000..7dffc5107d
--- /dev/null
+++ b/test/files/run/macro-def-path-dependent-d2/Test_3.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ println("it works")
+} \ No newline at end of file
diff --git a/test/files/run/macro-expand-implicit-argument.check b/test/files/run/macro-expand-implicit-argument.check
new file mode 100644
index 0000000000..fb42345748
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument.check
@@ -0,0 +1 @@
+List(1, 2, 3)
diff --git a/test/files/run/macro-expand-implicit-argument.flags b/test/files/run/macro-expand-implicit-argument.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-expand-implicit-argument/Macros_1.scala b/test/files/run/macro-expand-implicit-argument/Macros_1.scala
new file mode 100644
index 0000000000..7629c5a9e2
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument/Macros_1.scala
@@ -0,0 +1,59 @@
+import annotation.tailrec
+import scala.math.{min, max}
+import scala.{specialized => spec}
+
+import language.experimental.macros
+
+import scala.reflect.{ClassTag, TypeTag}
+import scala.reflect.macros.Context
+
+object Macros {
+ def alloc[@spec A:ClassTag](src:Array[A], s1:Int, len:Int) = {
+ val as = Array.ofDim[A](len)
+ System.arraycopy(src, s1, as, 0, len)
+ as
+ }
+
+ /**
+ * Efficient alternative to Array.apply.
+ *
+ * "As seen on scala-internals!"
+ */
+ def array[A](as:A*)(implicit ct: ClassTag[A]) = macro arrayMacro[A]
+
+ /**
+ * Takes in something like:
+ * ArrayUtil.alloc[Int](11, 22, 33, 44)(ct)
+ *
+ * and builds a tree like:
+ * {
+ * val arr:Array[Int] = ct.newArray(4)
+ * arr.update(0, 11)
+ * arr.update(1, 22)
+ * arr.update(2, 33)
+ * arr.update(3, 44)
+ * arr
+ * }
+ */
+ def arrayMacro[A:c.AbsTypeTag](c:Context)(as:c.Expr[A]*)(ct: c.Expr[ClassTag[A]]): c.Expr[Array[A]] = {
+ import c.mirror._
+ import c.universe._
+ def const(x:Int) = Literal(Constant(x))
+
+ val n = as.length
+ val arr = newTermName("arr")
+
+ val create = Apply(Select(ct.tree, "newArray"), List(const(n)))
+ val arrtpe = TypeTree(implicitly[c.AbsTypeTag[Array[A]]].tpe)
+ val valdef = ValDef(Modifiers(), arr, arrtpe, create)
+
+ val updates = (0 until n).map {
+ i => Apply(Select(Ident(arr), "update"), List(const(i), as(i).tree))
+ }
+
+ val exprs = Seq(valdef) ++ updates ++ Seq(Ident(arr))
+ val block = Block(exprs:_*)
+
+ c.Expr[Array[A]](block)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macro-expand-implicit-argument/Test_2.scala b/test/files/run/macro-expand-implicit-argument/Test_2.scala
new file mode 100644
index 0000000000..ce8a068fb4
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ import Macros._
+ println(array(1, 2, 3).toList)
+} \ No newline at end of file
diff --git a/test/files/run/partialfun.check b/test/files/run/partialfun.check
new file mode 100644
index 0000000000..a317f7b150
--- /dev/null
+++ b/test/files/run/partialfun.check
@@ -0,0 +1,6 @@
+47
+147
+100
+0:isDefinedAt
+1:isDefinedAt
+2:apply
diff --git a/test/files/run/partialfun.scala b/test/files/run/partialfun.scala
new file mode 100644
index 0000000000..4b360750c9
--- /dev/null
+++ b/test/files/run/partialfun.scala
@@ -0,0 +1,86 @@
+import collection._
+import collection.generic._
+
+object Test {
+ def collectIDA[A, B, Repr, That](_this: TraversableLike[A, Repr])(pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val repr: Repr = _this.asInstanceOf[Repr]
+ val b = bf(repr)
+ _this foreach { x => if (pf isDefinedAt x) b += pf(x) }
+ b.result
+ }
+
+ def collectRW[A, B, Repr, That](_this: TraversableLike[A, Repr])(pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
+ val repr: Repr = _this.asInstanceOf[Repr]
+ val b = bf(repr)
+ val f = pf runWith { b += _ }
+ _this foreach f
+ b.result
+ }
+
+ var cnt = 0
+
+ object Ex1 {
+ def unapply(x: Int) : Option[Int] = {
+ cnt += 1
+ if ((x % 3) == 0) Some(-x) else None
+ }
+ }
+
+ object Ex2 {
+ def unapply(x: Int) : Option[Int] = {
+ //cnt += 1
+ if ((x % 5) == 0) Some(x) else None
+ }
+ }
+
+ def resetCnt() = { val r = cnt; cnt = 0; r }
+
+ val pf: PartialFunction[Int,Int] = {
+ case Ex1(result) => result
+ case Ex2(result) => result
+ }
+
+ def collectTest() {
+ val xs = 1 to 100
+ resetCnt()
+
+ val ysIDA = collectIDA(xs)(pf)
+ val cntIDA = resetCnt()
+
+ val ysRW = collectRW(xs)(pf)
+ val cntRW = resetCnt()
+
+ val ys = xs collect pf
+
+ assert(ys == ysIDA)
+ assert(ys == ysRW)
+ assert(cntIDA == xs.length + ys.length)
+ assert(cntRW == xs.length)
+ println(ys.length)
+ println(cntIDA)
+ println(cntRW)
+ }
+
+ def orElseTest() {
+ val pf0 = new PartialFunction[Unit, Unit] {
+ def apply(u: Unit) { println("0:apply") }
+ def isDefinedAt(u: Unit) = { println("0:isDefinedAt"); false }
+ }
+ val pf1 = new PartialFunction[Unit, Unit] {
+ def apply(u: Unit) { println("1:apply") }
+ def isDefinedAt(u: Unit) = { println("1:isDefinedAt"); false }
+ }
+ val pf2 = new PartialFunction[Unit, Unit] {
+ def apply(u: Unit) { println("2:apply") }
+ def isDefinedAt(u: Unit) = { println("2:isDefinedAt"); true }
+ }
+
+ val chained = pf0 orElse pf1 orElse pf2
+ chained()
+ }
+
+ def main(args: Array[String]): Unit = {
+ collectTest()
+ orElseTest()
+ }
+}
diff --git a/test/files/run/reflection-sorted-decls.check b/test/files/run/reflection-sorted-decls.check
index 9a9832a683..02168c4e5f 100644
--- a/test/files/run/reflection-sorted-decls.check
+++ b/test/files/run/reflection-sorted-decls.check
@@ -1,7 +1,3 @@
value a
value b
value c
-method c
-method b
-method a
-constructor Foo$1
diff --git a/test/files/run/reflection-sorted-decls.scala b/test/files/run/reflection-sorted-decls.scala
index 242f17d9bb..5616e10b3b 100644
--- a/test/files/run/reflection-sorted-decls.scala
+++ b/test/files/run/reflection-sorted-decls.scala
@@ -3,6 +3,6 @@ object Test {
class Foo(val a: Int, val b: Int, val c: Int)
import scala.reflect.runtime.{currentMirror => cm}
val decls = cm.classSymbol(classOf[Foo]).typeSignature.declarations
- decls.sorted.toList foreach System.out.println
+ decls.sorted.toList.filter(!_.isMethod) foreach System.out.println
}
}
diff --git a/test/files/run/reflection-sorted-members.check b/test/files/run/reflection-sorted-members.check
index d58b691c42..bb85b5a13c 100644
--- a/test/files/run/reflection-sorted-members.check
+++ b/test/files/run/reflection-sorted-members.check
@@ -1,34 +1,4 @@
value a
value b
value c
-method c
-method b
-method a
-constructor Foo$1
value x
-method x
-constructor Bar$1
-method finalize
-method wait
-method wait
-method wait
-method equals
-method toString
-method hashCode
-method getClass
-method clone
-method notify
-method notifyAll
-constructor Object
-method eq
-method ne
-method ==
-method !=
-method ##
-method synchronized
-method $isInstanceOf
-method $asInstanceOf
-method ==
-method !=
-method isInstanceOf
-method asInstanceOf
diff --git a/test/files/run/reflection-sorted-members.scala b/test/files/run/reflection-sorted-members.scala
index 9980d79999..a8379234c0 100644
--- a/test/files/run/reflection-sorted-members.scala
+++ b/test/files/run/reflection-sorted-members.scala
@@ -6,6 +6,6 @@ object Test {
class Foo(val a: Int, val b: Int, val c: Int) extends Bar(a + b + c) with T1 with T2
import scala.reflect.runtime.{currentMirror => cm}
val members = cm.classSymbol(classOf[Foo]).typeSignature.members
- members.sorted.toList foreach System.out.println
+ members.sorted.toList.filter(!_.isMethod) foreach System.out.println
}
}
diff --git a/test/files/run/static-annot-repl.check b/test/files/run/static-annot-repl.check
new file mode 100644
index 0000000000..d1029a9809
--- /dev/null
+++ b/test/files/run/static-annot-repl.check
@@ -0,0 +1,32 @@
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> import annotation.static
+import annotation.static
+
+scala> @static var x1 = 42
+x1: Int = 42
+
+scala> @static val x2 = 43
+x2: Int = 43
+
+scala> @static def x3 = 44
+x3: Int
+
+scala> x1
+res0: Int = 42
+
+scala> x2
+res1: Int = 43
+
+scala> x3
+res2: Int = 44
+
+scala> class Test {
+ @static def x = 42
+}
+defined class Test
+
+scala> \ No newline at end of file
diff --git a/test/files/run/static-annot-repl.scala b/test/files/run/static-annot-repl.scala
new file mode 100644
index 0000000000..1d2e9b2d7e
--- /dev/null
+++ b/test/files/run/static-annot-repl.scala
@@ -0,0 +1,22 @@
+
+
+
+import scala.tools.partest.ReplTest
+
+
+
+object Test extends ReplTest {
+ def code = """
+import annotation.static
+@static var x1 = 42
+@static val x2 = 43
+@static def x3 = 44
+x1
+x2
+x3
+class Test {
+ @static def x = 42
+}
+"""
+
+}
diff --git a/test/files/run/static-annot/field.scala b/test/files/run/static-annot/field.scala
index a7d8158321..8408a51800 100644
--- a/test/files/run/static-annot/field.scala
+++ b/test/files/run/static-annot/field.scala
@@ -23,8 +23,10 @@ class Foo
trait Check {
def checkStatic(cls: Class[_]) {
cls.getDeclaredFields.find(_.getName == "bar") match {
- case Some(f) => assert(Modifier.isStatic(f.getModifiers), "no static modifier")
- case None => assert(false, "no static field bar in class")
+ case Some(f) =>
+ assert(Modifier.isStatic(f.getModifiers), "no static modifier")
+ case None =>
+ assert(false, "no static field bar in class")
}
}
@@ -170,6 +172,10 @@ object Foo7 {
@static val bar = "string"
}
class AndHisFriend
+
+ object AndHisLonelyFriend {
+ @static val bar = "another"
+ }
}
@@ -177,6 +183,9 @@ object Test7 extends Check {
def test() {
checkStatic(classOf[Foo7.AndHisFriend])
assert(Foo7.AndHisFriend.bar == "string")
+
+ checkStatic(Class.forName("Foo7$AndHisLonelyFriend"))
+ assert(Foo7.AndHisLonelyFriend.bar == "another")
}
}
diff --git a/test/files/run/stream-stack-overflow-filter-map.scala b/test/files/run/stream-stack-overflow-filter-map.scala
new file mode 100644
index 0000000000..f3a9dd49cb
--- /dev/null
+++ b/test/files/run/stream-stack-overflow-filter-map.scala
@@ -0,0 +1,44 @@
+import collection.generic.{FilterMonadic, CanBuildFrom}
+
+object Test extends App {
+ def mapSucc[Repr, That](s: FilterMonadic[Int, Repr])(implicit cbf: CanBuildFrom[Repr, Int, That]) = s map (_ + 1)
+ def flatMapId[T, Repr, That](s: FilterMonadic[T, Repr])(implicit cbf: CanBuildFrom[Repr, T, That]) = s flatMap (Seq(_))
+
+ def testStreamPred(s: Stream[Int])(p: Int => Boolean) {
+ val res1 = s withFilter p
+ val res2 = s filter p
+
+ val expected = s.toSeq filter p
+
+ val fMapped1 = flatMapId(res1)
+ val fMapped2 = flatMapId(res2)
+ assert(fMapped1 == fMapped2)
+ assert(fMapped1.toSeq == expected)
+
+ val mapped1 = mapSucc(res1)
+ val mapped2 = mapSucc(res2)
+ assert(mapped1 == mapped2)
+ assert(mapped1.toSeq == (expected map (_ + 1)))
+
+ assert((res1 map identity).toSeq == res2.toSeq)
+ }
+
+ def testStream(s: Stream[Int]) {
+ testStreamPred(s)(_ => false)
+ testStreamPred(s)(_ => true)
+ testStreamPred(s)(_ % 2 == 0)
+ testStreamPred(s)(_ % 3 == 0)
+ }
+
+ //Reduced version of the test case - either invocation used to cause a stack
+ //overflow before commit 80b3f433e5536d086806fa108ccdfacf10719cc2.
+ val resFMap = (1 to 10000).toStream withFilter (_ => false) flatMap (Seq(_))
+ val resMap = (1 to 10000).toStream withFilter (_ => false) map (_ + 1)
+
+ //Complete test case for withFilter + map/flatMap, as requested by @axel22.
+ for (j <- (0 to 3) :+ 10000) {
+ val stream = (1 to j).toStream
+ assert(stream.toSeq == (1 to j).toSeq)
+ testStream(stream)
+ }
+}
diff --git a/test/files/run/t1987b.check b/test/files/run/t1987b.check
new file mode 100644
index 0000000000..68d4b10e12
--- /dev/null
+++ b/test/files/run/t1987b.check
@@ -0,0 +1 @@
+ok!
diff --git a/test/files/run/t1987b/PullIteratees.scala b/test/files/run/t1987b/PullIteratees.scala
new file mode 100644
index 0000000000..a5a3e65d8f
--- /dev/null
+++ b/test/files/run/t1987b/PullIteratees.scala
@@ -0,0 +1,17 @@
+package scales.xml
+
+trait PullType
+class QName
+trait RetUrn[T]
+
+/**
+ * Iteratees related to pull parsing
+ */
+trait PullIteratees {
+ /**
+ * Without the overload it doesn't trigger the CCE, even though its
+ * not used
+ */
+ def iterate(path: List[QName], xml: String): RetUrn[String] = null
+ def iterate(path: List[QName], xml: Iterator[PullType]): RetUrn[String] = null
+}
diff --git a/test/files/run/t1987b/a.scala b/test/files/run/t1987b/a.scala
new file mode 100644
index 0000000000..c1be5fe3e0
--- /dev/null
+++ b/test/files/run/t1987b/a.scala
@@ -0,0 +1,6 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ scales.xml.CCE_Test.main(args)
+ println("ok!")
+ }
+}
diff --git a/test/files/run/t1987b/cce_test.scala b/test/files/run/t1987b/cce_test.scala
new file mode 100644
index 0000000000..4f9acf0264
--- /dev/null
+++ b/test/files/run/t1987b/cce_test.scala
@@ -0,0 +1,15 @@
+package scales.xml
+//import scales.xml._ // using another pacakge and importing doesn't CCE
+
+object CCE_Test {
+ def main(args: Array[String]): Unit = {
+ // without the import it doesn't trigger the CCE
+ import scaley.funny._
+
+ val pull = null.asInstanceOf[Iterator[PullType]]
+ val LogEntries = null.asInstanceOf[List[QName]]
+ // fully qualify with scales.xml. and it won't trigger it
+ iterate(LogEntries,
+ pull)
+ }
+}
diff --git a/test/files/run/t1987b/pkg1.scala b/test/files/run/t1987b/pkg1.scala
new file mode 100644
index 0000000000..6e749fc6b3
--- /dev/null
+++ b/test/files/run/t1987b/pkg1.scala
@@ -0,0 +1,4 @@
+package scaley
+
+package object funny {
+}
diff --git a/test/files/run/t1987b/pkg2.scala b/test/files/run/t1987b/pkg2.scala
new file mode 100644
index 0000000000..38056a199e
--- /dev/null
+++ b/test/files/run/t1987b/pkg2.scala
@@ -0,0 +1,3 @@
+package scales
+
+package object xml extends PullIteratees
diff --git a/test/files/run/t6052.scala b/test/files/run/t6052.scala
new file mode 100644
index 0000000000..385d5390d3
--- /dev/null
+++ b/test/files/run/t6052.scala
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+object Test extends App {
+ def seqarr(i: Int) = Array[Int]() ++ (0 until i)
+ def pararr(i: Int) = seqarr(i).par
+
+ def check[T](i: Int, f: Int => T) {
+ val gseq = seqarr(i).toSeq.groupBy(f)
+ val gpar = pararr(i).groupBy(f)
+ assert(gseq == gpar, (gseq, gpar))
+ }
+
+ for (i <- 0 until 20) check(i, _ > 0)
+ for (i <- 0 until 20) check(i, _ % 2)
+ for (i <- 0 until 20) check(i, _ % 4)
+}
diff --git a/test/files/run/t6236.check b/test/files/run/t6236.check
new file mode 100644
index 0000000000..a0a2e88d0a
--- /dev/null
+++ b/test/files/run/t6236.check
@@ -0,0 +1,2 @@
+353
+353 \ No newline at end of file
diff --git a/test/files/run/t6236/file_1.scala b/test/files/run/t6236/file_1.scala
new file mode 100644
index 0000000000..92d22799fc
--- /dev/null
+++ b/test/files/run/t6236/file_1.scala
@@ -0,0 +1,9 @@
+
+
+package p {
+ object y {
+ object x {
+ @scala.annotation.static val foo: Int = 353
+ }
+ }
+}
diff --git a/test/files/run/t6236/file_2.scala b/test/files/run/t6236/file_2.scala
new file mode 100644
index 0000000000..51823004ca
--- /dev/null
+++ b/test/files/run/t6236/file_2.scala
@@ -0,0 +1,10 @@
+
+
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(p.y.x.foo)
+ println(p.y.x.foo)
+ }
+}
+
diff --git a/test/files/run/t6261.scala b/test/files/run/t6261.scala
new file mode 100644
index 0000000000..b4463256c9
--- /dev/null
+++ b/test/files/run/t6261.scala
@@ -0,0 +1,130 @@
+import scala.collection.immutable._
+
+object Test extends App {
+
+ def test0() {
+ val m=ListMap(1->2,3->4)
+ if(m.tail ne m.tail)
+ println("ListMap.tail uses a builder, so it is not O(1)")
+ }
+
+ def test1() {
+ // test that a HashTrieMap with one leaf element is not created!
+ val x = HashMap.empty + (1->1) + (2->2)
+ if(x.getClass.getSimpleName != "HashTrieMap")
+ println("A hash map containing two non-colliding values should be a HashTrieMap")
+
+ val y = x - 1
+ if(y.getClass.getSimpleName != "HashMap1")
+ println("A hash map containing one element should always use HashMap1")
+ }
+
+ def test2() {
+ // class that always causes hash collisions
+ case class Collision(value:Int) { override def hashCode = 0 }
+
+ // create a set that should have a collison
+ val x = HashMap.empty + (Collision(0)->0) + (Collision(1) ->0)
+ if(x.getClass.getSimpleName != "HashMapCollision1")
+ println("HashMap of size >1 with collisions should use HashMapCollision")
+
+ // remove the collision again by removing all but one element
+ val y = x - Collision(0)
+ if(y.getClass.getSimpleName != "HashMap1")
+ println("HashMap of size 1 should use HashMap1" + y.getClass)
+ }
+ def test3() {
+ // finds an int x such that improved(x) differs in the first bit to improved(0),
+ // which is the worst case for the HashTrieSet
+ def findWorstCaseInts() {
+ // copy of improve from HashSet
+ def improve(hcode: Int) = {
+ var h: Int = hcode + ~(hcode << 9)
+ h = h ^ (h >>> 14)
+ h = h + (h << 4)
+ h ^ (h >>> 10)
+ }
+
+ // find two hashes which have a large separation
+ val x = 0
+ var y = 1
+ val ix = improve(x)
+ while(y!=0 && improve(y)!=ix+(1<<31))
+ y+=1
+ printf("%s %s %x %x\n",x,y,improve(x), improve(y))
+ }
+ // this is not done every test run since it would slow down ant test.suite too much.
+ // findWorstCaseInts()
+
+ // two numbers that are immediately adiacent when fed through HashSet.improve
+ val h0 = 0
+ val h1 = 1270889724
+
+ // h is the hashcode, i is ignored for the hashcode but relevant for equality
+ case class Collision(h:Int, i:Int) {
+ override def hashCode = h
+ }
+ val a = Collision(h0,0)->0
+ val b = Collision(h0,1)->0
+ val c = Collision(h1,0)->0
+
+ // create a HashSetCollision1
+ val x = HashMap(a) + b
+ if(x.getClass.getSimpleName != "HashMapCollision1")
+ println("x should be a HashMapCollision")
+ StructureTests.validate(x)
+ //StructureTests.printStructure(x)
+ require(x.size==2 && x.contains(a._1) && x.contains(b._1))
+
+ // go from a HashSetCollision1 to a HashTrieSet with maximum depth
+ val y = x + c
+ if(y.getClass.getSimpleName != "HashTrieMap")
+ println("y should be a HashTrieMap")
+ StructureTests.validate(y)
+ // StructureTests.printStructure(y)
+ require(y.size==3 && y.contains(a._1) && y.contains(b._1) && y.contains(c._1))
+
+ // go from a HashSet1 directly to a HashTrieSet with maximum depth
+ val z = HashMap(a) + c
+ if(y.getClass.getSimpleName != "HashTrieMap")
+ println("y should be a HashTrieMap")
+ StructureTests.validate(z)
+ // StructureTests.printStructure(z)
+ require(z.size == 2 && z.contains(a._1) && z.contains(c._1))
+ }
+ test0()
+ test1()
+ test2()
+ test3()
+}
+
+
+package scala.collection.immutable {
+ object StructureTests {
+ def printStructure(x:HashMap[_,_], prefix:String="") {
+ x match {
+ case m:HashMap.HashTrieMap[_,_] =>
+ println(prefix+m.getClass.getSimpleName + " " + m.size)
+ m.elems.foreach(child => printStructure(child, prefix + " "))
+ case m:HashMap.HashMapCollision1[_,_] =>
+ println(prefix+m.getClass.getSimpleName + " " + m.kvs.size)
+ case m:HashMap.HashMap1[_,_] =>
+ println(prefix+m.getClass.getSimpleName + " " + m.head)
+ case _ =>
+ println(prefix+"empty")
+ }
+ }
+
+ def validate(x:HashMap[_,_]) {
+ x match {
+ case m:HashMap.HashTrieMap[_,_] =>
+ require(m.elems.size>1 || (m.elems.size==1 && m.elems(0).isInstanceOf[HashMap.HashTrieMap[_,_]]))
+ m.elems.foreach(validate _)
+ case m:HashMap.HashMapCollision1[_,_] =>
+ require(m.kvs.size>1)
+ case m:HashMap.HashMap1[_,_] =>
+ case _ =>
+ }
+ }
+ }
+}
diff --git a/test/files/run/t6272.check b/test/files/run/t6272.check
new file mode 100644
index 0000000000..f00c965d83
--- /dev/null
+++ b/test/files/run/t6272.check
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/files/run/t6272.scala b/test/files/run/t6272.scala
new file mode 100644
index 0000000000..174436919b
--- /dev/null
+++ b/test/files/run/t6272.scala
@@ -0,0 +1,62 @@
+// x1, x2, and x3 resulted in: symbol variable bitmap$0 does not exist in A.<init>
+object A {
+
+ try {
+ lazy val x1 = 1
+ println(x1)
+ sys.error("!")
+ } catch {
+ case _: Throwable =>
+ lazy val x2 = 2
+ println(x2)
+ } finally {
+ lazy val x3 = 3
+ println(x3)
+ }
+
+ if ("".isEmpty) {
+ lazy val x4 = 4
+ println(x4)
+ }
+
+ var b = true
+ while(b) {
+ lazy val x5 = 5
+ println(x5)
+ b = false
+ }
+
+
+ def method {
+ try {
+ lazy val x6 = 6
+ println(x6)
+ sys.error("!")
+ } catch {
+ case _: Throwable =>
+ lazy val x7 = 7
+ println(x7)
+ } finally {
+ lazy val x8 = 8
+ println(x8)
+ }
+
+ if ("".isEmpty) {
+ lazy val x9 = 9
+ println(x9)
+ }
+
+ var b = true
+ while(b) {
+ lazy val x10 = 10
+ println(x10)
+ b = false
+ }
+ }
+}
+
+object Test {
+ def main(args: Array[String]) {
+ A.method
+ }
+}
diff --git a/test/files/run/t6292.scala b/test/files/run/t6292.scala
new file mode 100644
index 0000000000..51e31f95fc
--- /dev/null
+++ b/test/files/run/t6292.scala
@@ -0,0 +1,18 @@
+ import scala.collection.mutable.DoubleLinkedList
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ cloneAndtest(DoubleLinkedList[Int]())
+ cloneAndtest(DoubleLinkedList[Int](1))
+ cloneAndtest(DoubleLinkedList[Int](1,2,3,4))
+ }
+
+ def cloneAndtest(l: DoubleLinkedList[Int]): Unit =
+ testSame(l, l.clone.asInstanceOf[DoubleLinkedList[Int]])
+
+ def testSame(one: DoubleLinkedList[Int], two: DoubleLinkedList[Int]): Unit = {
+ def msg = s" for ${one} and ${two} !"
+ assert(one.size == two.size, s"Cloned sizes are not the same $msg!")
+ assert(one == two, s"Cloned lists are not equal $msg")
+ }
+}
diff --git a/test/files/run/try-catch-unify.check b/test/files/run/try-catch-unify.check
new file mode 100644
index 0000000000..67a8c64a33
--- /dev/null
+++ b/test/files/run/try-catch-unify.check
@@ -0,0 +1,4 @@
+Failure(java.lang.NumberFormatException: For input string: "Hi")
+Success(5.0)
+O NOES
+Failure(java.lang.NumberFormatException: For input string: "Hi")
diff --git a/test/files/run/try-catch-unify.scala b/test/files/run/try-catch-unify.scala
new file mode 100644
index 0000000000..8cb14d060e
--- /dev/null
+++ b/test/files/run/try-catch-unify.scala
@@ -0,0 +1,16 @@
+import util._
+
+import control.Exception._
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ println(catching(classOf[NumberFormatException]) withTry ("Hi".toDouble))
+ println(catching(classOf[NumberFormatException]) withTry ("5".toDouble))
+ try {
+ catching(classOf[NumberFormatException]) withTry (sys.error("O NOES"))
+ } catch {
+ case t => println(t.getMessage)
+ }
+ println(nonFatalCatch withTry ("Hi".toDouble))
+ }
+}
diff --git a/test/pending/neg/macro-invalidusage-badbounds-b.check b/test/pending/neg/macro-invalidusage-badbounds-b.check
new file mode 100644
index 0000000000..fd0b64533e
--- /dev/null
+++ b/test/pending/neg/macro-invalidusage-badbounds-b.check
@@ -0,0 +1,4 @@
+Macros_Test_2.scala:7: error: type arguments [Int] do not conform to macro method foo's type parameter bounds [U <: String]
+ foo[Int]
+ ^
+one error found
diff --git a/test/pending/neg/macro-invalidusage-badbounds-b.flags b/test/pending/neg/macro-invalidusage-badbounds-b.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/pending/neg/macro-invalidusage-badbounds-b.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala b/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala
index 89020de7dd..89020de7dd 100644
--- a/test/files/neg/macro-invalidusage-badbounds/Impls_1.scala
+++ b/test/pending/neg/macro-invalidusage-badbounds-b/Impls_1.scala
diff --git a/test/pending/neg/macro-invalidusage-badbounds-b/Macros_Test_2.scala b/test/pending/neg/macro-invalidusage-badbounds-b/Macros_Test_2.scala
new file mode 100644
index 0000000000..3139599108
--- /dev/null
+++ b/test/pending/neg/macro-invalidusage-badbounds-b/Macros_Test_2.scala
@@ -0,0 +1,8 @@
+object Macros {
+ def foo[U <: String] = macro Impls.foo[U]
+}
+
+object Test extends App {
+ import Macros._
+ foo[Int]
+} \ No newline at end of file