summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-09-03 08:22:51 +1000
committerJason Zaugg <jzaugg@gmail.com>2014-09-03 08:22:51 +1000
commit21644611b3c676210d312eca1e0169d21070b50e (patch)
treee732aa1f0b6b6d65c21e91b40298f722200593f7
parent61dbf4ac711094db38a4b2dfb853d88499c2b1a5 (diff)
parent91c4192c39d2bdebf37a97e41d374a39ece8af85 (diff)
downloadscala-21644611b3c676210d312eca1e0169d21070b50e.tar.gz
scala-21644611b3c676210d312eca1e0169d21070b50e.tar.bz2
scala-21644611b3c676210d312eca1e0169d21070b50e.zip
Merge pull request #3959 from lrytz/merge/2.11-to-2.12-is-it-really-sept-2-already-where-was-summer
Merge 2.11 to 2.12
-rw-r--r--bincompat-backward.whitelist.conf9
-rw-r--r--bincompat-forward.whitelist.conf114
-rwxr-xr-xbuild.xml10
-rw-r--r--src/compiler/scala/tools/nsc/CompilationUnits.scala7
-rw-r--r--src/compiler/scala/tools/nsc/CompileServer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/CompileSocket.scala3
-rw-r--r--src/compiler/scala/tools/nsc/CompilerCommand.scala10
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala258
-rw-r--r--src/compiler/scala/tools/nsc/Parsing.scala36
-rw-r--r--src/compiler/scala/tools/nsc/Properties.scala1
-rw-r--r--src/compiler/scala/tools/nsc/Reporting.scala15
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala58
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala53
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala130
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala41
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala501
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala46
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala56
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala861
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala846
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala396
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala293
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala70
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala21
-rw-r--r--src/compiler/scala/tools/nsc/javac/JavaScanners.scala2
-rw-r--r--src/compiler/scala/tools/nsc/plugins/Plugins.scala2
-rw-r--r--src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/reporters/Reporter.scala4
-rw-r--r--src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/MutableSettings.scala97
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala29
-rw-r--r--src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/settings/Warnings.scala146
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala41
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala59
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala10
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/LazyVals.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/TypingTransformers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala41
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Adaptations.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala112
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala429
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala130
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala142
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala41
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala25
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala116
-rw-r--r--src/compiler/scala/tools/reflect/FormatInterpolator.scala18
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala13
-rw-r--r--src/eclipse/repl/.classpath16
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala2
-rw-r--r--src/jline/LICENSE.txt33
-rw-r--r--src/jline/README.md24
-rw-r--r--src/jline/build.sbt49
-rwxr-xr-xsrc/jline/manual-test.sh9
-rw-r--r--src/jline/project/build.properties1
-rw-r--r--src/jline/project/plugins.sbt3
-rw-r--r--src/jline/src/main/java/scala/tools/jline/AnsiWindowsTerminal.java90
-rw-r--r--src/jline/src/main/java/scala/tools/jline/NoInterruptUnixTerminal.java44
-rw-r--r--src/jline/src/main/java/scala/tools/jline/Terminal.java59
-rw-r--r--src/jline/src/main/java/scala/tools/jline/TerminalFactory.java173
-rw-r--r--src/jline/src/main/java/scala/tools/jline/TerminalSupport.java179
-rw-r--r--src/jline/src/main/java/scala/tools/jline/UnixTerminal.java248
-rw-r--r--src/jline/src/main/java/scala/tools/jline/UnsupportedTerminal.java25
-rw-r--r--src/jline/src/main/java/scala/tools/jline/WindowsTerminal.java468
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/ConsoleReader.java2185
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/CursorBuffer.java106
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/Key.java82
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/Operation.java291
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/AggregateCompleter.java108
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/ArgumentCompleter.java398
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java193
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/Completer.java37
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/CompletionHandler.java25
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/EnumCompleter.java35
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/FileNameCompleter.java133
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/NullCompleter.java39
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/StringsCompleter.java79
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/completer/package-info.java22
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/history/FileHistory.java106
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/history/History.java71
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/history/MemoryHistory.java318
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/history/PersistentHistory.java34
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/history/package-info.java22
-rw-r--r--src/jline/src/main/java/scala/tools/jline/console/package-info.java22
-rw-r--r--src/jline/src/main/java/scala/tools/jline/internal/Configuration.java127
-rw-r--r--src/jline/src/main/java/scala/tools/jline/internal/Log.java112
-rw-r--r--src/jline/src/main/java/scala/tools/jline/internal/ReplayPrefixOneCharInputStream.java95
-rw-r--r--src/jline/src/main/java/scala/tools/jline/internal/TerminalLineSettings.java217
-rw-r--r--src/jline/src/main/java/scala/tools/jline/internal/package-info.java22
-rw-r--r--src/jline/src/main/java/scala/tools/jline/package-info.java22
-rw-r--r--src/jline/src/main/resources/scala/tools/jline/console/completer/CandidateListCompletionHandler.properties4
-rw-r--r--src/jline/src/main/resources/scala/tools/jline/keybindings.properties71
-rw-r--r--src/jline/src/main/resources/scala/tools/jline/windowsbindings.properties71
-rw-r--r--src/jline/src/test/java/scala/tools/jline/TerminalFactoryTest.java34
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTest.java261
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTestSupport.java143
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/EditLineTest.java208
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/completer/ArgumentCompleterTest.java46
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/completer/NullCompleterTest.java39
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/completer/StringsCompleterTest.java40
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/history/HistoryTest.java79
-rw-r--r--src/jline/src/test/java/scala/tools/jline/console/history/MemoryHistoryTest.java99
-rw-r--r--src/jline/src/test/java/scala/tools/jline/example/Example.java107
-rw-r--r--src/jline/src/test/java/scala/tools/jline/internal/TerminalLineSettingsTest.java146
-rw-r--r--src/library/scala/StringContext.scala15
-rw-r--r--src/library/scala/collection/IterableProxy.scala1
-rw-r--r--src/library/scala/collection/MapProxy.scala1
-rw-r--r--src/library/scala/collection/SetProxy.scala1
-rw-r--r--src/library/scala/collection/TraversableLike.scala2
-rw-r--r--src/library/scala/collection/TraversableProxy.scala1
-rw-r--r--src/library/scala/collection/immutable/Range.scala19
-rw-r--r--src/library/scala/collection/immutable/Stream.scala24
-rw-r--r--src/library/scala/concurrent/ExecutionContext.scala72
-rw-r--r--src/library/scala/runtime/SeqCharSequence.scala7
-rw-r--r--src/library/scala/util/matching/Regex.scala414
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala23
-rw-r--r--src/reflect/scala/reflect/api/Quasiquotes.scala2
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala3
-rw-r--r--src/reflect/scala/reflect/api/TreeCreator.scala6
-rw-r--r--src/reflect/scala/reflect/api/TypeCreator.scala2
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala39
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala4
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala10
-rw-r--r--src/reflect/scala/reflect/internal/Internals.scala2
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Reporting.scala3
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala117
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala4
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala7
-rw-r--r--src/reflect/scala/reflect/internal/pickling/UnPickler.scala11
-rw-r--r--src/reflect/scala/reflect/macros/Attachments.scala2
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala25
-rw-r--r--src/reflect/scala/reflect/runtime/SymbolLoaders.scala11
-rw-r--r--src/repl/scala/tools/nsc/interpreter/ILoop.scala9
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala9
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/Settings.scala2
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala2
-rw-r--r--test/files/jvm/innerClassAttribute.check54
-rw-r--r--test/files/jvm/innerClassAttribute/Classes_1.scala187
-rw-r--r--test/files/jvm/innerClassAttribute/JavaAnnot_1.java3
-rw-r--r--test/files/jvm/innerClassAttribute/Java_A_1.java10
-rw-r--r--test/files/jvm/innerClassAttribute/Test.scala352
-rw-r--r--test/files/jvm/interpreter.check2
-rw-r--r--test/files/jvm/javaReflection.check259
-rw-r--r--test/files/jvm/javaReflection/Classes_1.scala84
-rw-r--r--test/files/jvm/javaReflection/Test.scala137
-rw-r--r--test/files/jvm/throws-annot-from-java.check2
-rw-r--r--test/files/jvm/varargs.check3
-rw-r--r--test/files/jvm/varargs/JavaClass.java1
-rw-r--r--test/files/jvm/varargs/VaClass.scala2
-rw-r--r--test/files/jvm/xml05.check2
-rw-r--r--test/files/neg/forgot-interpolator.check16
-rw-r--r--test/files/neg/forgot-interpolator.scala4
-rw-r--r--test/files/neg/macro-basic-mamdmi.check10
-rw-r--r--test/files/neg/t3909.check1
-rw-r--r--test/files/neg/t4851.check4
-rw-r--r--test/files/neg/t4851.flags2
-rw-r--r--test/files/neg/t4851/J2.java4
-rw-r--r--test/files/neg/t5148.check9
-rw-r--r--test/files/neg/t5691.check24
-rw-r--r--test/files/neg/t5691.flags1
-rw-r--r--test/files/neg/t5691.scala27
-rw-r--r--test/files/neg/t6675b.scala2
-rw-r--r--test/files/neg/t7848-interp-warn.check6
-rw-r--r--test/files/neg/t7848-interp-warn.flags2
-rw-r--r--test/files/neg/t8035-no-adapted-args.check21
-rw-r--r--test/files/neg/t8035-no-adapted-args.flags1
-rw-r--r--test/files/neg/t8035-no-adapted-args.scala6
-rw-r--r--test/files/neg/t8266-invalid-interp.check4
-rw-r--r--test/files/neg/t8525.check15
-rw-r--r--test/files/neg/t8525.flags1
-rw-r--r--test/files/neg/t8525.scala10
-rw-r--r--test/files/neg/t8610-arg.check6
-rw-r--r--test/files/neg/t8610-arg.flags1
-rw-r--r--test/files/neg/t8610-arg.scala10
-rw-r--r--test/files/neg/t8610.check18
-rw-r--r--test/files/neg/t8610.flags1
-rw-r--r--test/files/neg/t8610.scala10
-rw-r--r--test/files/neg/t8736-c.check11
-rw-r--r--test/files/neg/t8736-c.flags1
-rw-r--r--test/files/neg/t8736-c.scala7
-rw-r--r--test/files/neg/warn-inferred-any.flags2
-rw-r--r--test/files/pos/macro-attachments/Macros_1.scala19
-rw-r--r--test/files/pos/macro-attachments/Test_2.scala3
-rw-r--r--test/files/pos/t8013.flags2
-rw-r--r--test/files/pos/t8736-b.flags1
-rw-r--r--test/files/pos/t8736-b.scala7
-rw-r--r--test/files/pos/t8736.flags1
-rw-r--r--test/files/pos/t8736.scala7
-rw-r--r--test/files/pos/t8743.scala15
-rw-r--r--test/files/pos/t8781/Macro_1.scala13
-rw-r--r--test/files/pos/t8781/Test_2.flags1
-rw-r--r--test/files/pos/t8781/Test_2.scala5
-rw-r--r--test/files/pos/t8793.scala15
-rw-r--r--test/files/pos/t8828.flags1
-rw-r--r--test/files/pos/t8828.scala20
-rw-r--r--test/files/run/abstypetags_serialize.check4
-rw-r--r--test/files/run/class-symbol-contravariant.check2
-rw-r--r--test/files/run/constant-type.check2
-rw-r--r--test/files/run/constrained-types.check2
-rw-r--r--test/files/run/exprs_serialize.check21
-rw-r--r--test/files/run/exprs_serialize.scala12
-rw-r--r--test/files/run/kind-repl-command.check2
-rw-r--r--test/files/run/lub-visibility.check2
-rw-r--r--test/files/run/macro-bundle-repl.check2
-rw-r--r--test/files/run/macro-rangepos-subpatterns.check1
-rw-r--r--test/files/run/macro-rangepos-subpatterns.flags1
-rw-r--r--test/files/run/macro-rangepos-subpatterns/Macros_1.scala18
-rw-r--r--test/files/run/macro-rangepos-subpatterns/Test_2.scala5
-rw-r--r--test/files/run/macro-repl-basic.check2
-rw-r--r--test/files/run/macro-repl-dontexpand.check2
-rw-r--r--test/files/run/macro-system-properties.check2
-rw-r--r--test/files/run/names-defaults.check1
-rw-r--r--test/files/run/names-defaults.scala4
-rw-r--r--test/files/run/private-override.check1
-rw-r--r--test/files/run/reflection-attachments.check0
-rw-r--r--test/files/run/reflection-equality.check2
-rw-r--r--test/files/run/reflection-magicsymbols-repl.check2
-rw-r--r--test/files/run/reflection-repl-classes.check2
-rw-r--r--test/files/run/reflection-repl-elementary.check2
-rw-r--r--test/files/run/reify-repl-fail-gracefully.check2
-rw-r--r--test/files/run/reify_newimpl_22.check2
-rw-r--r--test/files/run/reify_newimpl_23.check2
-rw-r--r--test/files/run/reify_newimpl_25.check2
-rw-r--r--test/files/run/reify_newimpl_26.check2
-rw-r--r--test/files/run/reify_newimpl_35.check2
-rw-r--r--test/files/run/repl-assign.check2
-rw-r--r--test/files/run/repl-bare-expr.check2
-rw-r--r--test/files/run/repl-colon-type.check2
-rw-r--r--test/files/run/repl-empty-package.check2
-rw-r--r--test/files/run/repl-javap-app.check6
-rw-r--r--test/files/run/repl-out-dir.check2
-rw-r--r--test/files/run/repl-parens.check2
-rw-r--r--test/files/run/repl-paste-2.check2
-rw-r--r--test/files/run/repl-paste-3.check2
-rw-r--r--test/files/run/repl-paste-4.scala2
-rw-r--r--test/files/run/repl-paste-raw.scala2
-rw-r--r--test/files/run/repl-paste.check2
-rw-r--r--test/files/run/repl-power.check2
-rw-r--r--test/files/run/repl-reset.check2
-rw-r--r--test/files/run/repl-save.scala2
-rw-r--r--test/files/run/repl-term-macros.check2
-rw-r--r--test/files/run/repl-transcript.check2
-rw-r--r--test/files/run/repl-trim-stack-trace.scala2
-rw-r--r--test/files/run/repl-type-verbose.check2
-rw-r--r--test/files/run/stringinterpolation_macro-run.check4
-rw-r--r--test/files/run/stringinterpolation_macro-run.scala1
-rw-r--r--test/files/run/t3376.check2
-rw-r--r--test/files/run/t4025.check2
-rw-r--r--test/files/run/t4172.check2
-rw-r--r--test/files/run/t4216.check2
-rw-r--r--test/files/run/t4285.check2
-rw-r--r--test/files/run/t4332.scala2
-rw-r--r--test/files/run/t4542.check2
-rw-r--r--test/files/run/t4594-repl-settings.scala2
-rw-r--r--test/files/run/t4671.check2
-rw-r--r--test/files/run/t4710.check2
-rw-r--r--test/files/run/t5072.check2
-rw-r--r--test/files/run/t5256c.check2
-rw-r--r--test/files/run/t5256d.check2
-rw-r--r--test/files/run/t5535.check2
-rw-r--r--test/files/run/t5537.check2
-rw-r--r--test/files/run/t5583.check2
-rw-r--r--test/files/run/t5655.check2
-rw-r--r--test/files/run/t5789.check2
-rw-r--r--test/files/run/t6086-repl.check2
-rw-r--r--test/files/run/t6146b.check2
-rw-r--r--test/files/run/t6187.check2
-rw-r--r--test/files/run/t6273.check2
-rw-r--r--test/files/run/t6320.check2
-rw-r--r--test/files/run/t6329_repl.check2
-rw-r--r--test/files/run/t6329_repl_bug.check2
-rw-r--r--test/files/run/t6381.check2
-rw-r--r--test/files/run/t6434.check2
-rw-r--r--test/files/run/t6439.check2
-rw-r--r--test/files/run/t6440.check9
-rw-r--r--test/files/run/t6440b.check9
-rw-r--r--test/files/run/t6507.check2
-rw-r--r--test/files/run/t6549.check2
-rw-r--r--test/files/run/t6631.scala18
-rw-r--r--test/files/run/t6937.check2
-rw-r--r--test/files/run/t7185.check2
-rw-r--r--test/files/run/t7319.check2
-rw-r--r--test/files/run/t7482a.check2
-rw-r--r--test/files/run/t7634.check2
-rw-r--r--test/files/run/t7747-repl.check2
-rw-r--r--test/files/run/t7801.check2
-rw-r--r--test/files/run/t7805-repl-i.check2
-rw-r--r--test/files/run/t8608-no-format.scala15
-rw-r--r--test/files/run/t8610.check7
-rw-r--r--test/files/run/t8610.flags1
-rw-r--r--test/files/run/t8610.scala13
-rw-r--r--test/files/run/t8738.scala16
-rw-r--r--test/files/run/t8823.scala10
-rw-r--r--test/files/run/tpeCache-tyconCache.check2
-rw-r--r--test/files/run/typetags_serialize.check5
-rw-r--r--test/files/run/typetags_serialize.scala5
-rw-r--r--test/files/run/typetags_without_scala_reflect_typetag_lookup.scala4
-rw-r--r--test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.scala4
-rw-r--r--test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala7
-rw-r--r--test/junit/scala/StringContextTest.scala27
-rw-r--r--test/junit/scala/collection/StreamTest.scala18
-rw-r--r--test/junit/scala/reflect/QTest.scala23
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala55
-rw-r--r--test/junit/scala/tools/nsc/settings/SettingsTest.scala30
-rw-r--r--test/junit/scala/util/matching/RegexTest.scala17
-rw-r--r--test/scaladoc/run/t8314.check3
-rw-r--r--test/scaladoc/run/t8314.scala16
-rw-r--r--test/scaladoc/run/t8557.check1
-rw-r--r--test/scaladoc/run/t8557.scala32
-rw-r--r--versions.properties1
327 files changed, 5264 insertions, 10664 deletions
diff --git a/bincompat-backward.whitelist.conf b/bincompat-backward.whitelist.conf
index ffacbf0442..1c48887b63 100644
--- a/bincompat-backward.whitelist.conf
+++ b/bincompat-backward.whitelist.conf
@@ -185,6 +185,15 @@ filter {
{
matchName="scala.reflect.runtime.SynchronizedOps.newNestedScope"
problemName=MissingMethodProblem
+ },
+ // see github.com/scala/scala/pull/3925, SI-8627, SI-6440
+ {
+ matchName="scala.collection.TraversableLike.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.Stream.filteredTail"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/bincompat-forward.whitelist.conf b/bincompat-forward.whitelist.conf
index 30dac79974..ec80e7cce9 100644
--- a/bincompat-forward.whitelist.conf
+++ b/bincompat-forward.whitelist.conf
@@ -254,6 +254,120 @@ filter {
{
matchName="scala.reflect.runtime.JavaUniverse.PerRunReporting"
problemName=MissingMethodProblem
+ },
+ // see SI-5919
+ {
+ matchName="scala.reflect.api.TypeTags$PredefTypeCreator"
+ problemName=MissingTypesProblem
+ },
+ {
+ matchName="scala.reflect.api.TreeCreator"
+ problemName=MissingTypesProblem
+ },
+ {
+ matchName="scala.reflect.api.TypeCreator"
+ problemName=MissingTypesProblem
+ },
+ {
+ matchName="scala.reflect.api.PredefTypeCreator"
+ problemName=MissingClassProblem
+ },
+ // see github.com/scala/scala/pull/3925, SI-8627, SI-6440
+ {
+ matchName="scala.collection.IterableViewLike#AbstractTransformed.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.AbstractTraversable.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.TraversableViewLike#AbstractTransformed.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.TraversableLike.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.SeqViewLike#AbstractTransformed.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.TreeSet.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.Stream.filteredTail"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.Stream.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.Stream.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.StringOps.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.immutable.TreeMap.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.concurrent.TrieMap.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofByte.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofLong.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofUnit.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofInt.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofChar.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofRef.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofDouble.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofFloat.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofBoolean.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.ArrayOps#ofShort.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.collection.mutable.TreeSet.filterImpl"
+ problemName=MissingMethodProblem
+ },
+ {
+ matchName="scala.reflect.io.AbstractFile.filterImpl"
+ problemName=MissingMethodProblem
}
]
}
diff --git a/build.xml b/build.xml
index 6d301e436c..231e091f4d 100755
--- a/build.xml
+++ b/build.xml
@@ -187,8 +187,6 @@ TODO:
<property name="copyright.string" value="Copyright 2002-2013, LAMP/EPFL"/>
- <property name="jline.version" value="2.11"/>
-
<!-- These are NOT the flags used to run SuperSabbus, but the ones written
into the script runners created with scala.tools.ant.ScalaTool -->
<property name="java.flags" value="-Xmx256M -Xms32M"/>
@@ -560,6 +558,7 @@ TODO:
<echo message="scala-swing.version.number = ${scala-swing.version.number}"/>
<echo message="akka-actor.version.number = ${akka-actor.version.number}"/>
<echo message="actors-migration.version.number = ${actors-migration.version.number}"/>
+ <echo message="jline.version = ${jline.version}"/>
<echo message="partest.version.number = ${partest.version.number}"/>
<echo message="scalacheck.version.number = ${scalacheck.version.number}"/>
@@ -574,6 +573,7 @@ TODO:
<entry key="scala-swing.version.number" value="${scala-swing.version.number}"/>
<entry key="akka-actor.version.number" value="${akka-actor.version.number}"/>
<entry key="actors-migration.version.number" value="${actors-migration.version.number}"/>
+ <entry key="jline.version" value="${jline.version}"/>
<entry key="partest.version.number" value="${partest.version.number}"/>
<entry key="scalacheck.version.number" value="${scalacheck.version.number}"/>
</propertyfile>
@@ -1440,9 +1440,13 @@ TODO:
<stopwatch name="test.junit.timer"/>
<mkdir dir="${test.junit.classes}"/>
<echo message="Note: details of failed tests will be output to ${build-junit.dir}"/>
+
+ <if><isset property="test.method" /><then><property name="test.methods" value="${test.method}" /></then></if>
<junit fork="yes" haltonfailure="yes" printsummary="on">
<classpath refid="test.junit.compiler.build.path"/>
- <batchtest fork="yes" todir="${build-junit.dir}">
+ <test fork="yes" todir="${build-junit.dir}" if="test.class" unless="test.methods" name="${test.class}" />
+ <test fork="yes" todir="${build-junit.dir}" if="test.methods" name="${test.class}" methods="${test.methods}" />
+ <batchtest fork="yes" todir="${build-junit.dir}" unless="test.class">
<fileset dir="${test.junit.classes}">
<include name="**/*Test.class"/>
</fileset>
diff --git a/src/compiler/scala/tools/nsc/CompilationUnits.scala b/src/compiler/scala/tools/nsc/CompilationUnits.scala
index f23bca77cd..0a356ed7b6 100644
--- a/src/compiler/scala/tools/nsc/CompilationUnits.scala
+++ b/src/compiler/scala/tools/nsc/CompilationUnits.scala
@@ -135,11 +135,8 @@ trait CompilationUnits { global: Global =>
@deprecated("Call global.currentRun.reporting.uncheckedWarning directly instead.", "2.11.2")
final def uncheckedWarning(pos: Position, msg: String): Unit = currentRun.reporting.uncheckedWarning(pos, msg)
- // called by ScalaDocAnalyzer, overridden by the IDE (in Reporter)
- // TODO: don't use reporter to communicate comments from parser to IDE!
- @deprecated("This method will be removed.", "2.11.2")
- final def comment(pos: Position, msg: String): Unit = reporter.comment(pos, msg)
-
+ @deprecated("This method will be removed. It does nothing.", "2.11.2")
+ final def comment(pos: Position, msg: String): Unit = {}
/** Is this about a .java source file? */
lazy val isJava = source.file.name.endsWith(".java")
diff --git a/src/compiler/scala/tools/nsc/CompileServer.scala b/src/compiler/scala/tools/nsc/CompileServer.scala
index 1f3a4237eb..029e1c4629 100644
--- a/src/compiler/scala/tools/nsc/CompileServer.scala
+++ b/src/compiler/scala/tools/nsc/CompileServer.scala
@@ -152,6 +152,7 @@ class StandardCompileServer extends SocketServer {
clearCompiler()
case ex: Throwable =>
warn("Compile server encountered fatal condition: " + ex)
+ reporter.error(null, "Compile server encountered fatal condition: " + ex.getMessage)
shutdown = true
throw ex
}
diff --git a/src/compiler/scala/tools/nsc/CompileSocket.scala b/src/compiler/scala/tools/nsc/CompileSocket.scala
index c4f06b59ec..c693fbe8e2 100644
--- a/src/compiler/scala/tools/nsc/CompileSocket.scala
+++ b/src/compiler/scala/tools/nsc/CompileSocket.scala
@@ -32,7 +32,8 @@ trait HasCompileSocket {
if (isErrorMessage(line))
noErrors = false
- compileSocket.echo(line)
+ // be consistent with scalac: everything goes to stderr
+ compileSocket.warn(line)
loop()
}
try loop()
diff --git a/src/compiler/scala/tools/nsc/CompilerCommand.scala b/src/compiler/scala/tools/nsc/CompilerCommand.scala
index a1d0d52dcf..3ded456378 100644
--- a/src/compiler/scala/tools/nsc/CompilerCommand.scala
+++ b/src/compiler/scala/tools/nsc/CompilerCommand.scala
@@ -103,7 +103,15 @@ class CompilerCommand(arguments: List[String], val settings: Settings) {
val components = global.phaseNames // global.phaseDescriptors // one initializes
s"Phase graph of ${components.size} components output to ${genPhaseGraph.value}*.dot."
}
- else ""
+ // would be nicer if we could ask all the options for their helpful messages
+ else {
+ val sb = new StringBuilder
+ allSettings foreach {
+ case s: MultiChoiceSetting if s.isHelping => sb append s.help
+ case _ =>
+ }
+ sb.toString
+ }
}
/**
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 572e579aca..82ffb35c3f 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -45,7 +45,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
with Printers
with DocComments
with Positions
- with Reporting { self =>
+ with Reporting
+ with Parsing { self =>
// the mirror --------------------------------------------------
@@ -218,6 +219,14 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** Called from parser, which signals hereby that a method definition has been parsed. */
def signalParseProgress(pos: Position) {}
+ /** Called by ScalaDocAnalyzer when a doc comment has been parsed. */
+ def signalParsedDocComment(comment: String, pos: Position) = {
+ // TODO: this is all very borken (only works for scaladoc comments, not regular ones)
+ // --> add hooks to parser and refactor Interactive global to handle comments directly
+ // in any case don't use reporter for parser hooks
+ reporter.comment(pos, comment)
+ }
+
/** Register new context; called for every created context
*/
def registerContext(c: analyzer.Context) {
@@ -395,7 +404,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
reporter.cancelled || unit.isJava && this.id > maxJavaPhase
}
- final def applyPhase(unit: CompilationUnit) {
+ final def withCurrentUnit(unit: CompilationUnit)(task: => Unit) {
if ((unit ne null) && unit.exists)
lastSeenSourceFile = unit.source
@@ -407,7 +416,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
currentRun.currentUnit = unit
if (!cancelled(unit)) {
currentRun.informUnitStarting(this, unit)
- apply(unit)
+ task
}
currentRun.advanceUnit()
} finally {
@@ -415,6 +424,8 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
currentRun.currentUnit = unit0
}
}
+
+ final def applyPhase(unit: CompilationUnit) = withCurrentUnit(unit)(apply(unit))
}
// phaseName = "parser"
@@ -831,198 +842,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
} reverse
}
- // ------------ Invalidations ---------------------------------
-
- /** Is given package class a system package class that cannot be invalidated?
- */
- private def isSystemPackageClass(pkg: Symbol) =
- pkg == RootClass ||
- pkg == definitions.ScalaPackageClass || {
- val pkgname = pkg.fullName
- (pkgname startsWith "scala.") && !(pkgname startsWith "scala.tools")
- }
-
- /** Invalidates packages that contain classes defined in a classpath entry, and
- * rescans that entry.
- * @param paths Fully qualified names that refer to directories or jar files that are
- * a entries on the classpath.
- * First, causes the classpath entry referred to by `path` to be rescanned, so that
- * any new files or deleted files or changes in subpackages are picked up.
- * Second, invalidates any packages for which one of the following considitions is met:
-
- * - the classpath entry contained during the last compilation run classfiles
- * that represent a member in the package
- * - the classpath entry now contains classfiles
- * that represent a member in the package
- * - the set of subpackages has changed.
- *
- * The invalidated packages are reset in their entirety; all member classes and member packages
- * are re-accessed using the new classpath.
- * Not invalidated are system packages that the compiler needs to access as parts
- * of standard definitions. The criterion what is a system package is currently:
- * any package rooted in "scala", with the exception of packages rooted in "scala.tools".
- * This can be refined later.
- * @return A pair consisting of
- * - a list of invalidated packages
- * - a list of of packages that should have been invalidated but were not because
- * they are system packages.
- */
- def invalidateClassPathEntries(paths: String*): (List[ClassSymbol], List[ClassSymbol]) = {
- val invalidated, failed = new mutable.ListBuffer[ClassSymbol]
- classPath match {
- case cp: MergedClassPath[_] =>
- def assoc(path: String): List[(PlatformClassPath, PlatformClassPath)] = {
- val dir = AbstractFile getDirectory path
- val canonical = dir.canonicalPath
- def matchesCanonical(e: ClassPath[_]) = e.origin match {
- case Some(opath) =>
- (AbstractFile getDirectory opath).canonicalPath == canonical
- case None =>
- false
- }
- cp.entries find matchesCanonical match {
- case Some(oldEntry) =>
- List(oldEntry -> cp.context.newClassPath(dir))
- case None =>
- println(s"canonical = $canonical, origins = ${cp.entries map (_.origin)}")
- error(s"cannot invalidate: no entry named $path in classpath $classPath")
- List()
- }
- }
- val subst = Map(paths flatMap assoc: _*)
- if (subst.nonEmpty) {
- platform updateClassPath subst
- informProgress(s"classpath updated on entries [${subst.keys mkString ","}]")
- def mkClassPath(elems: Iterable[PlatformClassPath]): PlatformClassPath =
- if (elems.size == 1) elems.head
- else new MergedClassPath(elems, classPath.context)
- val oldEntries = mkClassPath(subst.keys)
- val newEntries = mkClassPath(subst.values)
- reSync(RootClass, Some(classPath), Some(oldEntries), Some(newEntries), invalidated, failed)
- }
- }
- def show(msg: String, syms: scala.collection.Traversable[Symbol]) =
- if (syms.nonEmpty)
- informProgress(s"$msg: ${syms map (_.fullName) mkString ","}")
- show("invalidated packages", invalidated)
- show("could not invalidate system packages", failed)
- (invalidated.toList, failed.toList)
- }
-
- /** Re-syncs symbol table with classpath
- * @param root The root symbol to be resynced (a package class)
- * @param allEntries Optionally, the corresponding package in the complete current classPath
- * @param oldEntries Optionally, the corresponding package in the old classPath entries
- * @param newEntries Optionally, the corresponding package in the new classPath entries
- * @param invalidated A listbuffer collecting the invalidated package classes
- * @param failed A listbuffer collecting system package classes which could not be invalidated
- * The resyncing strategy is determined by the absence or presence of classes and packages.
- * If either oldEntries or newEntries contains classes, root is invalidated, provided a corresponding package
- * exists in allEntries, or otherwise is removed.
- * Otherwise, the action is determined by the following matrix, with columns:
- *
- * old new all sym action
- * + + + + recurse into all child packages of old ++ new
- * + - + + invalidate root
- * + - - + remove root from its scope
- * - + + + invalidate root
- * - + + - create and enter root
- * - - * * no action
- *
- * Here, old, new, all mean classpaths and sym means symboltable. + is presence of an
- * entry in its column, - is absence, * is don't care.
- *
- * Note that new <= all and old <= sym, so the matrix above covers all possibilities.
- */
- private def reSync(root: ClassSymbol,
- allEntries: OptClassPath, oldEntries: OptClassPath, newEntries: OptClassPath,
- invalidated: mutable.ListBuffer[ClassSymbol], failed: mutable.ListBuffer[ClassSymbol]) {
- ifDebug(informProgress(s"syncing $root, $oldEntries -> $newEntries"))
-
- val getName: ClassPath[AbstractFile] => String = (_.name)
- def hasClasses(cp: OptClassPath) = cp.isDefined && cp.get.classes.nonEmpty
- def invalidateOrRemove(root: ClassSymbol) = {
- allEntries match {
- case Some(cp) => root setInfo new loaders.PackageLoader(cp)
- case None => root.owner.info.decls unlink root.sourceModule
- }
- invalidated += root
- }
- def packageNames(cp: PlatformClassPath): Set[String] = cp.packages.toSet map getName
- def subPackage(cp: PlatformClassPath, name: String): OptClassPath =
- cp.packages find (cp1 => getName(cp1) == name)
-
- val classesFound = hasClasses(oldEntries) || hasClasses(newEntries)
- if (classesFound && !isSystemPackageClass(root)) {
- invalidateOrRemove(root)
- } else {
- if (classesFound) {
- if (root.isRoot) invalidateOrRemove(EmptyPackageClass)
- else failed += root
- }
- (oldEntries, newEntries) match {
- case (Some(oldcp) , Some(newcp)) =>
- for (pstr <- packageNames(oldcp) ++ packageNames(newcp)) {
- val pname = newTermName(pstr)
- val pkg = (root.info decl pname) orElse {
- // package was created by external agent, create symbol to track it
- assert(!subPackage(oldcp, pstr).isDefined)
- loaders.enterPackage(root, pstr, new loaders.PackageLoader(allEntries.get))
- }
- reSync(
- pkg.moduleClass.asInstanceOf[ClassSymbol],
- subPackage(allEntries.get, pstr), subPackage(oldcp, pstr), subPackage(newcp, pstr),
- invalidated, failed)
- }
- case (Some(oldcp), None) =>
- invalidateOrRemove(root)
- case (None, Some(newcp)) =>
- invalidateOrRemove(root)
- case (None, None) =>
- }
- }
- }
-
- /** Invalidate contents of setting -Yinvalidate */
- def doInvalidation() = settings.Yinvalidate.value match {
- case "" =>
- case entry => invalidateClassPathEntries(entry)
- }
-
// ----------- Runs ---------------------------------------
private var curRun: Run = null
private var curRunId = 0
- /** A hook that lets subclasses of `Global` define whether a package or class should be kept loaded for the
- * next compiler run. If the parameter `sym` is a class or object, and `clearOnNextRun(sym)` returns `true`,
- * then the symbol is unloaded and reset to its state before the last compiler run. If the parameter `sym` is
- * a package, and clearOnNextRun(sym)` returns `true`, the package is recursively searched for
- * classes to drop.
- *
- * Example: Let's say I want a compiler that drops all classes corresponding to the current project
- * between runs. Then `keepForNextRun` of a toplevel class or object should return `true` if the
- * class or object does not form part of the current project, `false` otherwise. For a package,
- * clearOnNextRun should return `true` if no class in that package forms part of the current project,
- * `false` otherwise.
- *
- * @param sym A class symbol, object symbol, package, or package class.
- */
- @deprecated("use invalidateClassPathEntries instead", "2.10.0")
- def clearOnNextRun(sym: Symbol) = false
- /* To try out clearOnNext run on the scala.tools.nsc project itself
- * replace `false` above with the following code
-
- settings.Xexperimental.value && { sym.isRoot || {
- sym.fullName match {
- case "scala" | "scala.tools" | "scala.tools.nsc" => true
- case _ => sym.owner.fullName.startsWith("scala.tools.nsc")
- }
- }}
-
- * Then, fsc -Xexperimental clears the nsc project between successive runs of `fsc`.
- */
-
object typeDeconstruct extends {
val global: Global.this.type = Global.this
} with typechecker.StructuredTypeStrings
@@ -1155,7 +979,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
/** A Run is a single execution of the compiler on a set of units.
*/
- class Run extends RunContextApi with RunReporting {
+ class Run extends RunContextApi with RunReporting with RunParsing {
/** Have been running into too many init order issues with Run
* during erroneous conditions. Moved all these vals up to the
* top of the file so at least they're not trivially null.
@@ -1292,47 +1116,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
first
}
- /** Reset all classes contained in current project, as determined by
- * the clearOnNextRun hook
- */
- @deprecated("use invalidateClassPathEntries instead", "2.10.0")
- def resetProjectClasses(root: Symbol): Unit = try {
- def unlink(sym: Symbol) =
- if (sym != NoSymbol) root.info.decls.unlink(sym)
- if (settings.verbose) inform("[reset] recursing in "+root)
- val toReload = mutable.Set[String]()
- for (sym <- root.info.decls) {
- if (sym.isInitialized && clearOnNextRun(sym))
- if (sym.hasPackageFlag) {
- resetProjectClasses(sym.moduleClass)
- openPackageModule(sym.moduleClass)
- } else {
- unlink(sym)
- unlink(root.info.decls.lookup(
- if (sym.isTerm) sym.name.toTypeName else sym.name.toTermName))
- toReload += sym.fullName
- // note: toReload could be set twice with the same name
- // but reinit must happen only once per name. That's why
- // the following classPath.findClass { ... } code cannot be moved here.
- }
- }
- for (fullname <- toReload)
- classPath.findClass(fullname) match {
- case Some(classRep) =>
- if (settings.verbose) inform("[reset] reinit "+fullname)
- loaders.initializeFromClassPath(root, classRep)
- case _ =>
- }
- } catch {
- case ex: Throwable =>
- // this handler should not be nessasary, but it seems that `fsc`
- // eats exceptions if they appear here. Need to find out the cause for
- // this and fix it.
- inform("[reset] exception happened: "+ex)
- ex.printStackTrace()
- throw ex
- }
-
// --------------- Miscellania -------------------------------
/** Progress tracking. Measured in "progress units" which are 1 per
@@ -1397,7 +1180,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val erasurePhase = phaseNamed("erasure")
val posterasurePhase = phaseNamed("posterasure")
// val lazyvalsPhase = phaseNamed("lazyvals")
- // val lambdaliftPhase = phaseNamed("lambdalift")
+ val lambdaliftPhase = phaseNamed("lambdalift")
// val constructorsPhase = phaseNamed("constructors")
val flattenPhase = phaseNamed("flatten")
val mixinPhase = phaseNamed("mixin")
@@ -1542,8 +1325,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
compileUnitsInternal(units, fromPhase)
private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) {
- doInvalidation()
-
units foreach addUnit
val startTime = currentTime
@@ -1619,13 +1400,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
// Clear any sets or maps created via perRunCaches.
perRunCaches.clearAll()
-
- // Reset project
- if (!stopPhase("namer")) {
- enteringPhase(namerPhase) {
- resetProjectClasses(RootClass)
- }
- }
}
/** Compile list of abstract files. */
diff --git a/src/compiler/scala/tools/nsc/Parsing.scala b/src/compiler/scala/tools/nsc/Parsing.scala
new file mode 100644
index 0000000000..4dd3c3f378
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/Parsing.scala
@@ -0,0 +1,36 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL, Typesafe Inc.
+ * @author Adriaan Moors
+ */
+
+package scala
+package tools.nsc
+
+import scala.reflect.internal.Positions
+import scala.tools.nsc.reporters.Reporter
+
+/** Similar to Reporting: gather global functionality specific to parsing.
+ */
+trait Parsing { self : Positions with Reporting =>
+ def currentRun: RunParsing
+
+ trait RunParsing {
+ val parsing: PerRunParsing = new PerRunParsing
+ }
+
+ class PerRunParsing {
+ // for repl
+ private[this] var incompleteHandler: (Position, String) => Unit = null
+ def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
+ val saved = incompleteHandler
+ incompleteHandler = handler
+ try thunk
+ finally incompleteHandler = saved
+ }
+
+ def incompleteHandled = incompleteHandler != null
+ def incompleteInputError(pos: Position, msg: String): Unit =
+ if (incompleteHandled) incompleteHandler(pos, msg)
+ else reporter.error(pos, msg)
+ }
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/Properties.scala b/src/compiler/scala/tools/nsc/Properties.scala
index ed5fda9c3f..59fefba954 100644
--- a/src/compiler/scala/tools/nsc/Properties.scala
+++ b/src/compiler/scala/tools/nsc/Properties.scala
@@ -14,6 +14,7 @@ object Properties extends scala.util.PropertiesTrait {
// settings based on jar properties
def residentPromptString = scalaPropOrElse("resident.prompt", "\nnsc> ")
def shellPromptString = scalaPropOrElse("shell.prompt", "\nscala> ")
+ def shellInterruptedString = scalaPropOrElse("shell.interrupted", ":quit\n")
// derived values
def isEmacsShell = propOrEmpty("env.emacs") != ""
diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala
index 0263586418..b164f395fe 100644
--- a/src/compiler/scala/tools/nsc/Reporting.scala
+++ b/src/compiler/scala/tools/nsc/Reporting.scala
@@ -104,20 +104,5 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w
if (settings.fatalWarnings && reporter.hasWarnings)
reporter.error(NoPosition, "No warnings can be incurred under -Xfatal-warnings.")
}
-
- // for repl
- private[this] var incompleteHandler: (Position, String) => Unit = null
- def withIncompleteHandler[T](handler: (Position, String) => Unit)(thunk: => T) = {
- val saved = incompleteHandler
- incompleteHandler = handler
- try thunk
- finally incompleteHandler = saved
- }
-
- def incompleteHandled = incompleteHandler != null
- def incompleteInputError(pos: Position, msg: String): Unit =
- if (incompleteHandled) incompleteHandler(pos, msg)
- else reporter.error(pos, msg)
-
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 883fd31dbc..8d810d456e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -154,8 +154,8 @@ self =>
def unit = global.currentUnit
// suppress warnings; silent abort on errors
- def warning(offset: Offset, msg: String) {}
- def deprecationWarning(offset: Offset, msg: String) {}
+ def warning(offset: Offset, msg: String): Unit = ()
+ def deprecationWarning(offset: Offset, msg: String): Unit = ()
def syntaxError(offset: Offset, msg: String): Unit = throw new MalformedInput(offset, msg)
def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg)
@@ -204,13 +204,11 @@ self =>
override def newScanner() = new UnitScanner(unit, patches)
- override def warning(offset: Offset, msg: String) {
+ override def warning(offset: Offset, msg: String): Unit =
reporter.warning(o2p(offset), msg)
- }
- override def deprecationWarning(offset: Offset, msg: String) {
+ override def deprecationWarning(offset: Offset, msg: String): Unit =
currentRun.reporting.deprecationWarning(o2p(offset), msg)
- }
private var smartParsing = false
@inline private def withSmartParsing[T](body: => T): T = {
@@ -226,15 +224,15 @@ self =>
for ((offset, msg) <- syntaxErrors)
reporter.error(o2p(offset), msg)
- override def syntaxError(offset: Offset, msg: String) {
+ override def syntaxError(offset: Offset, msg: String): Unit = {
if (smartParsing) syntaxErrors += ((offset, msg))
else reporter.error(o2p(offset), msg)
}
- override def incompleteInputError(msg: String) {
+ override def incompleteInputError(msg: String): Unit = {
val offset = source.content.length - 1
if (smartParsing) syntaxErrors += ((offset, msg))
- else currentRun.reporting.incompleteInputError(o2p(offset), msg)
+ else currentRun.parsing.incompleteInputError(o2p(offset), msg)
}
/** parse unit. If there are inbalanced braces,
@@ -335,7 +333,7 @@ self =>
*/
private var inScalaPackage = false
private var currentPackage = ""
- def resetPackage() {
+ def resetPackage(): Unit = {
inScalaPackage = false
currentPackage = ""
}
@@ -514,7 +512,7 @@ self =>
finally inFunReturnType = saved
}
- protected def skip(targetToken: Token) {
+ protected def skip(targetToken: Token): Unit = {
var nparens = 0
var nbraces = 0
while (true) {
@@ -544,27 +542,25 @@ self =>
}
def warning(offset: Offset, msg: String): Unit
def incompleteInputError(msg: String): Unit
- private def syntaxError(pos: Position, msg: String, skipIt: Boolean) {
- syntaxError(pos pointOrElse in.offset, msg, skipIt)
- }
def syntaxError(offset: Offset, msg: String): Unit
- def syntaxError(msg: String, skipIt: Boolean) {
+
+ private def syntaxError(pos: Position, msg: String, skipIt: Boolean): Unit =
+ syntaxError(pos pointOrElse in.offset, msg, skipIt)
+ def syntaxError(msg: String, skipIt: Boolean): Unit =
syntaxError(in.offset, msg, skipIt)
- }
- def syntaxError(offset: Offset, msg: String, skipIt: Boolean) {
+ def syntaxError(offset: Offset, msg: String, skipIt: Boolean): Unit = {
if (offset > lastErrorOffset) {
syntaxError(offset, msg)
- // no more errors on this token.
- lastErrorOffset = in.offset
+ lastErrorOffset = in.offset // no more errors on this token.
}
if (skipIt)
skip(UNDEF)
}
- def warning(msg: String) { warning(in.offset, msg) }
+ def warning(msg: String): Unit = warning(in.offset, msg)
- def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) {
+ def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean): Unit = {
if (in.token == EOF)
incompleteInputError(msg)
else
@@ -719,7 +715,7 @@ self =>
/** Convert tree to formal parameter. */
def convertToParam(tree: Tree): ValDef = atPos(tree.pos) {
- def removeAsPlaceholder(name: Name) {
+ def removeAsPlaceholder(name: Name): Unit = {
placeholderParams = placeholderParams filter (_.name != name)
}
def errorParam = makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.end))
@@ -1233,15 +1229,15 @@ self =>
skipIt = true)(EmptyTree)
// Like Swiss cheese, with holes
def stringCheese: Tree = atPos(in.offset) {
- val start = in.offset
+ val start = in.offset
val interpolator = in.name.encoded // ident() for INTERPOLATIONID
val partsBuf = new ListBuffer[Tree]
- val exprBuf = new ListBuffer[Tree]
+ val exprsBuf = new ListBuffer[Tree]
in.nextToken()
while (in.token == STRINGPART) {
partsBuf += literal()
- exprBuf += (
+ exprsBuf += (
if (inPattern) dropAnyBraces(pattern())
else in.token match {
case IDENTIFIER => atPos(in.offset)(Ident(ident()))
@@ -1254,11 +1250,13 @@ self =>
}
if (in.token == STRINGLIT) partsBuf += literal()
+ // Documenting that it is intentional that the ident is not rooted for purposes of virtualization
+ //val t1 = atPos(o2p(start)) { Select(Select (Ident(nme.ROOTPKG), nme.scala_), nme.StringContext) }
val t1 = atPos(o2p(start)) { Ident(nme.StringContext) }
val t2 = atPos(start) { Apply(t1, partsBuf.toList) }
t2 setPos t2.pos.makeTransparent
val t3 = Select(t2, interpolator) setPos t2.pos
- atPos(start) { Apply(t3, exprBuf.toList) }
+ atPos(start) { Apply(t3, exprsBuf.toList) }
}
if (inPattern) stringCheese
else withPlaceholders(stringCheese, isAny = true) // strinterpolator params are Any* by definition
@@ -1266,21 +1264,21 @@ self =>
/* ------------- NEW LINES ------------------------------------------------- */
- def newLineOpt() {
+ def newLineOpt(): Unit = {
if (in.token == NEWLINE) in.nextToken()
}
- def newLinesOpt() {
+ def newLinesOpt(): Unit = {
if (in.token == NEWLINE || in.token == NEWLINES)
in.nextToken()
}
- def newLineOptWhenFollowedBy(token: Offset) {
+ def newLineOptWhenFollowedBy(token: Offset): Unit = {
// note: next is defined here because current == NEWLINE
if (in.token == NEWLINE && in.next.token == token) newLineOpt()
}
- def newLineOptWhenFollowing(p: Token => Boolean) {
+ def newLineOptWhenFollowing(p: Token => Boolean): Unit = {
// note: next is defined here because current == NEWLINE
if (in.token == NEWLINE && p(in.next.token)) newLineOpt()
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
index 572497ac90..9ebc94b5fc 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -113,7 +113,7 @@ trait Scanners extends ScannersCommon {
case SU | CR | LF =>
case _ => nextChar() ; skipLineComment()
}
- private def maybeOpen() {
+ private def maybeOpen(): Unit = {
putCommentChar()
if (ch == '*') {
putCommentChar()
@@ -137,7 +137,7 @@ trait Scanners extends ScannersCommon {
def skipDocComment(): Unit = skipNestedComments()
def skipBlockComment(): Unit = skipNestedComments()
- private def skipToCommentEnd(isLineComment: Boolean) {
+ private def skipToCommentEnd(isLineComment: Boolean): Unit = {
nextChar()
if (isLineComment) skipLineComment()
else {
@@ -185,7 +185,7 @@ trait Scanners extends ScannersCommon {
/** append Unicode character to "cbuf" buffer
*/
- protected def putChar(c: Char) {
+ protected def putChar(c: Char): Unit = {
// assert(cbuf.size < 10000, cbuf)
cbuf.append(c)
}
@@ -196,7 +196,7 @@ trait Scanners extends ScannersCommon {
protected def emitIdentifierDeprecationWarnings = true
/** Clear buffer and set name and token */
- private def finishNamed(idtoken: Token = IDENTIFIER) {
+ private def finishNamed(idtoken: Token = IDENTIFIER): Unit = {
name = newTermName(cbuf.toString)
cbuf.clear()
token = idtoken
@@ -215,7 +215,7 @@ trait Scanners extends ScannersCommon {
}
/** Clear buffer and set string */
- private def setStrVal() {
+ private def setStrVal(): Unit = {
strVal = cbuf.toString
cbuf.clear()
}
@@ -270,7 +270,7 @@ trait Scanners extends ScannersCommon {
/** Produce next token, filling TokenData fields of Scanner.
*/
- def nextToken() {
+ def nextToken(): Unit = {
val lastToken = token
// Adapt sepRegions according to last token
(lastToken: @switch) match {
@@ -341,7 +341,7 @@ trait Scanners extends ScannersCommon {
prev copyFrom this
val nextLastOffset = charOffset - 1
fetchToken()
- def resetOffset() {
+ def resetOffset(): Unit = {
offset = prev.offset
lastOffset = prev.lastOffset
}
@@ -399,7 +399,7 @@ trait Scanners extends ScannersCommon {
/** read next token, filling TokenData fields of Scanner.
*/
- protected final def fetchToken() {
+ protected final def fetchToken(): Unit = {
offset = charOffset - 1
(ch: @switch) match {
@@ -604,7 +604,7 @@ trait Scanners extends ScannersCommon {
// Identifiers ---------------------------------------------------------------
- private def getBackquotedIdent() {
+ private def getBackquotedIdent(): Unit = {
nextChar()
getLitChars('`')
if (ch == '`') {
@@ -664,7 +664,7 @@ trait Scanners extends ScannersCommon {
else finishNamed()
}
- private def getIdentOrOperatorRest() {
+ private def getIdentOrOperatorRest(): Unit = {
if (isIdentifierPart(ch))
getIdentRest()
else ch match {
@@ -688,9 +688,11 @@ trait Scanners extends ScannersCommon {
setStrVal()
nextChar()
token = STRINGLIT
- } else syntaxError("unclosed string literal")
+ } else unclosedStringLit()
}
+ private def unclosedStringLit(): Unit = syntaxError("unclosed string literal")
+
private def getRawStringLit(): Unit = {
if (ch == '\"') {
nextRawChar()
@@ -764,7 +766,7 @@ trait Scanners extends ScannersCommon {
if (multiLine)
incompleteInputError("unclosed multi-line string literal")
else
- syntaxError("unclosed string literal")
+ unclosedStringLit()
}
else {
putChar(ch)
@@ -857,7 +859,7 @@ trait Scanners extends ScannersCommon {
/** read fractional part and exponent of floating point number
* if one is present.
*/
- protected def getFraction() {
+ protected def getFraction(): Unit = {
token = DOUBLELIT
while ('0' <= ch && ch <= '9') {
putChar(ch)
@@ -966,14 +968,13 @@ trait Scanners extends ScannersCommon {
def floatVal: Double = floatVal(negated = false)
- def checkNoLetter() {
+ def checkNoLetter(): Unit = {
if (isIdentifierPart(ch) && ch >= ' ')
syntaxError("Invalid literal number")
}
- /** Read a number into strVal and set base
- */
- protected def getNumber() {
+ /** Read a number into strVal and set base */
+ protected def getNumber(): Unit = {
val base1 = if (base < 10) 10 else base
// Read 8,9's even if format is octal, produce a malformed number error afterwards.
// At this point, we have already read the first digit, so to tell an innocent 0 apart
@@ -1052,7 +1053,7 @@ trait Scanners extends ScannersCommon {
/** Parse character literal if current character is followed by \',
* or follow with given op and return a symbol literal token
*/
- def charLitOr(op: () => Unit) {
+ def charLitOr(op: () => Unit): Unit = {
putChar(ch)
nextChar()
if (ch == '\'') {
@@ -1068,21 +1069,19 @@ trait Scanners extends ScannersCommon {
// Errors -----------------------------------------------------------------
- /** generate an error at the given offset
- */
- def syntaxError(off: Offset, msg: String) {
+ /** generate an error at the given offset */
+ def syntaxError(off: Offset, msg: String): Unit = {
error(off, msg)
token = ERROR
}
- /** generate an error at the current token offset
- */
+ /** generate an error at the current token offset */
def syntaxError(msg: String): Unit = syntaxError(offset, msg)
def deprecationWarning(msg: String): Unit = deprecationWarning(offset, msg)
/** signal an error where the input ended in the middle of a token */
- def incompleteInputError(msg: String) {
+ def incompleteInputError(msg: String): Unit = {
incompleteInputError(offset, msg)
token = EOF
}
@@ -1134,7 +1133,7 @@ trait Scanners extends ScannersCommon {
/** Initialization method: read first char, then first token
*/
- def init() {
+ def init(): Unit = {
nextChar()
nextToken()
}
@@ -1261,7 +1260,7 @@ trait Scanners extends ScannersCommon {
override def deprecationWarning(off: Offset, msg: String) = currentRun.reporting.deprecationWarning(unit.position(off), msg)
override def error (off: Offset, msg: String) = reporter.error(unit.position(off), msg)
- override def incompleteInputError(off: Offset, msg: String) = currentRun.reporting.incompleteInputError(unit.position(off), msg)
+ override def incompleteInputError(off: Offset, msg: String) = currentRun.parsing.incompleteInputError(unit.position(off), msg)
private var bracePatches: List[BracePatch] = patches
@@ -1490,6 +1489,6 @@ trait Scanners extends ScannersCommon {
// when skimming through the source file trying to heal braces
override def emitIdentifierDeprecationWarnings = false
- override def error(offset: Offset, msg: String) {}
+ override def error(offset: Offset, msg: String): Unit = ()
}
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
index 64b762696e..df2073785b 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
@@ -83,7 +83,7 @@ abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParse
private def initialUnitBody(unit: CompilationUnit): Tree = {
if (unit.isJava) new JavaUnitParser(unit).parse()
- else if (currentRun.reporting.incompleteHandled) newUnitParser(unit).parse()
+ else if (currentRun.parsing.incompleteHandled) newUnitParser(unit).parse()
else newUnitParser(unit).smartParse()
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
new file mode 100644
index 0000000000..e5b4c4a6c2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeAsmCommon.scala
@@ -0,0 +1,130 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc.backend.jvm
+
+import scala.tools.nsc.Global
+import PartialFunction._
+
+/**
+ * This trait contains code shared between GenBCode and GenASM that depends on types defined in
+ * the compiler cake (Global).
+ */
+final class BCodeAsmCommon[G <: Global](val global: G) {
+ import global._
+
+ /**
+ * True if `classSym` is an anonymous class or a local class. I.e., false if `classSym` is a
+ * member class. This method is used to decide if we should emit an EnclosingMethod attribute.
+ * It is also used to decide whether the "owner" field in the InnerClass attribute should be
+ * null.
+ */
+ def isAnonymousOrLocalClass(classSym: Symbol): Boolean = {
+ def isDelambdafyLambdaClass(classSym: Symbol): Boolean = {
+ classSym.isAnonymousFunction && (settings.Ydelambdafy.value == "method")
+ }
+
+ assert(classSym.isClass, s"not a class: $classSym")
+
+ !isDelambdafyLambdaClass(classSym) &&
+ (classSym.isAnonymousClass || !classSym.originalOwner.isClass)
+ }
+
+ /**
+ * Returns the enclosing method for non-member classes. In the following example
+ *
+ * class A {
+ * def f = {
+ * class B {
+ * class C
+ * }
+ * }
+ * }
+ *
+ * the method returns Some(f) for B, but None for C, because C is a member class. For non-member
+ * classes that are not enclosed by a method, it returns None:
+ *
+ * class A {
+ * { class B }
+ * }
+ *
+ * In this case, for B, we return None.
+ *
+ * The EnclosingMethod attribute needs to be added to non-member classes (see doc in BTypes).
+ * This is a source-level property, so we need to use the originalOwner chain to reconstruct it.
+ */
+ private def enclosingMethodForEnclosingMethodAttribute(classSym: Symbol): Option[Symbol] = {
+ assert(classSym.isClass, classSym)
+ def enclosingMethod(sym: Symbol): Option[Symbol] = {
+ if (sym.isClass || sym == NoSymbol) None
+ else if (sym.isMethod) Some(sym)
+ else enclosingMethod(sym.originalOwner)
+ }
+ enclosingMethod(classSym.originalOwner)
+ }
+
+ /**
+ * The enclosing class for emitting the EnclosingMethod attribute. Since this is a source-level
+ * property, this method looks at the originalOwner chain. See doc in BTypes.
+ */
+ private def enclosingClassForEnclosingMethodAttribute(classSym: Symbol): Symbol = {
+ assert(classSym.isClass, classSym)
+ def enclosingClass(sym: Symbol): Symbol = {
+ if (sym.isClass) sym
+ else enclosingClass(sym.originalOwner)
+ }
+ enclosingClass(classSym.originalOwner)
+ }
+
+ final case class EnclosingMethodEntry(owner: String, name: String, methodDescriptor: String)
+
+ /**
+ * If data for emitting an EnclosingMethod attribute. None if `classSym` is a member class (not
+ * an anonymous or local class). See doc in BTypes.
+ *
+ * The class is parametrized by two functions to obtain a bytecode class descriptor for a class
+ * symbol, and to obtain a method signature descriptor fro a method symbol. These function depend
+ * on the implementation of GenASM / GenBCode, so they need to be passed in.
+ */
+ def enclosingMethodAttribute(classSym: Symbol, classDesc: Symbol => String, methodDesc: Symbol => String): Option[EnclosingMethodEntry] = {
+ if (isAnonymousOrLocalClass(classSym)) {
+ val methodOpt = enclosingMethodForEnclosingMethodAttribute(classSym)
+ debuglog(s"enclosing method for $classSym is $methodOpt (in ${methodOpt.map(_.enclClass)})")
+ Some(EnclosingMethodEntry(
+ classDesc(enclosingClassForEnclosingMethodAttribute(classSym)),
+ methodOpt.map(_.javaSimpleName.toString).orNull,
+ methodOpt.map(methodDesc).orNull))
+ } else {
+ None
+ }
+ }
+
+ /**
+ * This is basically a re-implementation of sym.isStaticOwner, but using the originalOwner chain.
+ *
+ * The problem is that we are interested in a source-level property. Various phases changed the
+ * symbol's properties in the meantime, mostly lambdalift modified (destructively) the owner.
+ * Therefore, `sym.isStatic` is not what we want. For example, in
+ * object T { def f { object U } }
+ * the owner of U is T, so UModuleClass.isStatic is true. Phase travel does not help here.
+ */
+ def isOriginallyStaticOwner(sym: Symbol): Boolean = {
+ sym.isPackageClass || sym.isModuleClass && isOriginallyStaticOwner(sym.originalOwner)
+ }
+
+ /**
+ * The member classes of a class symbol. Note that the result of this method depends on the
+ * current phase, for example, after lambdalift, all local classes become member of the enclosing
+ * class.
+ */
+ def memberClassesOf(classSymbol: Symbol): List[Symbol] = classSymbol.info.decls.collect({
+ case sym if sym.isClass =>
+ sym
+ case sym if sym.isModule =>
+ val r = exitingPickler(sym.moduleClass)
+ assert(r != NoSymbol, sym.fullLocationString)
+ r
+ })(collection.breakOut)
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 4583462b71..397171049f 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -23,8 +23,9 @@ import scala.tools.asm
abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._
- import bCodeICodeCommon._
import bTypes._
+ import bCodeICodeCommon._
+ import coreBTypes._
/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
@@ -92,7 +93,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
val thrownKind = tpeTK(expr)
// `throw null` is valid although scala.Null (as defined in src/libray-aux) isn't a subtype of Throwable.
// Similarly for scala.Nothing (again, as defined in src/libray-aux).
- assert(thrownKind.isNullType || thrownKind.isNothingType || exemplars.get(thrownKind).isSubtypeOf(ThrowableReference))
+ assert(thrownKind.isNullType || thrownKind.isNothingType || thrownKind.asClassBType.isSubtypeOf(ThrowableReference))
genLoad(expr, thrownKind)
lineNumber(expr)
emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level.
@@ -123,7 +124,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// binary operation
case rarg :: Nil =>
- resKind = maxType(tpeTK(larg), tpeTK(rarg))
+ resKind = tpeTK(larg).maxType(tpeTK(rarg))
if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code)) {
assert(resKind.isIntegralType || (resKind == BOOL),
s"$resKind incompatible with arithmetic modulo operation.")
@@ -321,7 +322,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
generatedType =
if (tree.symbol == ArrayClass) ObjectReference
- else ClassBType(thisName) // inner class (if any) for claszSymbol already tracked.
+ else classBTypeFromSymbol(claszSymbol)
}
case Select(Ident(nme.EMPTY_PACKAGE_NAME), module) =>
@@ -459,9 +460,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case ClazzTag =>
val toPush: BType = {
- val kind = toTypeKind(const.typeValue)
- if (kind.isPrimitive) classLiteral(kind)
- else kind
+ toTypeKind(const.typeValue) match {
+ case kind: PrimitiveBType => boxedClassOfPrimitive(kind)
+ case kind => kind
+ }
}
mnode.visitLdcInsn(toPush.toASMType)
@@ -558,7 +560,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
abort(s"Erasure should have added an unboxing operation to prevent this cast. Tree: $app")
}
else if (r.isPrimitive) {
- bc isInstance classLiteral(r)
+ bc isInstance boxedClassOfPrimitive(r.asPrimitiveBType)
}
else {
assert(r.isRef, r) // ensure that it's not a method
@@ -619,7 +621,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
case rt: ClassBType =>
- assert(exemplar(ctor.owner).c == rt, s"Symbol ${ctor.owner.fullName} is different from $rt")
+ assert(classBTypeFromSymbol(ctor.owner) == rt, s"Symbol ${ctor.owner.fullName} is different from $rt")
mnode.visitTypeInsn(asm.Opcodes.NEW, rt.internalName)
bc dup generatedType
genLoadArguments(args, paramTKs(app))
@@ -632,16 +634,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) =>
val nativeKind = tpeTK(expr)
genLoad(expr, nativeKind)
- val MethodNameAndType(mname, mdesc) = asmBoxTo(nativeKind)
- bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
+ val MethodNameAndType(mname, methodType) = asmBoxTo(nativeKind)
+ bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor)
generatedType = boxResultType(fun.symbol) // was toTypeKind(fun.symbol.tpe.resultType)
case Apply(fun @ _, List(expr)) if currentRun.runDefinitions.isUnbox(fun.symbol) =>
genLoad(expr)
val boxType = unboxResultType(fun.symbol) // was toTypeKind(fun.symbol.owner.linkedClassOfClass.tpe)
generatedType = boxType
- val MethodNameAndType(mname, mdesc) = asmUnboxTo(boxType)
- bc.invokestatic(BoxesRunTime.internalName, mname, mdesc)
+ val MethodNameAndType(mname, methodType) = asmUnboxTo(boxType)
+ bc.invokestatic(BoxesRunTime.internalName, mname, methodType.descriptor)
case app @ Apply(fun, args) =>
val sym = fun.symbol
@@ -807,7 +809,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}
def adapt(from: BType, to: BType) {
- if (!conforms(from, to)) {
+ if (!from.conformsTo(to)) {
to match {
case UNIT => bc drop from
case _ => bc.emitT2T(from, to)
@@ -948,7 +950,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
def genCallMethod(method: Symbol, style: InvokeStyle, hostClass0: Symbol = null, pos: Position = NoPosition) {
val siteSymbol = claszSymbol
- val hostSymbol = if (hostClass0 == null) method.owner else hostClass0;
+ val hostSymbol = if (hostClass0 == null) method.owner else hostClass0
val methodOwner = method.owner
// info calls so that types are up to date; erasure may add lateINTERFACE to traits
hostSymbol.info ; methodOwner.info
@@ -966,8 +968,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
|| methodOwner == definitions.ObjectClass
)
val receiver = if (useMethodOwner) methodOwner else hostSymbol
- val bmOwner = asmClassType(receiver)
- val jowner = bmOwner.internalName
+ val jowner = internalName(receiver)
val jname = method.javaSimpleName.toString
val bmType = asmMethodType(method)
val mdescr = bmType.descriptor
@@ -977,7 +978,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
if (!isModuleInitialized &&
jMethodName == INSTANCE_CONSTRUCTOR_NAME &&
jname == INSTANCE_CONSTRUCTOR_NAME &&
- isStaticModule(siteSymbol)) {
+ isStaticModuleClass(siteSymbol)) {
isModuleInitialized = true
mnode.visitVarInsn(asm.Opcodes.ALOAD, 0)
mnode.visitFieldInsn(
@@ -1100,7 +1101,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genCZJUMP(success, failure, op, ObjectReference)
}
else {
- val tk = maxType(tpeTK(l), tpeTK(r))
+ val tk = tpeTK(l).maxType(tpeTK(r))
genLoad(l, tk)
genLoad(r, tk)
genCJUMP(success, failure, op, tk)
@@ -1206,7 +1207,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genCZJUMP(success, failure, icodes.NE, BOOL)
} else {
// l == r -> if (l eq null) r eq null else l.equals(r)
- val eqEqTempLocal = locals.makeLocal(AnyRefReference, nme.EQEQ_LOCAL_VAR.toString)
+ val eqEqTempLocal = locals.makeLocal(ObjectReference, nme.EQEQ_LOCAL_VAR.toString)
val lNull = new asm.Label
val lNonNull = new asm.Label
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 31a392ed55..5670715cd3 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -8,8 +8,7 @@ package tools.nsc
package backend.jvm
import scala.tools.asm
-import scala.annotation.switch
-import scala.collection.{ immutable, mutable }
+import scala.collection.mutable
import scala.tools.nsc.io.AbstractFile
/*
@@ -19,9 +18,10 @@ import scala.tools.nsc.io.AbstractFile
* @version 1.0
*
*/
-abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
+abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
import global._
import bTypes._
+ import coreBTypes._
/*
* must-single-thread
@@ -53,24 +53,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
// https://issues.scala-lang.org/browse/SI-3872
// -----------------------------------------------------------------------------------------
- /*
- * can-multi-thread
- */
- def firstCommonSuffix(as: List[Tracked], bs: List[Tracked]): ClassBType = {
- var chainA = as
- var chainB = bs
- var fcs: Tracked = null
- do {
- if (chainB contains chainA.head) fcs = chainA.head
- else if (chainA contains chainB.head) fcs = chainB.head
- else {
- chainA = chainA.tail
- chainB = chainB.tail
- }
- } while (fcs == null)
- fcs.c
- }
-
/* An `asm.ClassWriter` that uses `jvmWiseLUB()`
* The internal name of the least common ancestor of the types given by inameA and inameB.
* It's what ASM needs to know in order to compute stack map frames, http://asm.ow2.org/doc/developer-guide.html#controlflow
@@ -78,57 +60,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
final class CClassWriter(flags: Int) extends asm.ClassWriter(flags) {
/**
- * This method is thread re-entrant because chrs never grows during its operation (that's
- * because all TypeNames being looked up have already been entered).
- * To stress this point, rather than using `newTypeName()` we use `lookupTypeName()`
- *
- * can-multi-thread
+ * This method is thread-safe: it depends only on the BTypes component, which does not depend
+ * on global. TODO @lry move to a different place where no global is in scope, on bTypes.
*/
override def getCommonSuperClass(inameA: String, inameB: String): String = {
- val a = ClassBType(lookupTypeName(inameA.toCharArray))
- val b = ClassBType(lookupTypeName(inameB.toCharArray))
- val lca = jvmWiseLUB(a, b)
- val lcaName = lca.internalName // don't call javaName because that side-effects innerClassBuffer.
- assert(lcaName != "scala/Any")
-
- lcaName // ASM caches the answer during the lifetime of a ClassWriter. We outlive that. Not sure whether caching on our side would improve things.
- }
-
- }
-
- /**
- * Finding the least upper bound in agreement with the bytecode verifier (given two internal names
- * handed out by ASM)
- * Background:
- * http://gallium.inria.fr/~xleroy/publi/bytecode-verification-JAR.pdf
- * http://comments.gmane.org/gmane.comp.java.vm.languages/2293
- * https://issues.scala-lang.org/browse/SI-3872
- *
- * can-multi-thread
- */
- def jvmWiseLUB(a: ClassBType, b: ClassBType): ClassBType = {
-
- assert(a.isNonSpecial, s"jvmWiseLUB() received a non-plain-class $a")
- assert(b.isNonSpecial, s"jvmWiseLUB() received a non-plain-class $b")
-
- val ta = exemplars.get(a)
- val tb = exemplars.get(b)
-
- val res = (ta.isInterface, tb.isInterface) match {
- case (true, true) =>
- // exercised by test/files/run/t4761.scala
- if (tb.isSubtypeOf(ta.c)) ta.c
- else if (ta.isSubtypeOf(tb.c)) tb.c
- else ObjectReference
- case (true, false) =>
- if (tb.isSubtypeOf(a)) a else ObjectReference
- case (false, true) =>
- if (ta.isSubtypeOf(b)) b else ObjectReference
- case _ =>
- firstCommonSuffix(ta :: ta.superClasses, tb :: tb.superClasses)
+ val a = classBTypeFromInternalName(inameA)
+ val b = classBTypeFromInternalName(inameB)
+ val lub = a.jvmWiseLUB(b)
+ val lubName = lub.internalName
+ assert(lubName != "scala/Any")
+ lubName // ASM caches the answer during the lifetime of a ClassWriter. We outlive that. Not sure whether caching on our side would improve things.
}
- assert(res.isNonSpecial, "jvmWiseLUB() returned a non-plain-class.")
- res
}
/*
@@ -230,7 +172,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
def fieldSymbols(cls: Symbol): List[Symbol] = {
for (f <- cls.info.decls.toList ;
if !f.isMethod && f.isTerm && !f.isModule
- ) yield f;
+ ) yield f
}
/*
@@ -261,38 +203,16 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* can-multi-thread
*/
- final def addInnerClassesASM(jclass: asm.ClassVisitor, refedInnerClasses: Iterable[BType]) {
- // used to detect duplicates.
- val seen = mutable.Map.empty[String, String]
- // result without duplicates, not yet sorted.
- val result = mutable.Set.empty[InnerClassEntry]
-
- for(s: BType <- refedInnerClasses;
- e: InnerClassEntry <- exemplars.get(s).innersChain) {
-
- assert(e.name != null, "saveInnerClassesFor() is broken.") // documentation
- val doAdd = seen.get(e.name) match {
- // TODO is it ok for prevOName to be null? (Someone should really document the invariants of the InnerClasses bytecode attribute)
- case Some(prevOName) =>
- // this occurs e.g. when innerClassBuffer contains both class Thread$State, object Thread$State,
- // i.e. for them it must be the case that oname == java/lang/Thread
- assert(prevOName == e.outerName, "duplicate")
- false
- case None => true
- }
-
- if (doAdd) {
- seen += (e.name -> e.outerName)
- result += e
- }
-
+ final def addInnerClassesASM(jclass: asm.ClassVisitor, refedInnerClasses: List[ClassBType]) {
+ val allNestedClasses = refedInnerClasses.flatMap(_.enclosingNestedClassesChain).distinct
+
+ // sorting ensures nested classes are listed after their enclosing class thus satisfying the Eclipse Java compiler
+ for (nestedClass <- allNestedClasses.sortBy(_.internalName.toString)) {
+ // Extract the innerClassEntry - we know it exists, enclosingNestedClassesChain only returns nested classes.
+ val Some(e) = nestedClass.innerClassAttributeEntry
+ jclass.visitInnerClass(e.name, e.outerName, e.innerName, e.flags)
}
- // sorting ensures inner classes are listed after their enclosing class thus satisfying the Eclipse Java compiler
- for(e <- result.toList sortBy (_.name.toString)) {
- jclass.visitInnerClass(e.name, e.outerName, e.innerName, e.access)
- }
-
- } // end of method addInnerClassesASM()
+ }
/*
* Custom attribute (JVMS 4.7.1) "ScalaSig" used as marker only
@@ -323,8 +243,8 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
* can-multi-thread
*/
def createJAttribute(name: String, b: Array[Byte], offset: Int, len: Int): asm.Attribute = {
- val dest = new Array[Byte](len);
- System.arraycopy(b, offset, dest, 0, len);
+ val dest = new Array[Byte](len)
+ System.arraycopy(b, offset, dest, 0, len)
new asm.CustomAttr(name, dest)
}
@@ -385,9 +305,9 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
def debugLevel = settings.debuginfo.indexOfChoice
- val emitSource = debugLevel >= 1
- val emitLines = debugLevel >= 2
- val emitVars = debugLevel >= 3
+ final val emitSource = debugLevel >= 1
+ final val emitLines = debugLevel >= 2
+ final val emitVars = debugLevel >= 3
/*
* Contains class-symbols that:
@@ -396,152 +316,135 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* In other words, the lifetime of `innerClassBufferASM` is associated to "the class being generated".
*/
- val innerClassBufferASM = mutable.Set.empty[BType]
+ final val innerClassBufferASM = mutable.Set.empty[ClassBType]
- /*
- * Tracks (if needed) the inner class given by `sym`.
- *
- * must-single-thread
+ /**
+ * The class internal name for a given class symbol. If the symbol describes a nested class, the
+ * ClassBType is added to the innerClassBufferASM.
*/
- final def internalName(sym: Symbol): String = asmClassType(sym).internalName
+ final def internalName(sym: Symbol): String = {
+ // For each java class, the scala compiler creates a class and a module (thus a module class).
+ // If the `sym` is a java module class, we use the java class instead. This ensures that we
+ // register the class (instead of the module class) in innerClassBufferASM.
+ // The two symbols have the same name, so the resulting internalName is the same.
+ val classSym = if (sym.isJavaDefined && sym.isModuleClass) sym.linkedClassOfClass else sym
+ getClassBTypeAndRegisterInnerClass(classSym).internalName
+ }
- /*
- * Tracks (if needed) the inner class given by `sym`.
+ private def assertClassNotArray(sym: Symbol): Unit = {
+ assert(sym.isClass, sym)
+ assert(sym != definitions.ArrayClass || isCompilingArray, sym)
+ }
+
+ private def assertClassNotArrayNotPrimitive(sym: Symbol): Unit = {
+ assertClassNotArray(sym)
+ assert(!primitiveTypeMap.contains(sym) || isCompilingPrimitive, sym)
+ }
+
+ /**
+ * The ClassBType for a class symbol. If the class is nested, the ClassBType is added to the
+ * innerClassBufferASM.
*
- * must-single-thread
+ * The class symbol scala.Nothing is mapped to the class scala.runtime.Nothing$. Similarly,
+ * scala.Null is mapped to scala.runtime.Null$. This is because there exist no class files
+ * for the Nothing / Null. If used for example as a parameter type, we use the runtime classes
+ * in the classfile method signature.
+ *
+ * Note that the referenced class symbol may be an implementation class. For example when
+ * compiling a mixed-in method that forwards to the static method in the implementation class,
+ * the class descriptor of the receiver (the implementation class) is obtained by creating the
+ * ClassBType.
*/
- final def asmClassType(sym: Symbol): ClassBType = {
- assert(
- hasInternalName(sym),
- {
- val msg0 = if (sym.isAbstractType) "An AbstractTypeSymbol (SI-7122) " else "A symbol ";
- msg0 + s"has reached the bytecode emitter, for which no JVM-level internal name can be found: ${sym.fullName}"
- }
- )
- val phantOpt = phantomTypeMap.get(sym)
- if (phantOpt.isDefined) {
- return phantOpt.get
- }
- val tracked = exemplar(sym)
- val tk = tracked.c
- if (tracked.isInnerClass) {
- innerClassBufferASM += tk
- }
+ final def getClassBTypeAndRegisterInnerClass(sym: Symbol): ClassBType = {
+ assertClassNotArrayNotPrimitive(sym)
- tk
+ if (sym == definitions.NothingClass) RT_NOTHING
+ else if (sym == definitions.NullClass) RT_NULL
+ else {
+ val r = classBTypeFromSymbol(sym)
+ if (r.isNestedClass) innerClassBufferASM += r
+ r
+ }
}
- /*
- * Returns the BType for the given type.
- * Tracks (if needed) the inner class given by `t`.
+ /**
+ * This method returns the BType for a type reference, for example a parameter type.
*
- * must-single-thread
+ * If the result is a ClassBType for a nested class, it is added to the innerClassBufferASM.
+ *
+ * If `t` references a class, toTypeKind ensures that the class is not an implementation class.
+ * See also comment on getClassBTypeAndRegisterInnerClass, which is invoked for implementation
+ * classes.
*/
final def toTypeKind(t: Type): BType = {
+ import definitions.ArrayClass
- /* Interfaces have to be handled delicately to avoid introducing spurious errors,
- * but if we treat them all as AnyRef we lose too much information.
+ /**
+ * Primitive types are represented as TypeRefs to the class symbol of, for example, scala.Int.
+ * The `primitiveTypeMap` maps those class symbols to the corresponding PrimitiveBType.
*/
- def newReference(sym0: Symbol): BType = {
- assert(!primitiveTypeMap.contains(sym0), "Use primitiveTypeMap instead.")
- assert(sym0 != definitions.ArrayClass, "Use arrayOf() instead.")
-
- if (sym0 == definitions.NullClass) return RT_NULL;
- if (sym0 == definitions.NothingClass) return RT_NOTHING;
-
- val sym = (
- if (!sym0.isPackageClass) sym0
- else sym0.info.member(nme.PACKAGE) match {
- case NoSymbol => abort(s"SI-5604: Cannot use package as value: ${sym0.fullName}")
- case s => abort(s"SI-5604: found package class where package object expected: $s")
- }
- )
-
- // Can't call .toInterface (at this phase) or we trip an assertion.
- // See PackratParser#grow for a method which fails with an apparent mismatch
- // between "object PackratParsers$class" and "trait PackratParsers"
- if (sym.isImplClass) {
- // pos/spec-List.scala is the sole failure if we don't check for NoSymbol
- val traitSym = sym.owner.info.decl(tpnme.interfaceName(sym.name))
- if (traitSym != NoSymbol) {
- // this tracks the inner class in innerClassBufferASM, if needed.
- return asmClassType(traitSym)
- }
- }
-
- assert(hasInternalName(sym), s"Invoked for a symbol lacking JVM internal name: ${sym.fullName}")
- assert(!phantomTypeMap.contains(sym), "phantom types not supposed to reach here.")
-
- val tracked = exemplar(sym)
- val tk = tracked.c
- if (tracked.isInnerClass) {
- innerClassBufferASM += tk
- }
-
- tk
+ def primitiveOrClassToBType(sym: Symbol): BType = {
+ assertClassNotArray(sym)
+ assert(!sym.isImplClass, sym)
+ primitiveTypeMap.getOrElse(sym, getClassBTypeAndRegisterInnerClass(sym))
}
- def primitiveOrRefType(sym: Symbol): BType = {
- assert(sym != definitions.ArrayClass, "Use primitiveOrArrayOrRefType() instead.")
-
- primitiveTypeMap.getOrElse(sym, newReference(sym))
- }
-
- def primitiveOrRefType2(sym: Symbol): BType = {
- primitiveTypeMap.get(sym) match {
- case Some(pt) => pt
- case None =>
- sym match {
- case definitions.NullClass => RT_NULL
- case definitions.NothingClass => RT_NOTHING
- case _ if sym.isClass => newReference(sym)
- case _ =>
- assert(sym.isType, sym) // it must be compiling Array[a]
- ObjectReference
- }
- }
+ /**
+ * When compiling Array.scala, the type parameter T is not erased and shows up in method
+ * signatures, e.g. `def apply(i: Int): T`. A TyperRef to T is replaced by ObjectReference.
+ */
+ def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
+ assert(sym.isType && isCompilingArray, sym)
+ ObjectReference
}
- import definitions.ArrayClass
-
- // Call to .normalize fixes #3003 (follow type aliases). Otherwise, primitiveOrArrayOrRefType() would return ObjectReference.
- t.normalize match {
-
- case ThisType(sym) =>
- if (sym == ArrayClass) ObjectReference
- else phantomTypeMap.getOrElse(sym, exemplar(sym).c)
-
- case SingleType(_, sym) => primitiveOrRefType(sym)
-
- case _: ConstantType => toTypeKind(t.underlying)
-
- case TypeRef(_, sym, args) =>
- if (sym == ArrayClass) ArrayBType(toTypeKind(args.head))
- else primitiveOrRefType2(sym)
-
- case ClassInfoType(_, _, sym) =>
- assert(sym != ArrayClass, "ClassInfoType to ArrayClass!")
- primitiveOrRefType(sym)
-
- // TODO @lry check below comments / todo's
- // !!! Iulian says types which make no sense after erasure should not reach here, which includes the ExistentialType, AnnotatedType, RefinedType.
- case ExistentialType(_, t) => toTypeKind(t) // TODO shouldn't get here but the following does: akka-actor/src/main/scala/akka/util/WildcardTree.scala
- case AnnotatedType(_, w) => toTypeKind(w) // TODO test/files/jvm/annotations.scala causes an AnnotatedType to reach here.
- case RefinedType(parents, _) => parents.map(toTypeKind(_).asClassBType) reduceLeft jvmWiseLUB
-
- // For sure WildcardTypes shouldn't reach here either, but when debugging such situations this may come in handy.
- // case WildcardType => REFERENCE(ObjectClass)
- case norm => abort(
- s"Unknown type: $t, $norm [${t.getClass}, ${norm.getClass}] TypeRef? ${t.isInstanceOf[TypeRef]}"
- )
+ t.dealiasWiden match {
+ case TypeRef(_, ArrayClass, List(arg)) => ArrayBType(toTypeKind(arg)) // Array type such as Array[Int] (kept by erasure)
+ case TypeRef(_, sym, _) if !sym.isClass => nonClassTypeRefToBType(sym) // See comment on nonClassTypeRefToBType
+ case TypeRef(_, sym, _) => primitiveOrClassToBType(sym) // Common reference to a type such as scala.Int or java.lang.String
+ case ClassInfoType(_, _, sym) => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes toTypeKind(moduleClassSymbol.info)
+
+ /* AnnotatedType should (probably) be eliminated by erasure. However we know it happens for
+ * meta-annotated annotations (@(ann @getter) val x = 0), so we don't emit a warning.
+ * The type in the AnnotationInfo is an AnnotatedTpe. Tested in jvm/annotations.scala.
+ */
+ case a @ AnnotatedType(_, t) =>
+ debuglog(s"typeKind of annotated type $a")
+ toTypeKind(t)
+
+ /* ExistentialType should (probably) be eliminated by erasure. We know they get here for
+ * classOf constants:
+ * class C[T]
+ * class T { final val k = classOf[C[_]] }
+ */
+ case e @ ExistentialType(_, t) =>
+ debuglog(s"typeKind of existential type $e")
+ toTypeKind(t)
+
+ /* The cases below should probably never occur. They are kept for now to avoid introducing
+ * new compiler crashes, but we added a warning. The compiler / library bootstrap and the
+ * test suite don't produce any warning.
+ */
+
+ case tp =>
+ currentUnit.warning(tp.typeSymbol.pos,
+ s"an unexpected type representation reached the compiler backend while compiling $currentUnit: $tp. " +
+ "If possible, please file a bug on issues.scala-lang.org.")
+
+ tp match {
+ case ThisType(ArrayClass) => ObjectReference // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
+ case ThisType(sym) => getClassBTypeAndRegisterInnerClass(sym)
+ case SingleType(_, sym) => primitiveOrClassToBType(sym)
+ case ConstantType(_) => toTypeKind(t.underlying)
+ case RefinedType(parents, _) => parents.map(toTypeKind(_).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b))
+ }
}
-
- } // end of method toTypeKind()
+ }
/*
* must-single-thread
*/
- def asmMethodType(msym: Symbol): MethodBType = {
+ final def asmMethodType(msym: Symbol): MethodBType = {
assert(msym.isMethod, s"not a method-symbol: $msym")
val resT: BType =
if (msym.isClassConstructor || msym.isConstructor) UNIT
@@ -549,45 +452,17 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
MethodBType(msym.tpe.paramTypes map toTypeKind, resT)
}
- /*
- * Returns all direct member inner classes of `csym`,
- * thus making sure they get entries in the InnerClasses JVM attribute
- * even if otherwise not mentioned in the class being built.
- *
- * must-single-thread
- */
- final def trackMemberClasses(csym: Symbol, lateClosuresBTs: List[BType]): List[BType] = {
- val lateInnerClasses = exitingErasure {
- for (sym <- List(csym, csym.linkedClassOfClass); memberc <- sym.info.decls.map(innerClassSymbolFor) if memberc.isClass)
- yield memberc
- }
- // as a precaution, do the following outside the above `exitingErasure` otherwise funny internal names might be computed.
- val result = for(memberc <- lateInnerClasses) yield {
- val tracked = exemplar(memberc)
- val memberCTK = tracked.c
- assert(tracked.isInnerClass, s"saveInnerClassesFor() says this was no inner-class after all: ${memberc.fullName}")
-
- memberCTK
- }
-
- exemplar(csym).directMemberClasses = result
-
- result
- }
-
- /*
- * Tracks (if needed) the inner class given by `t`.
- *
- * must-single-thread
+ /**
+ * The jvm descriptor of a type. If `t` references a nested class, its ClassBType is added to
+ * the innerClassBufferASM.
*/
final def descriptor(t: Type): String = { toTypeKind(t).descriptor }
- /*
- * Tracks (if needed) the inner class given by `sym`.
- *
- * must-single-thread
+ /**
+ * The jvm descriptor for a symbol. If `sym` represents a nested class, its ClassBType is added
+ * to the innerClassBufferASM.
*/
- final def descriptor(sym: Symbol): String = { asmClassType(sym).descriptor }
+ final def descriptor(sym: Symbol): String = { getClassBTypeAndRegisterInnerClass(sym).descriptor }
} // end of trait BCInnerClassGen
@@ -792,7 +667,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*/
// TODO: evaluate the other flags we might be dropping on the floor here.
// TODO: ACC_SYNTHETIC ?
- val flags = PublicStatic | (
+ val flags = GenBCode.PublicStatic | (
if (m.isVarargsMethod) asm.Opcodes.ACC_VARARGS else 0
)
@@ -898,62 +773,13 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
def addSerialVUID(id: Long, jclass: asm.ClassVisitor) {
// add static serialVersionUID field if `clasz` annotated with `@SerialVersionUID(uid: Long)`
jclass.visitField(
- PublicStaticFinal,
+ GenBCode.PublicStaticFinal,
"serialVersionUID",
"J",
null, // no java-generic-signature
new java.lang.Long(id)
).visitEnd()
}
-
- /*
- * @param owner internal name of the enclosing class of the class.
- *
- * @param name the name of the method that contains the class.
-
- * @param methodType the method that contains the class.
- */
- case class EnclMethodEntry(owner: String, name: String, methodType: BType)
-
- /*
- * @return null if the current class is not internal to a method
- *
- * Quoting from JVMS 4.7.7 The EnclosingMethod Attribute
- * A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
- * A class may have no more than one EnclosingMethod attribute.
- *
- * must-single-thread
- */
- def getEnclosingMethodAttribute(clazz: Symbol): EnclMethodEntry = { // JVMS 4.7.7
-
- def newEEE(eClass: Symbol, m: Symbol) = {
- EnclMethodEntry(
- internalName(eClass),
- m.javaSimpleName.toString,
- asmMethodType(m)
- )
- }
-
- var res: EnclMethodEntry = null
- val sym = clazz.originalEnclosingMethod
- if (sym.isMethod) {
- debuglog(s"enclosing method for $clazz is $sym (in ${sym.enclClass})")
- res = newEEE(sym.enclClass, sym)
- } else if (clazz.isAnonymousClass) {
- val enclClass = clazz.rawowner
- assert(enclClass.isClass, enclClass)
- val sym = enclClass.primaryConstructor
- if (sym == NoSymbol) {
- log(s"Ran out of room looking for an enclosing method for $clazz: no constructor here: $enclClass.")
- } else {
- debuglog(s"enclosing method for $clazz is $sym (in $enclClass)")
- res = newEEE(enclClass, sym)
- }
- }
-
- res
- }
-
} // end of trait BCClassGen
/* basic functionality for class file building of plain, mirror, and beaninfo classes. */
@@ -982,11 +808,12 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- def genMirrorClass(modsym: Symbol, cunit: CompilationUnit): asm.tree.ClassNode = {
- assert(modsym.companionClass == NoSymbol, modsym)
+ def genMirrorClass(moduleClass: Symbol, cunit: CompilationUnit): asm.tree.ClassNode = {
+ assert(moduleClass.isModuleClass)
+ assert(moduleClass.companionClass == NoSymbol, moduleClass)
innerClassBufferASM.clear()
this.cunit = cunit
- val moduleName = internalName(modsym) // + "$"
+ val moduleName = internalName(moduleClass) // + "$"
val mirrorName = moduleName.substring(0, moduleName.length() - 1)
val flags = (asm.Opcodes.ACC_SUPER | asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_FINAL)
@@ -996,7 +823,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
flags,
mirrorName,
null /* no java-generic-signature */,
- JAVA_LANG_OBJECT.internalName,
+ ObjectReference.internalName,
EMPTY_STRING_ARRAY
)
@@ -1005,18 +832,18 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
null /* SourceDebugExtension */)
}
- val ssa = getAnnotPickle(mirrorName, modsym.companionSymbol)
+ val ssa = getAnnotPickle(mirrorName, moduleClass.companionSymbol)
mirrorClass.visitAttribute(if (ssa.isDefined) pickleMarkerLocal else pickleMarkerForeign)
- emitAnnotations(mirrorClass, modsym.annotations ++ ssa)
+ emitAnnotations(mirrorClass, moduleClass.annotations ++ ssa)
- addForwarders(isRemote(modsym), mirrorClass, mirrorName, modsym)
+ addForwarders(isRemote(moduleClass), mirrorClass, mirrorName, moduleClass)
- innerClassBufferASM ++= trackMemberClasses(modsym, Nil /* TODO what about Late-Closure-Classes */ )
+ innerClassBufferASM ++= classBTypeFromSymbol(moduleClass).info.memberClasses
addInnerClassesASM(mirrorClass, innerClassBufferASM.toList)
mirrorClass.visitEnd()
- ("" + modsym.name) // this side-effect is necessary, really.
+ ("" + moduleClass.name) // this side-effect is necessary, really.
mirrorClass
}
@@ -1039,10 +866,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
innerClassBufferASM.clear()
- val flags = mkFlags(
- javaFlags(cls),
- if (isDeprecated(cls)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag
- )
+ val flags = javaFlags(cls)
val beanInfoName = (internalName(cls) + "BeanInfo")
val beanInfoClass = new asm.tree.ClassNode
@@ -1088,9 +912,9 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
EMPTY_STRING_ARRAY // no throwable exceptions
)
- val stringArrayJType: BType = ArrayBType(JAVA_LANG_STRING)
+ val stringArrayJType: BType = ArrayBType(StringReference)
val conJType: BType = MethodBType(
- exemplar(definitions.ClassClass).c :: stringArrayJType :: stringArrayJType :: Nil,
+ classBTypeFromSymbol(definitions.ClassClass) :: stringArrayJType :: stringArrayJType :: Nil,
UNIT
)
@@ -1101,7 +925,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
constructor.visitLdcInsn(new java.lang.Integer(fi))
if (f == null) { constructor.visitInsn(asm.Opcodes.ACONST_NULL) }
else { constructor.visitLdcInsn(f) }
- constructor.visitInsn(JAVA_LANG_STRING.typedOpcode(asm.Opcodes.IASTORE))
+ constructor.visitInsn(StringReference.typedOpcode(asm.Opcodes.IASTORE))
fi += 1
}
}
@@ -1110,16 +934,16 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
constructor.visitVarInsn(asm.Opcodes.ALOAD, 0)
// push the class
- constructor.visitLdcInsn(exemplar(cls).c.toASMType)
+ constructor.visitLdcInsn(classBTypeFromSymbol(cls).toASMType)
// push the string array of field information
constructor.visitLdcInsn(new java.lang.Integer(fieldList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.internalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringReference.internalName)
push(fieldList)
// push the string array of method information
constructor.visitLdcInsn(new java.lang.Integer(methodList.length))
- constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, JAVA_LANG_STRING.internalName)
+ constructor.visitTypeInsn(asm.Opcodes.ANEWARRAY, StringReference.internalName)
push(methodList)
// invoke the superclass constructor, which will do the
@@ -1130,7 +954,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
constructor.visitMaxs(0, 0) // just to follow protocol, dummy arguments
constructor.visitEnd()
- innerClassBufferASM ++= trackMemberClasses(cls, Nil /* TODO what about Late-Closure-Classes */ )
+ innerClassBufferASM ++= classBTypeFromSymbol(cls).info.memberClasses
addInnerClassesASM(beanInfoClass, innerClassBufferASM.toList)
beanInfoClass.visitEnd()
@@ -1162,11 +986,11 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*/
def legacyAddCreatorCode(clinit: asm.MethodVisitor, cnode: asm.tree.ClassNode, thisName: String) {
// this tracks the inner class in innerClassBufferASM, if needed.
- val androidCreatorType = asmClassType(AndroidCreatorClass)
+ val androidCreatorType = getClassBTypeAndRegisterInnerClass(AndroidCreatorClass)
val tdesc_creator = androidCreatorType.descriptor
cnode.visitField(
- PublicStaticFinal,
+ GenBCode.PublicStaticFinal,
"CREATOR",
tdesc_creator,
null, // no java-generic-signature
@@ -1203,5 +1027,4 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
}
} // end of trait JAndroidBuilder
-
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
index 9b7c975960..d58368b19d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeIdiomatic.scala
@@ -19,29 +19,23 @@ import scala.collection.mutable
*
*/
abstract class BCodeIdiomatic extends SubComponent {
- protected val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
-
- val bTypes = new BTypes[global.type](global) {
- def chrs = global.chrs
- override type BTypeName = global.TypeName
- override def createNewName(s: String) = global.newTypeName(s)
- }
+ val bTypes = new BTypesFromSymbols[global.type](global)
import global._
import bTypes._
+ import coreBTypes._
val classfileVersion: Int = settings.target.value match {
case "jvm-1.5" => asm.Opcodes.V1_5
case "jvm-1.6" => asm.Opcodes.V1_6
case "jvm-1.7" => asm.Opcodes.V1_7
+ case "jvm-1.8" => asm.Opcodes.V1_8
}
val majorVersion: Int = (classfileVersion & 0xFF)
val emitStackMapFrame = (majorVersion >= 50)
- def mkFlags(args: Int*) = args.foldLeft(0)(_ | _)
-
- val extraProc: Int = mkFlags(
+ val extraProc: Int = GenBCode.mkFlags(
asm.ClassWriter.COMPUTE_MAXS,
if (emitStackMapFrame) asm.ClassWriter.COMPUTE_FRAMES else 0
)
@@ -51,15 +45,6 @@ abstract class BCodeIdiomatic extends SubComponent {
val CLASS_CONSTRUCTOR_NAME = "<clinit>"
val INSTANCE_CONSTRUCTOR_NAME = "<init>"
- val ObjectReference = ClassBType("java/lang/Object")
- val AnyRefReference = ObjectReference
- val objArrayReference = ArrayBType(ObjectReference)
-
- val JAVA_LANG_OBJECT = ObjectReference
- val JAVA_LANG_STRING = ClassBType("java/lang/String")
-
- var StringBuilderReference: BType = null
-
val EMPTY_STRING_ARRAY = Array.empty[String]
val EMPTY_INT_ARRAY = Array.empty[Int]
val EMPTY_LABEL_ARRAY = Array.empty[asm.Label]
@@ -238,7 +223,7 @@ abstract class BCodeIdiomatic extends SubComponent {
final def genStringConcat(el: BType) {
val jtype =
- if (el.isArray || el.isClass) JAVA_LANG_OBJECT
+ if (el.isArray || el.isClass) ObjectReference
else el
val bt = MethodBType(List(jtype), StringBuilderReference)
@@ -265,7 +250,7 @@ abstract class BCodeIdiomatic extends SubComponent {
assert(
from.isNonVoidPrimitiveType && to.isNonVoidPrimitiveType,
- s"Cannot emit primitive conversion from $from to $to"
+ s"Cannot emit primitive conversion from $from to $to - ${global.currentUnit}"
)
def pickOne(opcs: Array[Int]) { // TODO index on to.sort
@@ -536,7 +521,7 @@ abstract class BCodeIdiomatic extends SubComponent {
final def emitTypeBased(opcs: Array[Int], tk: BType) {
assert(tk != UNIT, tk)
val opc = {
- if (tk.isRef) { opcs(0) }
+ if (tk.isRef) { opcs(0) }
else if (tk.isIntSizedType) {
(tk: @unchecked) match {
case BOOL | BYTE => opcs(1)
@@ -647,7 +632,7 @@ abstract class BCodeIdiomatic extends SubComponent {
*/
final def coercionTo(code: Int): BType = {
import scalaPrimitives._
- (code: @scala.annotation.switch) match {
+ (code: @switch) match {
case B2B | C2B | S2B | I2B | L2B | F2B | D2B => BYTE
case B2C | C2C | S2C | I2C | L2C | F2C | D2C => CHAR
case B2S | C2S | S2S | I2S | L2S | F2S | D2S => SHORT
@@ -658,21 +643,6 @@ abstract class BCodeIdiomatic extends SubComponent {
}
}
- final val typeOfArrayOp: Map[Int, BType] = {
- import scalaPrimitives._
- Map(
- (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
- (List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
- (List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
- (List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
- (List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT)) ++
- (List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
- (List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
- (List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
- (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectReference)) : _*
- )
- }
-
/*
* Collects (in `result`) all LabelDef nodes enclosed (directly or not) by each node it visits.
*
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
index 8845ffa0cd..4592031a31 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala
@@ -26,6 +26,8 @@ import java.io.PrintWriter
abstract class BCodeSkelBuilder extends BCodeHelpers {
import global._
import bTypes._
+ import coreBTypes._
+ import bCodeAsmCommon._
/*
* There's a dedicated PlainClassBuilder for each CompilationUnit,
@@ -95,7 +97,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
claszSymbol = cd.symbol
isCZParcelable = isAndroidParcelableClass(claszSymbol)
- isCZStaticModule = isStaticModule(claszSymbol)
+ isCZStaticModule = isStaticModuleClass(claszSymbol)
isCZRemote = isRemote(claszSymbol)
thisName = internalName(claszSymbol)
@@ -116,7 +118,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
addClassFields()
- innerClassBufferASM ++= trackMemberClasses(claszSymbol, Nil)
+ innerClassBufferASM ++= classBTypeFromSymbol(claszSymbol).info.memberClasses
gen(cd.impl)
addInnerClassesASM(cnode, innerClassBufferASM.toList)
@@ -134,40 +136,28 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
private def initJClass(jclass: asm.ClassVisitor) {
val ps = claszSymbol.info.parents
- val superClass: String = if (ps.isEmpty) JAVA_LANG_OBJECT.internalName else internalName(ps.head.typeSymbol);
- val ifaces: Array[String] = {
- val arrIfacesTr: Array[Tracked] = exemplar(claszSymbol).ifaces
- val arrIfaces = new Array[String](arrIfacesTr.length)
- var i = 0
- while (i < arrIfacesTr.length) {
- val ifaceTr = arrIfacesTr(i)
- val bt = ifaceTr.c
- if (ifaceTr.isInnerClass) { innerClassBufferASM += bt }
- arrIfaces(i) = bt.internalName
- i += 1
- }
- arrIfaces
+ val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.typeSymbol)
+ val interfaceNames = classBTypeFromSymbol(claszSymbol).info.interfaces map {
+ case classBType =>
+ if (classBType.isNestedClass) { innerClassBufferASM += classBType }
+ classBType.internalName
}
- // `internalName()` tracks inner classes.
- val flags = mkFlags(
- javaFlags(claszSymbol),
- if (isDeprecated(claszSymbol)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag
- )
+ val flags = javaFlags(claszSymbol)
val thisSignature = getGenericSignature(claszSymbol, claszSymbol.owner)
cnode.visit(classfileVersion, flags,
thisName, thisSignature,
- superClass, ifaces)
+ superClass, interfaceNames.toArray)
if (emitSource) {
cnode.visitSource(cunit.source.toString, null /* SourceDebugExtension */)
}
- val enclM = getEnclosingMethodAttribute(claszSymbol)
- if (enclM != null) {
- val EnclMethodEntry(className, methodName, methodType) = enclM
- cnode.visitOuterClass(className, methodName, methodType.descriptor)
+ enclosingMethodAttribute(claszSymbol, internalName, asmMethodType(_).descriptor) match {
+ case Some(EnclosingMethodEntry(className, methodName, methodDescriptor)) =>
+ cnode.visitOuterClass(className, methodName, methodDescriptor)
+ case _ => ()
}
val ssa = getAnnotPickle(thisName, claszSymbol)
@@ -207,7 +197,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
*/
private def addModuleInstanceField() {
val fv =
- cnode.visitField(PublicStaticFinal, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED
+ cnode.visitField(GenBCode.PublicStaticFinal, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED
strMODULE_INSTANCE_FIELD,
"L" + thisName + ";",
null, // no java-generic-signature
@@ -223,7 +213,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
private def fabricateStaticInit() {
val clinit: asm.MethodVisitor = cnode.visitMethod(
- PublicStatic, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED
+ GenBCode.PublicStatic, // TODO confirm whether we really don't want ACC_SYNTHETIC nor ACC_DEPRECATED
CLASS_CONSTRUCTOR_NAME,
"()V",
null, // no java-generic-signature
@@ -254,10 +244,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
*/
for (f <- fieldSymbols(claszSymbol)) {
val javagensig = getGenericSignature(f, claszSymbol)
- val flags = mkFlags(
- javaFieldFlags(f),
- if (isDeprecated(f)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag
- )
+ val flags = javaFieldFlags(f)
val jfield = new asm.tree.FieldNode(
flags,
@@ -576,12 +563,11 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
val isNative = methSymbol.hasAnnotation(definitions.NativeAttr)
val isAbstractMethod = (methSymbol.isDeferred || methSymbol.owner.isInterface)
- val flags = mkFlags(
+ val flags = GenBCode.mkFlags(
javaFlags(methSymbol),
if (claszSymbol.isInterface) asm.Opcodes.ACC_ABSTRACT else 0,
if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0,
- if (isNative) asm.Opcodes.ACC_NATIVE else 0, // native methods of objects are generated in mirror classes
- if (isDeprecated(methSymbol)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag
+ if (isNative) asm.Opcodes.ACC_NATIVE else 0 // native methods of objects are generated in mirror classes
)
// TODO needed? for(ann <- m.symbol.annotations) { ann.symbol.initialize }
@@ -695,7 +681,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
// android creator code
if (isCZParcelable) {
// add a static field ("CREATOR") to this class to cache android.os.Parcelable$Creator
- val andrFieldDescr = asmClassType(AndroidCreatorClass).descriptor
+ val andrFieldDescr = getClassBTypeAndRegisterInnerClass(AndroidCreatorClass).descriptor
cnode.visitField(
asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL,
"CREATOR",
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
index c271e7b129..7c95b7fc3b 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSyncAndTry.scala
@@ -21,7 +21,7 @@ import scala.tools.asm
abstract class BCodeSyncAndTry extends BCodeBodyBuilder {
import global._
import bTypes._
-
+ import coreBTypes._
/*
* Functionality to lower `synchronized` and `try` expressions.
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
deleted file mode 100644
index 62dfb4917d..0000000000
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeTypes.scala
+++ /dev/null
@@ -1,861 +0,0 @@
-/* NSC -- new Scala compiler
- * Copyright 2005-2012 LAMP/EPFL
- * @author Martin Odersky
- */
-
-package scala
-package tools.nsc
-package backend.jvm
-
-import scala.tools.asm
-import scala.collection.{ immutable, mutable }
-
-/*
- * Utilities to mediate between types as represented in Scala ASTs and ASM trees.
- *
- * @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded
- * @version 1.0
- *
- */
-abstract class BCodeTypes extends BCodeIdiomatic {
- import global._
- import bTypes._
-
- // when compiling the Scala library, some assertions don't hold (e.g., scala.Boolean has null superClass although it's not an interface)
- val isCompilingStdLib = !(settings.sourcepath.isDefault)
-
- // special names
- var StringReference : ClassBType = null
- var ThrowableReference : ClassBType = null
- var jlCloneableReference : ClassBType = null // java/lang/Cloneable
- var jlNPEReference : ClassBType = null // java/lang/NullPointerException
- var jioSerializableReference : ClassBType = null // java/io/Serializable
- var scalaSerializableReference : ClassBType = null // scala/Serializable
- var classCastExceptionReference : ClassBType = null // java/lang/ClassCastException
-
- /* A map from scala primitive type-symbols to BTypes */
- var primitiveTypeMap: Map[Symbol, BType] = null
- /* A map from scala type-symbols for Nothing and Null to (runtime version) BTypes */
- var phantomTypeMap: Map[Symbol, ClassBType] = null
- /* Maps the method symbol for a box method to the boxed type of the result.
- * For example, the method symbol for `Byte.box()`) is mapped to the BType `Ljava/lang/Integer;`. */
- var boxResultType: Map[Symbol, BType] = null
- /* Maps the method symbol for an unbox method to the primitive type of the result.
- * For example, the method symbol for `Byte.unbox()`) is mapped to the BType BYTE. */
- var unboxResultType: Map[Symbol, BType] = null
-
- var hashMethodSym: Symbol = null // scala.runtime.ScalaRunTime.hash
-
- var AndroidParcelableInterface: Symbol = null
- var AndroidCreatorClass : Symbol = null // this is an inner class, use asmType() to get hold of its BType while tracking in innerClassBufferASM
-
- var BeanInfoAttr: Symbol = null
-
- /* The Object => String overload. */
- var String_valueOf: Symbol = null
-
- var ArrayInterfaces: Set[Tracked] = null
-
- // scala.FunctionX and scala.runtim.AbstractFunctionX
- val FunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1)
- val AbstractFunctionReference = new Array[Tracked](definitions.MaxFunctionArity + 1)
- val abstractFunctionArityMap = mutable.Map.empty[BType, Int]
-
- var PartialFunctionReference: ClassBType = null // scala.PartialFunction
- var AbstractPartialFunctionReference: ClassBType = null // scala.runtime.AbstractPartialFunction
-
- var BoxesRunTime: ClassBType = null
-
- /*
- * must-single-thread
- */
- def initBCodeTypes() {
- import definitions._
-
- primitiveTypeMap =
- Map(
- UnitClass -> UNIT,
- BooleanClass -> BOOL,
- CharClass -> CHAR,
- ByteClass -> BYTE,
- ShortClass -> SHORT,
- IntClass -> INT,
- LongClass -> LONG,
- FloatClass -> FLOAT,
- DoubleClass -> DOUBLE
- )
-
- phantomTypeMap =
- Map(
- NothingClass -> RT_NOTHING,
- NullClass -> RT_NULL,
- NothingClass -> RT_NOTHING, // we map on purpose to RT_NOTHING, getting rid of the distinction compile-time vs. runtime for NullClass.
- NullClass -> RT_NULL // ditto.
- )
-
- boxResultType =
- for((csym, msym) <- currentRun.runDefinitions.boxMethod)
- yield (msym -> classLiteral(primitiveTypeMap(csym)))
-
- unboxResultType =
- for((csym, msym) <- currentRun.runDefinitions.unboxMethod)
- yield (msym -> primitiveTypeMap(csym))
-
- // boxed classes are looked up in the `exemplars` map by jvmWiseLUB().
- // Other than that, they aren't needed there (e.g., `isSubtypeOf()` special-cases boxed classes, similarly for others).
- val boxedClasses = List(BoxedBooleanClass, BoxedCharacterClass, BoxedByteClass, BoxedShortClass, BoxedIntClass, BoxedLongClass, BoxedFloatClass, BoxedDoubleClass)
- for(csym <- boxedClasses) {
- val key = ClassBType(csym.javaBinaryName.toTypeName)
- val tr = buildExemplar(key, csym)
- symExemplars.put(csym, tr)
- exemplars.put(tr.c, tr)
- }
-
- // reversePrimitiveMap = (primitiveTypeMap map { case (s, pt) => (s.tpe, pt) } map (_.swap)).toMap
-
- hashMethodSym = getMember(ScalaRunTimeModule, nme.hash_)
-
- // TODO avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
- AndroidParcelableInterface = rootMirror.getClassIfDefined("android.os.Parcelable")
- AndroidCreatorClass = rootMirror.getClassIfDefined("android.os.Parcelable$Creator")
-
- // the following couldn't be an eager vals in Phase constructors:
- // that might cause cycles before Global has finished initialization.
- BeanInfoAttr = rootMirror.getRequiredClass("scala.beans.BeanInfo")
-
- String_valueOf = {
- getMember(StringModule, nme.valueOf) filter (sym =>
- sym.info.paramTypes match {
- case List(pt) => pt.typeSymbol == ObjectClass
- case _ => false
- }
- )
- }
-
- exemplar(JavaCloneableClass)
- exemplar(JavaSerializableClass)
- exemplar(SerializableClass)
-
- StringReference = exemplar(StringClass).c
- StringBuilderReference = exemplar(StringBuilderClass).c
- ThrowableReference = exemplar(ThrowableClass).c
- jlCloneableReference = exemplar(JavaCloneableClass).c
- jlNPEReference = exemplar(NullPointerExceptionClass).c
- jioSerializableReference = exemplar(JavaSerializableClass).c
- scalaSerializableReference = exemplar(SerializableClass).c
- classCastExceptionReference = exemplar(ClassCastExceptionClass).c
-
- PartialFunctionReference = exemplar(PartialFunctionClass).c
- for(idx <- 0 to definitions.MaxFunctionArity) {
- FunctionReference(idx) = exemplar(FunctionClass(idx))
- AbstractFunctionReference(idx) = exemplar(AbstractFunctionClass(idx))
- abstractFunctionArityMap += (AbstractFunctionReference(idx).c -> idx)
- AbstractPartialFunctionReference = exemplar(AbstractPartialFunctionClass).c
- }
-
- BoxesRunTime = ClassBType("scala/runtime/BoxesRunTime")
- }
-
- /*
- * must-single-thread
- */
- def clearBCodeTypes() {
- symExemplars.clear()
- exemplars.clear()
- }
-
- val PublicStatic = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC
- val PublicStaticFinal = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL
-
- val strMODULE_INSTANCE_FIELD = nme.MODULE_INSTANCE_FIELD.toString
-
- // ------------------------------------------------
- // accessory maps tracking the isInterface, innerClasses, superClass, and supportedInterfaces relations,
- // allowing answering `conforms()` without resorting to typer.
- // ------------------------------------------------
-
- /**
- * TODO @lry should probably be a map form ClassBType to Tracked
- */
- val exemplars = new java.util.concurrent.ConcurrentHashMap[BType, Tracked]
-
- /**
- * Maps class symbols to their corresponding `Tracked` instance.
- */
- val symExemplars = new java.util.concurrent.ConcurrentHashMap[Symbol, Tracked]
-
- /**
- * A `Tracked` instance stores information about a BType. This allows ansering type questions
- * without resolving to the compiler, in a thread-safe manner, in particular isSubtypeOf.
- *
- * @param c the BType described by this `Tracked`
- * @param flags the java flags for the type, computed by BCodeTypes#javaFlags
- * @param sc the bytecode-level superclass if any, null otherwise
- * @param ifaces the interfaces explicitly declared. Not included are those transitively
- * supported, but the utility method `allLeafIfaces()` can be used for that.
- * @param innersChain the containing classes for a non-package-level class `c`, null otherwise.
- *
- * Note: the optimizer may inline anonymous closures, thus eliding those inner classes (no
- * physical class file is emitted for elided classes). Before committing `innersChain` to
- * bytecode, cross-check with the list of elided classes (SI-6546).
- *
- * All methods of this class can-multi-thread
- *
- * TODO @lry c: ClassBType. rename to ClassBTypeInfo
- */
- case class Tracked(c: ClassBType, flags: Int, sc: Tracked, ifaces: Array[Tracked], innersChain: Array[InnerClassEntry]) {
-
- // not a case-field because we initialize it only for JVM classes we emit.
- // TODO @lry make it an Option[List[BType]]
- // TODO: this is currently not used. a commit in the optimizer branch uses this field to
- // re-compute inner classes (ee4c185). leaving it in for now.
- private var _directMemberClasses: List[BType] = null
-
- def directMemberClasses: List[BType] = {
- assert(_directMemberClasses != null, s"getter directMemberClasses() invoked too early for $c")
- _directMemberClasses
- }
-
- def directMemberClasses_=(bs: List[BType]) {
- if (_directMemberClasses != null) {
- // TODO we enter here when both mirror class and plain class are emitted for the same ModuleClassSymbol.
- assert(_directMemberClasses.sameElements(bs))
- }
- _directMemberClasses = bs
- }
-
- /* `isCompilingStdLib` saves the day when compiling:
- * (1) scala.Nothing (the test `c.isNonSpecial` fails for it)
- * (2) scala.Boolean (it has null superClass and is not an interface)
- */
- assert(c.isNonSpecial || isCompilingStdLib /*(1)*/, s"non well-formed plain-type: $this")
- assert(
- if (sc == null) { (c == ObjectReference) || isInterface || isCompilingStdLib /*(2)*/ }
- else { (c != ObjectReference) && !sc.isInterface }
- , "non well-formed plain-type: " + this
- )
- assert(ifaces.forall(i => i.c.isNonSpecial && i.isInterface), s"non well-formed plain-type: $this")
-
- import asm.Opcodes._
- def hasFlags(mask: Int) = (flags & mask) != 0
- def isInterface = hasFlags(ACC_INTERFACE)
- def isFinal = hasFlags(ACC_FINAL)
- def isInnerClass = { innersChain != null }
- def isLambda = {
- // ie isLCC || isTraditionalClosureClass
- isFinal && (c.simpleName.contains(tpnme.ANON_FUN_NAME.toString)) && isFunctionType(c)
- }
-
- /* can-multi-thread */
- def superClasses: List[Tracked] = {
- if (sc == null) Nil else sc :: sc.superClasses
- }
-
- /* can-multi-thread */
- def isSubtypeOf(other: BType): Boolean = {
- assert(other.isNonSpecial, "so called special cases have to be handled in BCodeTypes.conforms()")
-
- if (c == other) return true;
-
- val otherIsIface = exemplars.get(other).isInterface
-
- if (this.isInterface) {
- if (other == ObjectReference) return true;
- if (!otherIsIface) return false;
- }
- else {
- if (sc != null && sc.isSubtypeOf(other)) return true;
- if (!otherIsIface) return false;
- }
-
- var idx = 0
- while (idx < ifaces.length) {
- if (ifaces(idx).isSubtypeOf(other)) return true;
- idx += 1
- }
-
- false
- }
-
- /*
- * The `ifaces` field lists only those interfaces declared by `c`
- * From the set of all supported interfaces, this method discards those which are supertypes of others in the set.
- */
- def allLeafIfaces: Set[Tracked] = {
- if (sc == null) { ifaces.toSet }
- else { minimizeInterfaces(ifaces.toSet ++ sc.allLeafIfaces) }
- }
-
- /*
- * This type may not support in its entirety the interface given by the argument, however it may support some of its super-interfaces.
- * We visualize each such supported subset of the argument's functionality as a "branch". This method returns all such branches.
- *
- * In other words, let Ri be a branch supported by `ib`,
- * this method returns all Ri such that this <:< Ri, where each Ri is maximally deep.
- */
- def supportedBranches(ib: Tracked): Set[Tracked] = {
- assert(ib.isInterface, s"Non-interface argument: $ib")
-
- val result: Set[Tracked] =
- if (this.isSubtypeOf(ib.c)) { Set(ib) }
- else { ib.ifaces.toSet[Tracked].flatMap( bi => supportedBranches(bi) ) }
-
- checkAllInterfaces(result)
-
- result
- }
-
- override def toString = { c.toString }
-
- }
-
- /* must-single-thread */
- final def isDeprecated(sym: Symbol): Boolean = { sym.annotations exists (_ matches definitions.DeprecatedAttr) }
-
- /* must-single-thread */
- final def hasInternalName(sym: Symbol) = { sym.isClass || (sym.isModule && !sym.isMethod) }
-
- /* must-single-thread */
- def getSuperInterfaces(csym: Symbol): List[Symbol] = {
-
- // Additional interface parents based on annotations and other cues
- def newParentForAttr(ann: AnnotationInfo): Symbol = ann.symbol match {
- case definitions.RemoteAttr => definitions.RemoteInterfaceClass
- case _ => NoSymbol
- }
-
- /* Drop redundant interfaces (which are implemented by some other parent) from the immediate parents.
- * In other words, no two interfaces in the result are related by subtyping.
- * This method works on Symbols, a similar one (not duplicate) works on Tracked instances.
- */
- def minimizeInterfaces(lstIfaces: List[Symbol]): List[Symbol] = {
- var rest = lstIfaces
- var leaves = List.empty[Symbol]
- while (!rest.isEmpty) {
- val candidate = rest.head
- val nonLeaf = leaves exists { lsym => lsym isSubClass candidate }
- if (!nonLeaf) {
- leaves = candidate :: (leaves filterNot { lsym => candidate isSubClass lsym })
- }
- rest = rest.tail
- }
-
- leaves
- }
-
- val superInterfaces0: List[Symbol] = csym.mixinClasses
- val superInterfaces = existingSymbols(superInterfaces0 ++ csym.annotations.map(newParentForAttr)).distinct
-
- assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}")
- assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}")
-
- minimizeInterfaces(superInterfaces)
- }
-
- /*
- * Records the superClass and supportedInterfaces relations,
- * so that afterwards queries can be answered without resorting to typer.
- * This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
- * On the other hand, this method does record the inner-class status of the argument, via `buildExemplar()`.
- *
- * must-single-thread
- */
- final def exemplar(csym0: Symbol): Tracked = {
- assert(csym0 != NoSymbol, "NoSymbol can't be tracked")
-
- val csym = {
- if (csym0.isJavaDefined && csym0.isModuleClass) csym0.linkedClassOfClass
- else if (csym0.isModule) csym0.moduleClass
- else csym0 // we track only module-classes and plain-classes
- }
-
- assert(!primitiveTypeMap.contains(csym) || isCompilingStdLib, s"primitive types not tracked here: ${csym.fullName}")
- assert(!phantomTypeMap.contains(csym), s"phantom types not tracked here: ${csym.fullName}")
-
- val opt = symExemplars.get(csym)
- if (opt != null) {
- return opt
- }
- val key = new ClassBType(csym.javaBinaryName.toTypeName)
- assert(key.isNonSpecial || isCompilingStdLib, s"Not a class to track: ${csym.fullName}")
-
- // TODO accomodate the fix for SI-5031 of https://github.com/scala/scala/commit/0527b2549bcada2fda2201daa630369b377d0877
- // TODO Weaken this assertion? buildExemplar() needs to be updated, too. In the meantime, pos/t5031_3 has been moved to test/disabled/pos.
- val whatWasInExemplars = exemplars.get(key)
- assert(whatWasInExemplars == null, "Maps `symExemplars` and `exemplars` got out of synch.")
- val tr = buildExemplar(key, csym)
- symExemplars.put(csym, tr)
- if (csym != csym0) { symExemplars.put(csym0, tr) }
- exemplars.put(tr.c, tr) // tr.c is the hash-consed, internalized, canonical representative for csym's key.
- tr
- }
-
- /*
- * must-single-thread
- */
- private def buildExemplar(key: ClassBType, csym: Symbol): Tracked = {
- val sc =
- if (csym.isImplClass) definitions.ObjectClass
- else csym.superClass
- assert(
- if (csym == definitions.ObjectClass)
- sc == NoSymbol
- else if (csym.isInterface)
- sc == definitions.ObjectClass
- else
- ((sc != NoSymbol) && !sc.isInterface) || isCompilingStdLib,
- "superClass out of order"
- )
- val ifacesArr = getSuperInterfaces(csym).map(exemplar).toArray
-
- val flags = mkFlags(
- javaFlags(csym),
- if (isDeprecated(csym)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag
- )
-
- val tsc = if (sc == NoSymbol) null else exemplar(sc)
-
- val innersChain = saveInnerClassesFor(csym, key)
-
- Tracked(key, flags, tsc, ifacesArr, innersChain)
- }
-
- // ---------------- utilities around interfaces represented by Tracked instances. ----------------
-
- /* Drop redundant interfaces (those which are implemented by some other).
- * In other words, no two interfaces in the result are related by subtyping.
- * This method works on Tracked elements, a similar one (not duplicate) works on Symbols.
- */
- def minimizeInterfaces(lstIfaces: Set[Tracked]): Set[Tracked] = {
- checkAllInterfaces(lstIfaces)
- var rest = lstIfaces.toList
- var leaves = List.empty[Tracked]
- while (!rest.isEmpty) {
- val candidate = rest.head
- val nonLeaf = leaves exists { leaf => leaf.isSubtypeOf(candidate.c) }
- if (!nonLeaf) {
- leaves = candidate :: (leaves filterNot { leaf => candidate.isSubtypeOf(leaf.c) })
- }
- rest = rest.tail
- }
-
- leaves.toSet
- }
-
- def allInterfaces(is: Iterable[Tracked]): Boolean = { is forall { i => i.isInterface } }
- def nonInterfaces(is: Iterable[Tracked]): Iterable[Tracked] = { is filterNot { i => i.isInterface } }
-
- def checkAllInterfaces(ifaces: Iterable[Tracked]) {
- assert(allInterfaces(ifaces), s"Non-interfaces: ${nonInterfaces(ifaces).mkString}")
- }
-
- /*
- * Subtype check `a <:< b` on BTypes that takes into account the JVM built-in numeric promotions (e.g. BYTE to INT).
- * Its operation can be visualized more easily in terms of the Java bytecode type hierarchy.
- * This method used to be called, in the ICode world, TypeKind.<:<()
- *
- * can-multi-thread
- */
- final def conforms(a: BType, b: BType): Boolean = {
- if (a.isArray) { // may be null
- /* Array subtyping is covariant here, as in Java bytecode. Also necessary for Java interop. */
- if ((b == jlCloneableReference) ||
- (b == jioSerializableReference) ||
- (b == AnyRefReference)) { true }
- else if (b.isArray) { conforms(a.asArrayBType.componentType, // TODO @lry change to pattern match, get rid of casts
- b.asArrayBType.componentType) }
- else { false }
- }
- else if (a.isBoxed) { // may be null
- if (b.isBoxed) { a == b }
- else if (b == AnyRefReference) { true }
- else if (!(b.isClass)) { false }
- else { exemplars.get(a).isSubtypeOf(b) } // e.g., java/lang/Double conforms to java/lang/Number
- }
- else if (a.isNullType) { // known to be null
- if (b.isNothingType) { false }
- else if (b.isPrimitive) { false }
- else { true }
- }
- else if (a.isNothingType) { // known to be Nothing
- true
- }
- else if (a == UNIT) {
- b == UNIT
- }
- else if (a.isClass) { // may be null
- if (a.isNothingType) { true }
- else if (b.isClass) { exemplars.get(a).isSubtypeOf(b) }
- else if (b.isArray) { a.isNullType } // documentation only, because `if(a.isNullType)` (above) covers this case already.
- else { false }
- }
- else {
-
- def msg = s"(a: $a, b: $b)"
-
- assert(a.isNonVoidPrimitiveType, s"a isn't a non-Unit value type. $msg")
- assert(b.isPrimitive, s"b isn't a value type. $msg")
-
- (a eq b) || (a match {
- case BOOL | BYTE | SHORT | CHAR => b == INT || b == LONG // TODO Actually, BOOL does NOT conform to LONG. Even with adapt().
- case _ => a == b
- })
- }
- }
-
- /* The maxValueType of (Char, Byte) and of (Char, Short) is Int, to encompass the negative values of Byte and Short. See ticket #2087.
- *
- * can-multi-thread
- */
- def maxValueType(a: BType, other: BType): BType = {
- assert(a.isPrimitive, "maxValueType() is defined only for 1st arg valuetypes (2nd arg doesn't matter).")
-
- def uncomparable: Nothing = {
- abort(s"Uncomparable BTypes: $a with $other")
- }
-
- if (a.isNothingType) return other;
- if (other.isNothingType) return a;
- if (a == other) return a;
-
- a match {
-
- case UNIT => uncomparable
- case BOOL => uncomparable
-
- case BYTE =>
- if (other == CHAR) INT
- else if (other.isNumericType) other
- else uncomparable
-
- case SHORT =>
- other match {
- case BYTE => SHORT
- case CHAR => INT
- case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
- }
-
- case CHAR =>
- other match {
- case BYTE | SHORT => INT
- case INT | LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
- }
-
- case INT =>
- other match {
- case BYTE | SHORT | CHAR => INT
- case LONG | FLOAT | DOUBLE => other
- case _ => uncomparable
- }
-
- case LONG =>
- if (other.isIntegralType) LONG
- else if (other.isRealType) DOUBLE
- else uncomparable
-
- case FLOAT =>
- if (other == DOUBLE) DOUBLE
- else if (other.isNumericType) FLOAT
- else uncomparable
-
- case DOUBLE =>
- if (other.isNumericType) DOUBLE
- else uncomparable
-
- case _ => uncomparable
- }
- }
-
- /* Takes promotions of numeric primitives into account.
- *
- * can-multi-thread
- */
- final def maxType(a: BType, other: BType): BType = {
- if (a.isPrimitive) { maxValueType(a, other) }
- else {
- if (a.isNothingType) return other;
- if (other.isNothingType) return a;
- if (a == other) return a;
- // Approximate `lub`. The common type of two references is always AnyRef.
- // For 'real' least upper bound wrt to subclassing use method 'lub'.
- assert(a.isArray || a.isBoxed || a.isClass, s"This is not a valuetype and it's not something else, what is it? $a")
- // TODO For some reason, ICode thinks `REFERENCE(...).maxType(BOXED(whatever))` is `uncomparable`. Here, that has maxType AnyRefReference.
- // BTW, when swapping arguments, ICode says BOXED(whatever).maxType(REFERENCE(...)) == AnyRefReference, so I guess the above was an oversight in REFERENCE.maxType()
- if (other.isRef) { AnyRefReference }
- else { abort(s"Uncomparable BTypes: $a with $other") }
- }
- }
-
- /*
- * Whether the argument is a subtype of
- * scala.PartialFunction[-A, +B] extends (A => B)
- * N.B.: this method returns true for a scala.runtime.AbstractPartialFunction
- *
- * can-multi-thread
- */
- def isPartialFunctionType(t: BType): Boolean = {
- (t.isClass) && exemplars.get(t).isSubtypeOf(PartialFunctionReference)
- }
-
- /*
- * Whether the argument is a subtype of scala.FunctionX where 0 <= X <= definitions.MaxFunctionArity
- *
- * can-multi-thread
- */
- def isFunctionType(t: BType): Boolean = {
- if (!t.isClass) return false
- var idx = 0
- val et: Tracked = exemplars.get(t)
- while (idx <= definitions.MaxFunctionArity) {
- if (et.isSubtypeOf(FunctionReference(idx).c)) {
- return true
- }
- idx += 1
- }
- false
- }
-
- /*
- * must-single-thread
- */
- def isTopLevelModule(sym: Symbol): Boolean = {
- exitingPickler { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass }
- }
-
- /*
- * must-single-thread
- */
- def isStaticModule(sym: Symbol): Boolean = {
- sym.isModuleClass && !sym.isImplClass && !sym.isLifted
- }
-
- // ---------------------------------------------------------------------
- // ---------------- InnerClasses attribute (JVMS 4.7.6) ----------------
- // ---------------------------------------------------------------------
-
- val INNER_CLASSES_FLAGS =
- (asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_PRIVATE | asm.Opcodes.ACC_PROTECTED |
- asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_INTERFACE | asm.Opcodes.ACC_ABSTRACT | asm.Opcodes.ACC_FINAL)
-
- /*
- * @param name the internal name of an inner class.
- * @param outerName the internal name of the class to which the inner class belongs.
- * May be `null` for non-member inner classes (ie for a Java local class or a Java anonymous class).
- * @param innerName the (simple) name of the inner class inside its enclosing class. It's `null` for anonymous inner classes.
- * @param access the access flags of the inner class as originally declared in the enclosing class.
- */
- case class InnerClassEntry(name: String, outerName: String, innerName: String, access: Int) {
- assert(name != null, "Null isn't good as class name in an InnerClassEntry.")
- }
-
- /* For given symbol return a symbol corresponding to a class that should be declared as inner class.
- *
- * For example:
- * class A {
- * class B
- * object C
- * }
- *
- * then method will return:
- * NoSymbol for A,
- * the same symbol for A.B (corresponding to A$B class), and
- * A$C$ symbol for A.C.
- *
- * must-single-thread
- */
- def innerClassSymbolFor(s: Symbol): Symbol =
- if (s.isClass) s else if (s.isModule) s.moduleClass else NoSymbol
-
- /*
- * Computes the chain of inner-class (over the is-member-of relation) for the given argument.
- * The resulting chain will be cached in `exemplars`.
- *
- * The chain thus cached is valid during this compiler run, see in contrast
- * `innerClassBufferASM` for a cache that is valid only for the class being emitted.
- *
- * The argument can be any symbol, but given that this method is invoked only from `buildExemplar()`,
- * in practice it has been vetted to be a class-symbol.
- *
- * Returns:
- *
- * - a non-empty array of entries for an inner-class argument.
- * The array's first element is the outermost top-level class,
- * the array's last element corresponds to csym.
- *
- * - null otherwise.
- *
- * This method does not add to `innerClassBufferASM`, use instead `exemplar()` for that.
- *
- * must-single-thread
- */
- final def saveInnerClassesFor(csym: Symbol, csymTK: BType): Array[InnerClassEntry] = {
-
- val ics = innerClassSymbolFor(csym)
- if (ics == NoSymbol) {
- return null
- }
- assert(ics == csym, s"Disagreement between innerClassSymbolFor() and exemplar()'s tracked symbol for the same input: ${csym.fullName}")
-
- var chain: List[Symbol] = Nil
- var x = ics
- while (x ne NoSymbol) {
- assert(x.isClass, s"not a class symbol: ${x.fullName}")
- val isInner = !x.rawowner.isPackageClass
- if (isInner) {
- chain ::= x
- x = innerClassSymbolFor(x.rawowner)
- } else {
- x = NoSymbol
- }
- }
-
- if (chain.isEmpty) null
- else chain.map(toInnerClassEntry).toArray
- }
-
- /*
- * must-single-thread
- */
- private def toInnerClassEntry(innerSym: Symbol): InnerClassEntry = {
-
- /* The outer name for this inner class. Note that it returns null
- * when the inner class should not get an index in the constant pool.
- * That means non-member classes (anonymous). See Section 4.7.5 in the JVMS.
- */
- def outerName(innerSym: Symbol): Name = {
- if (innerSym.originalEnclosingMethod != NoSymbol)
- null
- else {
- val outerName = innerSym.rawowner.javaBinaryName
- if (isTopLevelModule(innerSym.rawowner)) nme.stripModuleSuffix(outerName)
- else outerName
- }
- }
-
- def innerName(innerSym: Symbol): String = {
- if (innerSym.isAnonymousClass || innerSym.isAnonymousFunction)
- null
- else
- innerSym.rawname + innerSym.moduleSuffix
- }
-
- val flagsWithFinal: Int = mkFlags(
- if (innerSym.rawowner.hasModuleFlag) asm.Opcodes.ACC_STATIC else 0,
- javaFlags(innerSym),
- if (isDeprecated(innerSym)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo-access flag
- ) & (INNER_CLASSES_FLAGS | asm.Opcodes.ACC_DEPRECATED)
- val flags = if (innerSym.isModuleClass) flagsWithFinal & ~asm.Opcodes.ACC_FINAL else flagsWithFinal // For SI-5676, object overriding.
-
- val jname = innerSym.javaBinaryName.toString // never null
- val oname = { // null when method-enclosed
- val on = outerName(innerSym)
- if (on == null) null else on.toString
- }
- val iname = { // null for anonymous inner class
- val in = innerName(innerSym)
- if (in == null) null else in.toString
- }
-
- InnerClassEntry(jname, oname, iname, flags)
- }
-
- // --------------------------------------------
- // ---------------- Java flags ----------------
- // --------------------------------------------
-
- /*
- * can-multi-thread
- */
- final def hasPublicBitSet(flags: Int) = ((flags & asm.Opcodes.ACC_PUBLIC) != 0)
-
- /*
- * must-single-thread
- */
- final def isRemote(s: Symbol) = (s hasAnnotation definitions.RemoteAttr)
-
- /*
- * Return the Java modifiers for the given symbol.
- * Java modifiers for classes:
- * - public, abstract, final, strictfp (not used)
- * for interfaces:
- * - the same as for classes, without 'final'
- * for fields:
- * - public, private (*)
- * - static, final
- * for methods:
- * - the same as for fields, plus:
- * - abstract, synchronized (not used), strictfp (not used), native (not used)
- *
- * (*) protected cannot be used, since inner classes 'see' protected members,
- * and they would fail verification after lifted.
- *
- * must-single-thread
- */
- def javaFlags(sym: Symbol): Int = {
- // constructors of module classes should be private
- // PP: why are they only being marked private at this stage and not earlier?
- val privateFlag =
- sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModule(sym.owner))
-
- // Final: the only fields which can receive ACC_FINAL are eager vals.
- // Neither vars nor lazy vals can, because:
- //
- // Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
- // "Another problem is that the specification allows aggressive
- // optimization of final fields. Within a thread, it is permissible to
- // reorder reads of a final field with those modifications of a final
- // field that do not take place in the constructor."
- //
- // A var or lazy val which is marked final still has meaning to the
- // scala compiler. The word final is heavily overloaded unfortunately;
- // for us it means "not overridable". At present you can't override
- // vars regardless; this may change.
- //
- // The logic does not check .isFinal (which checks flags for the FINAL flag,
- // and includes symbols marked lateFINAL) instead inspecting rawflags so
- // we can exclude lateFINAL. Such symbols are eligible for inlining, but to
- // avoid breaking proxy software which depends on subclassing, we do not
- // emit ACC_FINAL.
- // Nested objects won't receive ACC_FINAL in order to allow for their overriding.
-
- val finalFlag = (
- (((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModule(sym))
- && !sym.enclClass.isInterface
- && !sym.isClassConstructor
- && !sym.isMutable // lazy vals and vars both
- )
-
- // Primitives are "abstract final" to prohibit instantiation
- // without having to provide any implementations, but that is an
- // illegal combination of modifiers at the bytecode level so
- // suppress final if abstract if present.
- import asm.Opcodes._
- mkFlags(
- if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
- if (sym.isDeferred || sym.hasAbstractFlag) ACC_ABSTRACT else 0,
- if (sym.isInterface) ACC_INTERFACE else 0,
- if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0,
- if (sym.isStaticMember) ACC_STATIC else 0,
- if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
- if (sym.isArtifact) ACC_SYNTHETIC else 0,
- if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
- if (sym.hasEnumFlag) ACC_ENUM else 0,
- if (sym.isVarargsMethod) ACC_VARARGS else 0,
- if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0
- )
- }
-
- /*
- * must-single-thread
- */
- def javaFieldFlags(sym: Symbol) = {
- javaFlags(sym) | mkFlags(
- if (sym hasAnnotation definitions.TransientAttr) asm.Opcodes.ACC_TRANSIENT else 0,
- if (sym hasAnnotation definitions.VolatileAttr) asm.Opcodes.ACC_VOLATILE else 0,
- if (sym.isMutable) 0 else asm.Opcodes.ACC_FINAL
- )
- }
-
-} // end of class BCodeTypes
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
index 5b0fa6f7a8..7bf61b4f51 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala
@@ -1,37 +1,57 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
package scala.tools.nsc
package backend.jvm
-import scala.collection.immutable
-import scala.annotation.switch
import scala.tools.asm
import asm.Opcodes
-import scala.collection.mutable.ListBuffer
/**
- * BTypes is a backend component that defines the class BType, a number of basic instances and
- * some utilities.
- *
- * A BType is essentially an slice of the array `chrs` denoting the name of the type, and a field
- * denoting the kind (object, array, method, or one of the primitive types).
+ * The BTypes component defines The BType class hierarchy. BTypes encapsulates all type information
+ * that is required after building the ASM nodes. This includes optimizations, geneartion of
+ * InnerClass attributes and generation of stack map frames.
*
- * BTypes depends on Global just because it re-uses hash-consing of Name. It would be cleaner to
- * create an interface for BTypeName and extend it in scala.reflect.internal.Names#Name, that
- * would simplify testing BTypes (no Global needed).
+ * This representation is immutable and independent of the compiler data structures, hence it can
+ * be queried by concurrent threads.
*/
-abstract class BTypes[G <: Global](val __global_dont_use: G) {
- def chrs: Array[Char]
+abstract class BTypes {
+ /**
+ * A map from internal names to ClassBTypes. Every ClassBType is added to this map on its
+ * construction.
+ *
+ * This map is used when computing stack map frames. The asm.ClassWriter invokes the method
+ * `getCommonSuperClass`. In this method we need to obtain the ClassBType for a given internal
+ * name. The method assumes that every class type that appears in the bytecode exists in the map.
+ *
+ * Concurrent because stack map frames are computed when in the class writer, which might run
+ * on multiple classes concurrently.
+ */
+ protected val classBTypeFromInternalNameMap: collection.concurrent.Map[String, ClassBType]
/**
- * Interface for names stored in `chrs`
+ * The string represented by the `offset` / `length` values of a ClassBType, see comment of that
+ * class.
*/
- type BTypeName <: __global_dont_use.Name
+ protected def internalNameString(offset: Int, lenght: Int): String
/**
- * Create a new name in `chrs`. Names are assumed to be hash-consed. Equality on BType will use
- * reference equality to compare the names.
+ * Obtain a previously constructed ClassBType for a given internal name.
*/
- def createNewName(s: String): BTypeName
+ def classBTypeFromInternalName(internalName: String) = classBTypeFromInternalNameMap(internalName)
+
+ // Some core BTypes are required here, in class BType, where no Global instance is available.
+ // The Global is only available in the subclass BTypesFromSymbols. We cannot depend on the actual
+ // implementation (CoreBTypesProxy) here because it has members that refer to global.Symbol.
+ val coreBTypes: CoreBTypesProxyGlobalIndependent[this.type]
+ import coreBTypes._
+ /**
+ * A BType is either a primitve type, a ClassBType, an ArrayBType of one of these, or a MethodType
+ * referring to BTypes.
+ */
/*sealed*/ trait BType { // Not sealed for now due to SI-8546
final override def toString: String = this match {
case UNIT => "V"
@@ -43,9 +63,9 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
case FLOAT => "F"
case LONG => "J"
case DOUBLE => "D"
- case c @ ClassBType(_, _) => "L" + c.internalName + ";"
- case ArrayBType(component) => "[" + component
- case MethodBType(args, res) => "(" + args.mkString + ")" + res
+ case ClassBType(internalName) => "L" + internalName + ";"
+ case ArrayBType(component) => "[" + component
+ case MethodBType(args, res) => "(" + args.mkString + ")" + res
}
/**
@@ -73,18 +93,11 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
final def isMethod: Boolean = this.isInstanceOf[MethodBType]
final def isNonVoidPrimitiveType = isPrimitive && this != UNIT
- // TODO @lry should also include !isMethod in isNonSpecial? in this case it would be equivalent to isClass, so we could get rid of it.
- final def isNonSpecial = !isPrimitive && !isArray && !isPhantomType
- final def isNullType = this == RT_NULL || this == CT_NULL
- final def isNothingType = this == RT_NOTHING || this == CT_NOTHING
- final def isPhantomType = isNullType || isNothingType
-
- final def isBoxed = this match {
- case BOXED_UNIT | BOXED_BOOLEAN | BOXED_CHAR |
- BOXED_BYTE | BOXED_SHORT | BOXED_INT |
- BOXED_FLOAT | BOXED_LONG | BOXED_DOUBLE => true
- case _ => false
- }
+
+ final def isNullType = this == RT_NULL
+ final def isNothingType = this == RT_NOTHING
+
+ final def isBoxed = this.isClass && boxedClasses(this.asClassBType)
final def isIntSizedType = this == BOOL || this == CHAR || this == BYTE ||
this == SHORT || this == INT
@@ -94,6 +107,72 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
final def isNumericType = isIntegralType || isRealType
final def isWideType = size == 2
+ /*
+ * Subtype check `this <:< other` on BTypes that takes into account the JVM built-in numeric
+ * promotions (e.g. BYTE to INT). Its operation can be visualized more easily in terms of the
+ * Java bytecode type hierarchy.
+ */
+ final def conformsTo(other: BType): Boolean = {
+ assert(isRef || isPrimitive, s"conformsTo cannot handle $this")
+ assert(other.isRef || other.isPrimitive, s"conformsTo cannot handle $other")
+
+ this match {
+ case ArrayBType(component) =>
+ if (other == ObjectReference || other == jlCloneableReference || other == jioSerializableReference) true
+ else other match {
+ case ArrayBType(otherComponoent) => component.conformsTo(otherComponoent)
+ case _ => false
+ }
+
+ case classType: ClassBType =>
+ if (isBoxed) {
+ if (other.isBoxed) this == other
+ else if (other == ObjectReference) true
+ else other match {
+ case otherClassType: ClassBType => classType.isSubtypeOf(otherClassType) // e.g., java/lang/Double conforms to java/lang/Number
+ case _ => false
+ }
+ } else if (isNullType) {
+ if (other.isNothingType) false
+ else if (other.isPrimitive) false
+ else true // Null conforms to all classes (except Nothing) and arrays.
+ } else if (isNothingType) {
+ true
+ } else other match {
+ case otherClassType: ClassBType => classType.isSubtypeOf(otherClassType)
+ // case ArrayBType(_) => this.isNullType // documentation only, because `if (isNullType)` above covers this case
+ case _ =>
+ // isNothingType || // documentation only, because `if (isNothingType)` above covers this case
+ false
+ }
+
+ case UNIT =>
+ other == UNIT
+ case BOOL | BYTE | SHORT | CHAR =>
+ this == other || other == INT || other == LONG // TODO Actually, BOOL does NOT conform to LONG. Even with adapt().
+ case _ =>
+ assert(isPrimitive && other.isPrimitive, s"Expected primitive types $this - $other")
+ this == other
+ }
+ }
+
+ /**
+ * Compute the upper bound of two types.
+ * Takes promotions of numeric primitives into account.
+ */
+ final def maxType(other: BType): BType = this match {
+ case pt: PrimitiveBType => pt.maxValueType(other)
+
+ case _: ArrayBType | _: ClassBType =>
+ if (isNothingType) return other
+ if (other.isNothingType) return this
+ if (this == other) return this
+
+ assert(other.isRef, s"Cannot compute maxType: $this, $other")
+ // Approximate `lub`. The common type of two references is always ObjectReference.
+ ObjectReference
+ }
+
/**
* See documentation of [[typedOpcode]].
* The numbers are taken from asm.Type.VOID_TYPE ff., the values are those shifted by << 8.
@@ -160,50 +239,82 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
case FLOAT => asm.Type.FLOAT_TYPE
case LONG => asm.Type.LONG_TYPE
case DOUBLE => asm.Type.DOUBLE_TYPE
- case c @ ClassBType(_, _) => asm.Type.getObjectType(c.internalName) // (*)
- case a @ ArrayBType(_) => asm.Type.getObjectType(a.descriptor)
- case m @ MethodBType(_, _) => asm.Type.getMethodType(m.descriptor)
+ case ClassBType(internalName) => asm.Type.getObjectType(internalName) // see (*) above
+ case a: ArrayBType => asm.Type.getObjectType(a.descriptor)
+ case m: MethodBType => asm.Type.getMethodType(m.descriptor)
}
- def asRefBType : RefBType = this.asInstanceOf[RefBType]
- def asArrayBType: ArrayBType = this.asInstanceOf[ArrayBType]
- def asClassBType: ClassBType = this.asInstanceOf[ClassBType]
+ def asRefBType : RefBType = this.asInstanceOf[RefBType]
+ def asArrayBType : ArrayBType = this.asInstanceOf[ArrayBType]
+ def asClassBType : ClassBType = this.asInstanceOf[ClassBType]
+ def asPrimitiveBType : PrimitiveBType = this.asInstanceOf[PrimitiveBType]
}
- object BType {
+ sealed trait PrimitiveBType extends BType {
+
/**
- * @param chars The character array containing the descriptor
- * @param start The position where the descriptor starts
- * @return The BType and the index of the first character after the consumed descriptor
+ * The upper bound of two primitive types. The `other` type has to be either a primitive
+ * type or Nothing.
+ *
+ * The maxValueType of (Char, Byte) and of (Char, Short) is Int, to encompass the negative
+ * values of Byte and Short. See ticket #2087.
*/
- private[BTypes] def fromNonMethodDescriptor(chars: Array[Char], start: Int): (BType, Int) = {
- chars(start) match {
- case 'L' =>
- var i = start
- while (chars(i) != ';') { i += 1 }
- // Example: chars = "IILpkg/Cls;I"
- // ^ ^
- // start=2 i=10
- // `start + 1` to exclude the 'L', `i - start - 1` excludes the ';'
- (new ClassBType(new String(chars, start + 1, i - start - 1)), i + 1)
- case '[' =>
- val (res, next) = fromNonMethodDescriptor(chars, start + 1)
- (ArrayBType(res), next)
- case 'V' => (UNIT, start + 1)
- case 'Z' => (BOOL, start + 1)
- case 'C' => (CHAR, start + 1)
- case 'B' => (BYTE, start + 1)
- case 'S' => (SHORT, start + 1)
- case 'I' => (INT, start + 1)
- case 'F' => (FLOAT, start + 1)
- case 'J' => (LONG, start + 1)
- case 'D' => (DOUBLE, start + 1)
+ final def maxValueType(other: BType): BType = {
+
+ def uncomparable: Nothing = throw new AssertionError(s"Cannot compute maxValueType: $this, $other")
+
+ if (!other.isPrimitive && !other.isNothingType) uncomparable
+
+ if (other.isNothingType) return this
+ if (this == other) return this
+
+ this match {
+ case BYTE =>
+ if (other == CHAR) INT
+ else if (other.isNumericType) other
+ else uncomparable
+
+ case SHORT =>
+ other match {
+ case BYTE => SHORT
+ case CHAR => INT
+ case INT | LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable
+ }
+
+ case CHAR =>
+ other match {
+ case BYTE | SHORT => INT
+ case INT | LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable
+ }
+
+ case INT =>
+ other match {
+ case BYTE | SHORT | CHAR => INT
+ case LONG | FLOAT | DOUBLE => other
+ case _ => uncomparable
+ }
+
+ case LONG =>
+ if (other.isIntegralType) LONG
+ else if (other.isRealType) DOUBLE
+ else uncomparable
+
+ case FLOAT =>
+ if (other == DOUBLE) DOUBLE
+ else if (other.isNumericType) FLOAT
+ else uncomparable
+
+ case DOUBLE =>
+ if (other.isNumericType) DOUBLE
+ else uncomparable
+
+ case UNIT | BOOL => uncomparable
}
}
}
- sealed trait PrimitiveBType extends BType
-
case object UNIT extends PrimitiveBType
case object BOOL extends PrimitiveBType
case object CHAR extends PrimitiveBType
@@ -227,57 +338,408 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
* This can be verified for example using javap or ASMifier.
*/
def classOrArrayType: String = this match {
- case c: ClassBType => c.internalName
- case a: ArrayBType => a.descriptor
+ case ClassBType(internalName) => internalName
+ case a: ArrayBType => a.descriptor
}
}
/**
- * Class or Interface type.
+ * InnerClass and EnclosingMethod attributes (EnclosingMethod is displayed as OUTERCLASS in asm).
+ *
+ * In this summary, "class" means "class or interface".
+ *
+ * JLS: http://docs.oracle.com/javase/specs/jls/se8/html/index.html
+ * JVMS: http://docs.oracle.com/javase/specs/jvms/se8/html/index.html
+ *
+ * Terminology
+ * -----------
+ *
+ * - Nested class (JLS 8): class whose declaration occurs within the body of another class
+ *
+ * - Top-level class (JLS 8): non-nested class
+ *
+ * - Inner class (JLS 8.1.3): nested class that is not (explicitly or implicitly) static
+ *
+ * - Member class (JLS 8.5): class directly enclosed in the body of a class (and not, for
+ * example, defined in a method). Member classes cannot be anonymous. May be static.
+ *
+ * - Local class (JLS 14.3): nested, non-anonymous class that is not a member of a class
+ * - cannot be static (therefore they are "inner" classes)
+ * - can be defined in a method, a constructor or in an initializer block
+ *
+ * - Initializer block (JLS 8.6 / 8.7): block of statements in a java class
+ * - static initializer: executed before constructor body
+ * - instance initializer: exectued when class is initialized (instance creation, static
+ * field access, ...)
+ *
+ * - A static nested class can be defined as
+ * - a static member class (explicitly static), or
+ * - a member class of an interface (implicitly static)
+ * - local classes are never static, even if they are defined in a static method.
+ *
+ * Note: it is NOT the case that all inner classes (non-static) have an outer pointer. Example:
+ * class C { static void foo { class D {} } }
+ * The class D is an inner class (non-static), but javac does not add an outer pointer to it.
+ *
+ * InnerClass
+ * ----------
+ *
+ * The JVMS 4.7.6 requires an entry for every class mentioned in a CONSTANT_Class_info in the
+ * constant pool (CP) that is not a member of a package (JLS 7.1).
+ *
+ * The JLS 13.1, points 9. / 10. requires: a class must reference (in the CP)
+ * - its immediately enclosing class
+ * - all of its member classes
+ * - all local and anonymous classes that are referenced (or declared) elsewhere (method,
+ * constructor, initializer block, field initializer)
+ *
+ * In a comment, the 4.7.6 spec says: this implies an entry in the InnerClass attribute for
+ * - All enclosing classes (except the outermost, which is top-level)
+ * - My comment: not sure how this is implied, below (*) a Java counter-example.
+ * In any case, the Java compiler seems to add all enclosing classes, even if they are not
+ * otherwise mentioned in the CP. So we should do the same.
+ * - All nested classes (including anonymous and local, but not transitively)
+ *
+ * Fields in the InnerClass entries:
+ * - inner class: the (nested) class C we are talking about
+ * - outer class: the class of which C is a member. Has to be null for non-members, i.e. for
+ * local and anonymous classes. NOTE: this co-incides with the presence of an
+ * EnclosingMethod attribute (see below)
+ * - inner name: A string with the simple name of the inner class. Null for anonymous classes.
+ * - flags: access property flags, details in JVMS, table in 4.7.6. Static flag: see
+ * discussion below.
+ *
+ *
+ * Note 1: when a nested class is present in the InnerClass attribute, all of its enclosing
+ * classes have to be present as well (by the rules above). Example:
+ *
+ * class Outer { class I1 { class I2 { } } }
+ * class User { Outer.I1.I2 foo() { } }
+ *
+ * The return type "Outer.I1.I2" puts "Outer$I1$I2" in the CP, therefore the class is added to the
+ * InnerClass attribute. For this entry, the "outer class" field will be "Outer$I1". This in turn
+ * adds "Outer$I1" to the CP, which requires adding that class to the InnerClass attribute.
+ * (For local / anonymous classes this would not be the case, since the "outer class" attribute
+ * would be empty. However, no class (other than the enclosing class) can refer to them, as they
+ * have no name.)
+ *
+ * In the current implementation of the Scala compiler, when adding a class to the InnerClass
+ * attribute, all of its enclosing classes will be added as well. Javac seems to do the same,
+ * see (*).
+ *
+ *
+ * Note 2: If a class name is mentioned only in a CONSTANT_Utf8_info, but not in a
+ * CONSTANT_Class_info, the JVMS does not require an entry in the InnerClass attribute. However,
+ * the Java compiler seems to add such classes anyway. For example, when using an annotation, the
+ * annotation class is stored as a CONSTANT_Utf8_info in the CP:
+ *
+ * @O.Ann void foo() { }
+ *
+ * adds "const #13 = Asciz LO$Ann;;" in the constant pool. The "RuntimeInvisibleAnnotations"
+ * attribute refers to that constant pool entry. Even though there is no other reference to
+ * `O.Ann`, the java compiler adds an entry for that class to the InnerClass attribute (which
+ * entails adding a CONSTANT_Class_info for the class).
+ *
+ *
+ *
+ * EnclosingMethod
+ * ---------------
+ *
+ * JVMS 4.7.7: the attribute must be present "if and only if it represents a local class
+ * or an anonymous class" (i.e. not for member classes).
+ *
+ * The attribute is mis-named, it should be called "EnclosingClass". It has to be defined for all
+ * local and anonymous classes, no matter if there is an enclosing method or not. Accordingly, the
+ * "class" field (see below) must be always defined, while the "method" field may be null.
+ *
+ * NOTE: When a EnclosingMethod attribute is requried (local and anonymous classes), the "outer"
+ * field in the InnerClass table must be null.
+ *
+ * Fields:
+ * - class: the enclosing class
+ * - method: the enclosing method (or constructor). Null if the class is not enclosed by a
+ * method, i.e. for
+ * - local or anonymous classes defined in (static or non-static) initializer blocks
+ * - anonymous classes defined in initializer blocks or field initializers
+ *
+ * Note: the field is required for anonymous classes defined within local variable
+ * initializers (within a method), Java example below (**).
+ *
+ * For local and anonymous classes in initializer blocks or field initializers, and
+ * class-level anonymous classes, the scala compiler sets the "method" field to null.
+ *
+ *
+ * (*)
+ * public class Test {
+ * void foo() {
+ * class Foo1 {
+ * // constructor statement block
+ * {
+ * class Foo2 {
+ * class Foo3 { }
+ * }
+ * }
+ * }
+ * }
+ * }
+ *
+ * The class file Test$1Foo1$1Foo2$Foo3 has no reference to the class Test$1Foo1, however it
+ * still contains an InnerClass attribute for Test$1Foo1.
+ * Maybe this is just because the Java compiler follows the JVMS comment ("InnerClasses
+ * information for each enclosing class").
+ *
+ *
+ * (**)
+ * void foo() {
+ * // anonymous class defined in local variable initializer expression.
+ * Runnable x = true ? (new Runnable() {
+ * public void run() { return; }
+ * }) : null;
+ * }
+ *
+ * The EnclosingMethod attribute of the anonymous class mentions "foo" in the "method" field.
+ *
+ *
+ * Java Compatibility
+ * ------------------
+ *
+ * In the InnerClass entry for classes in top-level modules, the "outer class" is emitted as the
+ * mirror class (or the existing companion class), i.e. C1 is nested in T (not T$).
+ * For classes nested in a nested object, the "outer class" is the module class: C2 is nested in T$N$
+ * object T {
+ * class C1
+ * object N { class C2 }
+ * }
+ *
+ * Reason: java compat. It's a "best effort" "solution". If you want to use "C1" from Java, you
+ * can write "T.C1", and the Java compiler will translate that to the classfile T$C1.
+ *
+ * If we would emit the "outer class" of C1 as "T$", then in Java you'd need to write "T$.C1"
+ * because the java compiler looks at the InnerClass attribute to find if an inner class exists.
+ * However, the Java compiler would then translate the '.' to '$' and you'd get the class name
+ * "T$$C1". This class file obviously does not exist.
+ *
+ * Directly using the encoded class name "T$C1" in Java does not work: since the classfile
+ * describes a nested class, the Java compiler hides it from the classpath and will report
+ * "cannot find symbol T$C1". This means that the class T.N.C2 cannot be referenced from a
+ * Java source file in any way.
+ *
+ *
+ * STATIC flag
+ * -----------
+ *
+ * Java: static member classes have the static flag in the InnerClass attribute, for example B in
+ * class A { static class B { } }
+ *
+ * The spec is not very clear about when the static flag should be emitted. It says: "Marked or
+ * implicitly static in source."
+ *
+ * The presence of the static flag does NOT coincide with the absence of an "outer" field in the
+ * class. The java compiler never puts the static flag for local classes, even if they don't have
+ * an outer pointer:
+ *
+ * class A {
+ * void f() { class B {} }
+ * static void g() { calss C {} }
+ * }
*
- * Classes are represented using their name as a slice of the `chrs` array. This representation is
- * efficient because the JVM class name is initially created using `classSymbol.javaBinaryName`.
- * This already adds the necessary string to the `chrs` array, so it makes sense to reuse the same
- * name table in the backend.
+ * B has an outer pointer, C doesn't. Both B and C are NOT marked static in the InnerClass table.
*
- * Not a case class because that would expose the (Int, Int) constructor (didn't find a way to
- * make it private, also the factory in the companion).
+ * It seems sane to follow the same principle in the Scala compiler. So:
+ *
+ * package p
+ * object O1 {
+ * class C1 // static inner class
+ * object O2 { // static inner module
+ * def f = {
+ * class C2 { // non-static inner class, even though there's no outer pointer
+ * class C3 // non-static, has an outer pointer
+ * }
+ * }
+ * }
+ * }
+ *
+ * Mirror Classes
+ * --------------
+ *
+ * TODO: innerclass attributes on mirror class, bean info class
*/
- class ClassBType private(val offset: Int, val length: Int) extends RefBType {
- /**
- * Construct a ClassBType for a given (intenred) class name.
- *
- * @param n The class name as a slice of the `chrs` array, without the surrounding 'L' and ';'.
- * Note that `classSymbol.javaBinaryName` returns exactly such a name.
- */
- def this(n: BTypeName) = this(n.start, n.length)
+ /**
+ * A ClassBType represents a class or interface type. The necessary information to build a
+ * ClassBType is extracted from compiler symbols and types, see BTypesFromSymbols.
+ *
+ * The `offset` and `length` fields are used to represent the internal name of the class. They
+ * are indices into some character array. The internal name can be obtained through the method
+ * `internalNameString`, which is abstract in this component. Name creation is assumed to be
+ * hash-consed, so if two ClassBTypes have the same internal name, they NEED to have the same
+ * `offset` and `length`.
+ *
+ * The actual implementation in subclass BTypesFromSymbols uses the global `chrs` array from the
+ * name table. This representation is efficient because the JVM class name is obtained through
+ * `classSymbol.javaBinaryName`. This already adds the necessary string to the `chrs` array,
+ * so it makes sense to reuse the same name table in the backend.
+ *
+ * ClassBType is not a case class because we want a custom equals method, and because the
+ * extractor extracts the internalName, which is what you typically need.
+ */
+ final class ClassBType(val offset: Int, val length: Int) extends RefBType {
/**
- * Construct a ClassBType for a given java class name.
+ * Write-once variable allows initializing a cyclic graph of infos. This is required for
+ * nested classes. Example: for the definition `class A { class B }` we have
*
- * @param s A class name of the form "java/lang/String", without the surrounding 'L' and ';'.
+ * B.info.nestedInfo.outerClass == A
+ * A.info.memberClasses contains B
*/
- def this(s: String) = this({
- assert(!(s.head == 'L' && s.last == ';'), s"Descriptor instead of internal name: $s")
- createNewName(s)
- })
+ private var _info: ClassInfo = null
+
+ def info: ClassInfo = {
+ assert(_info != null, s"ClassBType.info not yet assigned: $this")
+ _info
+ }
+
+ def info_=(i: ClassInfo): Unit = {
+ assert(_info == null, s"Cannot set ClassBType.info multiple times: $this")
+ _info = i
+ checkInfoConsistency()
+ }
+
+ classBTypeFromInternalNameMap(internalName) = this
+
+ private def checkInfoConsistency(): Unit = {
+ // we assert some properties. however, some of the linked ClassBType (members, superClass,
+ // interfaces) may not yet have an `_info` (initialization of cyclic structures). so we do a
+ // best-effort verification.
+ def ifInit(c: ClassBType)(p: ClassBType => Boolean): Boolean = c._info == null || p(c)
+
+ def isJLO(t: ClassBType) = t.internalName == "java/lang/Object"
+
+ assert(!ClassBType.isInternalPhantomType(internalName), s"Cannot create ClassBType for phantom type $this")
+
+ assert(
+ if (info.superClass.isEmpty) { isJLO(this) || (isCompilingPrimitive && ClassBType.hasNoSuper(internalName)) }
+ else if (isInterface) isJLO(info.superClass.get)
+ else !isJLO(this) && ifInit(info.superClass.get)(!_.isInterface),
+ s"Invalid superClass in $this: ${info.superClass}"
+ )
+ assert(
+ info.interfaces.forall(c => ifInit(c)(_.isInterface)),
+ s"Invalid interfaces in $this: ${info.interfaces}"
+ )
+
+ assert(info.memberClasses.forall(c => ifInit(c)(_.isNestedClass)), info.memberClasses)
+ }
/**
* The internal name of a class is the string returned by java.lang.Class.getName, with all '.'
* replaced by '/'. For example "java/lang/String".
*/
- def internalName: String = new String(chrs, offset, length)
+ def internalName: String = internalNameString(offset, length)
/**
* @return The class name without the package prefix
*/
def simpleName: String = internalName.split("/").last
+ def isInterface = (info.flags & asm.Opcodes.ACC_INTERFACE) != 0
+
+ def superClassesTransitive: List[ClassBType] = info.superClass match {
+ case None => Nil
+ case Some(sc) => sc :: sc.superClassesTransitive
+ }
+
+ def isNestedClass = info.nestedInfo.isDefined
+
+ def enclosingNestedClassesChain: List[ClassBType] =
+ if (isNestedClass) this :: info.nestedInfo.get.enclosingClass.enclosingNestedClassesChain
+ else Nil
+
+ def innerClassAttributeEntry: Option[InnerClassEntry] = info.nestedInfo map {
+ case NestedInfo(_, outerName, innerName, isStaticNestedClass) =>
+ InnerClassEntry(
+ internalName,
+ outerName.orNull,
+ innerName.orNull,
+ GenBCode.mkFlags(
+ info.flags,
+ if (isStaticNestedClass) asm.Opcodes.ACC_STATIC else 0
+ ) & ClassBType.INNER_CLASSES_FLAGS
+ )
+ }
+
+ def isSubtypeOf(other: ClassBType): Boolean = {
+ if (this == other) return true
+
+ if (isInterface) {
+ if (other == ObjectReference) return true // interfaces conform to Object
+ if (!other.isInterface) return false // this is an interface, the other is some class other than object. interfaces cannot extend classes, so the result is false.
+ // else: this and other are both interfaces. continue to (*)
+ } else {
+ val sc = info.superClass
+ if (sc.isDefined && sc.get.isSubtypeOf(other)) return true // the superclass of this class conforms to other
+ if (!other.isInterface) return false // this and other are both classes, and the superclass of this does not conform
+ // else: this is a class, the other is an interface. continue to (*)
+ }
+
+ // (*) check if some interface of this class conforms to other.
+ info.interfaces.exists(_.isSubtypeOf(other))
+ }
+
+ /**
+ * Finding the least upper bound in agreement with the bytecode verifier
+ * Background:
+ * http://gallium.inria.fr/~xleroy/publi/bytecode-verification-JAR.pdf
+ * http://comments.gmane.org/gmane.comp.java.vm.languages/2293
+ * https://issues.scala-lang.org/browse/SI-3872
+ */
+ def jvmWiseLUB(other: ClassBType): ClassBType = {
+ def isNotNullOrNothing(c: ClassBType) = !c.isNullType && !c.isNothingType
+ assert(isNotNullOrNothing(this) && isNotNullOrNothing(other), s"jvmWiseLub for null or nothing: $this - $other")
+
+ val res: ClassBType = (this.isInterface, other.isInterface) match {
+ case (true, true) =>
+ // exercised by test/files/run/t4761.scala
+ if (other.isSubtypeOf(this)) this
+ else if (this.isSubtypeOf(other)) other
+ else ObjectReference
+
+ case (true, false) =>
+ if (other.isSubtypeOf(this)) this else ObjectReference
+
+ case (false, true) =>
+ if (this.isSubtypeOf(other)) other else ObjectReference
+
+ case _ =>
+ // TODO @lry I don't really understand the reasoning here.
+ // Both this and other are classes. The code takes (transitively) all superclasses and
+ // finds the first common one.
+ firstCommonSuffix(this :: this.superClassesTransitive, other :: other.superClassesTransitive)
+ }
+
+ assert(isNotNullOrNothing(res), s"jvmWiseLub computed: $res")
+ res
+ }
+
+ private def firstCommonSuffix(as: List[ClassBType], bs: List[ClassBType]): ClassBType = {
+ var chainA = as
+ var chainB = bs
+ var fcs: ClassBType = null
+ do {
+ if (chainB contains chainA.head) fcs = chainA.head
+ else if (chainA contains chainB.head) fcs = chainB.head
+ else {
+ chainA = chainA.tail
+ chainB = chainB.tail
+ }
+ } while (fcs == null)
+ fcs
+ }
+
/**
- * Custom equals / hashCode are needed because this is not a case class.
+ * Custom equals / hashCode: we only compare the name (offset / length)
*/
override def equals(o: Any): Boolean = (this eq o.asInstanceOf[Object]) || (o match {
- case ClassBType(`offset`, `length`) => true
+ case c: ClassBType => c.offset == this.offset && c.length == this.length
case _ => false
})
@@ -291,14 +753,92 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
}
object ClassBType {
- def apply(n: BTypeName): ClassBType = new ClassBType(n)
- def apply(s: String): ClassBType = new ClassBType(s)
-
- def unapply(c: ClassBType): Option[(Int, Int)] =
+ /**
+ * Pattern matching on a ClassBType extracts the `internalName` of the class.
+ */
+ def unapply(c: ClassBType): Option[String] =
if (c == null) None
- else Some((c.offset, c.length))
+ else Some(c.internalName)
+
+ /**
+ * Valid flags for InnerClass attribute entry.
+ * See http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6
+ */
+ private val INNER_CLASSES_FLAGS = {
+ asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_PRIVATE | asm.Opcodes.ACC_PROTECTED |
+ asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL | asm.Opcodes.ACC_INTERFACE |
+ asm.Opcodes.ACC_ABSTRACT | asm.Opcodes.ACC_SYNTHETIC | asm.Opcodes.ACC_ANNOTATION |
+ asm.Opcodes.ACC_ENUM
+ }
+
+ // Primitive classes have no super class. A ClassBType for those is only created when
+ // they are actually being compiled (e.g., when compiling scala/Boolean.scala).
+ private val hasNoSuper = Set(
+ "scala/Unit",
+ "scala/Boolean",
+ "scala/Char",
+ "scala/Byte",
+ "scala/Short",
+ "scala/Int",
+ "scala/Float",
+ "scala/Long",
+ "scala/Double"
+ )
+
+ private val isInternalPhantomType = Set(
+ "scala/Null",
+ "scala/Nothing"
+ )
}
+ /**
+ * The type info for a class. Used for symboltable-independent subtype checks in the backend.
+ *
+ * @param superClass The super class, not defined for class java/lang/Object.
+ * @param interfaces All transitively implemented interfaces, except for those inherited
+ * through the superclass.
+ * @param flags The java flags, obtained through `javaFlags`. Used also to derive
+ * the flags for InnerClass entries.
+ * @param memberClasses Classes nested in this class. Those need to be added to the
+ * InnerClass table, see the InnerClass spec summary above.
+ * @param nestedInfo If this describes a nested class, information for the InnerClass table.
+ */
+ case class ClassInfo(superClass: Option[ClassBType], interfaces: List[ClassBType], flags: Int,
+ memberClasses: List[ClassBType], nestedInfo: Option[NestedInfo])
+
+ /**
+ * Information required to add a class to an InnerClass table.
+ * The spec summary above explains what information is required for the InnerClass entry.
+ *
+ * @param enclosingClass The enclosing class, if it is also nested. When adding a class
+ * to the InnerClass table, enclosing nested classes are also added.
+ * @param outerName The outerName field in the InnerClass entry, may be None.
+ * @param innerName The innerName field, may be None.
+ * @param isStaticNestedClass True if this is a static nested class (not inner class) (*)
+ *
+ * (*) Note that the STATIC flag in ClassInfo.flags, obtained through javaFlags(classSym), is not
+ * correct for the InnerClass entry, see javaFlags. The static flag in the InnerClass describes
+ * a source-level propety: if the class is in a static context (does not have an outer pointer).
+ * This is checked when building the NestedInfo.
+ */
+ case class NestedInfo(enclosingClass: ClassBType,
+ outerName: Option[String],
+ innerName: Option[String],
+ isStaticNestedClass: Boolean)
+
+ /**
+ * This class holds the data for an entry in the InnerClass table. See the InnerClass summary
+ * above in this file.
+ *
+ * There's some overlap with the class NestedInfo, but it's not exactly the same and cleaner to
+ * keep separate.
+ * @param name The internal name of the class.
+ * @param outerName The internal name of the outer class, may be null.
+ * @param innerName The simple name of the inner class, may be null.
+ * @param flags The flags for this class in the InnerClass entry.
+ */
+ case class InnerClassEntry(name: String, outerName: String, innerName: String, flags: Int)
+
case class ArrayBType(componentType: BType) extends RefBType {
def dimension: Int = componentType match {
case a: ArrayBType => 1 + a.dimension
@@ -311,107 +851,23 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) {
}
}
- case class MethodBType(argumentTypes: List[BType], returnType: BType) extends BType {
- private def this(types: (List[BType], BType)) = this(types._1, types._2)
- def this(descriptor: String) = this(MethodBType.decomposeMethodDescriptor(descriptor))
- }
+ case class MethodBType(argumentTypes: List[BType], returnType: BType) extends BType
- object MethodBType {
- private def decomposeMethodDescriptor(descriptor: String): (List[BType], BType) = {
- val chars = descriptor.toCharArray
- assert(chars(0) == '(', s"Not a valid method descriptor: $descriptor")
- var i = 1
- val argTypes = new ListBuffer[BType]
- while (chars(i) != ')') {
- val (argType, next) = BType.fromNonMethodDescriptor(chars, i)
- argTypes += argType
- i = next
- }
- val (resType, _) = BType.fromNonMethodDescriptor(chars, i + 1) // `i + 1` to skip the ')'
- (argTypes.toList, resType)
- }
- def apply(descriptor: String) = {
- val (argTypes, resType) = decomposeMethodDescriptor(descriptor)
- new MethodBType(argTypes, resType)
- }
- }
-
- val BOXED_UNIT = ClassBType("java/lang/Void")
- val BOXED_BOOLEAN = ClassBType("java/lang/Boolean")
- val BOXED_BYTE = ClassBType("java/lang/Byte")
- val BOXED_SHORT = ClassBType("java/lang/Short")
- val BOXED_CHAR = ClassBType("java/lang/Character")
- val BOXED_INT = ClassBType("java/lang/Integer")
- val BOXED_LONG = ClassBType("java/lang/Long")
- val BOXED_FLOAT = ClassBType("java/lang/Float")
- val BOXED_DOUBLE = ClassBType("java/lang/Double")
-
- /*
- * RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
- * method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
- *
- * Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
- * names of NothingClass and NullClass can't be emitted as-is.
+ /* Some definitions that are required for the implementation of BTypes. They are abstract because
+ * initializing them requires information from types / symbols, which is not accessible here in
+ * BTypes.
+ *
+ * They are defs (not vals) because they are implemented using vars (see comment on CoreBTypes).
*/
- val RT_NOTHING = ClassBType("scala/runtime/Nothing$")
- val RT_NULL = ClassBType("scala/runtime/Null$")
- val CT_NOTHING = ClassBType("scala/Nothing")
- val CT_NULL = ClassBType("scala/Null")
-
- val srBooleanRef = ClassBType("scala/runtime/BooleanRef")
- val srByteRef = ClassBType("scala/runtime/ByteRef")
- val srCharRef = ClassBType("scala/runtime/CharRef")
- val srIntRef = ClassBType("scala/runtime/IntRef")
- val srLongRef = ClassBType("scala/runtime/LongRef")
- val srFloatRef = ClassBType("scala/runtime/FloatRef")
- val srDoubleRef = ClassBType("scala/runtime/DoubleRef")
/**
- * Map from type kinds to the Java reference types.
- * Useful when pushing class literals onto the operand stack (ldc instruction taking a class
- * literal).
- * @see Predef.classOf
- * @see genConstant()
- *
- * TODO @lry rename to "boxedClassOfPrimitive" or so, check usages
+ * Just a named pair, used in CoreBTypes.asmBoxTo/asmUnboxTo.
*/
- val classLiteral = immutable.Map[BType, ClassBType](
- UNIT -> BOXED_UNIT,
- BOOL -> BOXED_BOOLEAN,
- BYTE -> BOXED_BYTE,
- SHORT -> BOXED_SHORT,
- CHAR -> BOXED_CHAR,
- INT -> BOXED_INT,
- LONG -> BOXED_LONG,
- FLOAT -> BOXED_FLOAT,
- DOUBLE -> BOXED_DOUBLE
- )
-
- case class MethodNameAndType(name: String, descriptor: String)
-
- val asmBoxTo: immutable.Map[BType, MethodNameAndType] = {
- Map(
- BOOL -> MethodNameAndType("boxToBoolean", "(Z)Ljava/lang/Boolean;" ) ,
- BYTE -> MethodNameAndType("boxToByte", "(B)Ljava/lang/Byte;" ) ,
- CHAR -> MethodNameAndType("boxToCharacter", "(C)Ljava/lang/Character;") ,
- SHORT -> MethodNameAndType("boxToShort", "(S)Ljava/lang/Short;" ) ,
- INT -> MethodNameAndType("boxToInteger", "(I)Ljava/lang/Integer;" ) ,
- LONG -> MethodNameAndType("boxToLong", "(J)Ljava/lang/Long;" ) ,
- FLOAT -> MethodNameAndType("boxToFloat", "(F)Ljava/lang/Float;" ) ,
- DOUBLE -> MethodNameAndType("boxToDouble", "(D)Ljava/lang/Double;" )
- )
- }
+ final case class MethodNameAndType(name: String, methodType: MethodBType)
- val asmUnboxTo: immutable.Map[BType, MethodNameAndType] = {
- Map(
- BOOL -> MethodNameAndType("unboxToBoolean", "(Ljava/lang/Object;)Z") ,
- BYTE -> MethodNameAndType("unboxToByte", "(Ljava/lang/Object;)B") ,
- CHAR -> MethodNameAndType("unboxToChar", "(Ljava/lang/Object;)C") ,
- SHORT -> MethodNameAndType("unboxToShort", "(Ljava/lang/Object;)S") ,
- INT -> MethodNameAndType("unboxToInt", "(Ljava/lang/Object;)I") ,
- LONG -> MethodNameAndType("unboxToLong", "(Ljava/lang/Object;)J") ,
- FLOAT -> MethodNameAndType("unboxToFloat", "(Ljava/lang/Object;)F") ,
- DOUBLE -> MethodNameAndType("unboxToDouble", "(Ljava/lang/Object;)D")
- )
- }
+ /**
+ * True if the current compilation unit is of a primitive class (scala.Boolean et al).
+ * Used only in assertions. Abstract here because its implementation depends on global.
+ */
+ def isCompilingPrimitive: Boolean
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
new file mode 100644
index 0000000000..0e2f938602
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -0,0 +1,396 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2014 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala.tools.nsc
+package backend.jvm
+
+import scala.tools.asm
+
+/**
+ * This class mainly contains the method classBTypeFromSymbol, which extracts the necessary
+ * information from a symbol and its type to create the correpsonding ClassBType. It requires
+ * access to the compiler (global parameter).
+ *
+ * The mixin CoreBTypes defines core BTypes that are used in the backend. Building these BTypes
+ * uses classBTypeFromSymbol, hence requires access to the compiler (global).
+ *
+ * BTypesFromSymbols extends BTypes because the implementation of BTypes requires access to some
+ * of the core btypes. They are declared in BTypes as abstract members. Note that BTypes does
+ * not have access to the compiler instance.
+ */
+class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
+ import global._
+ import definitions._
+
+ val bCodeICodeCommon: BCodeICodeCommon[global.type] = new BCodeICodeCommon(global)
+ val bCodeAsmCommon: BCodeAsmCommon[global.type] = new BCodeAsmCommon(global)
+ import bCodeAsmCommon._
+
+ // Why the proxy, see documentation of class [[CoreBTypes]].
+ val coreBTypes = new CoreBTypesProxy[this.type](this)
+ import coreBTypes._
+
+ final def intializeCoreBTypes(): Unit = {
+ coreBTypes.setBTypes(new CoreBTypes[this.type](this))
+ }
+
+ def internalNameString(offset: Int, length: Int) = new String(global.chrs, offset, length)
+
+ protected val classBTypeFromInternalNameMap = {
+ global.perRunCaches.recordCache(collection.concurrent.TrieMap.empty[String, ClassBType])
+ }
+
+ /**
+ * Cache for the method classBTypeFromSymbol.
+ */
+ private val convertedClasses = perRunCaches.newMap[Symbol, ClassBType]()
+
+ // helpers that need access to global.
+ // TODO @lry create a separate component, they don't belong to BTypesFromSymbols
+
+ final val strMODULE_INSTANCE_FIELD = nme.MODULE_INSTANCE_FIELD.toString
+
+ private val primitiveCompilationUnits = Set(
+ "Unit.scala",
+ "Boolean.scala",
+ "Char.scala",
+ "Byte.scala",
+ "Short.scala",
+ "Int.scala",
+ "Float.scala",
+ "Long.scala",
+ "Double.scala"
+ )
+
+ /**
+ * True if the current compilation unit is of a primitive class (scala.Boolean et al).
+ * Used only in assertions.
+ */
+ def isCompilingPrimitive = {
+ primitiveCompilationUnits(currentUnit.source.file.name)
+ }
+
+ def isCompilingArray = {
+ currentUnit.source.file.name == "Array.scala"
+ }
+
+ // end helpers
+
+ /**
+ * The ClassBType for a class symbol `sym`.
+ */
+ final def classBTypeFromSymbol(classSym: Symbol): ClassBType = {
+ assert(classSym != NoSymbol, "Cannot create ClassBType from NoSymbol")
+ assert(classSym.isClass, s"Cannot create ClassBType from non-class symbol $classSym")
+ assert(
+ (!primitiveTypeMap.contains(classSym) || isCompilingPrimitive) &&
+ (classSym != NothingClass && classSym != NullClass),
+ s"Cannot create ClassBType for special class symbol ${classSym.fullName}")
+
+ convertedClasses.getOrElse(classSym, {
+ val internalName = classSym.javaBinaryName.toTypeName
+ // We first create and add the ClassBType to the hash map before computing its info. This
+ // allows initializing cylic dependencies, see the comment on variable ClassBType._info.
+ val classBType = new ClassBType(internalName.start, internalName.length)
+ convertedClasses(classSym) = classBType
+ setClassInfo(classSym, classBType)
+ })
+ }
+
+ private def setClassInfo(classSym: Symbol, classBType: ClassBType): ClassBType = {
+ val superClassSym = if (classSym.isImplClass) ObjectClass else classSym.superClass
+ assert(
+ if (classSym == ObjectClass)
+ superClassSym == NoSymbol
+ else if (classSym.isInterface)
+ superClassSym == ObjectClass
+ else
+ // A ClassBType for a primitive class (scala.Boolean et al) is only created when compiling these classes.
+ ((superClassSym != NoSymbol) && !superClassSym.isInterface) || (isCompilingPrimitive && primitiveTypeMap.contains(classSym)),
+ s"Bad superClass for $classSym: $superClassSym"
+ )
+ val superClass = if (superClassSym == NoSymbol) None
+ else Some(classBTypeFromSymbol(superClassSym))
+
+ val interfaces = getSuperInterfaces(classSym).map(classBTypeFromSymbol)
+
+ val flags = javaFlags(classSym)
+
+ /* The InnerClass table of a class C must contain all nested classes of C, even if they are only
+ * declared but not otherwise referenced in C (from the bytecode or a method / field signature).
+ * We collect them here.
+ *
+ * Nested classes that are also referenced in C will be added to the innerClassBufferASM during
+ * code generation, but those duplicates will be eliminated when emitting the InnerClass
+ * attribute.
+ *
+ * Why doe we need to collect classes into innerClassBufferASM at all? To collect references to
+ * nested classes, but NOT nested in C, that are used within C.
+ */
+ val nestedClassSymbols = {
+ // The lambdalift phase lifts all nested classes to the enclosing class, so if we collect
+ // member classes right after lambdalift, we obtain all nested classes, including local and
+ // anonymous ones.
+ val nestedClasses = exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(classSym))
+
+ // If this is a top-level class, and it has a companion object, the member classes of the
+ // companion are added as members of the class. For example:
+ // class C { }
+ // object C {
+ // class D
+ // def f = { class E }
+ // }
+ // The class D is added as a member of class C. The reason is that the InnerClass attribute
+ // for D will containt class "C" and NOT the module class "C$" as the outer class of D.
+ // This is done by buildNestedInfo, the reason is Java compatibility, see comment in BTypes.
+ // For consistency, the InnerClass entry for D needs to be present in C - to Java it looks
+ // like D is a member of C, not C$.
+ val linkedClass = exitingPickler(classSym.linkedClassOfClass) // linkedCoC does not work properly in late phases
+ val companionModuleMembers = {
+ // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
+ // not local classes of the companion module (E in the exmaple) that were lifted by lambdalift.
+ if (isTopLevelModuleClass(linkedClass)) exitingPickler(memberClassesOf(linkedClass))
+ else Nil
+ }
+
+ nestedClasses ++ companionModuleMembers
+ }
+
+ /**
+ * For nested java classes, the scala compiler creates both a class and a module (and therefore
+ * a module class) symbol. For example, in `class A { class B {} }`, the nestedClassSymbols
+ * for A contain both the class B and the module class B.
+ * Here we get rid of the module class B, making sure that the class B is present.
+ */
+ val nestedClassSymbolsNoJavaModuleClasses = nestedClassSymbols.filter(s => {
+ if (s.isJavaDefined && s.isModuleClass) {
+ // We could also search in nestedClassSymbols for s.linkedClassOfClass, but sometimes that
+ // returns NoSymbol, so it doesn't work.
+ val nb = nestedClassSymbols.count(mc => mc.name == s.name && mc.owner == s.owner)
+ assert(nb == 2, s"Java member module without member class: $s - $nestedClassSymbols")
+ false
+ } else true
+ })
+
+ val memberClasses = nestedClassSymbolsNoJavaModuleClasses.map(classBTypeFromSymbol)
+
+ val nestedInfo = buildNestedInfo(classSym)
+
+ classBType.info = ClassInfo(superClass, interfaces, flags, memberClasses, nestedInfo)
+ classBType
+ }
+
+ /**
+ * All interfaces implemented by a class, except for those inherited through the superclass.
+ *
+ * TODO @lry share code with GenASM
+ */
+ private def getSuperInterfaces(classSym: Symbol): List[Symbol] = {
+
+ // Additional interface parents based on annotations and other cues
+ def newParentForAnnotation(ann: AnnotationInfo): Symbol = ann.symbol match {
+ case RemoteAttr => RemoteInterfaceClass
+ case _ => NoSymbol
+ }
+
+ /**
+ * Drop redundant interfaces (which are implemented by some other parent) from the immediate
+ * parents. In other words, no two interfaces in the result are related by subtyping.
+ */
+ def dropRedundantInterfaces(lstIfaces: List[Symbol]): List[Symbol] = {
+ var rest = lstIfaces
+ var leaves = List.empty[Symbol]
+ while (!rest.isEmpty) {
+ val candidate = rest.head
+ val nonLeaf = leaves exists { lsym => lsym isSubClass candidate }
+ if (!nonLeaf) {
+ leaves = candidate :: (leaves filterNot { lsym => candidate isSubClass lsym })
+ }
+ rest = rest.tail
+ }
+
+ leaves
+ }
+
+ val superInterfaces0: List[Symbol] = classSym.mixinClasses
+ val superInterfaces = existingSymbols(superInterfaces0 ++ classSym.annotations.map(newParentForAnnotation)).distinct
+
+ assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}")
+ assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}")
+
+ dropRedundantInterfaces(superInterfaces)
+ }
+
+ private def buildNestedInfo(innerClassSym: Symbol): Option[NestedInfo] = {
+ assert(innerClassSym.isClass, s"Cannot build NestedInfo for non-class symbol $innerClassSym")
+
+ val isNested = !innerClassSym.rawowner.isPackageClass
+ if (!isNested) None
+ else {
+ // See comment in BTypes, when is a class marked static in the InnerClass table.
+ val isStaticNestedClass = isOriginallyStaticOwner(innerClassSym.originalOwner)
+
+ // After lambdalift (which is where we are), the rawowoner field contains the enclosing class.
+ val enclosingClassSym = {
+ if (innerClassSym.isJavaDefined && innerClassSym.rawowner.isModuleClass) {
+ // Example java source: class C { static class D { } }
+ // The Scala compiler creates a class and a module symbol for C. Because D is a static
+ // nested class, the symbol for D is nested in the module class C (not in the class C).
+ // For the InnerClass attribute, we use the class symbol C, which represents the situation
+ // in the source code.
+
+ // Cannot use innerClassSym.isStatic: this method looks at the owner, which is a package
+ // at this pahse (after lambdalift, flatten).
+ assert(isOriginallyStaticOwner(innerClassSym.originalOwner), innerClassSym.originalOwner)
+
+ // phase travel for linkedCoC - does not always work in late phases
+ exitingPickler(innerClassSym.rawowner.linkedClassOfClass)
+ }
+ else innerClassSym.rawowner
+ }
+ val enclosingClass: ClassBType = classBTypeFromSymbol(enclosingClassSym)
+
+ val outerName: Option[String] = {
+ if (isAnonymousOrLocalClass(innerClassSym)) {
+ None
+ } else {
+ val outerName = innerClassSym.rawowner.javaBinaryName
+ // Java compatibility. See the big comment in BTypes that summarizes the InnerClass spec.
+ val outerNameModule = if (isTopLevelModuleClass(innerClassSym.rawowner)) outerName.dropModule
+ else outerName
+ Some(outerNameModule.toString)
+ }
+ }
+
+ val innerName: Option[String] = {
+ if (innerClassSym.isAnonymousClass || innerClassSym.isAnonymousFunction) None
+ else Some(innerClassSym.rawname + innerClassSym.moduleSuffix) // moduleSuffix for module classes
+ }
+
+ Some(NestedInfo(enclosingClass, outerName, innerName, isStaticNestedClass))
+ }
+ }
+
+ /**
+ * True for module classes of package level objects. The backend will generate a mirror class for
+ * such objects.
+ */
+ final def isTopLevelModuleClass(sym: Symbol): Boolean = exitingPickler {
+ // phase travel to pickler required for isNestedClass (looks at owner)
+ val r = sym.isModuleClass && !sym.isNestedClass
+ // The mixin phase adds the `lateMODULE` flag to trait implementation classes. Since the flag
+ // is late, it should not be visible here inside the time travel. We check this.
+ if (r) assert(!sym.isImplClass, s"isModuleClass should be false for impl class $sym")
+ r
+ }
+
+ /**
+ * True for module classes of modules that are top-level or owned only by objects. Module classes
+ * for such objects will get a MODULE$ flag and a corresponding static initializer.
+ */
+ final def isStaticModuleClass(sym: Symbol): Boolean = {
+ /* (1) Phase travel to to pickler is required to exclude implementation classes; they have the
+ * lateMODULEs after mixin, so isModuleClass would be true.
+ * (2) isStaticModuleClass is a source-level property. See comment on isOriginallyStaticOwner.
+ */
+ exitingPickler { // (1)
+ sym.isModuleClass &&
+ isOriginallyStaticOwner(sym.originalOwner) // (2)
+ }
+ }
+
+ // legacy, to be removed when the @remote annotation gets removed
+ final def isRemote(s: Symbol) = (s hasAnnotation definitions.RemoteAttr)
+ final def hasPublicBitSet(flags: Int) = ((flags & asm.Opcodes.ACC_PUBLIC) != 0)
+
+ /**
+ * Return the Java modifiers for the given symbol.
+ * Java modifiers for classes:
+ * - public, abstract, final, strictfp (not used)
+ * for interfaces:
+ * - the same as for classes, without 'final'
+ * for fields:
+ * - public, private (*)
+ * - static, final
+ * for methods:
+ * - the same as for fields, plus:
+ * - abstract, synchronized (not used), strictfp (not used), native (not used)
+ * for all:
+ * - deprecated
+ *
+ * (*) protected cannot be used, since inner classes 'see' protected members,
+ * and they would fail verification after lifted.
+ */
+ final def javaFlags(sym: Symbol): Int = {
+ // constructors of module classes should be private. introduced in b06edbc, probably to prevent
+ // creating module instances from java. for nested modules, the constructor needs to be public
+ // since they are created by the outer class and stored in a field. a java client can create
+ // new instances via outerClassInstance.new InnerModuleClass$().
+ // TODO: do this early, mark the symbol private.
+ val privateFlag =
+ sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModuleClass(sym.owner))
+
+ // Symbols marked in source as `final` have the FINAL flag. (In the past, the flag was also
+ // added to modules and module classes, not anymore since 296b706).
+ // Note that the presence of the `FINAL` flag on a symbol does not correspond 1:1 to emitting
+ // ACC_FINAL in bytecode.
+ //
+ // Top-level modules are marked ACC_FINAL in bytecode (even without the FINAL flag). Nested
+ // objects don't get the flag to allow overriding (under -Yoverride-objects, SI-5676).
+ //
+ // For fields, only eager val fields can receive ACC_FINAL. vars or lazy vals can't:
+ // Source: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
+ // "Another problem is that the specification allows aggressive
+ // optimization of final fields. Within a thread, it is permissible to
+ // reorder reads of a final field with those modifications of a final
+ // field that do not take place in the constructor."
+ //
+ // A var or lazy val which is marked final still has meaning to the
+ // scala compiler. The word final is heavily overloaded unfortunately;
+ // for us it means "not overridable". At present you can't override
+ // vars regardless; this may change.
+ //
+ // The logic does not check .isFinal (which checks flags for the FINAL flag,
+ // and includes symbols marked lateFINAL) instead inspecting rawflags so
+ // we can exclude lateFINAL. Such symbols are eligible for inlining, but to
+ // avoid breaking proxy software which depends on subclassing, we do not
+ // emit ACC_FINAL.
+
+ val finalFlag = (
+ (((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModuleClass(sym))
+ && !sym.enclClass.isInterface
+ && !sym.isClassConstructor
+ && !sym.isMutable // lazy vals and vars both
+ )
+
+ // Primitives are "abstract final" to prohibit instantiation
+ // without having to provide any implementations, but that is an
+ // illegal combination of modifiers at the bytecode level so
+ // suppress final if abstract if present.
+ import asm.Opcodes._
+ GenBCode.mkFlags(
+ if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
+ if (sym.isDeferred || sym.hasAbstractFlag) ACC_ABSTRACT else 0,
+ if (sym.isInterface) ACC_INTERFACE else 0,
+ if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0,
+ if (sym.isStaticMember) ACC_STATIC else 0,
+ if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
+ if (sym.isArtifact) ACC_SYNTHETIC else 0,
+ if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
+ if (sym.hasEnumFlag) ACC_ENUM else 0,
+ if (sym.isVarargsMethod) ACC_VARARGS else 0,
+ if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0,
+ if (sym.isDeprecated) asm.Opcodes.ACC_DEPRECATED else 0
+ )
+ }
+
+ def javaFieldFlags(sym: Symbol) = {
+ javaFlags(sym) | GenBCode.mkFlags(
+ if (sym hasAnnotation TransientAttr) asm.Opcodes.ACC_TRANSIENT else 0,
+ if (sym hasAnnotation VolatileAttr) asm.Opcodes.ACC_VOLATILE else 0,
+ if (sym.isMutable) 0 else asm.Opcodes.ACC_FINAL
+ )
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
new file mode 100644
index 0000000000..fac3c93be2
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala
@@ -0,0 +1,293 @@
+package scala.tools.nsc
+package backend.jvm
+
+import scala.annotation.switch
+
+/**
+ * Core BTypes and some other definitions. The initialization of these definitions requies access
+ * to symbols / types (global).
+ *
+ * The symbols used to initialize the ClassBTypes may change from one compiler run to the next. To
+ * make sure the definitions are consistent with the symbols in the current run, the
+ * `intializeCoreBTypes` method in BTypesFromSymbols creates a new instance of CoreBTypes in each
+ * compiler run.
+ *
+ * The class BTypesFromSymbols does not directly reference CoreBTypes, but CoreBTypesProxy. The
+ * reason is that having a `var bTypes: CoreBTypes` would not allow `import bTypes._`. Instead, the
+ * proxy class holds a `CoreBTypes` in a variable field and forwards to this instance.
+ *
+ * The definitions in `CoreBTypes` need to be lazy vals to break an initialization cycle. When
+ * creating a new instance to assign to the proxy, the `classBTypeFromSymbol` invoked in the
+ * constructor will actucally go through the proxy. The lazy vals make sure the instance is assigned
+ * in the proxy before the fields are initialized.
+ *
+ * Note: if we did not re-create the core BTypes on each compiler run, BType.classBTypeFromInternalNameMap
+ * could not be a perRunCache anymore: the classes defeined here need to be in that map, they are
+ * added when the ClassBTypes are created. The per run cache removes them, so they would be missing
+ * in the second run.
+ */
+class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) {
+ import bTypes._
+ import global._
+ import rootMirror.{requiredClass, getClassIfDefined}
+ import definitions._
+
+ /**
+ * Maps primitive types to their corresponding PrimitiveBType. The map is defined lexically above
+ * the first use of `classBTypeFromSymbol` because that method looks at the map.
+ */
+ lazy val primitiveTypeMap: Map[Symbol, PrimitiveBType] = Map(
+ UnitClass -> UNIT,
+ BooleanClass -> BOOL,
+ CharClass -> CHAR,
+ ByteClass -> BYTE,
+ ShortClass -> SHORT,
+ IntClass -> INT,
+ LongClass -> LONG,
+ FloatClass -> FLOAT,
+ DoubleClass -> DOUBLE
+ )
+
+ lazy val BOXED_UNIT : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.Void])
+ lazy val BOXED_BOOLEAN : ClassBType = classBTypeFromSymbol(BoxedBooleanClass)
+ lazy val BOXED_BYTE : ClassBType = classBTypeFromSymbol(BoxedByteClass)
+ lazy val BOXED_SHORT : ClassBType = classBTypeFromSymbol(BoxedShortClass)
+ lazy val BOXED_CHAR : ClassBType = classBTypeFromSymbol(BoxedCharacterClass)
+ lazy val BOXED_INT : ClassBType = classBTypeFromSymbol(BoxedIntClass)
+ lazy val BOXED_LONG : ClassBType = classBTypeFromSymbol(BoxedLongClass)
+ lazy val BOXED_FLOAT : ClassBType = classBTypeFromSymbol(BoxedFloatClass)
+ lazy val BOXED_DOUBLE : ClassBType = classBTypeFromSymbol(BoxedDoubleClass)
+
+ /**
+ * Map from primitive types to their boxed class type. Useful when pushing class literals onto the
+ * operand stack (ldc instruction taking a class literal), see genConstant.
+ */
+ lazy val boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = Map(
+ UNIT -> BOXED_UNIT,
+ BOOL -> BOXED_BOOLEAN,
+ BYTE -> BOXED_BYTE,
+ SHORT -> BOXED_SHORT,
+ CHAR -> BOXED_CHAR,
+ INT -> BOXED_INT,
+ LONG -> BOXED_LONG,
+ FLOAT -> BOXED_FLOAT,
+ DOUBLE -> BOXED_DOUBLE
+ )
+
+ lazy val boxedClasses: Set[ClassBType] = boxedClassOfPrimitive.values.toSet
+
+ /**
+ * Maps the method symbol for a box method to the boxed type of the result. For example, the
+ * method symbol for `Byte.box()` is mapped to the ClassBType `java/lang/Byte`.
+ */
+ lazy val boxResultType: Map[Symbol, ClassBType] = {
+ for ((valueClassSym, boxMethodSym) <- currentRun.runDefinitions.boxMethod)
+ yield boxMethodSym -> boxedClassOfPrimitive(primitiveTypeMap(valueClassSym))
+ }
+
+ /**
+ * Maps the method symbol for an unbox method to the primitive type of the result.
+ * For example, the method symbol for `Byte.unbox()`) is mapped to the PrimitiveBType BYTE. */
+ lazy val unboxResultType: Map[Symbol, PrimitiveBType] = {
+ for ((valueClassSym, unboxMethodSym) <- currentRun.runDefinitions.unboxMethod)
+ yield unboxMethodSym -> primitiveTypeMap(valueClassSym)
+ }
+
+ /*
+ * RT_NOTHING and RT_NULL exist at run-time only. They are the bytecode-level manifestation (in
+ * method signatures only) of what shows up as NothingClass resp. NullClass in Scala ASTs.
+ *
+ * Therefore, when RT_NOTHING or RT_NULL are to be emitted, a mapping is needed: the internal
+ * names of NothingClass and NullClass can't be emitted as-is.
+ * TODO @lry Once there's a 2.11.3 starr, use the commented argument list. The current starr crashes on the type literal `scala.runtime.Nothing$`
+ */
+ lazy val RT_NOTHING : ClassBType = classBTypeFromSymbol(rootMirror.getRequiredClass("scala.runtime.Nothing$")) // (requiredClass[scala.runtime.Nothing$])
+ lazy val RT_NULL : ClassBType = classBTypeFromSymbol(rootMirror.getRequiredClass("scala.runtime.Null$")) // (requiredClass[scala.runtime.Null$])
+
+ lazy val ObjectReference : ClassBType = classBTypeFromSymbol(ObjectClass)
+ lazy val objArrayReference : ArrayBType = ArrayBType(ObjectReference)
+
+ lazy val StringReference : ClassBType = classBTypeFromSymbol(StringClass)
+ lazy val StringBuilderReference : ClassBType = classBTypeFromSymbol(StringBuilderClass)
+ lazy val ThrowableReference : ClassBType = classBTypeFromSymbol(ThrowableClass)
+ lazy val jlCloneableReference : ClassBType = classBTypeFromSymbol(JavaCloneableClass) // java/lang/Cloneable
+ lazy val jlNPEReference : ClassBType = classBTypeFromSymbol(NullPointerExceptionClass) // java/lang/NullPointerException
+ lazy val jioSerializableReference : ClassBType = classBTypeFromSymbol(JavaSerializableClass) // java/io/Serializable
+ lazy val scalaSerializableReference : ClassBType = classBTypeFromSymbol(SerializableClass) // scala/Serializable
+ lazy val classCastExceptionReference : ClassBType = classBTypeFromSymbol(ClassCastExceptionClass) // java/lang/ClassCastException
+
+ lazy val srBooleanRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BooleanRef])
+ lazy val srByteRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.ByteRef])
+ lazy val srCharRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.CharRef])
+ lazy val srIntRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.IntRef])
+ lazy val srLongRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.LongRef])
+ lazy val srFloatRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.FloatRef])
+ lazy val srDoubleRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.DoubleRef])
+
+ lazy val hashMethodSym: Symbol = getMember(ScalaRunTimeModule, nme.hash_)
+
+ // TODO @lry avoiding going through through missingHook for every line in the REPL: https://github.com/scala/scala/commit/8d962ed4ddd310cc784121c426a2e3f56a112540
+ lazy val AndroidParcelableInterface : Symbol = getClassIfDefined("android.os.Parcelable")
+ lazy val AndroidCreatorClass : Symbol = getClassIfDefined("android.os.Parcelable$Creator")
+
+ lazy val BeanInfoAttr: Symbol = requiredClass[scala.beans.BeanInfo]
+
+ /* The Object => String overload. */
+ lazy val String_valueOf: Symbol = {
+ getMember(StringModule, nme.valueOf) filter (sym => sym.info.paramTypes match {
+ case List(pt) => pt.typeSymbol == ObjectClass
+ case _ => false
+ })
+ }
+
+ // scala.FunctionX and scala.runtim.AbstractFunctionX
+ lazy val FunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(FunctionClass(i)))(collection.breakOut)
+ lazy val AbstractFunctionReference : Vector[ClassBType] = (0 to MaxFunctionArity).map(i => classBTypeFromSymbol(AbstractFunctionClass(i)))(collection.breakOut)
+ lazy val AbstractFunctionArityMap : Map[ClassBType, Int] = AbstractFunctionReference.zipWithIndex.toMap
+
+ lazy val PartialFunctionReference : ClassBType = classBTypeFromSymbol(PartialFunctionClass)
+ lazy val AbstractPartialFunctionReference : ClassBType = classBTypeFromSymbol(AbstractPartialFunctionClass)
+
+ lazy val BoxesRunTime: ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime])
+
+ /**
+ * Methods in scala.runtime.BoxesRuntime
+ */
+ lazy val asmBoxTo : Map[BType, MethodNameAndType] = Map(
+ BOOL -> MethodNameAndType("boxToBoolean", MethodBType(List(BOOL), BOXED_BOOLEAN)),
+ BYTE -> MethodNameAndType("boxToByte", MethodBType(List(BYTE), BOXED_BYTE)),
+ CHAR -> MethodNameAndType("boxToCharacter", MethodBType(List(CHAR), BOXED_CHAR)),
+ SHORT -> MethodNameAndType("boxToShort", MethodBType(List(SHORT), BOXED_SHORT)),
+ INT -> MethodNameAndType("boxToInteger", MethodBType(List(INT), BOXED_INT)),
+ LONG -> MethodNameAndType("boxToLong", MethodBType(List(LONG), BOXED_LONG)),
+ FLOAT -> MethodNameAndType("boxToFloat", MethodBType(List(FLOAT), BOXED_FLOAT)),
+ DOUBLE -> MethodNameAndType("boxToDouble", MethodBType(List(DOUBLE), BOXED_DOUBLE))
+ )
+
+ lazy val asmUnboxTo: Map[BType, MethodNameAndType] = Map(
+ BOOL -> MethodNameAndType("unboxToBoolean", MethodBType(List(ObjectReference), BOOL)),
+ BYTE -> MethodNameAndType("unboxToByte", MethodBType(List(ObjectReference), BYTE)),
+ CHAR -> MethodNameAndType("unboxToChar", MethodBType(List(ObjectReference), CHAR)),
+ SHORT -> MethodNameAndType("unboxToShort", MethodBType(List(ObjectReference), SHORT)),
+ INT -> MethodNameAndType("unboxToInt", MethodBType(List(ObjectReference), INT)),
+ LONG -> MethodNameAndType("unboxToLong", MethodBType(List(ObjectReference), LONG)),
+ FLOAT -> MethodNameAndType("unboxToFloat", MethodBType(List(ObjectReference), FLOAT)),
+ DOUBLE -> MethodNameAndType("unboxToDouble", MethodBType(List(ObjectReference), DOUBLE))
+ )
+
+ lazy val typeOfArrayOp: Map[Int, BType] = {
+ import scalaPrimitives._
+ Map(
+ (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
+ (List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
+ (List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
+ (List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
+ (List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT)) ++
+ (List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
+ (List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
+ (List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
+ (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> ObjectReference)) : _*
+ )
+ }
+}
+
+/**
+ * This trait make some core BTypes availalbe that don't depend on a Global instance. Some core
+ * BTypes are required to be accessible in the BTypes trait, which does not have access to Global.
+ *
+ * BTypes cannot refer to CoreBTypesProxy because some of its members depend on global, for example
+ * the type Symbol in
+ * def primitiveTypeMap: Map[Symbol, PrimitiveBType]
+ */
+trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] {
+ val bTypes: BTS
+ import bTypes._
+
+ def boxedClasses: Set[ClassBType]
+
+ def RT_NOTHING : ClassBType
+ def RT_NULL : ClassBType
+
+ def ObjectReference : ClassBType
+ def jlCloneableReference : ClassBType
+ def jioSerializableReference : ClassBType
+}
+
+/**
+ * See comment in class [[CoreBTypes]].
+ */
+final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) extends CoreBTypesProxyGlobalIndependent[BTFS] {
+ import bTypes._
+ import global._
+
+ private[this] var _coreBTypes: CoreBTypes[bTypes.type] = _
+ def setBTypes(coreBTypes: CoreBTypes[BTFS]): Unit = {
+ _coreBTypes = coreBTypes.asInstanceOf[CoreBTypes[bTypes.type]]
+ }
+
+ def primitiveTypeMap: Map[Symbol, PrimitiveBType] = _coreBTypes.primitiveTypeMap
+
+ def BOXED_UNIT : ClassBType = _coreBTypes.BOXED_UNIT
+ def BOXED_BOOLEAN : ClassBType = _coreBTypes.BOXED_BOOLEAN
+ def BOXED_BYTE : ClassBType = _coreBTypes.BOXED_BYTE
+ def BOXED_SHORT : ClassBType = _coreBTypes.BOXED_SHORT
+ def BOXED_CHAR : ClassBType = _coreBTypes.BOXED_CHAR
+ def BOXED_INT : ClassBType = _coreBTypes.BOXED_INT
+ def BOXED_LONG : ClassBType = _coreBTypes.BOXED_LONG
+ def BOXED_FLOAT : ClassBType = _coreBTypes.BOXED_FLOAT
+ def BOXED_DOUBLE : ClassBType = _coreBTypes.BOXED_DOUBLE
+
+ def boxedClasses: Set[ClassBType] = _coreBTypes.boxedClasses
+
+ def boxedClassOfPrimitive: Map[PrimitiveBType, ClassBType] = _coreBTypes.boxedClassOfPrimitive
+
+ def boxResultType: Map[Symbol, ClassBType] = _coreBTypes.boxResultType
+
+ def unboxResultType: Map[Symbol, PrimitiveBType] = _coreBTypes.unboxResultType
+
+ def RT_NOTHING : ClassBType = _coreBTypes.RT_NOTHING
+ def RT_NULL : ClassBType = _coreBTypes.RT_NULL
+
+ def ObjectReference : ClassBType = _coreBTypes.ObjectReference
+ def objArrayReference : ArrayBType = _coreBTypes.objArrayReference
+
+ def StringReference : ClassBType = _coreBTypes.StringReference
+ def StringBuilderReference : ClassBType = _coreBTypes.StringBuilderReference
+ def ThrowableReference : ClassBType = _coreBTypes.ThrowableReference
+ def jlCloneableReference : ClassBType = _coreBTypes.jlCloneableReference
+ def jlNPEReference : ClassBType = _coreBTypes.jlNPEReference
+ def jioSerializableReference : ClassBType = _coreBTypes.jioSerializableReference
+ def scalaSerializableReference : ClassBType = _coreBTypes.scalaSerializableReference
+ def classCastExceptionReference : ClassBType = _coreBTypes.classCastExceptionReference
+
+ def srBooleanRef : ClassBType = _coreBTypes.srBooleanRef
+ def srByteRef : ClassBType = _coreBTypes.srByteRef
+ def srCharRef : ClassBType = _coreBTypes.srCharRef
+ def srIntRef : ClassBType = _coreBTypes.srIntRef
+ def srLongRef : ClassBType = _coreBTypes.srLongRef
+ def srFloatRef : ClassBType = _coreBTypes.srFloatRef
+ def srDoubleRef : ClassBType = _coreBTypes.srDoubleRef
+
+ def hashMethodSym: Symbol = _coreBTypes.hashMethodSym
+
+ def AndroidParcelableInterface : Symbol = _coreBTypes.AndroidParcelableInterface
+ def AndroidCreatorClass : Symbol = _coreBTypes.AndroidCreatorClass
+
+ def BeanInfoAttr: Symbol = _coreBTypes.BeanInfoAttr
+
+ def String_valueOf: Symbol = _coreBTypes.String_valueOf
+
+ def FunctionReference : Vector[ClassBType] = _coreBTypes.FunctionReference
+ def AbstractFunctionReference : Vector[ClassBType] = _coreBTypes.AbstractFunctionReference
+ def AbstractFunctionArityMap : Map[ClassBType, Int] = _coreBTypes.AbstractFunctionArityMap
+
+ def PartialFunctionReference : ClassBType = _coreBTypes.PartialFunctionReference
+ def AbstractPartialFunctionReference : ClassBType = _coreBTypes.AbstractPartialFunctionReference
+
+ def BoxesRunTime: ClassBType = _coreBTypes.BoxesRunTime
+
+ def asmBoxTo : Map[BType, MethodNameAndType] = _coreBTypes.asmBoxTo
+ def asmUnboxTo: Map[BType, MethodNameAndType] = _coreBTypes.asmUnboxTo
+
+ def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp
+}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index b0fb3069c1..2593903b9d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -26,6 +26,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
import icodes.opcodes._
import definitions._
+ val bCodeAsmCommon: BCodeAsmCommon[global.type] = new BCodeAsmCommon(global)
+ import bCodeAsmCommon._
+
// Strangely I can't find this in the asm code
// 255, but reserving 1 for "this"
final val MaximumJvmParameters = 254
@@ -381,6 +384,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
case "jvm-1.5" => asm.Opcodes.V1_5
case "jvm-1.6" => asm.Opcodes.V1_6
case "jvm-1.7" => asm.Opcodes.V1_7
+ case "jvm-1.8" => asm.Opcodes.V1_8
}
private val majorVersion: Int = (classfileVersion & 0xFF)
@@ -620,7 +624,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
* That means non-member classes (anonymous). See Section 4.7.5 in the JVMS.
*/
def outerName(innerSym: Symbol): String = {
- if (innerSym.originalEnclosingMethod != NoSymbol)
+ if (isAnonymousOrLocalClass(innerSym))
null
else {
val outerName = javaName(innerSym.rawowner)
@@ -635,10 +639,16 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
else
innerSym.rawname + innerSym.moduleSuffix
- // add inner classes which might not have been referenced yet
- exitingErasure {
- for (sym <- List(csym, csym.linkedClassOfClass); m <- sym.info.decls.map(innerClassSymbolFor) if m.isClass)
- innerClassBuffer += m
+ // This collects all inner classes of csym, including local and anonymous: lambdalift makes
+ // them members of their enclosing class.
+ innerClassBuffer ++= exitingPhase(currentRun.lambdaliftPhase)(memberClassesOf(csym))
+
+ // Add members of the companion object (if top-level). why, see comment in BTypes.scala.
+ val linkedClass = exitingPickler(csym.linkedClassOfClass) // linkedCoC does not work properly in late phases
+ if (isTopLevelModule(linkedClass)) {
+ // phase travel to exitingPickler: this makes sure that memberClassesOf only sees member classes,
+ // not local classes that were lifted by lambdalift.
+ innerClassBuffer ++= exitingPickler(memberClassesOf(linkedClass))
}
val allInners: List[Symbol] = innerClassBuffer.toList filterNot deadCode.elidedClosures
@@ -652,7 +662,8 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
// sort them so inner classes succeed their enclosing class to satisfy the Eclipse Java compiler
for (innerSym <- allInners sortBy (_.name.length)) { // TODO why not sortBy (_.name.toString()) ??
val flagsWithFinal: Int = mkFlags(
- if (innerSym.rawowner.hasModuleFlag) asm.Opcodes.ACC_STATIC else 0,
+ // See comment in BTypes, when is a class marked static in the InnerClass table.
+ if (isOriginallyStaticOwner(innerSym.originalOwner)) asm.Opcodes.ACC_STATIC else 0,
javaFlags(innerSym),
if(isDeprecated(innerSym)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo-access flag
) & (INNER_CLASSES_FLAGS | asm.Opcodes.ACC_DEPRECATED)
@@ -1218,10 +1229,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
null /* SourceDebugExtension */)
}
- val enclM = getEnclosingMethodAttribute()
- if(enclM != null) {
- val EnclMethodEntry(className, methodName, methodType) = enclM
- jclass.visitOuterClass(className, methodName, methodType.getDescriptor)
+ enclosingMethodAttribute(clasz.symbol, javaName, javaType(_).getDescriptor) match {
+ case Some(EnclosingMethodEntry(className, methodName, methodDescriptor)) =>
+ jclass.visitOuterClass(className, methodName, methodDescriptor)
+ case _ => ()
}
// typestate: entering mode with valid call sequences:
@@ -1282,45 +1293,6 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
}
- /**
- * @param owner internal name of the enclosing class of the class.
- *
- * @param name the name of the method that contains the class.
-
- * @param methodType the method that contains the class.
- */
- case class EnclMethodEntry(owner: String, name: String, methodType: asm.Type)
-
- /**
- * @return null if the current class is not internal to a method
- *
- * Quoting from JVMS 4.7.7 The EnclosingMethod Attribute
- * A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
- * A class may have no more than one EnclosingMethod attribute.
- *
- */
- private def getEnclosingMethodAttribute(): EnclMethodEntry = { // JVMS 4.7.7
- var res: EnclMethodEntry = null
- val clazz = clasz.symbol
- val sym = clazz.originalEnclosingMethod
- if (sym.isMethod) {
- debuglog("enclosing method for %s is %s (in %s)".format(clazz, sym, sym.enclClass))
- res = EnclMethodEntry(javaName(sym.enclClass), javaName(sym), javaType(sym))
- } else if (clazz.isAnonymousClass) {
- val enclClass = clazz.rawowner
- assert(enclClass.isClass, enclClass)
- val sym = enclClass.primaryConstructor
- if (sym == NoSymbol) {
- log("Ran out of room looking for an enclosing method for %s: no constructor here.".format(enclClass))
- } else {
- debuglog("enclosing method for %s is %s (in %s)".format(clazz, sym, enclClass))
- res = EnclMethodEntry(javaName(enclClass), javaName(sym), javaType(sym))
- }
- }
-
- res
- }
-
def genField(f: IField) {
debuglog("Adding field: " + f.symbol.fullName)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
index a401de05e5..0a7c894a69 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala
@@ -46,6 +46,9 @@ import scala.tools.asm
abstract class GenBCode extends BCodeSyncAndTry {
import global._
+ import bTypes._
+ import coreBTypes._
+
val phaseName = "jvm"
override def newPhase(prev: Phase) = new BCodePhase(prev)
@@ -130,7 +133,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
return
}
else {
- try { visit(item) }
+ try { withCurrentUnit(item.cunit)(visit(item)) }
catch {
case ex: Throwable =>
ex.printStackTrace()
@@ -165,7 +168,7 @@ abstract class GenBCode extends BCodeSyncAndTry {
// -------------- mirror class, if needed --------------
val mirrorC =
- if (isStaticModule(claszSymbol) && isTopLevelModule(claszSymbol)) {
+ if (isTopLevelModuleClass(claszSymbol)) {
if (claszSymbol.companionClass == NoSymbol) {
mirrorCodeGen.genMirrorClass(claszSymbol, cunit)
} else {
@@ -271,8 +274,8 @@ abstract class GenBCode extends BCodeSyncAndTry {
override def run() {
arrivalPos = 0 // just in case
- scalaPrimitives.init
- initBCodeTypes()
+ scalaPrimitives.init()
+ bTypes.intializeCoreBTypes()
// initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated.
bytecodeWriter = initBytecodeWriter(cleanup.getEntryPoints)
@@ -297,9 +300,6 @@ abstract class GenBCode extends BCodeSyncAndTry {
* (2) if requested, check-java-signatures, over and beyond the syntactic checks in `getGenericSignature()`
*
*/
-
- // clearing maps
- clearBCodeTypes()
}
/*
@@ -385,3 +385,10 @@ abstract class GenBCode extends BCodeSyncAndTry {
} // end of class BCodePhase
} // end of class GenBCode
+
+object GenBCode {
+ def mkFlags(args: Int*) = args.foldLeft(0)(_ | _)
+
+ final val PublicStatic = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC
+ final val PublicStaticFinal = asm.Opcodes.ACC_PUBLIC | asm.Opcodes.ACC_STATIC | asm.Opcodes.ACC_FINAL
+}
diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
index bddcf6567c..ac86dfd665 100644
--- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
+++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala
@@ -861,7 +861,7 @@ trait JavaScanners extends ast.parser.ScannersCommon {
in = new JavaCharArrayReader(unit.source.content, !settings.nouescape.value, syntaxError)
init()
def error (pos: Int, msg: String) = reporter.error(pos, msg)
- def incompleteInputError(pos: Int, msg: String) = currentRun.reporting.incompleteInputError(pos, msg)
+ def incompleteInputError(pos: Int, msg: String) = currentRun.parsing.incompleteInputError(pos, msg)
def deprecationWarning(pos: Int, msg: String) = currentRun.reporting.deprecationWarning(pos, msg)
implicit def g2p(pos: Int): Position = Position.offset(unit.source, pos)
}
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
index 12f9aeba27..6e3d013e52 100644
--- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala
+++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala
@@ -33,7 +33,7 @@ trait Plugins { global: Global =>
}
val maybes = Plugin.loadAllFrom(paths, dirs, settings.disable.value)
val (goods, errors) = maybes partition (_.isSuccess)
- // Explicit parameterization of recover to suppress -Xlint warning about inferred Any
+ // Explicit parameterization of recover to avoid -Xlint warning about inferred Any
errors foreach (_.recover[Any] {
// legacy behavior ignores altogether, so at least warn devs
case e: MissingPluginException => if (global.isDeveloper) warning(e.getMessage)
diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
index 6c592ead0d..5e4914fa83 100644
--- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala
@@ -30,6 +30,7 @@ abstract class AbstractReporter extends Reporter {
private def isVerbose = settings.verbose.value
private def noWarnings = settings.nowarnings.value
private def isPromptSet = settings.prompt.value
+ private def isDebug = settings.debug
protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean) {
if (severity == INFO) {
@@ -46,7 +47,7 @@ abstract class AbstractReporter extends Reporter {
severity.count += 1
display(pos, msg, severity)
}
- else if (settings.debug) {
+ else if (isDebug) {
severity.count += 1
display(pos, "[ suppressed ] " + msg, severity)
}
@@ -57,6 +58,7 @@ abstract class AbstractReporter extends Reporter {
}
}
+
/** Logs a position and returns true if it was already logged.
* @note Two positions are considered identical for logging if they have the same point.
*/
diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
index 5b576a547d..3d688efae1 100644
--- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala
+++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala
@@ -13,8 +13,8 @@ import scala.reflect.internal.util._
* This describes the internal interface for issuing information, warnings and errors.
* The only abstract method in this class must be info0.
*
- * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter
- * This interface should be considered private to the compiler.
+ * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter,
+ * and remove this class.
*/
abstract class Reporter extends scala.reflect.internal.Reporter {
/** Informational messages. If `!force`, they may be suppressed. */
diff --git a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
index 38a7525862..d0b8fd70ed 100644
--- a/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/AbsScalaSettings.scala
@@ -29,7 +29,7 @@ trait AbsScalaSettings {
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting
- def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting
+ def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: Option[() => Unit])(helper: MultiChoiceSetting => String): MultiChoiceSetting
def OutputSetting(outputDirs: OutputDirs, default: String): OutputSetting
def PathSetting(name: String, descr: String, default: String): PathSetting
def PhasesSetting(name: String, descr: String, default: String): PhasesSetting
diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
index 54e444decf..f26192f88a 100644
--- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala
@@ -211,11 +211,10 @@ class MutableSettings(val errorFn: String => Unit)
add(new ChoiceSetting(name, helpArg, descr, choices, default))
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]) = add(new IntSetting(name, descr, default, range, parser))
def MultiStringSetting(name: String, arg: String, descr: String) = add(new MultiStringSetting(name, arg, descr))
- def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String]): MultiChoiceSetting = {
- val fullChoix = choices.mkString(": ", ",", ".")
- val fullDescr = s"$descr$fullChoix"
- add(new MultiChoiceSetting(name, helpArg, fullDescr, choices))
- }
+ def MultiChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: Option[() => Unit] = None)(
+ helper: MultiChoiceSetting => String = _ => choices.mkString(f"$descr:%n", f"%n ", f"%n")
+ ) =
+ add(new MultiChoiceSetting(name, helpArg, descr, choices, default, helper))
def OutputSetting(outputDirs: OutputDirs, default: String) = add(new OutputSetting(outputDirs, default))
def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default))
def StringSetting(name: String, arg: String, descr: String, default: String) = add(new StringSetting(name, arg, descr, default))
@@ -444,7 +443,7 @@ class MutableSettings(val errorFn: String => Unit)
value = s.equalsIgnoreCase("true")
}
override def tryToSetColon(args: List[String]) = args match {
- case Nil => tryToSet(Nil)
+ case Nil => tryToSet(Nil)
case List(x) =>
if (x.equalsIgnoreCase("true")) {
value = true
@@ -452,7 +451,8 @@ class MutableSettings(val errorFn: String => Unit)
} else if (x.equalsIgnoreCase("false")) {
value = false
Some(Nil)
- } else errorAndValue("'" + x + "' is not a valid choice for '" + name + "'", None)
+ } else errorAndValue(s"'$x' is not a valid choice for '$name'", None)
+ case _ => errorAndValue(s"'$name' accepts only one boolean value", None)
}
}
@@ -553,12 +553,58 @@ class MutableSettings(val errorFn: String => Unit)
}
}
+ /** A setting that receives any combination of enumerated values,
+ * including "_" to mean all values and "help" for verbose info.
+ * In non-colonated mode, stops consuming args at the first
+ * non-value, instead of at the next option, as for a multi-string.
+ */
class MultiChoiceSetting private[nsc](
name: String,
arg: String,
descr: String,
- override val choices: List[String])
- extends MultiStringSetting(name, arg, descr)
+ override val choices: List[String],
+ val default: Option[() => Unit],
+ helper: MultiChoiceSetting => String
+ ) extends MultiStringSetting(name, s"_,$arg,-$arg", s"$descr: `_' for all, `$name:help' to list") {
+
+ private def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
+ private def choosing = choices.nonEmpty
+ private def isChoice(s: String) = (s == "_") || (choices contains (s stripPrefix "-"))
+
+ private var sawHelp = false
+ private var sawAll = false
+ private val adderAll = () => sawAll = true
+ private val noargs = () => errorFn(s"'$name' requires an option. See '$name:help'.")
+
+ override protected def tts(args: List[String], halting: Boolean) = {
+ val added = collection.mutable.ListBuffer.empty[String]
+ def tryArg(arg: String) = arg match {
+ case "_" if choosing => addAll()
+ case "help" if choosing => sawHelp = true
+ case s if !choosing || isChoice(s) => added += s
+ case s => badChoice(s, name)
+ }
+ def stoppingAt(arg: String) = (arg startsWith "-") || (choosing && !isChoice(arg))
+ def loop(args: List[String]): List[String] = args match {
+ case arg :: _ if halting && stoppingAt(arg) => args
+ case arg :: rest => tryArg(arg) ; loop(rest)
+ case Nil => Nil
+ }
+ val rest = loop(args)
+ if (rest.size == args.size)
+ (default getOrElse noargs)() // if no arg consumed, trigger default action or error
+ else
+ value ++= added.toList // update all new settings at once
+ Some(rest)
+ }
+
+ def isHelping: Boolean = sawHelp
+ def help: String = helper(this)
+ def addAll(): Unit = (default getOrElse adderAll)()
+
+ // the semantics is: s is enabled, i.e., either s or (_ but not -s)
+ override def contains(s: String) = isChoice(s) && (value contains s) || (sawAll && !(value contains s"-$s"))
+ }
/** A setting that accumulates all strings supplied to it,
* until it encounters one starting with a '-'.
@@ -570,24 +616,23 @@ class MutableSettings(val errorFn: String => Unit)
extends Setting(name, descr) with Clearable {
type T = List[String]
protected var v: T = Nil
- def appendToValue(str: String) { value ++= List(str) }
- def badChoice(s: String, n: String) = errorFn(s"'$s' is not a valid choice for '$name'")
-
- def tryToSet(args: List[String]) = {
- val (strings, rest) = args span (x => !x.startsWith("-"))
- strings foreach {
- case "_" if choices.nonEmpty => choices foreach appendToValue
- case s if choices.isEmpty || (choices contains s) => appendToValue(s)
- case s => badChoice(s, name)
+ def appendToValue(str: String) = value ++= List(str)
+
+ // try to set. halting means halt at first non-arg
+ protected def tts(args: List[String], halting: Boolean) = {
+ def loop(args: List[String]): List[String] = args match {
+ case arg :: rest => if (halting && (arg startsWith "-")) args else { appendToValue(arg) ; loop(rest) }
+ case Nil => Nil
}
- Some(rest)
+ Some(loop(args))
}
- override def tryToSetColon(args: List[String]) = tryToSet(args)
+ def tryToSet(args: List[String]) = tts(args, halting = true)
+ override def tryToSetColon(args: List[String]) = tts(args, halting = false)
override def tryToSetFromPropertyValue(s: String) = tryToSet(s.trim.split(',').toList) // used from ide
- def clear(): Unit = (v = Nil)
- def unparse: List[String] = value map (name + ":" + _)
- def contains(s: String) = value contains s
+ def clear(): Unit = (v = Nil)
+ def unparse: List[String] = value map (name + ":" + _)
+ def contains(s: String) = value contains s
withHelpSyntax(name + ":<" + arg + ">")
}
@@ -606,10 +651,8 @@ class MutableSettings(val errorFn: String => Unit)
protected var v: T = default
def indexOfChoice: Int = choices indexOf value
- private def usageErrorMessage = {
- "Usage: %s:<%s>\n where <%s> choices are %s (default: %s)\n".format(
- name, helpArg, helpArg, choices mkString ", ", default)
- }
+ private def usageErrorMessage = f"Usage: $name:<$helpArg>%n where <$helpArg> choices are ${choices mkString ", "} (default: $default)%n"
+
def tryToSet(args: List[String]) = errorAndValue(usageErrorMessage, None)
override def tryToSetColon(args: List[String]) = args match {
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index d22dcacad6..8e69598614 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -44,8 +44,11 @@ trait ScalaSettings extends AbsScalaSettings
/** If any of these settings is enabled, the compiler should print a message and exit. */
def infoSettings = List[Setting](version, help, Xhelp, Yhelp, showPlugins, showPhases, genPhaseGraph)
+ /** Any -multichoice:help? Nicer if any option could report that it had help to offer. */
+ private def multihelp = allSettings exists { case s: MultiChoiceSetting => s.isHelping case _ => false }
+
/** Is an info setting set? */
- def isInfo = infoSettings exists (_.isSetByUser)
+ def isInfo = (infoSettings exists (_.isSetByUser)) || multihelp
/** Disable a setting */
def disable(s: Setting) = allSettings -= s
@@ -67,8 +70,27 @@ trait ScalaSettings extends AbsScalaSettings
// Would be nice to build this dynamically from scala.languageFeature.
// The two requirements: delay error checking until you have symbols, and let compiler command build option-specific help.
val language = {
- val features = List("dynamics", "postfixOps", "reflectiveCalls", "implicitConversions", "higherKinds", "existentials", "experimental.macros")
- MultiChoiceSetting("-language", "feature", "Enable one or more language features", features)
+ val features = List(
+ "dynamics" -> "Allow direct or indirect subclasses of scala.Dynamic",
+ "postfixOps" -> "Allow postfix operator notation, such as `1 to 10 toList'",
+ "reflectiveCalls" -> "Allow reflective access to members of structural types",
+ "implicitConversions" -> "Allow definition of implicit functions called views",
+ "higherKinds" -> "Allow higher-kinded types", // "Ask Adriaan, but if you have to ask..."
+ "existentials" -> "Existential types (besides wildcard types) can be written and inferred",
+ "experimental.macros" -> "Allow macro defintion (besides implementation and application)"
+ )
+ val description = "Enable or disable language features"
+ MultiChoiceSetting(
+ name = "-language",
+ helpArg = "feature",
+ descr = description,
+ choices = features map (_._1)
+ ) { s =>
+ val helpline: ((String, String)) => String = {
+ case (name, text) => f" $name%-25s $text%n"
+ }
+ features map helpline mkString (f"$description:%n", "", f"%n")
+ }
}
/*
@@ -185,7 +207,6 @@ trait ScalaSettings extends AbsScalaSettings
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
- val Yinvalidate = StringSetting ("-Yinvalidate", "classpath-entry", "Invalidate classpath entry before run", "")
val YvirtClasses = false // too embryonic to even expose as a -Y //BooleanSetting ("-Yvirtual-classes", "Support virtual classes")
val YdisableUnreachablePrevention = BooleanSetting("-Ydisable-unreachable-prevention", "Disable the prevention of unreachable blocks in code generation.")
val YnoLoadImplClass = BooleanSetting ("-Yno-load-impl-class", "Do not load $class.class files.")
diff --git a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
index 37dfafb01c..d42c0dd730 100644
--- a/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/StandardScalaSettings.scala
@@ -39,7 +39,7 @@ trait StandardScalaSettings {
val optimise: BooleanSetting // depends on post hook which mutates other settings
val print = BooleanSetting ("-print", "Print program with Scala-specific features removed.")
val target = ChoiceSetting ("-target", "target", "Target platform for object files. All JVM 1.5 targets are deprecated.",
- List("jvm-1.5", "jvm-1.6", "jvm-1.7"), "jvm-1.6")
+ List("jvm-1.5", "jvm-1.6", "jvm-1.7", "jvm-1.8"), "jvm-1.6")
val unchecked = BooleanSetting ("-unchecked", "Enable additional warnings where generated code depends on assumptions.")
val uniqid = BooleanSetting ("-uniqid", "Uniquely tag all identifiers in debugging output.")
val usejavacp = BooleanSetting ("-usejavacp", "Utilize the java.class.path in classpath resolution.")
diff --git a/src/compiler/scala/tools/nsc/settings/Warnings.scala b/src/compiler/scala/tools/nsc/settings/Warnings.scala
index 1509ad13b8..4c37633301 100644
--- a/src/compiler/scala/tools/nsc/settings/Warnings.scala
+++ b/src/compiler/scala/tools/nsc/settings/Warnings.scala
@@ -17,12 +17,15 @@ trait Warnings {
// Warning semantics.
val fatalWarnings = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.")
- // These warnings are all so noisy as to be useless in their
+ // These additional warnings are all so noisy as to be useless in their
// present form, but have the potential to offer useful info.
protected def allWarnings = lintWarnings ++ List(
warnDeadCode,
warnValueDiscard,
- warnNumericWiden
+ warnNumericWiden,
+ warnUnused, // SI-7712, SI-7707 warnUnused not quite ready for prime-time
+ warnUnusedImport, // currently considered too noisy for general use
+ warnValueOverrides // currently turned off as experimental
)
// These warnings should be pretty quiet unless you're doing
// something inadvisable.
@@ -31,27 +34,130 @@ trait Warnings {
warnNullaryOverride,
warnNullaryUnit,
warnAdaptedArgs,
- warnInferAny
- // warnUnused SI-7712, SI-7707 warnUnused not quite ready for prime-time
- // warnUnusedImport currently considered too noisy for general use
+ warnInferAny,
+ warnMissingInterpolator,
+ warnDocDetached,
+ warnPrivateShadow,
+ warnTypeParameterShadow,
+ warnPolyImplicitOverload,
+ warnOptionImplicit,
+ warnDelayedInit,
+ warnByNameRightAssociative,
+ warnPackageObjectClasses,
+ warnUnsoundMatch
)
- private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.")
+ // Individual warnings. They can be set with -Ywarn.
+ private def nonlintflag(name: String, text: String): BooleanSetting = BooleanSetting(name, text)
+
+ val warnDeadCode = nonlintflag("-Ywarn-dead-code",
+ "Warn when dead code is identified.")
+ val warnValueDiscard = nonlintflag("-Ywarn-value-discard",
+ "Warn when non-Unit expression results are unused.")
+ val warnNumericWiden = nonlintflag("-Ywarn-numeric-widen",
+ "Warn when numerics are widened.")
+ val warnUnused = nonlintflag("-Ywarn-unused",
+ "Warn when local and private vals, vars, defs, and types are are unused")
+ val warnUnusedImport = nonlintflag("-Ywarn-unused-import",
+ "Warn when imports are unused")
+
+ // Lint warnings that have no -Y avatar, created with new instead of the autoregistering factory method.
+ // They evaluate true if set to true or else are unset but -Xlint is true
+ private def lintflag(name: String, text: String): BooleanSetting =
+ new BooleanSetting(name, text) {
+ override def value = if (isSetByUser) super.value else xlint
+ }
+
+ val warnAdaptedArgs = lintflag("adapted-args",
+ "Warn if an argument list is modified to match the receiver.")
+ val warnNullaryUnit = lintflag("nullary-unit",
+ "Warn when nullary methods return Unit.")
+ val warnInaccessible = lintflag("inaccessible",
+ "Warn about inaccessible types in method signatures.")
+ val warnNullaryOverride = lintflag("nullary-override",
+ "Warn when non-nullary `def f()' overrides nullary `def f'.")
+ val warnInferAny = lintflag("infer-any",
+ "Warn when a type argument is inferred to be `Any`.")
+ val warnMissingInterpolator = lintflag("missing-interpolator",
+ "A string literal appears to be missing an interpolator id.")
+ val warnDocDetached = lintflag("doc-detached",
+ "A ScalaDoc comment appears to be detached from its element.")
+ val warnPrivateShadow = lintflag("private-shadow",
+ "A private field (or class parameter) shadows a superclass field.")
+ val warnTypeParameterShadow = lintflag("type-parameter-shadow",
+ "A local type parameter shadows a type already in scope.")
+ val warnPolyImplicitOverload = lintflag("poly-implicit-overload",
+ "Parameterized overloaded implicit methods are not visible as view bounds")
+ val warnOptionImplicit = lintflag("option-implicit",
+ "Option.apply used implicit view.")
+ val warnDelayedInit = lintflag("delayedinit-select",
+ "Selecting member of DelayedInit")
+ val warnByNameRightAssociative = lintflag("by-name-right-associative",
+ "By-name parameter of right associative operator")
+ val warnPackageObjectClasses = lintflag("package-object-classes",
+ "Class or object defined in package object")
+ val warnUnsoundMatch = lintflag("unsound-match",
+ "Pattern match may not be typesafe")
- // Individual warnings.
- val warnAdaptedArgs = BooleanSetting ("-Ywarn-adapted-args", "Warn if an argument list is modified to match the receiver.")
- val warnDeadCode = BooleanSetting ("-Ywarn-dead-code", "Warn when dead code is identified.")
- val warnValueDiscard = BooleanSetting ("-Ywarn-value-discard", "Warn when non-Unit expression results are unused.")
- val warnNumericWiden = BooleanSetting ("-Ywarn-numeric-widen", "Warn when numerics are widened.")
- val warnNullaryUnit = BooleanSetting ("-Ywarn-nullary-unit", "Warn when nullary methods return Unit.")
- val warnInaccessible = BooleanSetting ("-Ywarn-inaccessible", "Warn about inaccessible types in method signatures.")
- val warnNullaryOverride = BooleanSetting ("-Ywarn-nullary-override", "Warn when non-nullary overrides nullary, e.g. `def foo()` over `def foo`.")
- val warnInferAny = BooleanSetting ("-Ywarn-infer-any", "Warn when a type argument is inferred to be `Any`.")
- val warnUnused = BooleanSetting ("-Ywarn-unused", "Warn when local and private vals, vars, defs, and types are are unused")
- val warnUnusedImport = BooleanSetting ("-Ywarn-unused-import", "Warn when imports are unused")
-
- // Warning groups.
- val lint = BooleanSetting("-Xlint", "Enable recommended additional warnings.") enablingIfNotSetByUser lintWarnings
+ // Experimental lint warnings that are turned off, but which could be turned on programmatically.
+ // These warnings are said to blind those who dare enable them.
+ // They are not activated by -Xlint and can't be enabled on the command line.
+ val warnValueOverrides = {
+ val flag = lintflag("value-overrides", "Generated value class method overrides an implementation")
+ flag.value = false
+ flag
+ }
+
+ // The Xlint warning group.
+ private val xlint = new BooleanSetting("-Zunused", "True if -Xlint or -Xlint:_")
+ // On -Xlint or -Xlint:_, set xlint, otherwise set the lint warning unless already set true
+ val lint = {
+ val description = "Enable or disable specific warnings"
+ val choices = (lintWarnings map (_.name)).sorted
+ MultiChoiceSetting(
+ name = "-Xlint",
+ helpArg = "warning",
+ descr = description,
+ choices = choices,
+ default = Some(() => xlint.value = true)
+ ) { s =>
+ def helpline(n: String) = lintWarnings.find(_.name == n).map(w => f" ${w.name}%-25s ${w.helpDescription}%n")
+ choices flatMap (helpline(_)) mkString (f"$description:%n", "", f"%n")
+ } withPostSetHook { x =>
+ val Neg = "-"
+ def setPolitely(b: BooleanSetting, v: Boolean) = if (!b.isSetByUser || !b) b.value = v
+ def set(w: String, v: Boolean) = lintWarnings find (_.name == w) foreach (setPolitely(_, v))
+ def propagate(ss: List[String]): Unit = ss match {
+ case w :: rest => if (w startsWith Neg) set(w stripPrefix Neg, false) else set(w, true) ; propagate(rest)
+ case Nil => ()
+ }
+ propagate(x.value)
+ }
+ }
+
+ // Lint warnings that are currently -Y, but deprecated in that usage
+ @deprecated("Use warnAdaptedArgs", since="2.11.2")
+ val YwarnAdaptedArgs = BooleanSetting("-Ywarn-adapted-args",
+ "Warn if an argument list is modified to match the receiver.") enabling List(warnAdaptedArgs)
+ //withDeprecationMessage "Enable -Xlint:adapted-args"
+ @deprecated("Use warnNullaryUnit", since="2.11.2")
+ val YwarnNullaryUnit = BooleanSetting("-Ywarn-nullary-unit",
+ "Warn when nullary methods return Unit.") enabling List(warnNullaryUnit)
+ //withDeprecationMessage "Enable -Xlint:nullary-unit"
+ @deprecated("Use warnInaccessible", since="2.11.2")
+ val YwarnInaccessible = BooleanSetting("-Ywarn-inaccessible",
+ "Warn about inaccessible types in method signatures.") enabling List(warnInaccessible)
+ //withDeprecationMessage "Enable -Xlint:inaccessible"
+ @deprecated("Use warnNullaryOverride", since="2.11.2")
+ val YwarnNullaryOverride = BooleanSetting("-Ywarn-nullary-override",
+ "Warn when non-nullary `def f()' overrides nullary `def f'.") enabling List(warnNullaryOverride)
+ //withDeprecationMessage "Enable -Xlint:nullary-override"
+ @deprecated("Use warnInferAny", since="2.11.2")
+ val YwarnInferAny = BooleanSetting("-Ywarn-infer-any",
+ "Warn when a type argument is inferred to be `Any`.") enabling List(warnInferAny)
+ //withDeprecationMessage "Enable -Xlint:infer-any"
+
+ private lazy val warnSelectNullable = BooleanSetting("-Xcheck-null", "This option is obsolete and does nothing.")
// Backward compatibility.
@deprecated("Use fatalWarnings", "2.11.0") def Xwarnfatal = fatalWarnings // used by sbt
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 447fa66ae4..82c2a4d6ed 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -240,6 +240,12 @@ abstract class SymbolLoaders {
}
}
+ private def phaseBeforeRefchecks: Phase = {
+ var resPhase = phase
+ while (resPhase.refChecked) resPhase = resPhase.prev
+ resPhase
+ }
+
/**
* Load contents of a package
*/
@@ -248,19 +254,24 @@ abstract class SymbolLoaders {
protected def doComplete(root: Symbol) {
assert(root.isPackageClass, root)
- root.setInfo(new PackageClassInfoType(newScope, root))
-
- if (!root.isRoot) {
- for (classRep <- classpath.classes) {
- initializeFromClassPath(root, classRep)
- }
- }
- if (!root.isEmptyPackageClass) {
- for (pkg <- classpath.packages) {
- enterPackage(root, pkg.name, new PackageLoader(pkg))
+ // Time travel to a phase before refchecks avoids an initialization issue. `openPackageModule`
+ // creates a module symbol and invokes invokes `companionModule` while the `infos` field is
+ // still null. This calls `isModuleNotMethod`, which forces the `info` if run after refchecks.
+ enteringPhase(phaseBeforeRefchecks) {
+ root.setInfo(new PackageClassInfoType(newScope, root))
+
+ if (!root.isRoot) {
+ for (classRep <- classpath.classes) {
+ initializeFromClassPath(root, classRep)
+ }
}
+ if (!root.isEmptyPackageClass) {
+ for (pkg <- classpath.packages) {
+ enterPackage(root, pkg.name, new PackageLoader(pkg))
+ }
- openPackageModule(root)
+ openPackageModule(root)
+ }
}
}
}
@@ -290,7 +301,13 @@ abstract class SymbolLoaders {
protected def doComplete(root: Symbol) {
val start = if (Statistics.canEnable) Statistics.startTimer(classReadNanos) else null
- classfileParser.parse(classfile, root)
+
+ // Running the classfile parser after refchecks can lead to "illegal class file dependency"
+ // errors. More concretely, the classfile parser calls "sym.companionModule", which calls
+ // "isModuleNotMethod" on the companion. After refchecks, this method forces the info, which
+ // may run the classfile parser. This produces the error.
+ enteringPhase(phaseBeforeRefchecks)(classfileParser.parse(classfile, root))
+
if (root.associatedFile eq NoAbstractFile) {
root match {
// In fact, the ModuleSymbol forwards its setter to the module class
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index 1f8ab7e887..9cc8d779a0 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -37,6 +37,15 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
/** the following two members override abstract members in Transform */
val phaseName: String = "delambdafy"
+ override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = {
+ if (settings.Ydelambdafy.value == "method") new Phase(prev)
+ else new SkipPhase(prev)
+ }
+
+ class SkipPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) {
+ def apply(unit: global.CompilationUnit): Unit = ()
+ }
+
protected def newTransformer(unit: CompilationUnit): Transformer =
new DelambdafyTransformer(unit)
@@ -252,39 +261,39 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
captureProxies2 += ((capture, sym))
}
- // the Optional proxy that will hold a reference to the 'this'
- // object used by the lambda, if any. NoSymbol if there is no this proxy
- val thisProxy = {
- val target = targetMethod(originalFunction)
- if (thisReferringMethods contains target) {
- val sym = anonClass.newVariable(nme.FAKE_LOCAL_THIS, originalFunction.pos, SYNTHETIC)
- sym.info = oldClass.tpe
- sym
- } else NoSymbol
- }
+ // the Optional proxy that will hold a reference to the 'this'
+ // object used by the lambda, if any. NoSymbol if there is no this proxy
+ val thisProxy = {
+ val target = targetMethod(originalFunction)
+ if (thisReferringMethods contains target) {
+ val sym = anonClass.newVariable(nme.FAKE_LOCAL_THIS, originalFunction.pos, SYNTHETIC)
+ sym.info = oldClass.tpe
+ sym
+ } else NoSymbol
+ }
- val decapturify = new DeCapturifyTransformer(captureProxies2, unit, oldClass, anonClass, originalFunction.symbol.pos, thisProxy)
+ val decapturify = new DeCapturifyTransformer(captureProxies2, unit, oldClass, anonClass, originalFunction.symbol.pos, thisProxy)
- val accessorMethod = createAccessorMethod(thisProxy, originalFunction)
+ val accessorMethod = createAccessorMethod(thisProxy, originalFunction)
- val decapturedFunction = decapturify.transform(originalFunction).asInstanceOf[Function]
+ val decapturedFunction = decapturify.transform(originalFunction).asInstanceOf[Function]
- val members = (optionSymbol(thisProxy).toList ++ (captureProxies2 map (_._2))) map {member =>
- anonClass.info.decls enter member
- ValDef(member, gen.mkZero(member.tpe)) setPos decapturedFunction.pos
- }
+ val members = (optionSymbol(thisProxy).toList ++ (captureProxies2 map (_._2))) map {member =>
+ anonClass.info.decls enter member
+ ValDef(member, gen.mkZero(member.tpe)) setPos decapturedFunction.pos
+ }
- // constructor
- val constr = createConstructor(anonClass, members)
+ // constructor
+ val constr = createConstructor(anonClass, members)
- // apply method with same arguments and return type as original lambda.
- val applyMethodDef = createApplyMethod(anonClass, decapturedFunction, accessorMethod, thisProxy)
+ // apply method with same arguments and return type as original lambda.
+ val applyMethodDef = createApplyMethod(anonClass, decapturedFunction, accessorMethod, thisProxy)
- val bridgeMethod = createBridgeMethod(anonClass, originalFunction, applyMethodDef)
+ val bridgeMethod = createBridgeMethod(anonClass, originalFunction, applyMethodDef)
- def fulldef(sym: Symbol) =
- if (sym == NoSymbol) sym.toString
- else s"$sym: ${sym.tpe} in ${sym.owner}"
+ def fulldef(sym: Symbol) =
+ if (sym == NoSymbol) sym.toString
+ else s"$sym: ${sym.tpe} in ${sym.owner}"
bridgeMethod foreach (bm =>
// TODO SI-6260 maybe just create the apply method with the signature (Object => Object) in all cases
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index ec4deb6be0..3d8b2f02f3 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -468,8 +468,12 @@ abstract class Erasure extends AddInterfaces
if (!bridgeNeeded)
return
- val newFlags = (member.flags | BRIDGE | ARTIFACT) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED)
- val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos
+ var newFlags = (member.flags | BRIDGE | ARTIFACT) & ~(ACCESSOR | DEFERRED | LAZY | lateDEFERRED)
+ // If `member` is a ModuleSymbol, the bridge should not also be a ModuleSymbol. Otherwise we
+ // end up with two module symbols with the same name in the same scope, which is surprising
+ // when implementing later phases.
+ if (member.isModule) newFlags = (newFlags | METHOD) & ~(MODULE | lateMETHOD | STABLE)
+ val bridge = other.cloneSymbolImpl(root, newFlags) setPos root.pos
debuglog("generating bridge from %s (%s): %s to %s: %s".format(
other, flagsToString(newFlags),
@@ -1133,7 +1137,7 @@ abstract class Erasure extends AddInterfaces
val tree2 = mixinTransformer.transform(tree1)
// debuglog("tree after addinterfaces: \n" + tree2)
- newTyper(rootContext(unit, tree, erasedTypes = true)).typed(tree2)
+ newTyper(rootContextPostTyper(unit, tree)).typed(tree2)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
index c3fbfae322..fa53ef48b5 100644
--- a/src/compiler/scala/tools/nsc/transform/Flatten.scala
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -76,8 +76,17 @@ abstract class Flatten extends InfoTransform {
for (sym <- decls) {
if (sym.isTerm && !sym.isStaticModule) {
decls1 enter sym
- if (sym.isModule)
+ if (sym.isModule) {
+ // Nested, non-static moduls are transformed to methods.
+ assert(sym.isMethod, s"Non-static $sym should have the lateMETHOD flag from RefChecks")
+ // Note that module classes are not entered into the 'decls' of the ClassInfoType
+ // of the outer class, only the module symbols are. So the current loop does
+ // not visit module classes. Therefore we set the LIFTED flag here for module
+ // classes.
+ // TODO: should we also set the LIFTED flag for static, nested module classes?
+ // currently they don't get the flag, even though they are lifted to the package
sym.moduleClass setFlag LIFTED
+ }
} else if (sym.isClass)
liftSymbol(sym)
}
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index f85d8222f0..d69c9d9a65 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -449,6 +449,8 @@ abstract class LambdaLift extends InfoTransform {
if (sym.isClass) sym.owner = sym.owner.toInterface
if (sym.isMethod) sym setFlag LIFTED
liftedDefs(sym.owner) ::= tree
+ // TODO: this modifies the ClassInfotype of the enclosing class, which is associated with another phase (explicitouter).
+ // This breaks type history: in a phase travel to before lambda lift, the ClassInfoType will contain lifted classes.
sym.owner.info.decls enterUnique sym
debuglog("lifted: " + sym + " from " + oldOwner + " to " + sym.owner)
EmptyTree
diff --git a/src/compiler/scala/tools/nsc/transform/LazyVals.scala b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
index b71d14a04f..38671ebaae 100644
--- a/src/compiler/scala/tools/nsc/transform/LazyVals.scala
+++ b/src/compiler/scala/tools/nsc/transform/LazyVals.scala
@@ -192,13 +192,15 @@ abstract class LazyVals extends Transform with TypingTransformers with ast.TreeD
def mkSlowPathDef(clazz: Symbol, lzyVal: Symbol, cond: Tree, syncBody: List[Tree],
stats: List[Tree], retVal: Tree): Tree = {
+ // Q: is there a reason to first set owner to `clazz` (by using clazz.newMethod), and then
+ // changing it to lzyVal.owner very soon after? Could we just do lzyVal.owner.newMethod?
val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, STABLE | PRIVATE)
defSym setInfo MethodType(List(), lzyVal.tpe.resultType)
defSym.owner = lzyVal.owner
debuglog(s"crete slow compute path $defSym with owner ${defSym.owner} for lazy val $lzyVal")
if (bitmaps.contains(lzyVal))
bitmaps(lzyVal).map(_.owner = defSym)
- val rhs: Tree = (gen.mkSynchronizedCheck(clazz, cond, syncBody, stats)).changeOwner(currentOwner -> defSym)
+ val rhs: Tree = gen.mkSynchronizedCheck(clazz, cond, syncBody, stats).changeOwner(currentOwner -> defSym)
DefDef(defSym, addBitmapDefs(lzyVal, BLOCK(rhs, retVal)))
}
diff --git a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
index 3feadcd9b2..dc3313e2e4 100644
--- a/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
+++ b/src/compiler/scala/tools/nsc/transform/TypingTransformers.scala
@@ -17,9 +17,9 @@ trait TypingTransformers {
abstract class TypingTransformer(unit: CompilationUnit) extends Transformer {
var localTyper: analyzer.Typer =
if (phase.erasedTypes)
- erasure.newTyper(erasure.rootContext(unit, EmptyTree, erasedTypes = true)).asInstanceOf[analyzer.Typer]
- else
- analyzer.newTyper(analyzer.rootContext(unit, EmptyTree, true))
+ erasure.newTyper(erasure.rootContextPostTyper(unit, EmptyTree)).asInstanceOf[analyzer.Typer]
+ else // TODO: AM: should some phases use a regular rootContext instead of a post-typer one??
+ analyzer.newTyper(analyzer.rootContextPostTyper(unit, EmptyTree))
protected var curTree: Tree = _
override final def atOwner[A](owner: Symbol)(trans: => A): A = atOwner(curTree, owner)(trans)
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
index 2209aac00f..9b85f1b36a 100644
--- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala
+++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala
@@ -69,7 +69,6 @@ abstract class UnCurry extends InfoTransform
private val byNameArgs = mutable.HashSet[Tree]()
private val noApply = mutable.HashSet[Tree]()
private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]()
- private val repeatedParams = mutable.Map[Symbol, List[ValDef]]()
/** Add a new synthetic member for `currentOwner` */
private def addNewMember(t: Tree): Unit =
@@ -428,7 +427,7 @@ abstract class UnCurry extends InfoTransform
treeCopy.ValDef(p, p.mods, p.name, p.tpt, EmptyTree)
})
- if (dd.symbol hasAnnotation VarargsClass) saveRepeatedParams(dd)
+ if (dd.symbol hasAnnotation VarargsClass) validateVarargs(dd)
withNeedLift(needLift = false) {
if (dd.symbol.isClassConstructor) {
@@ -699,19 +698,12 @@ abstract class UnCurry extends InfoTransform
}
}
-
- /* Analyzes repeated params if method is annotated as `varargs`.
- * If the repeated params exist, it saves them into the `repeatedParams` map,
- * which is used later.
- */
- private def saveRepeatedParams(dd: DefDef): Unit =
+ private def validateVarargs(dd: DefDef): Unit =
if (dd.symbol.isConstructor)
reporter.error(dd.symbol.pos, "A constructor cannot be annotated with a `varargs` annotation.")
- else treeInfo.repeatedParams(dd) match {
- case Nil =>
- reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.")
- case reps =>
- repeatedParams(dd.symbol) = reps
+ else {
+ val hasRepeated = mexists(dd.symbol.paramss)(sym => definitions.isRepeatedParamType(sym.tpe))
+ if (!hasRepeated) reporter.error(dd.symbol.pos, "A method without repeated parameters cannot be annotated with the `varargs` annotation.")
}
/* Called during post transform, after the method argument lists have been flattened.
@@ -719,7 +711,7 @@ abstract class UnCurry extends InfoTransform
* varargs forwarder.
*/
private def addJavaVarargsForwarders(dd: DefDef, flatdd: DefDef): DefDef = {
- if (!dd.symbol.hasAnnotation(VarargsClass) || !repeatedParams.contains(dd.symbol))
+ if (!dd.symbol.hasAnnotation(VarargsClass) || !enteringUncurry(mexists(dd.symbol.paramss)(sym => definitions.isRepeatedParamType(sym.tpe))))
return flatdd
def toArrayType(tp: Type): Type = {
@@ -735,19 +727,18 @@ abstract class UnCurry extends InfoTransform
)
}
- val reps = repeatedParams(dd.symbol)
- val rpsymbols = reps.map(_.symbol).toSet
val theTyper = typer.atOwner(dd, currentClass)
- val flatparams = flatdd.vparamss.head
+ val flatparams = flatdd.symbol.paramss.head
+ val isRepeated = enteringUncurry(dd.symbol.info.paramss.flatten.map(sym => definitions.isRepeatedParamType(sym.tpe)))
// create the type
- val forwformals = flatparams map {
- case p if rpsymbols(p.symbol) => toArrayType(p.symbol.tpe)
- case p => p.symbol.tpe
+ val forwformals = map2(flatparams, isRepeated) {
+ case (p, true) => toArrayType(p.tpe)
+ case (p, false)=> p.tpe
}
val forwresult = dd.symbol.tpe_*.finalResultType
val forwformsyms = map2(forwformals, flatparams)((tp, oldparam) =>
- currentClass.newValueParameter(oldparam.name, oldparam.symbol.pos).setInfo(tp)
+ currentClass.newValueParameter(oldparam.name.toTermName, oldparam.pos).setInfo(tp)
)
def mono = MethodType(forwformsyms, forwresult)
val forwtype = dd.symbol.tpe match {
@@ -761,13 +752,13 @@ abstract class UnCurry extends InfoTransform
// create the tree
val forwtree = theTyper.typedPos(dd.pos) {
- val locals = map2(forwParams, flatparams) {
- case (_, fp) if !rpsymbols(fp.symbol) => null
- case (argsym, fp) =>
+ val locals = map3(forwParams, flatparams, isRepeated) {
+ case (_, fp, false) => null
+ case (argsym, fp, true) =>
Block(Nil,
gen.mkCast(
gen.mkWrapArray(Ident(argsym), elementType(ArrayClass, argsym.tpe)),
- seqType(elementType(SeqClass, fp.symbol.tpe))
+ seqType(elementType(SeqClass, fp.tpe))
)
)
}
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
index 6f81cbe152..b2dc6e4e52 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchAnalysis.scala
@@ -50,7 +50,7 @@ trait TreeAndTypeAnalysis extends Debugging {
// but the annotation didn't bubble up...
// This is a pretty poor approximation.
def unsoundAssumptionUsed = binder.name != nme.WILDCARD && !(pt <:< pat.tpe)
- if (settings.lint && unsoundAssumptionUsed)
+ if (settings.warnUnsoundMatch && unsoundAssumptionUsed)
reporter.warning(pat.pos,
sm"""The value matched by $pat is bound to ${binder.name}, which may be used under the
|unsound assumption that it has type ${pat.tpe}, whereas we can only safely
diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
index 37c39c07be..2f4d228347 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
@@ -82,7 +82,8 @@ trait Adaptations {
} else if (settings.warnAdaptedArgs)
context.warning(t.pos, adaptWarningMessage(s"Adapting argument list by creating a ${args.size}-tuple: this may not be what you want."))
- !settings.noAdaptedArgs || !(args.isEmpty && settings.future)
+ // return `true` if the adaptation should be kept
+ !(settings.noAdaptedArgs || (args.isEmpty && settings.future))
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 9715fdaf00..20e462bbce 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -27,6 +27,16 @@ trait ContextErrors {
override def toString() = "[Type error at:" + errPos + "] " + errMsg
}
+ abstract class AbsAmbiguousTypeError extends AbsTypeError
+
+ case class AmbiguousTypeError(errPos: Position, errMsg: String)
+ extends AbsAmbiguousTypeError
+
+ case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
+ extends AbsAmbiguousTypeError {
+ def errPos = underlyingTree.pos
+ }
+
sealed abstract class TreeTypeError extends AbsTypeError {
def underlyingTree: Tree
def errPos = underlyingTree.pos
@@ -38,9 +48,6 @@ trait ContextErrors {
case class AccessTypeError(underlyingTree: Tree, errMsg: String)
extends TreeTypeError
- case class AmbiguousTypeError(errPos: Position, errMsg: String)
- extends AbsTypeError
-
case class SymbolTypeError(underlyingSym: Symbol, errMsg: String)
extends AbsTypeError {
@@ -75,8 +82,6 @@ trait ContextErrors {
s"diverging implicit expansion for type ${pt}\nstarting with ${sym.fullLocationString}"
}
- case class AmbiguousImplicitTypeError(underlyingTree: Tree, errMsg: String)
- extends TreeTypeError
case class PosAndMsgTypeError(errPos: Position, errMsg: String)
extends AbsTypeError
@@ -90,10 +95,6 @@ trait ContextErrors {
issueTypeError(SymbolTypeError(sym, msg))
}
- def issueAmbiguousTypeError(pre: Type, sym1: Symbol, sym2: Symbol, err: AmbiguousTypeError)(implicit context: Context) {
- context.issueAmbiguousError(pre, sym1, sym2, err)
- }
-
def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) }
def typeErrorMsg(found: Type, req: Type) = "type mismatch" + foundReqMsg(found, req)
@@ -123,6 +124,36 @@ trait ContextErrors {
import ErrorUtils._
+ private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
+ def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
+ val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
+ // TODO: clean this up! (This is a more explicit version of what the code use to do, to reveal the issue.)
+ throw new TypeError(analyzer.lastTreeToTyper.pos, message)
+ }
+
+ def MacroCantExpand210xMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
+
+ def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
+ MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
+
+ def NoImplicitFoundError(tree: Tree, param: Symbol)(implicit context: Context): Unit = {
+ def errMsg = {
+ val paramName = param.name
+ val paramTp = param.tpe
+ def evOrParam = (
+ if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
+ "evidence parameter of type"
+ else
+ s"parameter $paramName:")
+ paramTp.typeSymbolDirect match {
+ case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
+ case _ => s"could not find implicit value for $evOrParam $paramTp"
+ }
+ }
+ issueNormalTypeError(tree, errMsg)
+ }
+
trait TyperContextErrors {
self: Typer =>
@@ -141,24 +172,6 @@ trait ContextErrors {
setError(tree)
}
- def NoImplicitFoundError(tree: Tree, param: Symbol) = {
- def errMsg = {
- val paramName = param.name
- val paramTp = param.tpe
- def evOrParam = (
- if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
- "evidence parameter of type"
- else
- s"parameter $paramName:"
- )
- paramTp.typeSymbolDirect match {
- case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
- case _ => s"could not find implicit value for $evOrParam $paramTp"
- }
- }
- issueNormalTypeError(tree, errMsg)
- }
-
def AdaptTypeError(tree: Tree, found: Type, req: Type) = {
// SI-3971 unwrapping to the outermost Apply helps prevent confusion with the
// error message point.
@@ -733,17 +746,6 @@ trait ContextErrors {
NormalTypeError(expandee, "too many argument lists for " + fun)
}
- private def MacroIncompatibleEngineError(friendlyMessage: String, internalMessage: String) = {
- def debugDiagnostic = s"(internal diagnostic: $internalMessage)"
- val message = if (macroDebugLite || macroDebugVerbose) s"$friendlyMessage $debugDiagnostic" else friendlyMessage
- issueNormalTypeError(lastTreeToTyper, message)
- }
-
- def MacroCantExpand210xMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("can't expand macros compiled by previous versions of Scala", internalMessage)
-
- def MacroCantExpandIncompatibleMacrosError(internalMessage: String) =
- MacroIncompatibleEngineError("macro cannot be expanded, because it was compiled by an incompatible macro engine", internalMessage)
case object MacroExpansionException extends Exception with scala.util.control.ControlThrowable
@@ -883,19 +885,21 @@ trait ContextErrors {
val WrongNumber, NoParams, ArgsDoNotConform = Value
}
- private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) =
- if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
- val methodName = nme.defaultGetterToMethod(sym1.name)
- (sym1.enclClass.pos,
- "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
- " define default arguments")
- } else {
- (pos,
- ("ambiguous reference to overloaded definition,\n" +
- "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
- "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
- "\nmatch " + rest)
- )
+ private def issueAmbiguousTypeErrorUnlessErroneous(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String): Unit =
+ if (!(pre.isErroneous || sym1.isErroneous || sym2.isErroneous)) {
+ if (sym1.hasDefault && sym2.hasDefault && sym1.enclClass == sym2.enclClass) {
+ val methodName = nme.defaultGetterToMethod(sym1.name)
+ context.issueAmbiguousError(AmbiguousTypeError(sym1.enclClass.pos,
+ "in "+ sym1.enclClass +", multiple overloaded alternatives of " + methodName +
+ " define default arguments"))
+ } else {
+ context.issueAmbiguousError(AmbiguousTypeError(pos,
+ ("ambiguous reference to overloaded definition,\n" +
+ "both " + sym1 + sym1.locationString + " of type " + pre.memberType(sym1) +
+ "\nand " + sym2 + sym2.locationString + " of type " + pre.memberType(sym2) +
+ "\nmatch " + rest)
+ ))
+ }
}
def AccessError(tree: Tree, sym: Symbol, ctx: Context, explanation: String): AbsTypeError =
@@ -952,8 +956,7 @@ trait ContextErrors {
val msg0 =
"argument types " + argtpes.mkString("(", ",", ")") +
(if (pt == WildcardType) "" else " and expected result type " + pt)
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, msg0)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, msg0)
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)
@@ -966,8 +969,7 @@ trait ContextErrors {
}
def AmbiguousExprAlternativeError(tree: Tree, pre: Type, best: Symbol, firstCompeting: Symbol, pt: Type, lastTry: Boolean) = {
- val (pos, msg) = ambiguousErrorMsgPos(tree.pos, pre, best, firstCompeting, "expected type " + pt)
- issueAmbiguousTypeError(pre, best, firstCompeting, AmbiguousTypeError(pos, msg))
+ issueAmbiguousTypeErrorUnlessErroneous(tree.pos, pre, best, firstCompeting, "expected type " + pt)
setErrorOnLastTry(lastTry, tree)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 72ca9b879a..a79f162140 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -9,6 +9,7 @@ package typechecker
import scala.collection.{ immutable, mutable }
import scala.annotation.tailrec
import scala.reflect.internal.util.shortClassOfInstance
+import scala.tools.nsc.reporters.Reporter
/**
* @author Martin Odersky
@@ -98,7 +99,7 @@ trait Contexts { self: Analyzer =>
}
- def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, erasedTypes: Boolean = false): Context = {
+ def rootContext(unit: CompilationUnit, tree: Tree = EmptyTree, throwing: Boolean = false, checking: Boolean = false): Context = {
val rootImportsContext = (startContext /: rootImports(unit))((c, sym) => c.make(gen.mkWildcardImport(sym)))
// there must be a scala.xml package when xml literals were parsed in this unit
@@ -113,18 +114,21 @@ trait Contexts { self: Analyzer =>
else rootImportsContext.make(gen.mkImport(ScalaXmlPackage, nme.TopScope, nme.dollarScope))
val c = contextWithXML.make(tree, unit = unit)
- if (erasedTypes) c.setThrowErrors() else c.setReportErrors()
- c(EnrichmentEnabled | ImplicitsEnabled) = !erasedTypes
+
+ c.initRootContext(throwing, checking)
c
}
+ def rootContextPostTyper(unit: CompilationUnit, tree: Tree = EmptyTree): Context =
+ rootContext(unit, tree, throwing = true)
+
def resetContexts() {
startContext.enclosingContextChain foreach { context =>
context.tree match {
case Import(qual, _) => qual setType singleType(qual.symbol.owner.thisType, qual.symbol)
case _ =>
}
- context.reportBuffer.clearAll()
+ context.reporter.clearAll()
}
}
@@ -178,7 +182,8 @@ trait Contexts { self: Analyzer =>
* @param _outer The next outer context.
*/
class Context private[typechecker](val tree: Tree, val owner: Symbol, val scope: Scope,
- val unit: CompilationUnit, _outer: Context) {
+ val unit: CompilationUnit, _outer: Context,
+ private[this] var _reporter: ContextReporter = new ThrowingReporter) {
private def outerIsNoContext = _outer eq null
final def outer: Context = if (outerIsNoContext) NoContext else _outer
@@ -254,8 +259,6 @@ trait Contexts { self: Analyzer =>
def macrosEnabled = this(MacrosEnabled)
def enrichmentEnabled_=(value: Boolean) = this(EnrichmentEnabled) = value
def enrichmentEnabled = this(EnrichmentEnabled)
- def checking_=(value: Boolean) = this(Checking) = value
- def checking = this(Checking)
def retyping_=(value: Boolean) = this(ReTyping) = value
def retyping = this(ReTyping)
def inSecondTry = this(SecondTry)
@@ -265,8 +268,9 @@ trait Contexts { self: Analyzer =>
def defaultModeForTyped: Mode = if (inTypeConstructorAllowed) Mode.NOmode else Mode.EXPRmode
- /** These messages are printed when issuing an error */
- var diagnostic: List[String] = Nil
+ /** To enrich error messages involving default arguments.
+ When extending the notion, group diagnostics in an object. */
+ var diagUsedDefaults: Boolean = false
/** Saved type bounds for type parameters which are narrowed in a GADT. */
var savedTypeBounds: List[(Symbol, Type)] = List()
@@ -310,7 +314,7 @@ trait Contexts { self: Analyzer =>
*/
def savingUndeterminedTypeParams[A](reportAmbiguous: Boolean = ambiguousErrors)(body: => A): A = {
withMode() {
- this(AmbiguousErrors) = reportAmbiguous
+ setAmbiguousErrors(reportAmbiguous)
val saved = extractUndetparams()
try body
finally undetparams = saved
@@ -321,54 +325,59 @@ trait Contexts { self: Analyzer =>
// Error reporting policies and buffer.
//
- private var _reportBuffer: ReportBuffer = new ReportBuffer
- /** A buffer for errors and warnings, used with `this.bufferErrors == true` */
- def reportBuffer = _reportBuffer
- /** Discard the current report buffer, and replace with an empty one */
- def useFreshReportBuffer() = _reportBuffer = new ReportBuffer
- /** Discard the current report buffer, and replace with `other` */
- def restoreReportBuffer(other: ReportBuffer) = _reportBuffer = other
-
- /** The first error, if any, in the report buffer */
- def firstError: Option[AbsTypeError] = reportBuffer.firstError
- def errors: Seq[AbsTypeError] = reportBuffer.errors
- /** Does the report buffer contain any errors? */
- def hasErrors = reportBuffer.hasErrors
-
- def reportErrors = this(ReportErrors)
- def bufferErrors = this(BufferErrors)
+ // the reporter for this context
+ def reporter: ContextReporter = _reporter
+
+ // if set, errors will not be reporter/thrown
+ def bufferErrors = reporter.isBuffering
+ def reportErrors = !bufferErrors
+
+ // whether to *report* (which is separate from buffering/throwing) ambiguity errors
def ambiguousErrors = this(AmbiguousErrors)
- def throwErrors = contextMode.inNone(ReportErrors | BufferErrors)
-
- def setReportErrors(): Unit = set(enable = ReportErrors | AmbiguousErrors, disable = BufferErrors)
- def setBufferErrors(): Unit = set(enable = BufferErrors, disable = ReportErrors | AmbiguousErrors)
- def setThrowErrors(): Unit = this(ReportErrors | AmbiguousErrors | BufferErrors) = false
- def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
-
- /** Append the given errors to the report buffer */
- def updateBuffer(errors: Traversable[AbsTypeError]) = reportBuffer ++= errors
- /** Clear all errors from the report buffer */
- def flushBuffer() { reportBuffer.clearAllErrors() }
- /** Return and clear all errors from the report buffer */
- def flushAndReturnBuffer(): immutable.Seq[AbsTypeError] = {
- val current = reportBuffer.errors
- reportBuffer.clearAllErrors()
- current
- }
- /** Issue and clear all warnings from the report buffer */
- def flushAndIssueWarnings() {
- reportBuffer.warnings foreach {
- case (pos, msg) => reporter.warning(pos, msg)
+ private def setAmbiguousErrors(report: Boolean): Unit = this(AmbiguousErrors) = report
+
+ /**
+ * Try inference twice: once without views and once with views,
+ * unless views are already disabled.
+ */
+ abstract class TryTwice {
+ def tryOnce(isLastTry: Boolean): Unit
+
+ final def apply(): Unit = {
+ val doLastTry =
+ // do first try if implicits are enabled
+ if (implicitsEnabled) {
+ // We create a new BufferingReporter to
+ // distinguish errors that occurred before entering tryTwice
+ // and our first attempt in 'withImplicitsDisabled'. If the
+ // first attempt fails, we try with implicits on
+ // and the original reporter.
+ // immediate reporting of ambiguous errors is suppressed, so that they are buffered
+ inSilentMode {
+ try {
+ set(disable = ImplicitsEnabled | EnrichmentEnabled) // restored by inSilentMode
+ tryOnce(false)
+ reporter.hasErrors
+ } catch {
+ case ex: CyclicReference => throw ex
+ case ex: TypeError => true // recoverable cyclic references?
+ }
+ }
+ } else true
+
+ // do last try if try with implicits enabled failed
+ // (or if it was not attempted because they were disabled)
+ if (doLastTry)
+ tryOnce(true)
}
- reportBuffer.clearAllWarnings()
}
//
// Temporary mode adjustment
//
- @inline def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
+ @inline final def withMode[T](enabled: ContextMode = NOmode, disabled: ContextMode = NOmode)(op: => T): T = {
val saved = contextMode
set(enabled, disabled)
try op
@@ -402,12 +411,18 @@ trait Contexts { self: Analyzer =>
// See comment on FormerNonStickyModes.
@inline final def withOnlyStickyModes[T](op: => T): T = withMode(disabled = FormerNonStickyModes)(op)
- /** @return true if the `expr` evaluates to true within a silent Context that incurs no errors */
+ // inliner note: this has to be a simple method for inlining to work -- moved the `&& !reporter.hasErrors` out
@inline final def inSilentMode(expr: => Boolean): Boolean = {
- withMode() { // withMode with no arguments to restore the mode mutated by `setBufferErrors`.
- setBufferErrors()
- try expr && !hasErrors
- finally reportBuffer.clearAll()
+ val savedContextMode = contextMode
+ val savedReporter = reporter
+
+ setAmbiguousErrors(false)
+ _reporter = new BufferingReporter
+
+ try expr
+ finally {
+ contextMode = savedContextMode
+ _reporter = savedReporter
}
}
@@ -423,7 +438,8 @@ trait Contexts { self: Analyzer =>
* `Context#imports`.
*/
def make(tree: Tree = tree, owner: Symbol = owner,
- scope: Scope = scope, unit: CompilationUnit = unit): Context = {
+ scope: Scope = scope, unit: CompilationUnit = unit,
+ reporter: ContextReporter = this.reporter): Context = {
val isTemplateOrPackage = tree match {
case _: Template | _: PackageDef => true
case _ => false
@@ -446,16 +462,15 @@ trait Contexts { self: Analyzer =>
// The blank canvas
val c = if (isImport)
- new Context(tree, owner, scope, unit, this) with ImportContext
+ new Context(tree, owner, scope, unit, this, reporter) with ImportContext
else
- new Context(tree, owner, scope, unit, this)
+ new Context(tree, owner, scope, unit, this, reporter)
// Fields that are directly propagated
c.variance = variance
- c.diagnostic = diagnostic
+ c.diagUsedDefaults = diagUsedDefaults
c.openImplicits = openImplicits
c.contextMode = contextMode // note: ConstructorSuffix, a bit within `mode`, is conditionally overwritten below.
- c._reportBuffer = reportBuffer
// Fields that may take on a different value in the child
c.prefix = prefixInChild
@@ -470,22 +485,38 @@ trait Contexts { self: Analyzer =>
c
}
+ /** Use reporter (possibly buffered) for errors/warnings and enable implicit conversion **/
+ def initRootContext(throwing: Boolean = false, checking: Boolean = false): Unit = {
+ _reporter =
+ if (checking) new CheckingReporter
+ else if (throwing) new ThrowingReporter
+ else new ImmediateReporter
+
+ setAmbiguousErrors(!throwing)
+ this(EnrichmentEnabled | ImplicitsEnabled) = !throwing
+ }
+
def make(tree: Tree, owner: Symbol, scope: Scope): Context =
// TODO SI-7345 Moving this optimization into the main overload of `make` causes all tests to fail.
- // even if it is extened to check that `unit == this.unit`. Why is this?
+ // even if it is extended to check that `unit == this.unit`. Why is this?
if (tree == this.tree && owner == this.owner && scope == this.scope) this
else make(tree, owner, scope, unit)
/** Make a child context that represents a new nested scope */
- def makeNewScope(tree: Tree, owner: Symbol): Context =
- make(tree, owner, newNestedScope(scope))
+ def makeNewScope(tree: Tree, owner: Symbol, reporter: ContextReporter = this.reporter): Context =
+ make(tree, owner, newNestedScope(scope), reporter = reporter)
/** Make a child context that buffers errors and warnings into a fresh report buffer. */
def makeSilent(reportAmbiguousErrors: Boolean = ambiguousErrors, newtree: Tree = tree): Context = {
- val c = make(newtree)
- c.setBufferErrors()
+ // A fresh buffer so as not to leak errors/warnings into `this`.
+ val c = make(newtree, reporter = new BufferingReporter)
c.setAmbiguousErrors(reportAmbiguousErrors)
- c._reportBuffer = new ReportBuffer // A fresh buffer so as not to leak errors/warnings into `this`.
+ c
+ }
+
+ def makeNonSilent(newtree: Tree): Context = {
+ val c = make(newtree, reporter = reporter.makeImmediate)
+ c.setAmbiguousErrors(true)
c
}
@@ -508,7 +539,9 @@ trait Contexts { self: Analyzer =>
*/
def makeConstructorContext = {
val baseContext = enclClass.outer.nextEnclosing(!_.tree.isInstanceOf[Template])
- val argContext = baseContext.makeNewScope(tree, owner)
+ // must propagate reporter!
+ // (caught by neg/t3649 when refactoring reporting to be specified only by this.reporter and not also by this.contextMode)
+ val argContext = baseContext.makeNewScope(tree, owner, reporter = this.reporter)
argContext.contextMode = contextMode
argContext.inSelfSuperCall = true
def enterElems(c: Context) {
@@ -533,65 +566,16 @@ trait Contexts { self: Analyzer =>
// Error and warning issuance
//
- private def addDiagString(msg: String) = {
- val ds =
- if (diagnostic.isEmpty) ""
- else diagnostic.mkString("\n","\n", "")
- if (msg endsWith ds) msg else msg + ds
- }
-
- private def unitError(pos: Position, msg: String): Unit =
- if (checking) onTreeCheckerError(pos, msg) else reporter.error(pos, msg)
-
- @inline private def issueCommon(err: AbsTypeError)(pf: PartialFunction[AbsTypeError, Unit]) {
- // TODO: are errors allowed to have pos == NoPosition??
- // if not, Jason suggests doing: val pos = err.errPos.orElse( { devWarning("Que?"); context.tree.pos })
- if (settings.Yissuedebug) {
- log("issue error: " + err.errMsg)
- (new Exception).printStackTrace()
- }
- if (pf isDefinedAt err) pf(err)
- else if (bufferErrors) { reportBuffer += err }
- else throw new TypeError(err.errPos, err.errMsg)
- }
-
/** Issue/buffer/throw the given type error according to the current mode for error reporting. */
- def issue(err: AbsTypeError) {
- issueCommon(err) { case _ if reportErrors =>
- unitError(err.errPos, addDiagString(err.errMsg))
- }
- }
-
- /** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(pre: Type, sym1: Symbol, sym2: Symbol, err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors =>
- if (!pre.isErroneous && !sym1.isErroneous && !sym2.isErroneous)
- unitError(err.errPos, err.errMsg)
- }
- }
-
+ private[typechecker] def issue(err: AbsTypeError) = reporter.issue(err)(this)
/** Issue/buffer/throw the given implicit ambiguity error according to the current mode for error reporting. */
- def issueAmbiguousError(err: AbsTypeError) {
- issueCommon(err) { case _ if ambiguousErrors => unitError(err.errPos, addDiagString(err.errMsg)) }
- }
-
- /** Issue/throw the given `err` according to the current mode for error reporting. */
- def error(pos: Position, err: Throwable) =
- if (reportErrors) unitError(pos, addDiagString(err.getMessage()))
- else throw err
-
+ private[typechecker] def issueAmbiguousError(err: AbsAmbiguousTypeError) = reporter.issueAmbiguousError(err)(this)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def error(pos: Position, msg: String) = {
- val msg1 = addDiagString(msg)
- if (reportErrors) unitError(pos, msg1)
- else throw new TypeError(pos, msg1)
- }
-
+ def error(pos: Position, msg: String) = reporter.error(pos, msg)
/** Issue/throw the given error message according to the current mode for error reporting. */
- def warning(pos: Position, msg: String, force: Boolean = false) {
- if (reportErrors || force) reporter.warning(pos, msg)
- else if (bufferErrors) reportBuffer += (pos -> msg)
- }
+ def warning(pos: Position, msg: String) = reporter.warning(pos, msg)
+ def echo(pos: Position, msg: String) = reporter.echo(pos, msg)
+
def deprecationWarning(pos: Position, sym: Symbol, msg: String): Unit =
currentRun.reporting.deprecationWarning(pos, sym, msg)
@@ -601,7 +585,6 @@ trait Contexts { self: Analyzer =>
def featureWarning(pos: Position, featureName: String, featureDesc: String, featureTrait: Symbol, construct: => String = "", required: Boolean): Unit =
currentRun.reporting.featureWarning(pos, featureName, featureDesc, featureTrait, construct, required)
- def echo(pos: Position, msg: String): Unit = reporter.echo(pos, msg)
// nextOuter determines which context is searched next for implicits
// (after `this`, which contributes `newImplicits` below.) In
@@ -1238,61 +1221,176 @@ trait Contexts { self: Analyzer =>
override final def toString = super.toString + " with " + s"ImportContext { $impInfo; outer.owner = ${outer.owner} }"
}
- /** A buffer for warnings and errors that are accumulated during speculative type checking. */
- final class ReportBuffer {
+ /** A reporter for use during type checking. It has multiple modes for handling errors.
+ *
+ * The default (immediate mode) is to send the error to the global reporter.
+ * When switched into buffering mode via makeBuffering, errors and warnings are buffered and not be reported
+ * (there's a special case for ambiguity errors for some reason: those are force to the reporter when context.ambiguousErrors,
+ * or else they are buffered -- TODO: can we simplify this?)
+ *
+ * When using the type checker after typers, an error results in a TypeError being thrown. TODO: get rid of this mode.
+ *
+ * To handle nested contexts, reporters share buffers. TODO: only buffer in BufferingReporter, emit immediately in ImmediateReporter
+ */
+ abstract class ContextReporter(private[this] var _errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, private[this] var _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends Reporter {
type Error = AbsTypeError
type Warning = (Position, String)
- private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ def issue(err: AbsTypeError)(implicit context: Context): Unit = handleError(err.errPos, addDiagString(err.errMsg))
- // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
- // is replicated here out of conservatism.
- private var _errorBuffer: mutable.LinkedHashSet[Error] = _
- private def errorBuffer = {if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer}
- def errors: immutable.Seq[Error] = errorBuffer.toVector
+ protected def handleError(pos: Position, msg: String): Unit
+ protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = ()
+ protected def handleWarning(pos: Position, msg: String): Unit = reporter.warning(pos, msg)
- private var _warningBuffer: mutable.LinkedHashSet[Warning] = _
- private def warningBuffer = {if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer}
- def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ def makeImmediate: ContextReporter = this
+ def makeBuffering: ContextReporter = this
+ def isBuffering: Boolean = false
- def +=(error: AbsTypeError): this.type = {
- errorBuffer += error
- this
- }
- def ++=(errors: Traversable[AbsTypeError]): this.type = {
- errorBuffer ++= errors
- this
- }
- def +=(warning: Warning): this.type = {
- warningBuffer += warning
- this
+ /** Emit an ambiguous error according to context.ambiguousErrors
+ *
+ * - when true, use global.reporter regardless of whether we're buffering (TODO: can we change this?)
+ * - else, let this context reporter decide
+ */
+ final def issueAmbiguousError(err: AbsAmbiguousTypeError)(implicit context: Context): Unit =
+ if (context.ambiguousErrors) reporter.error(err.errPos, addDiagString(err.errMsg)) // force reporting... see TODO above
+ else handleSuppressedAmbiguous(err)
+
+ @inline final def withFreshErrorBuffer[T](expr: => T): T = {
+ val previousBuffer = _errorBuffer
+ _errorBuffer = newBuffer
+ val res = expr // expr will read _errorBuffer
+ _errorBuffer = previousBuffer
+ res
}
- def clearAll(): this.type = {
- clearAllErrors(); clearAllWarnings();
+ @inline final def propagatingErrorsTo[T](target: ContextReporter)(expr: => T): T = {
+ val res = expr // TODO: make sure we're okay skipping the try/finally overhead
+ if ((this ne target) && hasErrors) { // `this eq target` in e.g., test/files/neg/divergent-implicit.scala
+ // assert(target.errorBuffer ne _errorBuffer)
+ target ++= errors
+ // TODO: is clearAllErrors necessary? (no tests failed when dropping it)
+ // NOTE: even though `this ne target`, it may still be that `target.errorBuffer eq _errorBuffer`,
+ // so don't clear the buffer, but null out the reference so that a new one will be created when necessary (should be never??)
+ // (we should refactor error buffering to avoid mutation on shared buffers)
+ clearAllErrors()
+ }
+ res
}
- def clearAllErrors(): this.type = {
- errorBuffer.clear()
- this
- }
- def clearErrors(removeF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(!PartialFunction.cond(_)(removeF))
- this
+ protected final def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit =
+ severity match {
+ case ERROR => handleError(pos, msg)
+ case WARNING => handleWarning(pos, msg)
+ case INFO => reporter.echo(pos, msg)
+ }
+
+ final override def hasErrors = super.hasErrors || errorBuffer.nonEmpty
+
+ // TODO: everything below should be pushed down to BufferingReporter (related to buffering)
+ // Implicit relies on this most heavily, but there you know reporter.isInstanceOf[BufferingReporter]
+ // can we encode this statically?
+
+ // have to pass in context because multiple contexts may share the same ReportBuffer
+ def reportFirstDivergentError(fun: Tree, param: Symbol, paramTp: Type)(implicit context: Context): Unit =
+ errors.collectFirst {
+ case dte: DivergentImplicitTypeError => dte
+ } match {
+ case Some(divergent) =>
+ // DivergentImplicit error has higher priority than "no implicit found"
+ // no need to issue the problem again if we are still in silent mode
+ if (context.reportErrors) {
+ context.issue(divergent.withPt(paramTp))
+ errorBuffer.retain {
+ case dte: DivergentImplicitTypeError => false
+ case _ => true
+ }
+ }
+ case _ =>
+ NoImplicitFoundError(fun, param)(context)
+ }
+
+ def retainDivergentErrorsExcept(saved: DivergentImplicitTypeError) =
+ errorBuffer.retain {
+ case err: DivergentImplicitTypeError => err ne saved
+ case _ => false
+ }
+
+ def propagateImplicitTypeErrorsTo(target: ContextReporter) = {
+ errors foreach {
+ case err@(_: DivergentImplicitTypeError | _: AmbiguousImplicitTypeError) =>
+ target.errorBuffer += err
+ case _ =>
+ }
+ // debuglog("propagateImplicitTypeErrorsTo: " + errors)
}
- def retainErrors(leaveF: PartialFunction[AbsTypeError, Boolean]): this.type = {
- errorBuffer.retain(PartialFunction.cond(_)(leaveF))
- this
+
+ protected def addDiagString(msg: String)(implicit context: Context): String = {
+ val diagUsedDefaultsMsg = "Error occurred in an application involving default arguments."
+ if (context.diagUsedDefaults && !(msg endsWith diagUsedDefaultsMsg)) msg + "\n" + diagUsedDefaultsMsg
+ else msg
}
- def clearAllWarnings(): this.type = {
- warningBuffer.clear()
- this
+
+ final def emitWarnings() = if (_warningBuffer != null) {
+ _warningBuffer foreach {
+ case (pos, msg) => reporter.warning(pos, msg)
+ }
+ _warningBuffer = null
}
- def hasErrors = errorBuffer.nonEmpty
- def firstError = errorBuffer.headOption
+ // [JZ] Contexts, pre- the SI-7345 refactor, avoided allocating the buffers until needed. This
+ // is replicated here out of conservatism.
+ private def newBuffer[A] = mutable.LinkedHashSet.empty[A] // Important to use LinkedHS for stable results.
+ final protected def errorBuffer = { if (_errorBuffer == null) _errorBuffer = newBuffer; _errorBuffer }
+ final protected def warningBuffer = { if (_warningBuffer == null) _warningBuffer = newBuffer; _warningBuffer }
+
+ final def errors: immutable.Seq[Error] = errorBuffer.toVector
+ final def warnings: immutable.Seq[Warning] = warningBuffer.toVector
+ final def firstError: Option[AbsTypeError] = errorBuffer.headOption
+
+ // TODO: remove ++= and clearAll* entirely in favor of more high-level combinators like withFreshErrorBuffer
+ final private[typechecker] def ++=(errors: Traversable[AbsTypeError]): Unit = errorBuffer ++= errors
+
+ // null references to buffers instead of clearing them,
+ // as the buffers may be shared between different reporters
+ final def clearAll(): Unit = { _errorBuffer = null; _warningBuffer = null }
+ final def clearAllErrors(): Unit = { _errorBuffer = null }
+ }
+
+ private[typechecker] class ImmediateReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def makeBuffering: ContextReporter = new BufferingReporter(errorBuffer, warningBuffer)
+ protected def handleError(pos: Position, msg: String): Unit = reporter.error(pos, msg)
+ }
+
+
+ private[typechecker] class BufferingReporter(_errorBuffer: mutable.LinkedHashSet[AbsTypeError] = null, _warningBuffer: mutable.LinkedHashSet[(Position, String)] = null) extends ContextReporter(_errorBuffer, _warningBuffer) {
+ override def isBuffering = true
+
+ override def issue(err: AbsTypeError)(implicit context: Context): Unit = errorBuffer += err
+
+ // this used to throw new TypeError(pos, msg) -- buffering lets us report more errors (test/files/neg/macro-basic-mamdmi)
+ // the old throwing behavior was relied on by diagnostics in manifestOfType
+ protected def handleError(pos: Position, msg: String): Unit = errorBuffer += TypeErrorWrapper(new TypeError(pos, msg))
+ override protected def handleSuppressedAmbiguous(err: AbsAmbiguousTypeError): Unit = errorBuffer += err
+ override protected def handleWarning(pos: Position, msg: String): Unit = warningBuffer += ((pos, msg))
+
+ // TODO: emit all buffered errors, warnings
+ override def makeImmediate: ContextReporter = new ImmediateReporter(errorBuffer, warningBuffer)
}
+ /** Used after typer (specialization relies on TypeError being thrown, among other post-typer phases).
+ *
+ * TODO: get rid of it, use ImmediateReporter and a check for reporter.hasErrors where necessary
+ */
+ private[typechecker] class ThrowingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = throw new TypeError(pos, msg)
+ }
+
+ /** Used during a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
+ private[typechecker] class CheckingReporter extends ContextReporter {
+ protected def handleError(pos: Position, msg: String): Unit = onTreeCheckerError(pos, msg)
+ }
+
+
class ImportInfo(val tree: Import, val depth: Int) {
def pos = tree.pos
def posOf(sel: ImportSelector) = tree.pos withPoint sel.namePos
@@ -1385,8 +1483,6 @@ object ContextMode {
def apply(bits: Int): ContextMode = new ContextMode(bits)
final val NOmode: ContextMode = 0
- final val ReportErrors: ContextMode = 1 << 0
- final val BufferErrors: ContextMode = 1 << 1
final val AmbiguousErrors: ContextMode = 1 << 2
/** Are we in a secondary constructor after the this constructor call? */
@@ -1409,8 +1505,6 @@ object ContextMode {
/** To selectively allow enrichment in patterns, where other kinds of implicit conversions are not allowed */
final val EnrichmentEnabled: ContextMode = 1 << 8
- /** Are we in a run of [[scala.tools.nsc.typechecker.TreeCheckers]]? */
- final val Checking: ContextMode = 1 << 9
/** Are we retypechecking arguments independently from the function applied to them? See `Typer.tryTypedApply`
* TODO - iron out distinction/overlap with SecondTry.
@@ -1447,17 +1541,14 @@ object ContextMode {
PatternAlternative | StarPatterns | SuperInit | SecondTry | ReturnExpr | TypeConstructorAllowed
)
- final val DefaultMode: ContextMode = MacrosEnabled
+ final val DefaultMode: ContextMode = MacrosEnabled
private val contextModeNameMap = Map(
- ReportErrors -> "ReportErrors",
- BufferErrors -> "BufferErrors",
AmbiguousErrors -> "AmbiguousErrors",
ConstructorSuffix -> "ConstructorSuffix",
SelfSuperCall -> "SelfSuperCall",
ImplicitsEnabled -> "ImplicitsEnabled",
MacrosEnabled -> "MacrosEnabled",
- Checking -> "Checking",
ReTyping -> "ReTyping",
PatternAlternative -> "PatternAlternative",
StarPatterns -> "StarPatterns",
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 73c3e6f016..b85c8e6d42 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -71,13 +71,10 @@ trait Implicits {
typingStack.printTyping(tree, "typing implicit: %s %s".format(tree, context.undetparamsString))
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
- if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
- context.updateBuffer(implicitSearchContext.reportBuffer.errors.collect {
- case dte: DivergentImplicitTypeError => dte
- case ate: AmbiguousImplicitTypeError => ate
- })
- debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
- }
+
+ if (result.isFailure && saveAmbiguousDivergent && implicitSearchContext.reporter.hasErrors)
+ implicitSearchContext.reporter.propagateImplicitTypeErrorsTo(context.reporter)
+
// SI-7944 undetermined type parameters that result from inference within typedImplicit land in
// `implicitSearchContext.undetparams`, *not* in `context.undetparams`
// Here, we copy them up to parent context (analogously to the way the errors are copied above),
@@ -99,7 +96,7 @@ trait Implicits {
def wrapper(inference: => SearchResult) = wrapper1(inference)
val result = wrapper(inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos))
if (result.isFailure && !silent) {
- val err = context.firstError
+ val err = context.reporter.firstError
val errPos = err.map(_.errPos).getOrElse(pos)
val errMsg = err.map(_.errMsg).getOrElse("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
onError(errPos, errMsg)
@@ -635,7 +632,7 @@ trait Implicits {
}
case _ => fallback
}
- context.firstError match { // using match rather than foreach to avoid non local return.
+ context.reporter.firstError match { // using match rather than foreach to avoid non local return.
case Some(err) =>
log("implicit adapt failed: " + err.errMsg)
return fail(err.errMsg)
@@ -658,8 +655,8 @@ trait Implicits {
}
}
- if (context.hasErrors)
- fail("hasMatchingSymbol reported error: " + context.firstError.get.errMsg)
+ if (context.reporter.hasErrors)
+ fail("hasMatchingSymbol reported error: " + context.reporter.firstError.get.errMsg)
else if (itree3.isErroneous)
fail("error typechecking implicit candidate")
else if (isLocalToCallsite && !hasMatchingSymbol(itree2))
@@ -677,7 +674,7 @@ trait Implicits {
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
checkBounds(itree3, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg)
case None =>
@@ -716,7 +713,7 @@ trait Implicits {
case t => t
}
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) =>
fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg)
case None =>
@@ -857,13 +854,11 @@ trait Implicits {
SearchFailure
} else {
if (search.isFailure) {
- // We don't want errors that occur during checking implicit info
+ // Discard the divergentError we saved (if any), as well as all errors that are not of type DivergentImplicitTypeError
+ // We don't want errors that occur while checking the implicit info
// to influence the check of further infos, but we should retain divergent implicit errors
// (except for the one we already squirreled away)
- val saved = divergentError.getOrElse(null)
- context.reportBuffer.retainErrors {
- case err: DivergentImplicitTypeError => err ne saved
- }
+ context.reporter.retainDivergentErrorsExcept(divergentError.getOrElse(null))
}
search
}
@@ -909,7 +904,7 @@ trait Implicits {
// the first `DivergentImplicitTypeError` that is being propagated
// from a nested implicit search; this one will be
// re-issued if this level of the search fails.
- DivergentImplicitRecovery(typedFirstPending, firstPending, context.errors) match {
+ DivergentImplicitRecovery(typedFirstPending, firstPending, context.reporter.errors) match {
case sr if sr.isDivergent => Nil
case sr if sr.isFailure => rankImplicits(otherPending, acc)
case newBest =>
@@ -1146,7 +1141,7 @@ trait Implicits {
try {
val tree1 = typedPos(pos.focus)(arg)
- context.firstError match {
+ context.reporter.firstError match {
case Some(err) => processMacroExpansionError(err.errPos, err.errMsg)
case None => new SearchResult(tree1, EmptyTreeTypeSubstituter, Nil)
}
@@ -1278,19 +1273,20 @@ trait Implicits {
if (tagInScope.isEmpty) mot(tp, Nil, Nil)
else {
if (ReflectRuntimeUniverse == NoSymbol) {
- // todo. write a test for this
- context.error(pos,
+ // TODO: write a test for this (the next error message is already checked by neg/interop_typetags_without_classtags_arenot_manifests.scala)
+ // TODO: this was using context.error, and implicit search always runs in silent mode, thus it was actually throwing a TypeError
+ // with the new strategy-based reporting, a BufferingReporter buffers instead of throwing
+ // it would be good to rework this logic to fit into the regular context.error mechanism
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires Scala reflection, which is not present on the classpath.
|to proceed put scala-reflect.jar on your compilation classpath and recompile.""")
- return SearchFailure
}
if (resolveClassTag(pos, tp, allowMaterialization = true) == EmptyTree) {
- context.error(pos,
+ throw new TypeError(pos,
sm"""to create a manifest here, it is necessary to interoperate with the type tag `$tagInScope` in scope.
|however typetag -> manifest conversion requires a class tag for the corresponding type to be present.
|to proceed add a class tag to the type `$tp` (e.g. by introducing a context bound) and recompile.""")
- return SearchFailure
}
val cm = typed(Ident(ReflectRuntimeCurrentMirror))
val internal = gen.mkAttributedSelect(gen.mkAttributedRef(ReflectRuntimeUniverse), UniverseInternal)
@@ -1346,52 +1342,66 @@ trait Implicits {
* If all fails return SearchFailure
*/
def bestImplicit: SearchResult = {
- val failstart = if (Statistics.canEnable) Statistics.startTimer(inscopeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(inscopeSucceedNanos) else null
+ val stats = Statistics.canEnable
+ val failstart = if (stats) Statistics.startTimer(inscopeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(inscopeSucceedNanos) else null
var result = searchImplicit(context.implicitss, isLocalToCallsite = true)
- if (result.isFailure) {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(inscopeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(inscopeImplicitHits)
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(inscopeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(inscopeSucceedNanos, succstart)
+ Statistics.incCounter(inscopeImplicitHits)
+ }
}
+
if (result.isFailure) {
- val previousErrs = context.flushAndReturnBuffer()
- val failstart = if (Statistics.canEnable) Statistics.startTimer(oftypeFailNanos) else null
- val succstart = if (Statistics.canEnable) Statistics.startTimer(oftypeSucceedNanos) else null
+ val failstart = if (stats) Statistics.startTimer(oftypeFailNanos) else null
+ val succstart = if (stats) Statistics.startTimer(oftypeSucceedNanos) else null
+
+ // SI-6667, never search companions after an ambiguous error in in-scope implicits
+ val wasAmbigious = result.isAmbiguousFailure
+
+ // TODO: encapsulate
+ val previousErrs = context.reporter.errors
+ context.reporter.clearAllErrors()
- val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits
result = materializeImplicit(pt)
+
// `materializeImplicit` does some preprocessing for `pt`
// is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
if (result.isFailure && !wasAmbigious)
result = searchImplicit(implicitsOfExpectedType, isLocalToCallsite = false)
- if (result.isFailure) {
- context.updateBuffer(previousErrs)
- if (Statistics.canEnable) Statistics.stopTimer(oftypeFailNanos, failstart)
- } else {
- if (Statistics.canEnable) Statistics.stopTimer(oftypeSucceedNanos, succstart)
- if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
+ if (result.isFailure)
+ context.reporter ++= previousErrs
+
+ if (stats) {
+ if (result.isFailure) Statistics.stopTimer(oftypeFailNanos, failstart)
+ else {
+ Statistics.stopTimer(oftypeSucceedNanos, succstart)
+ Statistics.incCounter(oftypeImplicitHits)
+ }
}
}
if (result.isSuccess && isView) {
def maybeInvalidConversionError(msg: String) {
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
+ // AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
if (context.ambiguousErrors)
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg))
}
pt match {
case Function1(_, out) =>
- def prohibit(sym: Symbol) = if (sym.tpe <:< out) {
- maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
- result = SearchFailure
+ // must inline to avoid capturing result
+ def prohibit(sym: Symbol) = (sym.tpe <:< out) && {
+ maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
+ true
}
- prohibit(AnyRefClass)
- if (settings.isScala211) prohibit(AnyValClass)
+ if (prohibit(AnyRefClass) || (settings.isScala211 && prohibit(AnyValClass)))
+ result = SearchFailure
case _ => false
}
if (settings.isScala211 && isInvalidConversionSource(pt)) {
@@ -1399,8 +1409,9 @@ trait Implicits {
result = SearchFailure
}
}
- if (result.isFailure)
- debuglog("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
+
+ if (result.isFailure && settings.debug) // debuglog is not inlined for some reason
+ log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
result
}
@@ -1422,20 +1433,19 @@ trait Implicits {
val eligible = new ImplicitComputation(iss, isLocalToCallsite).eligible
eligible.toList.flatMap {
(ii: ImplicitInfo) =>
- // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
- // thus, start each type var off with a fresh for every typedImplicit
- resetTVars()
- // any previous errors should not affect us now
- context.flushBuffer()
-
- val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
- if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
- else Nil
+ // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
+ // thus, start each type var off with a fresh for every typedImplicit
+ resetTVars()
+ // any previous errors should not affect us now
+ context.reporter.clearAllErrors()
+ val res = typedImplicit(ii, ptChecked = false, isLocalToCallsite)
+ if (res.tree ne EmptyTree) List((res, tvars map (_.constr)))
+ else Nil
+ }
}
- }
eligibleInfos(context.implicitss, isLocalToCallsite = true) ++
eligibleInfos(implicitsOfExpectedType, isLocalToCallsite = false)
- }
+ }
}
object ImplicitNotFoundMsg {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index a3f1da60ce..fb7651ffd6 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -199,8 +199,6 @@ trait Infer extends Checkable {
def getContext = context
- def issue(err: AbsTypeError): Unit = context.issue(err)
-
def explainTypes(tp1: Type, tp2: Type) = {
if (context.reportErrors)
withDisambiguation(List(), tp1, tp2)(global.explainTypes(tp1, tp2))
@@ -781,7 +779,7 @@ trait Infer extends Checkable {
def applicableExpectingPt(pt: Type): Boolean = {
val silent = context.makeSilent(reportAmbiguousErrors = false)
val result = newTyper(silent).infer.isApplicable(undetparams, ftpe, argtpes0, pt)
- if (silent.hasErrors && !pt.isWildcard)
+ if (silent.reporter.hasErrors && !pt.isWildcard)
applicableExpectingPt(WildcardType) // second try
else
result
@@ -1266,33 +1264,36 @@ trait Infer extends Checkable {
* If no alternative matches `pt`, take the parameterless one anyway.
*/
def inferExprAlternative(tree: Tree, pt: Type): Tree = {
- def tryOurBests(pre: Type, alts: List[Symbol], isSecondTry: Boolean): Unit = {
- val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
- val alts1 = if (alts0.isEmpty) alts else alts0
- val bests = bestAlternatives(alts1) { (sym1, sym2) =>
- val tp1 = pre memberType sym1
- val tp2 = pre memberType sym2
-
- ( (tp2 eq ErrorType)
- || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
- || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
- )
- }
- // todo: missing test case for bests.isEmpty
- bests match {
- case best :: Nil => tree setSymbol best setType (pre memberType best)
- case best :: competing :: _ if alts0.nonEmpty =>
- // SI-6912 Don't give up and leave an OverloadedType on the tree.
- // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
- // unless an error is issued. We're not issuing an error, in the assumption that it would be
- // spurious in light of the erroneous expected type
- if (pt.isErroneous) setError(tree)
- else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
- case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ val c = context
+ class InferTwice(pre: Type, alts: List[Symbol]) extends c.TryTwice {
+ def tryOnce(isSecondTry: Boolean): Unit = {
+ val alts0 = alts filter (alt => isWeaklyCompatible(pre memberType alt, pt))
+ val alts1 = if (alts0.isEmpty) alts else alts0
+ val bests = bestAlternatives(alts1) { (sym1, sym2) =>
+ val tp1 = pre memberType sym1
+ val tp2 = pre memberType sym2
+
+ ( (tp2 eq ErrorType)
+ || isWeaklyCompatible(tp1, pt) && !isWeaklyCompatible(tp2, pt)
+ || isStrictlyMoreSpecific(tp1, tp2, sym1, sym2)
+ )
+ }
+ // todo: missing test case for bests.isEmpty
+ bests match {
+ case best :: Nil => tree setSymbol best setType (pre memberType best)
+ case best :: competing :: _ if alts0.nonEmpty =>
+ // SI-6912 Don't give up and leave an OverloadedType on the tree.
+ // Originally I wrote this as `if (secondTry) ... `, but `tryTwice` won't attempt the second try
+ // unless an error is issued. We're not issuing an error, in the assumption that it would be
+ // spurious in light of the erroneous expected type
+ if (pt.isErroneous) setError(tree)
+ else AmbiguousExprAlternativeError(tree, pre, best, competing, pt, isSecondTry)
+ case _ => if (bests.isEmpty || alts0.isEmpty) NoBestExprAlternativeError(tree, pt, isSecondTry)
+ }
}
}
tree.tpe match {
- case OverloadedType(pre, alts) => tryTwice(tryOurBests(pre, alts, _)) ; tree
+ case OverloadedType(pre, alts) => (new InferTwice(pre, alts)).apply() ; tree
case _ => tree
}
}
@@ -1370,70 +1371,41 @@ trait Infer extends Checkable {
* @pre tree.tpe is an OverloadedType.
*/
def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], argtpes0: List[Type], pt0: Type): Unit = {
- val OverloadedType(pre, alts) = tree.tpe
- var varargsStar = false
- val argtpes = argtpes0 mapConserve {
- case RepeatedType(tp) => varargsStar = true ; tp
- case tp => tp
- }
- def followType(sym: Symbol) = followApply(pre memberType sym)
- def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
- val applicable0 = alts filter (alt => context inSilentMode isApplicable(undetparams, followType(alt), argtpes, pt))
- val applicable = overloadsToConsiderBySpecificity(applicable0, argtpes, varargsStar)
- val ranked = bestAlternatives(applicable)((sym1, sym2) =>
- isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
- )
- ranked match {
- case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
- case best :: Nil => tree setSymbol best setType (pre memberType best) // success
- case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
- case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
- }
- }
- // This potentially makes up to four attempts: tryTwice may execute
+ // This potentially makes up to four attempts: tryOnce may execute
// with and without views enabled, and bestForExpectedType will try again
// with pt = WildcardType if it fails with pt != WildcardType.
- tryTwice { isLastTry =>
- val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
- debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
- bestForExpectedType(pt, isLastTry)
- }
- }
+ val c = context
+ class InferMethodAlternativeTwice extends c.TryTwice {
+ private[this] val OverloadedType(pre, alts) = tree.tpe
+ private[this] var varargsStar = false
+ private[this] val argtpes = argtpes0 mapConserve {
+ case RepeatedType(tp) => varargsStar = true ; tp
+ case tp => tp
+ }
- /** Try inference twice, once without views and once with views,
- * unless views are already disabled.
- */
- def tryTwice(infer: Boolean => Unit): Unit = {
- if (context.implicitsEnabled) {
- val savedContextMode = context.contextMode
- var fallback = false
- context.setBufferErrors()
- // We cache the current buffer because it is impossible to
- // distinguish errors that occurred before entering tryTwice
- // and our first attempt in 'withImplicitsDisabled'. If the
- // first attempt fails we try with implicits on *and* clean
- // buffer but that would also flush any pre-tryTwice valid
- // errors, hence some manual buffer tweaking is necessary.
- val errorsToRestore = context.flushAndReturnBuffer()
- try {
- context.withImplicitsDisabled(infer(false))
- if (context.hasErrors) {
- fallback = true
- context.contextMode = savedContextMode
- context.flushBuffer()
- infer(true)
+ private def followType(sym: Symbol) = followApply(pre memberType sym)
+ // separate method to help the inliner
+ private def isAltApplicable(pt: Type)(alt: Symbol) = context inSilentMode { isApplicable(undetparams, followType(alt), argtpes, pt) && !context.reporter.hasErrors }
+ private def rankAlternatives(sym1: Symbol, sym2: Symbol) = isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
+ private def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
+ val applicable = overloadsToConsiderBySpecificity(alts filter isAltApplicable(pt), argtpes, varargsStar)
+ val ranked = bestAlternatives(applicable)(rankAlternatives)
+ ranked match {
+ case best :: competing :: _ => AmbiguousMethodAlternativeError(tree, pre, best, competing, argtpes, pt, isLastTry) // ambiguous
+ case best :: Nil => tree setSymbol best setType (pre memberType best) // success
+ case Nil if pt.isWildcard => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
+ case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
}
- } catch {
- case ex: CyclicReference => throw ex
- case ex: TypeError => // recoverable cyclic references
- context.contextMode = savedContextMode
- if (!fallback) infer(true) else ()
- } finally {
- context.contextMode = savedContextMode
- context.updateBuffer(errorsToRestore)
+ }
+
+ private[this] val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0
+ def tryOnce(isLastTry: Boolean): Unit = {
+ debuglog(s"infer method alt ${tree.symbol} with alternatives ${alts map pre.memberType} argtpes=$argtpes pt=$pt")
+ bestForExpectedType(pt, isLastTry)
}
}
- else infer(true)
+
+ (new InferMethodAlternativeTwice).apply()
}
/** Assign `tree` the type of all polymorphic alternatives
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 9c22688581..da7b8b09aa 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -226,7 +226,8 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
val Apply(_, pickledPayload) = wrapped
val payload = pickledPayload.map{ case Assign(k, v) => (unpickleAtom(k), unpickleAtom(v)) }.toMap
- import typer.TyperErrorGen._
+ // TODO: refactor error handling: fail always throws a TypeError,
+ // and uses global state (analyzer.lastTreeToTyper) to determine the position for the error
def fail(msg: String) = MacroCantExpandIncompatibleMacrosError(msg)
def unpickle[T](field: String, clazz: Class[T]): T = {
def failField(msg: String) = fail(s"$field $msg")
@@ -576,7 +577,10 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
// also see http://groups.google.com/group/scala-internals/browse_thread/thread/492560d941b315cc
val expanded1 = try onSuccess(duplicateAndKeepPositions(expanded)) finally popMacroContext()
if (!hasMacroExpansionAttachment(expanded1)) linkExpandeeAndExpanded(expandee, expanded1)
- if (settings.Ymacroexpand.value == settings.MacroExpand.Discard) expandee.setType(expanded1.tpe)
+ if (settings.Ymacroexpand.value == settings.MacroExpand.Discard) {
+ suppressMacroExpansion(expandee)
+ expandee.setType(expanded1.tpe)
+ }
else expanded1
case Fallback(fallback) => onFallback(fallback)
case Delayed(delayed) => onDelayed(delayed)
@@ -621,7 +625,7 @@ trait Macros extends MacroRuntimes with Traces with Helpers {
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
// therefore we need to re-enable the conversions back temporarily
val result = typer.context.withImplicitsEnabled(typer.typed(tree, mode, pt))
- if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reportBuffer.errors}")
+ if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reporter.errors}")
result
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 1328119aac..fdff2f3076 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -717,7 +717,7 @@ trait Namers extends MethodSynthesis {
m.updateAttachment(new ConstructorDefaultsAttachment(tree, null))
}
val owner = tree.symbol.owner
- if (settings.lint && owner.isPackageObjectClass && !mods.isImplicit) {
+ if (settings.warnPackageObjectClasses && owner.isPackageObjectClass && !mods.isImplicit) {
reporter.warning(tree.pos,
"it is not recommended to define classes/objects inside of package objects.\n" +
"If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead."
@@ -1494,8 +1494,7 @@ trait Namers extends MethodSynthesis {
case defn: MemberDef =>
val ainfos = defn.mods.annotations filterNot (_ eq null) map { ann =>
val ctx = typer.context
- val annCtx = ctx.make(ann)
- annCtx.setReportErrors()
+ val annCtx = ctx.makeNonSilent(ann)
// need to be lazy, #1782. beforeTyper to allow inferView in annotation args, SI-5892.
AnnotationInfo lazily {
enteringTyper(newTyper(annCtx) typedAnnotation ann)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 43902d1c65..b6387fd56b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -379,18 +379,37 @@ trait NamesDefaults { self: Analyzer =>
def makeNamedTypes(syms: List[Symbol]) = syms map (sym => NamedType(sym.name, sym.tpe))
- def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name] = nameOfNamedArg _): (List[Symbol], Boolean) = {
- val namedArgs = args.dropWhile(arg => {
- val n = argName(arg)
- n.isEmpty || params.forall(p => p.name != n.get)
- })
- val namedParams = params.drop(args.length - namedArgs.length)
- // missing: keep those with a name which doesn't exist in namedArgs
- val missingParams = namedParams.filter(p => namedArgs.forall(arg => {
+ /**
+ * Returns the parameter symbols of an invocation expression that are not defined by the list
+ * of arguments.
+ *
+ * @param args The list of arguments
+ * @param params The list of parameter sybols of the invoked method
+ * @param argName A function that extracts the name of an argument expression, if it is a named argument.
+ */
+ def missingParams[T](args: List[T], params: List[Symbol], argName: T => Option[Name]): (List[Symbol], Boolean) = {
+ // The argument list contains first a mix of positional args and named args that are on the
+ // right parameter position, and then a number or named args on different positions.
+
+ // collect all named arguments whose position does not match the parameter they define
+ val namedArgsOnChangedPosition = args.zip(params) dropWhile {
+ case (arg, param) =>
+ val n = argName(arg)
+ // drop the argument if
+ // - it's not named, or
+ // - it's named, but defines the parameter on its current position, or
+ // - it's named, but none of the parameter names matches (treated as a positional argument, an assignment expression)
+ n.isEmpty || n.get == param.name || params.forall(_.name != n.get)
+ } map (_._1)
+
+ val paramsWithoutPositionalArg = params.drop(args.length - namedArgsOnChangedPosition.length)
+
+ // missing parameters: those with a name which is not specified in one of the namedArgsOnChangedPosition
+ val missingParams = paramsWithoutPositionalArg.filter(p => namedArgsOnChangedPosition.forall { arg =>
val n = argName(arg)
n.isEmpty || n.get != p.name
- }))
- val allPositional = missingParams.length == namedParams.length
+ })
+ val allPositional = missingParams.length == paramsWithoutPositionalArg.length
(missingParams, allPositional)
}
@@ -407,7 +426,7 @@ trait NamesDefaults { self: Analyzer =>
previousArgss: List[List[Tree]], params: List[Symbol],
pos: scala.reflect.internal.util.Position, context: Context): (List[Tree], List[Symbol]) = {
if (givenArgs.length < params.length) {
- val (missing, positional) = missingParams(givenArgs, params)
+ val (missing, positional) = missingParams(givenArgs, params, nameOfNamedArg)
if (missing forall (_.hasDefault)) {
val defaultArgs = missing flatMap (p => {
val defGetter = defaultGetter(p, context)
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
index cf3f265f0c..da0e67a2a5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
@@ -261,7 +261,7 @@ trait PatternTypers {
def doTypedUnapply(tree: Tree, fun0: Tree, fun: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
if (args.length > MaxTupleArity)
return duplErrorTree(TooManyArgsPatternError(fun))
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 1b3da26bf2..1cb775959d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -167,7 +167,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
// This has become noisy with implicit classes.
- if (settings.lint && settings.developer) {
+ if (settings.warnPolyImplicitOverload && settings.developer) {
clazz.info.decls filter (x => x.isImplicit && x.typeParams.nonEmpty) foreach { sym =>
// implicit classes leave both a module symbol and a method symbol as residue
val alts = clazz.info.decl(sym.name).alternatives filterNot (_.isModule)
@@ -954,7 +954,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def apply(tp: Type) = mapOver(tp).normalize
}
- def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.lint) (fn, args) match {
+ def checkImplicitViewOptionApply(pos: Position, fn: Tree, args: List[Tree]): Unit = if (settings.warnOptionImplicit) (fn, args) match {
case (tap@TypeApply(fun, targs), List(view: ApplyImplicitView)) if fun.symbol == currentRun.runDefinitions.Option_apply =>
reporter.warning(pos, s"Suspicious application of an implicit view (${view.fun}) in the argument to Option.apply.") // SI-6567
case _ =>
@@ -1320,7 +1320,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
&& !qual.tpe.isInstanceOf[ThisType]
&& sym.accessedOrSelf.isVal
)
- if (settings.lint.value && isLikelyUninitialized)
+ if (settings.warnDelayedInit && isLikelyUninitialized)
reporter.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value")
}
@@ -1387,7 +1387,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
private def checkByNameRightAssociativeDef(tree: DefDef) {
tree match {
case DefDef(_, name, _, params :: _, _, _) =>
- if (settings.lint && !treeInfo.isLeftAssoc(name.decodedName) && params.exists(p => isByName(p.symbol)))
+ if (settings.warnByNameRightAssociative && !treeInfo.isLeftAssoc(name.decodedName) && params.exists(p => isByName(p.symbol)))
reporter.warning(tree.pos,
"by-name parameters will be evaluated eagerly when called as a right-associative infix operator. For more details, see SI-1980.")
case _ =>
@@ -1633,7 +1633,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if (settings.warnNullaryUnit)
checkNullaryMethodReturnType(sym)
if (settings.warnInaccessible) {
- if (!sym.isConstructor && !sym.isEffectivelyFinal && !sym.isSynthetic)
+ if (!sym.isConstructor && !sym.isEffectivelyFinalOrNotOverridden && !sym.isSynthetic)
checkAccessibilityOfReferencedTypes(tree)
}
tree match {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index d3a41b9570..38b00a015b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -247,7 +247,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
// also exists in a superclass, because they may be surprised
// to find out that a constructor parameter will shadow a
// field. See SI-4762.
- if (settings.lint) {
+ if (settings.warnPrivateShadow) {
if (sym.isPrivateLocal && sym.paramss.isEmpty) {
qual.symbol.ancestors foreach { parent =>
parent.info.decls filterNot (x => x.isPrivate || x.isLocalToThis) foreach { m2 =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index 9516f94135..d0237fb468 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -339,12 +339,11 @@ trait SyntheticMethods extends ast.TreeDSL {
!hasOverridingImplementation(m) || {
clazz.isDerivedValueClass && (m == Any_hashCode || m == Any_equals) && {
// Without a means to suppress this warning, I've thought better of it.
- //
- // if (settings.lint) {
- // (clazz.info nonPrivateMember m.name) filter (m => (m.owner != AnyClass) && (m.owner != clazz) && !m.isDeferred) andAlso { m =>
- // currentUnit.warning(clazz.pos, s"Implementation of ${m.name} inherited from ${m.owner} overridden in $clazz to enforce value class semantics")
- // }
- // }
+ if (settings.warnValueOverrides) {
+ (clazz.info nonPrivateMember m.name) filter (m => (m.owner != AnyClass) && (m.owner != clazz) && !m.isDeferred) andAlso { m =>
+ currentUnit.warning(clazz.pos, s"Implementation of ${m.name} inherited from ${m.owner} overridden in $clazz to enforce value class semantics")
+ }
+ }
true
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 399a4ca8d5..743bbe53bd 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -208,8 +208,7 @@ abstract class TreeCheckers extends Analyzer {
}
def check(unit: CompilationUnit) {
informProgress("checking "+unit)
- val context = rootContext(unit)
- context.checking = true
+ val context = rootContext(unit, checking = true)
tpeOfTree.clear()
SymbolTracker.check(phase, unit)
val checker = new TreeChecker(context)
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index 7440f69e93..8d29d28908 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -572,11 +572,11 @@ trait TypeDiagnostics {
} else f
}
def apply(tree: Tree): Tree = {
- // Error suppression will squash some of these warnings unless we circumvent it.
+ // Error suppression (in context.warning) would squash some of these warnings.
// It is presumed if you are using a -Y option you would really like to hear
- // the warnings you've requested.
+ // the warnings you've requested; thus, use reporter.warning.
if (settings.warnDeadCode && context.unit.exists && treeOK(tree) && exprOK)
- context.warning(tree.pos, "dead code following this construct", force = true)
+ reporter.warning(tree.pos, "dead code following this construct")
tree
}
@@ -600,6 +600,23 @@ trait TypeDiagnostics {
)
}
+ // warn about class/method/type-members' type parameters that shadow types already in scope
+ def warnTypeParameterShadow(tparams: List[TypeDef], sym: Symbol): Unit =
+ if (settings.warnTypeParameterShadow && !isPastTyper && !sym.isSynthetic) {
+ def enclClassOrMethodOrTypeMember(c: Context): Context =
+ if (!c.owner.exists || c.owner.isClass || c.owner.isMethod || (c.owner.isType && !c.owner.isParameter)) c
+ else enclClassOrMethodOrTypeMember(c.outer)
+
+ val tt = tparams.filter(_.name != typeNames.WILDCARD).foreach { tp =>
+ // we don't care about type params shadowing other type params in the same declaration
+ enclClassOrMethodOrTypeMember(context).outer.lookupSymbol(tp.name, s => s != tp.symbol && s.hasRawInfo && reallyExists(s)) match {
+ case LookupSucceeded(_, sym2) => context.warning(tp.pos,
+ s"type parameter ${tp.name} defined in $sym shadows $sym2 defined in ${sym2.owner}. You may want to rename your type parameter, or possibly remove it.")
+ case _ =>
+ }
+ }
+ }
+
/** Report a type error.
*
* @param pos The position where to report the error
@@ -629,7 +646,7 @@ trait TypeDiagnostics {
throw new FatalError("cannot redefine root "+sym)
}
case _ =>
- context0.error(ex.pos, ex)
+ context0.error(ex.pos, ex.msg)
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 2c31ef2e8e..422b940cd3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -155,21 +155,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
} else {
mkArg = gen.mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args
if (!param.hasDefault && !paramFailed) {
- context.reportBuffer.errors.collectFirst {
- case dte: DivergentImplicitTypeError => dte
- } match {
- case Some(divergent) =>
- // DivergentImplicit error has higher priority than "no implicit found"
- // no need to issue the problem again if we are still in silent mode
- if (context.reportErrors) {
- context.issue(divergent.withPt(paramTp))
- context.reportBuffer.clearErrors {
- case dte: DivergentImplicitTypeError => true
- }
- }
- case _ =>
- NoImplicitFoundError(fun, param)
- }
+ context.reporter.reportFirstDivergentError(fun, param, paramTp)(context)
paramFailed = true
}
/* else {
@@ -478,20 +464,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (cond) typerWithLocalContext(c)(f) else f(this)
@inline
- final def typerWithLocalContext[T](c: Context)(f: Typer => T): T = {
- val res = f(newTyper(c))
- if (c.hasErrors)
- context.updateBuffer(c.flushAndReturnBuffer())
- res
- }
-
- @inline
- final def withSavedContext[T](c: Context)(f: => T) = {
- val savedErrors = c.flushAndReturnBuffer()
- val res = f
- c.updateBuffer(savedErrors)
- res
- }
+ final def typerWithLocalContext[T](c: Context)(f: Typer => T): T =
+ c.reporter.propagatingErrorsTo(context.reporter)(f(newTyper(c)))
/** The typer for a label definition. If this is part of a template we
* first have to enter the label definition.
@@ -684,6 +658,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (Statistics.canEnable) Statistics.stopCounter(subtypeFailed, subtypeStart)
if (Statistics.canEnable) Statistics.stopTimer(failedSilentNanos, failedSilentStart)
}
+ @inline def wrapResult(reporter: ContextReporter, result: T) =
+ if (reporter.hasErrors) {
+ stopStats()
+ SilentTypeError(reporter.errors: _*)
+ } else SilentResultValue(result)
+
try {
if (context.reportErrors ||
reportAmbiguousErrors != context.ambiguousErrors ||
@@ -697,20 +677,17 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
context.undetparams = context1.undetparams
context.savedTypeBounds = context1.savedTypeBounds
context.namedApplyBlockInfo = context1.namedApplyBlockInfo
- if (context1.hasErrors) {
- stopStats()
- SilentTypeError(context1.errors: _*)
- } else {
- // If we have a successful result, emit any warnings it created.
- context1.flushAndIssueWarnings()
- SilentResultValue(result)
- }
+
+ // If we have a successful result, emit any warnings it created.
+ if (!context1.reporter.hasErrors)
+ context1.reporter.emitWarnings()
+
+ wrapResult(context1.reporter, result)
} else {
assert(context.bufferErrors || isPastTyper, "silent mode is not available past typer")
- withSavedContext(context){
- val res = op(this)
- val errorsToReport = context.flushAndReturnBuffer()
- if (errorsToReport.isEmpty) SilentResultValue(res) else SilentTypeError(errorsToReport.head)
+
+ context.reporter.withFreshErrorBuffer {
+ wrapResult(context.reporter, op(this))
}
}
} catch {
@@ -816,14 +793,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
// avoid throwing spurious DivergentImplicit errors
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else
withCondConstrTyper(treeInfo.isSelfOrSuperConstrCall(tree))(typer1 =>
if (original != EmptyTree && pt != WildcardType) (
typer1 silent { tpr =>
val withImplicitArgs = tpr.applyImplicitArgs(tree)
- if (tpr.context.hasErrors) tree // silent will wrap it in SilentTypeError anyway
+ if (tpr.context.reporter.hasErrors) tree // silent will wrap it in SilentTypeError anyway
else tpr.typed(withImplicitArgs, mode, pt)
}
orElse { _ =>
@@ -1057,7 +1034,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val silentContext = context.makeImplicit(context.ambiguousErrors)
val res = newTyper(silentContext).typed(
new ApplyImplicitView(coercion, List(tree)) setPos tree.pos, mode, pt)
- silentContext.firstError match {
+ silentContext.reporter.firstError match {
case Some(err) => context.issue(err)
case None => return res
}
@@ -1749,6 +1726,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
|you want, you must write the annotation class in Java.""".stripMargin)
}
+ warnTypeParameterShadow(tparams1, clazz)
+
if (!isPastTyper) {
for (ann <- clazz.getAnnotation(DeprecatedAttr)) {
val m = companionSymbolOf(clazz, context)
@@ -2151,6 +2130,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val tparams1 = ddef.tparams mapConserve typedTypeDef
val vparamss1 = ddef.vparamss mapConserve (_ mapConserve typedValDef)
+ warnTypeParameterShadow(tparams1, meth)
+
meth.annotations.map(_.completeInfo())
for (vparams1 <- vparamss1; vparam1 <- vparams1 dropRight 1)
@@ -2227,6 +2208,8 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
val typedMods = typedModifiers(tdef.mods)
tdef.symbol.annotations.map(_.completeInfo())
+ warnTypeParameterShadow(tparams1, tdef.symbol)
+
// @specialized should not be pickled when compiling with -no-specialize
if (settings.nospecialization && currentRun.compiles(tdef.symbol)) {
tdef.symbol.removeAnnotation(definitions.SpecializedClass)
@@ -2990,7 +2973,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
ConstructorsOrderError(stat)
}
- if (treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
+ if (!isPastTyper && treeInfo.isPureExprForWarningPurposes(result)) context.warning(stat.pos,
"a pure expression does nothing in statement position; " +
"you may be omitting necessary parentheses"
)
@@ -3149,7 +3132,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Mode, pt: Type): Tree = {
// TODO_NMT: check the assumption that args nonEmpty
def duplErrTree = setError(treeCopy.Apply(tree, fun0, args))
- def duplErrorTree(err: AbsTypeError) = { issue(err); duplErrTree }
+ def duplErrorTree(err: AbsTypeError) = { context.issue(err); duplErrTree }
def preSelectOverloaded(fun: Tree): Tree = {
if (fun.hasSymbolField && fun.symbol.isOverloaded) {
@@ -3229,7 +3212,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
(arg1, arg1.tpe.deconst)
}.unzip
}
- if (context.hasErrors)
+ if (context.reporter.hasErrors)
setError(tree)
else {
inferMethodAlternative(fun, undetparams, argTpes, pt)
@@ -3248,25 +3231,25 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
* to that. This is the last thing which is tried (after
* default arguments)
*/
- def tryTupleApply: Tree = (
+ def tryTupleApply: Tree = {
if (eligibleForTupleConversion(paramTypes, argslen) && !phase.erasedTypes) {
val tupleArgs = List(atPos(tree.pos.makeTransparent)(gen.mkTuple(args)))
// expected one argument, but got 0 or >1 ==> try applying to tuple
// the inner "doTypedApply" does "extractUndetparams" => restore when it fails
val savedUndetparams = context.undetparams
silent(_.doTypedApply(tree, fun, tupleArgs, mode, pt)) map { t =>
- // Depending on user options, may warn or error here if
- // a Unit or tuple was inserted.
- val keepTree = (
- !mode.typingExprNotFun
- || t.symbol == null
- || checkValidAdaptation(t, args)
- )
- if (keepTree) t else EmptyTree
+ // Depending on user options, may warn or error here if
+ // a Unit or tuple was inserted.
+ val keepTree = (
+ !mode.typingExprNotFun // why? introduced in 4e488a60, doc welcome
+ || t.symbol == null // ditto
+ || checkValidAdaptation(t, args)
+ )
+ if (keepTree) t else EmptyTree
} orElse { _ => context.undetparams = savedUndetparams ; EmptyTree }
}
else EmptyTree
- )
+ }
/* Treats an application which uses named or default arguments.
* Also works if names + a vararg used: when names are used, the vararg
@@ -3357,8 +3340,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
duplErrTree
} else if (lencmp2 == 0) {
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
- val note = "Error occurred in an application involving default arguments."
- if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
+ context.diagUsedDefaults = true
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
} else {
rollbackNamesDefaultsOwnerChanges()
@@ -4331,7 +4313,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
c.retyping = true
try {
val res = newTyper(c).typedArgs(args, mode)
- if (c.hasErrors) None else Some(res)
+ if (c.reporter.hasErrors) None else Some(res)
} catch {
case ex: CyclicReference =>
throw ex
@@ -4395,7 +4377,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case _ => ()
}
}
- typeErrors foreach issue
+ typeErrors foreach context.issue
setError(treeCopy.Apply(tree, fun, args))
}
@@ -4449,7 +4431,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
doTypedApply(tree, fun2, args, mode, pt)
case err: SilentTypeError =>
onError({
- err.reportableErrors foreach issue
+ err.reportableErrors foreach context.issue
args foreach (arg => typed(arg, mode, ErrorType))
setError(tree)
})
@@ -4686,7 +4668,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else
// before failing due to access, try a dynamic call.
asDynamicCall getOrElse {
- issue(accessibleError.get)
+ context.issue(accessibleError.get)
setError(tree)
}
case _ =>
@@ -5099,7 +5081,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
def isPlausible(m: Symbol) = m.alternatives exists (m => requiresNoArgs(m.info))
def maybeWarn(s: String): Unit = {
- def warn(message: String) = context.warning(lit.pos, s"$message Did you forget the interpolator?")
+ def warn(message: String) = context.warning(lit.pos, s"possible missing interpolator: $message")
def suspiciousSym(name: TermName) = context.lookupSymbol(name, _ => true).symbol
def suspiciousExpr = InterpolatorCodeRegex findFirstIn s
def suspiciousIdents = InterpolatorIdentRegex findAllIn s map (s => suspiciousSym(s drop 1))
@@ -5107,9 +5089,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// heuristics - no warning on e.g. a string with only "$asInstanceOf"
if (s contains ' ') (
if (suspiciousExpr.nonEmpty)
- warn("That looks like an interpolated expression!") // "${...}"
+ warn("detected an interpolated expression") // "${...}"
else
- suspiciousIdents find isPlausible foreach (sym => warn(s"`$$${sym.name}` looks like an interpolated identifier!")) // "$id"
+ suspiciousIdents find isPlausible foreach (sym => warn(s"detected interpolated identifier `$$${sym.name}`")) // "$id"
)
}
lit match {
@@ -5119,7 +5101,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
def typedLiteral(tree: Literal) = {
- if (settings.lint) warnMissingInterpolator(tree)
+ if (settings.warnMissingInterpolator) warnMissingInterpolator(tree)
tree setType (if (tree.value.tag == UnitTag) UnitTpe else ConstantType(tree.value))
}
diff --git a/src/compiler/scala/tools/reflect/FormatInterpolator.scala b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
index 57be1afdfe..b445f1e2bb 100644
--- a/src/compiler/scala/tools/reflect/FormatInterpolator.scala
+++ b/src/compiler/scala/tools/reflect/FormatInterpolator.scala
@@ -182,13 +182,23 @@ abstract class FormatInterpolator {
case (part, n) => copyPart(part, n)
}
- //q"{..$evals; ${fstring.toString}.format(..$ids)}"
- locally {
+ //q"{..$evals; new StringOps(${fstring.toString}).format(..$ids)}"
+ val format = fstring.toString
+ if (ids.isEmpty && !format.contains("%")) Literal(Constant(format))
+ else {
+ val scalaPackage = Select(Ident(nme.ROOTPKG), TermName("scala"))
+ val newStringOps = Select(
+ New(Select(Select(Select(scalaPackage,
+ TermName("collection")), TermName("immutable")), TypeName("StringOps"))),
+ termNames.CONSTRUCTOR
+ )
val expr =
Apply(
Select(
- Literal(Constant(fstring.toString)),
- newTermName("format")),
+ Apply(
+ newStringOps,
+ List(Literal(Constant(format)))),
+ TermName("format")),
ids.toList
)
val p = c.macroApplication.pos
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 923297bafb..1643e0061f 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -142,7 +142,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
run.symSource(ownerClass) = NoAbstractFile // need to set file to something different from null, so that currentRun.defines works
phase = run.typerPhase // need to set a phase to something <= typerPhase, otherwise implicits in typedSelect will be disabled
globalPhase = run.typerPhase // amazing... looks like phase and globalPhase are different things, so we need to set them separately
- currentTyper.context.setReportErrors() // need to manually set context mode, otherwise typer.silent will throw exceptions
+ currentTyper.context.initRootContext() // need to manually set context mode, otherwise typer.silent will throw exceptions
reporter.reset()
val expr3 = withContext(transform(currentTyper, expr2))
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index b68022afd9..392b7fc881 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -69,9 +69,16 @@ trait Parsers { self: Quasiquotes =>
override def makeTupleType(trees: List[Tree]): Tree = TupleTypePlaceholder(trees)
// q"{ $x }"
- override def makeBlock(stats: List[Tree]): Tree = stats match {
- case (head @ Ident(name)) :: Nil if isHole(name) => Block(Nil, head)
- case _ => super.makeBlock(stats)
+ override def makeBlock(stats: List[Tree]): Tree = method match {
+ case nme.apply =>
+ stats match {
+ // we don't want to eagerly flatten trees with placeholders as they
+ // might have to be wrapped into a block depending on their value
+ case (head @ Ident(name)) :: Nil if isHole(name) => Block(Nil, head)
+ case _ => gen.mkBlock(stats, doFlatten = true)
+ }
+ case nme.unapply => gen.mkBlock(stats, doFlatten = false)
+ case other => global.abort("unreachable")
}
// tq"$a => $b"
diff --git a/src/eclipse/repl/.classpath b/src/eclipse/repl/.classpath
index 601a231aeb..8ff9aabfbf 100644
--- a/src/eclipse/repl/.classpath
+++ b/src/eclipse/repl/.classpath
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="repl"/>
- <classpathentry combineaccessrules="false" kind="src" path="/asm"/>
- <classpathentry kind="var" path="M2_REPO/jline/jline/2.11/jline-2.11.jar"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
- <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_COMPILER_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.11.jar"/>
- <classpathentry kind="output" path="build-quick-repl"/>
+ <classpathentry kind="src" path="repl"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/asm"/>
+ <classpathentry kind="var" path="M2_REPO/jline/jline/2.12/jline-2.12.jar"/>
+ <!-- <classpathentry kind="var" path="SCALA_BASEDIR/build/deps/repl/jline-2.12.jar"/> -->
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-compiler"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/scala-library"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="output" path="build-quick-repl"/>
</classpath>
diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index 95027a26b1..174254d523 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -142,8 +142,6 @@ class Global(settings: Settings, _reporter: Reporter, projectName: String = "")
// don't keep the original owner in presentation compiler runs
// (the map will grow indefinitely, and the only use case is the backend)
override protected def saveOriginalOwner(sym: Symbol) { }
- override protected def originalEnclosingMethod(sym: Symbol) =
- abort("originalOwner is not kept in presentation compiler runs.")
override def forInteractive = true
override protected def synchronizeNames = true
diff --git a/src/jline/LICENSE.txt b/src/jline/LICENSE.txt
deleted file mode 100644
index 1cdc44c211..0000000000
--- a/src/jline/LICENSE.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-Copyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or
-without modification, are permitted provided that the following
-conditions are met:
-
-Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with
-the distribution.
-
-Neither the name of JLine nor the names of its contributors
-may be used to endorse or promote products derived from this
-software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
-IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/src/jline/README.md b/src/jline/README.md
deleted file mode 100644
index 829476145d..0000000000
--- a/src/jline/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-Description
------------
-
-JLine 2.x
-
-License
--------
-
-BSD
-
-Building
---------
-
-### Requirements
-
-* SBT
-* Java 5+
-
-This is a fork with scala specific modifications.
-The original repository was: git://github.com/jdillon/jline2.git
-
-You can now build with sbt:
-
- sbt update proguard
diff --git a/src/jline/build.sbt b/src/jline/build.sbt
deleted file mode 100644
index 873f7574f1..0000000000
--- a/src/jline/build.sbt
+++ /dev/null
@@ -1,49 +0,0 @@
-seq(ProguardPlugin.proguardSettings :_*)
-
-name := "jline"
-
-organization := "org.scala-lang"
-
-version := "2.11.0-SNAPSHOT"
-
-scalaVersion := "2.10.1"
-
-// Only need these because of weird testing jline issues.
-retrieveManaged := true
-
-parallelExecution in Test := false
-
-libraryDependencies ++= Seq(
- "org.fusesource.jansi" % "jansi" % "1.10",
- "com.novocode" % "junit-interface" % "0.9" % "test->default"
-)
-
-javacOptions ++= Seq("-source", "1.5", "-target", "1.5")
-
-proguardOptions ++= Seq(
- "-dontshrink",
- "-keep class *",
- "-keepdirectories"
-)
-
-proguardInJars := Nil
-
-makeInJarFilter ~= { prevFilter =>
- val jansiFilter = List(
- "!META-INF/MANIFEST.MF",
- "org/fusesource/hawtjni/runtime",
- "org/fusesource/hawtjni/runtime/Callback.class",
- "org/fusesource/hawtjni/runtime/Library.class",
- "!org/fusesource/hawtjni/**",
- "!META-INF/maven/org.fusesource.hawtjni",
- "!META-INF/maven/org.fusesource.jansi",
- "!META-INF/maven/org.fusesource.hawtjni/**",
- "!META-INF/maven/org.fusesource.jansi/**"
- ).mkString(",")
- // In sbt 0.9.8 the scala-library.jar line was not necessary,
- // but in 0.9.9 it started showing up here. Who knows.
- file =>
- if (file startsWith "jansi-") jansiFilter
- else if (file == "scala-library.jar") "!**"
- else prevFilter(file)
-}
diff --git a/src/jline/manual-test.sh b/src/jline/manual-test.sh
deleted file mode 100755
index 744e1756e8..0000000000
--- a/src/jline/manual-test.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-#
-# Apparently the jline bundled with sbt interferes with testing some
-# changes: for instance after changing the keybindings I kept seeing
-# failures until I realized what was happening and bypassed sbt, like this.
-CP=lib_managed/jars/com.novocode/junit-interface/junit-interface-0.9.jar:lib_managed/jars/junit/junit-dep/junit-dep-4.8.2.jar:lib_managed/jars/org.fusesource.jansi/jansi/jansi-1.10.jar:lib_managed/jars/org.hamcrest/hamcrest-core/hamcrest-core-1.1.jar:lib_managed/jars/org.scala-tools.testing/test-interface/test-interface-0.5.jar:target/scala-2.10/test-classes:target/scala-2.10/jline_2.10-2.11.0-SNAPSHOT.min.jar
-
-sbt proguard
-java -cp $CP org.junit.runner.JUnitCore scala.tools.jline.console.EditLineTest
diff --git a/src/jline/project/build.properties b/src/jline/project/build.properties
deleted file mode 100644
index 9b860e23c5..0000000000
--- a/src/jline/project/build.properties
+++ /dev/null
@@ -1 +0,0 @@
-sbt.version=0.12.3
diff --git a/src/jline/project/plugins.sbt b/src/jline/project/plugins.sbt
deleted file mode 100644
index 9c13de92d8..0000000000
--- a/src/jline/project/plugins.sbt
+++ /dev/null
@@ -1,3 +0,0 @@
-resolvers += Resolver.url("sbt-plugin-releases-scalasbt", url("http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
-
-addSbtPlugin("org.scala-sbt" % "xsbt-proguard-plugin" % "0.1.3")
diff --git a/src/jline/src/main/java/scala/tools/jline/AnsiWindowsTerminal.java b/src/jline/src/main/java/scala/tools/jline/AnsiWindowsTerminal.java
deleted file mode 100644
index 94697137d3..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/AnsiWindowsTerminal.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * MODIFICATIONS: methods to deal with wrapping the output stream.
- */
-
-package scala.tools.jline;
-
-import org.fusesource.jansi.AnsiConsole;
-import org.fusesource.jansi.AnsiOutputStream;
-import org.fusesource.jansi.WindowsAnsiOutputStream;
-
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-
-/**
- * ANSI-supported {@link WindowsTerminal}.
- *
- * @since 2.0
- */
-public class AnsiWindowsTerminal
- extends WindowsTerminal
-{
- private final boolean ansiSupported = detectAnsiSupport();
-
- @Override
- public OutputStream wrapOutIfNeeded(OutputStream out) {
- return wrapOutputStream(out);
- }
-
- /**
- * Returns an ansi output stream handler. We return whatever was
- * passed if we determine we cannot handle ansi based on Kernel32 calls.
- *
- * @return an @{link AltWindowAnsiOutputStream} instance or the passed
- * stream.
- */
- private static OutputStream wrapOutputStream(final OutputStream stream) {
- String os = System.getProperty("os.name");
- if( os.startsWith("Windows") ) {
- // On windows we know the console does not interpret ANSI codes..
- try {
- return new WindowsAnsiOutputStream(stream);
- } catch (Throwable ignore) {
- // this happens when JNA is not in the path.. or
- // this happens when the stdout is being redirected to a file.
- }
- // Use the ANSIOutputStream to strip out the ANSI escape sequences.
- return new AnsiOutputStream(stream);
- }
- return stream;
- }
-
- private static boolean detectAnsiSupport() {
- OutputStream out = AnsiConsole.wrapOutputStream(new ByteArrayOutputStream());
- try {
- out.close();
- }
- catch (Exception e) {
- // ignore;
- }
- return out instanceof WindowsAnsiOutputStream;
- }
-
- public AnsiWindowsTerminal() throws Exception {
- super();
- }
-
- @Override
- public boolean isAnsiSupported() {
- return ansiSupported;
- }
-
- @Override
- public boolean hasWeirdWrap() {
- return false;
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/NoInterruptUnixTerminal.java b/src/jline/src/main/java/scala/tools/jline/NoInterruptUnixTerminal.java
deleted file mode 100644
index ef7cf23c4a..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/NoInterruptUnixTerminal.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package scala.tools.jline;
-
-// Based on Apache Karaf impl
-
-/**
- * Non-interruptable (via CTRL-C) {@link UnixTerminal}.
- *
- * @since 2.0
- */
-public class NoInterruptUnixTerminal
- extends UnixTerminal
-{
- public NoInterruptUnixTerminal() throws Exception {
- super();
- }
-
- @Override
- public void init() throws Exception {
- super.init();
- getSettings().set("intr undef");
- }
-
- @Override
- public void restore() throws Exception {
- getSettings().set("intr ^C");
- super.restore();
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/Terminal.java b/src/jline/src/main/java/scala/tools/jline/Terminal.java
deleted file mode 100644
index 79611c244d..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/Terminal.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Representation of the input terminal for a platform.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public interface Terminal
-{
- void init() throws Exception;
-
- void restore() throws Exception;
-
- void reset() throws Exception;
-
- boolean isSupported();
-
- int getWidth();
-
- int getHeight();
-
- boolean isAnsiSupported();
-
- /**
- * When ANSI is not natively handled, the output will have to be wrapped.
- */
- OutputStream wrapOutIfNeeded(OutputStream out);
-
- /**
- * For terminals that don't wrap when character is written in last column,
- * only when the next character is written.
- * These are the ones that have 'am' and 'xn' termcap attributes (xterm and
- * rxvt flavors falls under that category)
- */
- boolean hasWeirdWrap();
-
- boolean isEchoEnabled();
-
- void setEchoEnabled(boolean enabled);
-
- int readCharacter(InputStream in) throws IOException;
-
- int readVirtualKey(InputStream in) throws IOException;
-
- InputStream getDefaultBindings();
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/TerminalFactory.java b/src/jline/src/main/java/scala/tools/jline/TerminalFactory.java
deleted file mode 100644
index 95b7c28bd5..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/TerminalFactory.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-import scala.tools.jline.internal.Configuration;
-import scala.tools.jline.internal.Log;
-
-import java.text.MessageFormat;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Creates terminal instances.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class TerminalFactory
-{
- public static final String JLINE_TERMINAL = "jline.terminal";
-
- public static final String AUTO = "auto";
-
- public static final String UNIX = "unix";
-
- public static final String WIN = "win";
-
- public static final String WINDOWS = "windows";
-
- public static final String NONE = "none";
-
- public static final String OFF = "off";
-
- public static final String FALSE = "false";
-
- private static final InheritableThreadLocal<Terminal> holder = new InheritableThreadLocal<Terminal>();
-
- public static synchronized Terminal create() {
- if (Log.TRACE) {
- //noinspection ThrowableInstanceNeverThrown
- Log.trace(new Throwable("CREATE MARKER"));
- }
-
- String type = Configuration.getString(JLINE_TERMINAL);
- if (type == null) {
- type = AUTO;
- }
-
- Log.debug("Creating terminal; type=", type);
-
- Terminal t;
- try {
- String tmp = type.toLowerCase();
-
- if (tmp.equals(UNIX)) {
- t = getFlavor(Flavor.UNIX);
- }
- else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
- t = getFlavor(Flavor.WINDOWS);
- }
- else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
- t = new UnsupportedTerminal();
- }
- else {
- if (tmp.equals(AUTO)) {
- String os = Configuration.getOsName();
- Flavor flavor = Flavor.UNIX;
- if (os.contains(WINDOWS)) {
- flavor = Flavor.WINDOWS;
- }
- t = getFlavor(flavor);
- }
- else {
- try {
- t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
- }
- catch (Exception e) {
- throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
- }
- }
- }
- }
- catch (Exception e) {
- Log.error("Failed to construct terminal; falling back to unsupported", e);
- t = new UnsupportedTerminal();
- }
-
- Log.debug("Created Terminal: ", t);
-
- try {
- t.init();
- }
- catch (Exception e) {
- Log.error("Terminal initialization failed; falling back to unsupported", e);
- return new UnsupportedTerminal();
- }
-
- return t;
- }
-
- public static synchronized void reset() {
- holder.remove();
- }
-
- public static synchronized void resetIf(final Terminal t) {
- if (holder.get() == t) {
- reset();
- }
- }
-
- public static enum Type
- {
- AUTO,
- WINDOWS,
- UNIX,
- NONE
- }
-
- public static synchronized void configure(final String type) {
- assert type != null;
- System.setProperty(JLINE_TERMINAL, type);
- }
-
- public static synchronized void configure(final Type type) {
- assert type != null;
- configure(type.name().toLowerCase());
- }
-
- //
- // Flavor Support
- //
-
- public static enum Flavor
- {
- WINDOWS,
- UNIX
- }
-
- private static final Map<Flavor, Class<? extends Terminal>> FLAVORS = new HashMap<Flavor, Class<? extends Terminal>>();
-
- static {
- registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
- registerFlavor(Flavor.UNIX, UnixTerminal.class);
- }
-
- public static synchronized Terminal get() {
- Terminal t = holder.get();
- if (t == null) {
- t = create();
- holder.set(t);
- }
- return t;
- }
-
- public static Terminal getFlavor(final Flavor flavor) throws Exception {
- Class<? extends Terminal> type = FLAVORS.get(flavor);
- if (type != null) {
- return type.newInstance();
- }
-
- throw new InternalError();
- }
-
- public static void registerFlavor(final Flavor flavor, final Class<? extends Terminal> type) {
- FLAVORS.put(flavor, type);
- }
-
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/TerminalSupport.java b/src/jline/src/main/java/scala/tools/jline/TerminalSupport.java
deleted file mode 100644
index 1ca12cb73f..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/TerminalSupport.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-import scala.tools.jline.internal.Log;
-import scala.tools.jline.internal.Configuration;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Provides support for {@link Terminal} instances.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public abstract class TerminalSupport
- implements Terminal
-{
- public static String DEFAULT_KEYBINDINGS_PROPERTIES = "keybindings.properties";
-
- public static final String JLINE_SHUTDOWNHOOK = "jline.shutdownhook";
-
- public static final int DEFAULT_WIDTH = 80;
-
- public static final int DEFAULT_HEIGHT = 24;
-
- private Thread shutdownHook;
-
- private boolean shutdownHookEnabled;
-
- private boolean supported;
-
- private boolean echoEnabled;
-
- private boolean ansiSupported;
-
- protected TerminalSupport(final boolean supported) {
- this.supported = supported;
- this.shutdownHookEnabled = Configuration.getBoolean(JLINE_SHUTDOWNHOOK, false);
- }
-
- public void init() throws Exception {
- installShutdownHook(new RestoreHook());
- }
-
- public void restore() throws Exception {
- TerminalFactory.resetIf(this);
- removeShutdownHook();
- }
-
- public void reset() throws Exception {
- restore();
- init();
- }
-
- // Shutdown hooks causes classloader leakage in sbt,
- // so they are only installed if -Djline.shutdownhook is true.
- protected void installShutdownHook(final Thread hook) {
- if (!shutdownHookEnabled) {
- Log.debug("Not install shutdown hook " + hook + " because they are disabled.");
- return;
- }
-
- assert hook != null;
-
- if (shutdownHook != null) {
- throw new IllegalStateException("Shutdown hook already installed");
- }
-
- try {
- Runtime.getRuntime().addShutdownHook(hook);
- shutdownHook = hook;
- }
- catch (AbstractMethodError e) {
- // JDK 1.3+ only method. Bummer.
- Log.trace("Failed to register shutdown hook: ", e);
- }
- }
-
- protected void removeShutdownHook() {
- if (!shutdownHookEnabled)
- return;
-
- if (shutdownHook != null) {
- try {
- Runtime.getRuntime().removeShutdownHook(shutdownHook);
- }
- catch (AbstractMethodError e) {
- // JDK 1.3+ only method. Bummer.
- Log.trace("Failed to remove shutdown hook: ", e);
- }
- catch (IllegalStateException e) {
- // The VM is shutting down, not a big deal; ignore
- }
- shutdownHook = null;
- }
- }
-
- public final boolean isSupported() {
- return supported;
- }
-
- public synchronized boolean isAnsiSupported() {
- return ansiSupported;
- }
-
- protected synchronized void setAnsiSupported(final boolean supported) {
- this.ansiSupported = supported;
- Log.debug("Ansi supported: ", supported);
- }
-
- /**
- * Subclass to change behavior if needed.
- * @return the passed out
- */
- public OutputStream wrapOutIfNeeded(OutputStream out) {
- return out;
- }
-
- /**
- * Defaults to true which was the behaviour before this method was added.
- */
- public boolean hasWeirdWrap() {
- return true;
- }
-
- public int getWidth() {
- return DEFAULT_WIDTH;
- }
-
- public int getHeight() {
- return DEFAULT_HEIGHT;
- }
-
- public synchronized boolean isEchoEnabled() {
- return echoEnabled;
- }
-
- public synchronized void setEchoEnabled(final boolean enabled) {
- this.echoEnabled = enabled;
- Log.debug("Echo enabled: ", enabled);
- }
-
- public int readCharacter(final InputStream in) throws IOException {
- return in.read();
- }
-
- public int readVirtualKey(final InputStream in) throws IOException {
- return readCharacter(in);
- }
-
- public InputStream getDefaultBindings() {
- return TerminalSupport.class.getResourceAsStream(DEFAULT_KEYBINDINGS_PROPERTIES);
- }
-
- //
- // RestoreHook
- //
-
- protected class RestoreHook
- extends Thread
- {
- public void start() {
- try {
- restore();
- }
- catch (Exception e) {
- Log.trace("Failed to restore: ", e);
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/UnixTerminal.java b/src/jline/src/main/java/scala/tools/jline/UnixTerminal.java
deleted file mode 100644
index 94a1b98c0d..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/UnixTerminal.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-import scala.tools.jline.console.Key;
-import scala.tools.jline.internal.Configuration;
-import scala.tools.jline.internal.Log;
-import scala.tools.jline.internal.ReplayPrefixOneCharInputStream;
-import scala.tools.jline.internal.TerminalLineSettings;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Map;
-
-import static scala.tools.jline.UnixTerminal.UnixKey.*;
-import static scala.tools.jline.console.Key.*;
-
-/**
- * Terminal that is used for unix platforms. Terminal initialization
- * is handled by issuing the <em>stty</em> command against the
- * <em>/dev/tty</em> file to disable character echoing and enable
- * character input. All known unix systems (including
- * Linux and Macintosh OS X) support the <em>stty</em>), so this
- * implementation should work for an reasonable POSIX system.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
- * @since 2.0
- */
-public class UnixTerminal
- extends TerminalSupport
-{
- private final TerminalLineSettings settings = new TerminalLineSettings();
-
- private final ReplayPrefixOneCharInputStream replayStream;
-
- private final InputStreamReader replayReader;
-
- public UnixTerminal() throws Exception {
- super(true);
-
- this.replayStream = new ReplayPrefixOneCharInputStream(Configuration.getInputEncoding());
- this.replayReader = new InputStreamReader(replayStream, replayStream.getEncoding());
- }
-
- protected TerminalLineSettings getSettings() {
- return settings;
- }
-
- /**
- * Remove line-buffered input by invoking "stty -icanon min 1"
- * against the current terminal.
- */
- @Override
- public void init() throws Exception {
- super.init();
-
- setAnsiSupported(true);
-
- // set the console to be character-buffered instead of line-buffered
- settings.set("-icanon min 1");
-
- setEchoEnabled(false);
- }
-
- /**
- * Restore the original terminal configuration, which can be used when
- * shutting down the console reader. The ConsoleReader cannot be
- * used after calling this method.
- */
- @Override
- public void restore() throws Exception {
- settings.restore();
- super.restore();
- // print a newline after the terminal exits.
- // this should probably be a configurable.
- System.out.println();
- }
-
- /**
- * Returns the value of <tt>stty columns</tt> param.
- */
- @Override
- public int getWidth() {
- int w = settings.getProperty("columns");
- return w < 1 ? DEFAULT_WIDTH : w;
- }
-
- /**
- * Returns the value of <tt>stty rows>/tt> param.
- */
- @Override
- public int getHeight() {
- int h = settings.getProperty("rows");
- return h < 1 ? DEFAULT_HEIGHT : h;
- }
-
- @Override
- public synchronized void setEchoEnabled(final boolean enabled) {
- try {
- if (enabled) {
- settings.set("echo");
- }
- else {
- settings.set("-echo");
- }
- super.setEchoEnabled(enabled);
- }
- catch (Exception e) {
- Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo: ", e);
- }
- }
-
- @Override
- public int readVirtualKey(final InputStream in) throws IOException {
- int c = readCharacter(in);
-
- if (Key.valueOf(c) == DELETE && settings.getProperty("erase") == DELETE.code) {
- c = BACKSPACE.code;
- }
-
- UnixKey key = UnixKey.valueOf(c);
-
- // in Unix terminals, arrow keys are represented by a sequence of 3 characters. E.g., the up arrow key yields 27, 91, 68
- if (key == ARROW_START) {
- // also the escape key is 27 thats why we read until we have something different than 27
- // this is a bugfix, because otherwise pressing escape and than an arrow key was an undefined state
- while (key == ARROW_START) {
- c = readCharacter(in);
- key = UnixKey.valueOf(c);
- }
-
- if (key == ARROW_PREFIX || key == O_PREFIX) {
- c = readCharacter(in);
- key = UnixKey.valueOf(c);
-
- if (key == ARROW_UP) {
- return CTRL_P.code;
- }
- else if (key == ARROW_DOWN) {
- return CTRL_N.code;
- }
- else if (key == ARROW_LEFT) {
- return CTRL_B.code;
- }
- else if (key == ARROW_RIGHT) {
- return CTRL_F.code;
- }
- else if (key == HOME_CODE) {
- return CTRL_A.code;
- }
- else if (key == END_CODE) {
- return CTRL_E.code;
- }
- else if (key == DEL_THIRD) {
- readCharacter(in); // read 4th & ignore
- return DELETE.code;
- }
- }
- else if (c == 'b') { // alt-b: go back a word
- return CTRL_O.code; // PREV_WORD
- }
- else if (c == 'f') { // alt-f: go forward a word
- return CTRL_T.code; // NEXT_WORD
- }
- else if (key == DEL) { // alt-backspace: delete previous word
- return CTRL_W.code; // DELETE_PREV_WORD
- }
- else if (c == 'd') { // alt-d: delete next word
- return CTRL_X.code; // DELETE_NEXT_WORD
- }
-
- }
-
- // handle unicode characters, thanks for a patch from amyi@inf.ed.ac.uk
- if (c > 128) {
- // handle unicode characters longer than 2 bytes,
- // thanks to Marc.Herbert@continuent.com
- replayStream.setInput(c, in);
- // replayReader = new InputStreamReader(replayStream, encoding);
- c = replayReader.read();
- }
-
- return c;
- }
-
- /**
- * Unix keys.
- */
- public static enum UnixKey
- {
- ARROW_START(27),
-
- ARROW_PREFIX(91),
-
- ARROW_LEFT(68),
-
- ARROW_RIGHT(67),
-
- ARROW_UP(65),
-
- ARROW_DOWN(66),
-
- O_PREFIX(79),
-
- HOME_CODE(72),
-
- END_CODE(70),
-
- DEL_THIRD(51),
-
- DEL_SECOND(126),
-
- DEL(127);
-
-
- public final short code;
-
- UnixKey(final int code) {
- this.code = (short) code;
- }
-
- private static final Map<Short, UnixKey> codes;
-
- static {
- Map<Short, UnixKey> map = new HashMap<Short, UnixKey>();
-
- for (UnixKey key : UnixKey.values()) {
- map.put(key.code, key);
- }
-
- codes = map;
- }
-
- public static UnixKey valueOf(final int code) {
- return codes.get((short) code);
- }
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/UnsupportedTerminal.java b/src/jline/src/main/java/scala/tools/jline/UnsupportedTerminal.java
deleted file mode 100644
index 04fe4f7f16..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/UnsupportedTerminal.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-/**
- * An unsupported terminal.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class UnsupportedTerminal
- extends TerminalSupport
-{
- public UnsupportedTerminal() {
- super(false);
- setAnsiSupported(false);
- setEchoEnabled(true);
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/WindowsTerminal.java b/src/jline/src/main/java/scala/tools/jline/WindowsTerminal.java
deleted file mode 100644
index 4c70155f59..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/WindowsTerminal.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline;
-
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.HashMap;
-import java.util.Map;
-
-import scala.tools.jline.internal.Configuration;
-import org.fusesource.jansi.internal.WindowsSupport;
-
-import scala.tools.jline.internal.Log;
-import scala.tools.jline.internal.ReplayPrefixOneCharInputStream;
-
-import static scala.tools.jline.WindowsTerminal.ConsoleMode.*;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.*;
-import static scala.tools.jline.console.Key.*;
-
-/**
- * Terminal implementation for Microsoft Windows. Terminal initialization in
- * {@link #init} is accomplished by extracting the
- * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
- * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
- * property), loading the library, and then calling the Win32 APIs <a
- * href="http://msdn.microsoft.com/library/default.asp?
- * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
- * <a href="http://msdn.microsoft.com/library/default.asp?
- * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
- * disable character echoing.
- * <p/>
- * <p>
- * By default, the {@link #readCharacter} method will attempt to test to see if
- * the specified {@link InputStream} is {@link System#in} or a wrapper around
- * {@link FileDescriptor#in}, and if so, will bypass the character reading to
- * directly invoke the readc() method in the JNI library. This is so the class
- * can read special keys (like arrow keys) which are otherwise inaccessible via
- * the {@link System#in} stream. Using JNI reading can be bypassed by setting
- * the <code>jline.WindowsTerminal.directConsole</code> system property
- * to <code>false</code>.
- * </p>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class WindowsTerminal
- extends TerminalSupport
-{
- public static final String JLINE_WINDOWS_TERMINAL_INPUT_ENCODING = "jline.WindowsTerminal.input.encoding";
-
- public static final String JLINE_WINDOWS_TERMINAL_OUTPUT_ENCODING = "jline.WindowsTerminal.output.encoding";
-
- public static final String JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE = "jline.WindowsTerminal.directConsole";
-
- public static final String WINDOWSBINDINGS_PROPERTIES = "windowsbindings.properties";
-
- public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
-
- private boolean directConsole;
-
- private int originalMode;
-
- private final ReplayPrefixOneCharInputStream replayStream;
-
- private final InputStreamReader replayReader;
-
- public WindowsTerminal() throws Exception {
- super(true);
-
- this.replayStream =
- new ReplayPrefixOneCharInputStream(Configuration.getString(JLINE_WINDOWS_TERMINAL_INPUT_ENCODING, Configuration.getFileEncoding()));
- this.replayReader = new InputStreamReader(replayStream, replayStream.getEncoding());
- }
-
- @Override
- public void init() throws Exception {
- super.init();
-
- setAnsiSupported(Boolean.getBoolean(ANSI));
-
- //
- // FIXME: Need a way to disable direct console and sysin detection muck
- //
-
- setDirectConsole(Boolean.getBoolean(JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE));
-
- this.originalMode = getConsoleMode();
- setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
- setEchoEnabled(false);
- }
-
- /**
- * Restore the original terminal configuration, which can be used when
- * shutting down the console reader. The ConsoleReader cannot be
- * used after calling this method.
- */
- @Override
- public void restore() throws Exception {
- // restore the old console mode
- setConsoleMode(originalMode);
- super.restore();
- }
-
- @Override
- public int getWidth() {
- int w = getWindowsTerminalWidth();
- return w < 1 ? DEFAULT_WIDTH : w;
- }
-
- @Override
- public int getHeight() {
- int h = getWindowsTerminalHeight();
- return h < 1 ? DEFAULT_HEIGHT : h;
- }
-
- @Override
- public void setEchoEnabled(final boolean enabled) {
- // Must set these four modes at the same time to make it work fine.
- if (enabled) {
- setConsoleMode(getConsoleMode() |
- ENABLE_ECHO_INPUT.code |
- ENABLE_LINE_INPUT.code |
- ENABLE_PROCESSED_INPUT.code |
- ENABLE_WINDOW_INPUT.code);
- }
- else {
- setConsoleMode(getConsoleMode() &
- ~(ENABLE_LINE_INPUT.code |
- ENABLE_ECHO_INPUT.code |
- ENABLE_PROCESSED_INPUT.code |
- ENABLE_WINDOW_INPUT.code));
- }
- super.setEchoEnabled(enabled);
- }
-
- /**
- * Whether or not to allow the use of the JNI console interaction.
- */
- public void setDirectConsole(final boolean flag) {
- this.directConsole = flag;
- Log.debug("Direct console: ", flag);
- }
-
- /**
- * Whether or not to allow the use of the JNI console interaction.
- */
- public Boolean getDirectConsole() {
- return directConsole;
- }
-
-
- @Override
- public int readCharacter(final InputStream in) throws IOException {
- // if we can detect that we are directly wrapping the system
- // input, then bypass the input stream and read directly (which
- // allows us to access otherwise unreadable strokes, such as
- // the arrow keys)
-
- if (directConsole || isSystemIn(in)) {
- return readByte();
- }
- else {
- return super.readCharacter(in);
- }
- }
-
- private boolean isSystemIn(final InputStream in) throws IOException {
- assert in != null;
-
- if (in == System.in) {
- return true;
- }
- else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public int readVirtualKey(final InputStream in) throws IOException {
- int indicator = readCharacter(in);
-
- // in Windows terminals, arrow keys are represented by
- // a sequence of 2 characters. E.g., the up arrow
- // key yields 224, 72
- if (indicator == SPECIAL_KEY_INDICATOR.code || indicator == NUMPAD_KEY_INDICATOR.code) {
- int c = readCharacter(in);
- WindowsKey key = WindowsKey.valueOf(c);
- if (key == null)
- return 0;
-
- switch (key) {
- case UP_ARROW_KEY:
- return CTRL_P.code; // translate UP -> CTRL-P
-
- case LEFT_ARROW_KEY:
- return CTRL_B.code; // translate LEFT -> CTRL-B
-
- case RIGHT_ARROW_KEY:
- return CTRL_F.code; // translate RIGHT -> CTRL-F
-
- case DOWN_ARROW_KEY:
- return CTRL_N.code; // translate DOWN -> CTRL-N
-
- case DELETE_KEY:
- return CTRL_QM.code; // translate DELETE -> CTRL-?
-
- case HOME_KEY:
- return CTRL_A.code;
-
- case END_KEY:
- return CTRL_E.code;
-
- case PAGE_UP_KEY:
- return CTRL_K.code;
-
- case PAGE_DOWN_KEY:
- return CTRL_L.code;
-
- case ESCAPE_KEY:
- return CTRL_OB.code; // translate ESCAPE -> CTRL-[
-
- case INSERT_KEY:
- return CTRL_C.code;
-
- default:
- return 0;
- }
- }
- else if (indicator > 128) {
- // handle unicode characters longer than 2 bytes,
- // thanks to Marc.Herbert@continuent.com
- replayStream.setInput(indicator, in);
- // replayReader = new InputStreamReader(replayStream, encoding);
- indicator = replayReader.read();
-
- }
-
- return indicator;
- }
-
- @Override
- public InputStream getDefaultBindings() {
- return WindowsTerminal.class.getResourceAsStream(WINDOWSBINDINGS_PROPERTIES);
- }
-
- //
- // Native Bits
- //
- private int getConsoleMode() {
- return WindowsSupport.getConsoleMode();
- }
-
- private void setConsoleMode(int mode) {
- WindowsSupport.setConsoleMode(mode);
- }
-
- private int readByte() {
- return WindowsSupport.readByte();
- }
-
- private int getWindowsTerminalWidth() {
- return WindowsSupport.getWindowsTerminalWidth();
- }
-
- private int getWindowsTerminalHeight() {
- return WindowsSupport.getWindowsTerminalHeight();
- }
-
- /**
- * Console mode
- * <p/>
- * Constants copied <tt>wincon.h</tt>.
- */
- public static enum ConsoleMode
- {
- /**
- * The ReadFile or ReadConsole function returns only when a carriage return
- * character is read. If this mode is disable, the functions return when one
- * or more characters are available.
- */
- ENABLE_LINE_INPUT(2),
-
- /**
- * Characters read by the ReadFile or ReadConsole function are written to
- * the active screen buffer as they are read. This mode can be used only if
- * the ENABLE_LINE_INPUT mode is also enabled.
- */
- ENABLE_ECHO_INPUT(4),
-
- /**
- * CTRL+C is processed by the system and is not placed in the input buffer.
- * If the input buffer is being read by ReadFile or ReadConsole, other
- * control keys are processed by the system and are not returned in the
- * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
- * enabled, backspace, carriage return, and linefeed characters are handled
- * by the system.
- */
- ENABLE_PROCESSED_INPUT(1),
-
- /**
- * User interactions that change the size of the console screen buffer are
- * reported in the console's input buffee. Information about these events
- * can be read from the input buffer by applications using
- * theReadConsoleInput function, but not by those using ReadFile
- * orReadConsole.
- */
- ENABLE_WINDOW_INPUT(8),
-
- /**
- * If the mouse pointer is within the borders of the console window and the
- * window has the keyboard focus, mouse events generated by mouse movement
- * and button presses are placed in the input buffer. These events are
- * discarded by ReadFile or ReadConsole, even when this mode is enabled.
- */
- ENABLE_MOUSE_INPUT(16),
-
- /**
- * When enabled, text entered in a console window will be inserted at the
- * current cursor location and all text following that location will not be
- * overwritten. When disabled, all following text will be overwritten. An OR
- * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
- * flag to enable this functionality.
- */
- ENABLE_PROCESSED_OUTPUT(1),
-
- /**
- * This flag enables the user to use the mouse to select and edit text. To
- * enable this option, use the OR to combine this flag with
- * ENABLE_EXTENDED_FLAGS.
- */
- ENABLE_WRAP_AT_EOL_OUTPUT(2),;
-
- public final int code;
-
- ConsoleMode(final int code) {
- this.code = code;
- }
- }
-
- /**
- * Windows keys.
- * <p/>
- * Constants copied <tt>wincon.h</tt>.
- */
- public static enum WindowsKey
- {
- /**
- * On windows terminals, this character indicates that a 'special' key has
- * been pressed. This means that a key such as an arrow key, or delete, or
- * home, etc. will be indicated by the next character.
- */
- SPECIAL_KEY_INDICATOR(224),
-
- /**
- * On windows terminals, this character indicates that a special key on the
- * number pad has been pressed.
- */
- NUMPAD_KEY_INDICATOR(0),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
- * this character indicates an left arrow key press.
- */
- LEFT_ARROW_KEY(75),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an
- * right arrow key press.
- */
- RIGHT_ARROW_KEY(77),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an up
- * arrow key press.
- */
- UP_ARROW_KEY(72),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an
- * down arrow key press.
- */
- DOWN_ARROW_KEY(80),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the delete key was pressed.
- */
- DELETE_KEY(83),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the home key was pressed.
- */
- HOME_KEY(71),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the end key was pressed.
- */
- END_KEY(79),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the page up key was pressed.
- */
- PAGE_UP_KEY(73),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the page down key was pressed.
- */
- PAGE_DOWN_KEY(81),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the insert key was pressed.
- */
- INSERT_KEY(82),
-
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
- * this character indicates that the escape key was pressed.
- */
- ESCAPE_KEY(0),;
-
- public final int code;
-
- WindowsKey(final int code) {
- this.code = code;
- }
-
- private static final Map<Integer, WindowsKey> codes;
-
- static {
- Map<Integer, WindowsKey> map = new HashMap<Integer, WindowsKey>();
-
- for (WindowsKey key : WindowsKey.values()) {
- map.put(key.code, key);
- }
-
- codes = map;
- }
-
- public static WindowsKey valueOf(final int code) {
- return codes.get(code);
- }
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/ConsoleReader.java b/src/jline/src/main/java/scala/tools/jline/console/ConsoleReader.java
deleted file mode 100644
index a375b84a5c..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/ConsoleReader.java
+++ /dev/null
@@ -1,2185 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console;
-
-import scala.tools.jline.Terminal;
-import scala.tools.jline.TerminalFactory;
-import scala.tools.jline.console.completer.CandidateListCompletionHandler;
-import scala.tools.jline.console.completer.Completer;
-import scala.tools.jline.console.completer.CompletionHandler;
-import scala.tools.jline.console.history.History;
-import scala.tools.jline.console.history.MemoryHistory;
-import scala.tools.jline.internal.Configuration;
-import scala.tools.jline.internal.Log;
-import org.fusesource.jansi.AnsiOutputStream;
-
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
-import java.awt.event.ActionListener;
-import java.io.*;
-import java.util.*;
-
-/**
- * A reader for console applications. It supports custom tab-completion,
- * saveable command history, and command line editing. On some platforms,
- * platform-specific commands will need to be issued before the reader will
- * function properly. See {@link jline.Terminal#init} for convenience
- * methods for issuing platform-specific setup commands.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- */
-public class ConsoleReader
-{
- public static final String JLINE_NOBELL = "jline.nobell";
-
- public static final String JLINE_EXPANDEVENTS = "jline.expandevents";
-
- public static final char BACKSPACE = '\b';
-
- public static final char RESET_LINE = '\r';
-
- public static final char KEYBOARD_BELL = '\07';
-
- public static final char NULL_MASK = 0;
-
- public static final int TAB_WIDTH = 4;
-
- private static final ResourceBundle
- resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
-
- private final Terminal terminal;
-
- private InputStream in;
-
- private final Writer out;
-
- private final CursorBuffer buf = new CursorBuffer();
-
- private String prompt;
-
- private boolean bellEnabled = true;
-
- private boolean expandEvents = false;
-
- private Character mask;
-
- private Character echoCharacter;
-
- private StringBuffer searchTerm = null;
-
- private String previousSearchTerm = "";
-
- private int searchIndex = -1;
-
- public ConsoleReader(final InputStream in, final OutputStream out, final InputStream bindings, final Terminal term) throws
- IOException
- {
- this.in = in;
- this.terminal = term != null ? term : TerminalFactory.get();
- this.out = new PrintWriter(getTerminal().wrapOutIfNeeded(out));
- this.keyBindings = loadKeyBindings(bindings);
-
- setBellEnabled(!Configuration.getBoolean(JLINE_NOBELL, false));
- setExpandEvents(Configuration.getBoolean(JLINE_EXPANDEVENTS, false));
- }
-
- /**
- * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
- * to let the terminal wrap the output stream if needed.
- */
- public ConsoleReader(final InputStream in, final Writer out, final InputStream bindings, final Terminal term) throws
- IOException
- {
- this.in = in;
- this.out = out;
- this.terminal = term != null ? term : TerminalFactory.get();
- this.keyBindings = loadKeyBindings(bindings);
-
- setBellEnabled(!Configuration.getBoolean(JLINE_NOBELL, false));
- }
-
- /**
- * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
- * to let the terminal wrap the output stream if needed.
- */
- public ConsoleReader(final InputStream in, final Writer out, final Terminal term) throws IOException {
- this(in, out, null, term);
- }
-
- /**
- * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
- * to let the terminal wrap the output stream if needed.
- */
- public ConsoleReader(final InputStream in, final Writer out) throws IOException
- {
- this(in, out, null, null);
- }
-
- /**
- * Create a new reader using {@link FileDescriptor#in} for input and
- * {@link System#out} for output.
- * <p/>
- * {@link FileDescriptor#in} is used because it has a better chance of not being buffered.
- */
- public ConsoleReader() throws IOException {
- this(new FileInputStream(FileDescriptor.in), System.out, null, null );
- }
-
- // FIXME: Only used for tests
-
- void setInput(final InputStream in) {
- this.in = in;
- }
-
- public InputStream getInput() {
- return in;
- }
-
- public Writer getOutput() {
- return out;
- }
-
- public Terminal getTerminal() {
- return terminal;
- }
-
- public CursorBuffer getCursorBuffer() {
- return buf;
- }
-
- public void setBellEnabled(final boolean enabled) {
- this.bellEnabled = enabled;
- }
-
- public boolean isBellEnabled() {
- return bellEnabled;
- }
-
- public void setExpandEvents(final boolean expand) {
- this.expandEvents = expand;
- }
-
- public boolean getExpandEvents() {
- return expandEvents;
- }
-
- public void setPrompt(final String prompt) {
- this.prompt = prompt;
- }
-
- public String getPrompt() {
- return prompt;
- }
-
- /**
- * Set the echo character. For example, to have "*" entered when a password is typed:
- * <p/>
- * <pre>
- * myConsoleReader.setEchoCharacter(new Character('*'));
- * </pre>
- * <p/>
- * Setting the character to
- * <p/>
- * <pre>
- * null
- * </pre>
- * <p/>
- * will restore normal character echoing. Setting the character to
- * <p/>
- * <pre>
- * new Character(0)
- * </pre>
- * <p/>
- * will cause nothing to be echoed.
- *
- * @param c the character to echo to the console in place of the typed character.
- */
- public void setEchoCharacter(final Character c) {
- this.echoCharacter = c;
- }
-
- /**
- * Returns the echo character.
- */
- public Character getEchoCharacter() {
- return echoCharacter;
- }
-
- /**
- * Erase the current line.
- *
- * @return false if we failed (e.g., the buffer was empty)
- */
- protected final boolean resetLine() throws IOException {
- if (buf.cursor == 0) {
- return false;
- }
-
- backspaceAll();
-
- return true;
- }
-
- int getCursorPosition() {
- // FIXME: does not handle anything but a line with a prompt absolute position
- String prompt = getPrompt();
- return ((prompt == null) ? 0 : stripAnsi(lastLine(prompt)).length()) + buf.cursor;
- }
-
- /**
- * Returns the text after the last '\n'.
- * prompt is returned if no '\n' characters are present.
- * null is returned if prompt is null.
- */
- private String lastLine(String str) {
- if (str == null) return "";
- int last = str.lastIndexOf("\n");
-
- if (last >= 0) {
- return str.substring(last + 1, str.length());
- }
-
- return str;
- }
-
- private String stripAnsi(String str) {
- if (str == null) return "";
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- AnsiOutputStream aos = new AnsiOutputStream(baos);
- aos.write(str.getBytes());
- aos.flush();
- return baos.toString();
- } catch (IOException e) {
- return str;
- }
- }
-
- /**
- * Move the cursor position to the specified absolute index.
- */
- public final boolean setCursorPosition(final int position) throws IOException {
- return moveCursor(position - buf.cursor) != 0;
- }
-
- /**
- * Set the current buffer's content to the specified {@link String}. The
- * visual console will be modified to show the current buffer.
- *
- * @param buffer the new contents of the buffer.
- */
- private void setBuffer(final String buffer) throws IOException {
- // don't bother modifying it if it is unchanged
- if (buffer.equals(buf.buffer.toString())) {
- return;
- }
-
- // obtain the difference between the current buffer and the new one
- int sameIndex = 0;
-
- for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
- && (i < l2); i++) {
- if (buffer.charAt(i) == buf.buffer.charAt(i)) {
- sameIndex++;
- }
- else {
- break;
- }
- }
-
- int diff = buf.cursor - sameIndex;
- if (diff < 0) { // we can't backspace here so try from the end of the buffer
- moveToEnd();
- diff = buf.buffer.length() - sameIndex;
- }
-
- backspace(diff); // go back for the differences
- killLine(); // clear to the end of the line
- buf.buffer.setLength(sameIndex); // the new length
- putString(buffer.substring(sameIndex)); // append the differences
- }
-
- private void setBuffer(final CharSequence buffer) throws IOException {
- setBuffer(String.valueOf(buffer));
- }
-
- /**
- * Output put the prompt + the current buffer
- */
- public final void drawLine() throws IOException {
- String prompt = getPrompt();
- if (prompt != null) {
- print(prompt);
- }
-
- print(buf.buffer.toString());
-
- if (buf.length() != buf.cursor) { // not at end of line
- back(buf.length() - buf.cursor - 1);
- }
- // force drawBuffer to check for weird wrap (after clear screen)
- drawBuffer();
- }
-
- /**
- * Clear the line and redraw it.
- */
- public final void redrawLine() throws IOException {
- print(RESET_LINE);
-// flush();
- drawLine();
- }
-
- /**
- * Clear the buffer and add its contents to the history.
- *
- * @return the former contents of the buffer.
- */
- final String finishBuffer() throws IOException { // FIXME: Package protected because used by tests
- String str = buf.buffer.toString();
-
- if (expandEvents) {
- str = expandEvents(str);
- }
-
- // we only add it to the history if the buffer is not empty
- // and if mask is null, since having a mask typically means
- // the string was a password. We clear the mask after this call
- if (str.length() > 0) {
- if (mask == null && isHistoryEnabled()) {
- history.add(str);
- }
- else {
- mask = null;
- }
- }
-
- history.moveToEnd();
-
- buf.buffer.setLength(0);
- buf.cursor = 0;
-
- return str;
- }
-
- /**
- * Expand event designator such as !!, !#, !3, etc...
- * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
- *
- * @param str
- * @return
- */
- protected String expandEvents(String str) throws IOException {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < str.length(); i++) {
- char c = str.charAt(i);
- switch (c) {
- case '!':
- if (i + 1 < str.length()) {
- c = str.charAt(++i);
- boolean neg = false;
- String rep = null;
- int i1, idx;
- switch (c) {
- case '!':
- if (history.size() == 0) {
- throw new IllegalArgumentException("!!: event not found");
- }
- rep = history.get(history.index() - 1).toString();
- break;
- case '#':
- sb.append(sb.toString());
- break;
- case '?':
- i1 = str.indexOf('?', i + 1);
- if (i1 < 0) {
- i1 = str.length();
- }
- String sc = str.substring(i + 1, i1);
- i = i1;
- idx = searchBackwards(sc);
- if (idx < 0) {
- throw new IllegalArgumentException("!?" + sc + ": event not found");
- } else {
- rep = history.get(idx).toString();
- }
- break;
- case ' ':
- case '\t':
- sb.append('!');
- sb.append(c);
- break;
- case '-':
- neg = true;
- i++;
- // fall through
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- i1 = i;
- for (; i < str.length(); i++) {
- c = str.charAt(i);
- if (c < '0' || c > '9') {
- break;
- }
- }
- idx = 0;
- try {
- idx = Integer.parseInt(str.substring(i1, i));
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
- }
- if (neg) {
- if (idx < history.size()) {
- rep = (history.get(history.index() - idx)).toString();
- } else {
- throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
- }
- } else {
- if (idx >= history.index() - history.size() && idx < history.index()) {
- rep = (history.get(idx)).toString();
- } else {
- throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
- }
- }
- break;
- default:
- String ss = str.substring(i);
- i = str.length();
- idx = searchBackwards(ss, history.index(), true);
- if (idx < 0) {
- throw new IllegalArgumentException("!" + ss + ": event not found");
- } else {
- rep = history.get(idx).toString();
- }
- break;
- }
- if (rep != null) {
- sb.append(rep);
- }
- } else {
- sb.append(c);
- }
- break;
- case '^':
- if (i == 0) {
- int i1 = str.indexOf('^', i + 1);
- int i2 = str.indexOf('^', i1 + 1);
- if (i2 < 0) {
- i2 = str.length();
- }
- if (i1 > 0 && i2 > 0) {
- String s1 = str.substring(i + 1, i1);
- String s2 = str.substring(i1 + 1, i2);
- String s = history.get(history.index() - 1).toString().replace(s1, s2);
- sb.append(s);
- i = i2 + 1;
- break;
- }
- }
- sb.append(c);
- break;
- default:
- sb.append(c);
- break;
- }
- }
- String result = sb.toString();
- if (!str.equals(result)) {
- print(result);
- println();
- flush();
- }
- return result;
-
- }
-
- /**
- * Write out the specified string to the buffer and the output stream.
- */
- public final void putString(final CharSequence str) throws IOException {
- buf.write(str);
- print(str);
- drawBuffer();
- }
-
- /**
- * Output the specified character, both to the buffer and the output stream.
- */
- private void putChar(final int c, final boolean print) throws IOException {
- buf.write((char) c);
-
- if (print) {
- if (mask == null) {
- // no masking
- print(c);
- }
- else if (mask == NULL_MASK) {
- // Don't print anything
- }
- else {
- print(mask);
- }
-
- drawBuffer();
- }
- }
-
- /**
- * Redraw the rest of the buffer from the cursor onwards. This is necessary
- * for inserting text into the buffer.
- *
- * @param clear the number of characters to clear after the end of the buffer
- */
- private void drawBuffer(final int clear) throws IOException {
- // debug ("drawBuffer: " + clear);
- if (buf.cursor == buf.length() && clear == 0) {
- } else {
- char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
- if (mask != null) {
- Arrays.fill(chars, mask);
- }
- if (getTerminal().hasWeirdWrap()) {
- // need to determine if wrapping will occur:
- int width = getTerminal().getWidth();
- int pos = getCursorPosition();
- for (int i = 0; i < chars.length; i++) {
- print(chars[i]);
- if ((pos + i + 1) % width == 0) {
- print(32); // move cursor to next line by printing dummy space
- print(13); // CR / not newline.
- }
- }
- } else {
- print(chars);
- }
- clearAhead(clear, chars.length);
- if (getTerminal().isAnsiSupported()) {
- if (chars.length > 0) {
- back(chars.length);
- }
- } else {
- back(chars.length);
- }
- }
- if (getTerminal().hasWeirdWrap()) {
- int width = getTerminal().getWidth();
- // best guess on whether the cursor is in that weird location...
- // Need to do this without calling ansi cursor location methods
- // otherwise it breaks paste of wrapped lines in xterm.
- if (getCursorPosition() > 0 && (getCursorPosition() % width == 0)
- && buf.cursor == buf.length() && clear == 0) {
- // the following workaround is reverse-engineered from looking
- // at what bash sent to the terminal in the same situation
- print(32); // move cursor to next line by printing dummy space
- print(13); // CR / not newline.
- }
- }
- }
-
- /**
- * Redraw the rest of the buffer from the cursor onwards. This is necessary
- * for inserting text into the buffer.
- */
- private void drawBuffer() throws IOException {
- drawBuffer(0);
- }
-
- /**
- * Clear ahead the specified number of characters without moving the cursor.
- *
- * @param num the number of characters to clear
- * @param delta the difference between the internal cursor and the screen
- * cursor - if > 0, assume some stuff was printed and weird wrap has to be
- * checked
- */
- private void clearAhead(final int num, int delta) throws IOException {
- if (num == 0) {
- return;
- }
-
- if (getTerminal().isAnsiSupported()) {
- int width = getTerminal().getWidth();
- int screenCursorCol = getCursorPosition() + delta;
- // clear current line
- printAnsiSequence("K");
- // if cursor+num wraps, then we need to clear the line(s) below too
- int curCol = screenCursorCol % width;
- int endCol = (screenCursorCol + num - 1) % width;
- int lines = num / width;
- if (endCol < curCol) lines++;
- for (int i = 0; i < lines; i++) {
- printAnsiSequence("B");
- printAnsiSequence("2K");
- }
- for (int i = 0; i < lines; i++) {
- printAnsiSequence("A");
- }
- return;
- }
-
- // print blank extra characters
- print(' ', num);
-
- // we need to flush here so a "clever" console doesn't just ignore the redundancy
- // of a space followed by a backspace.
-// flush();
-
- // reset the visual cursor
- back(num);
-
-// flush();
- }
-
- /**
- * Move the visual cursor backwards without modifying the buffer cursor.
- */
- protected void back(final int num) throws IOException {
- if (num == 0) return;
- if (getTerminal().isAnsiSupported()) {
- int width = getTerminal().getWidth();
- int cursor = getCursorPosition();
- int realCursor = cursor + num;
- int realCol = realCursor % width;
- int newCol = cursor % width;
- int moveup = num / width;
- int delta = realCol - newCol;
- if (delta < 0) moveup++;
- if (moveup > 0) {
- printAnsiSequence(moveup + "A");
- }
- printAnsiSequence((1 + newCol) + "G");
- return;
- }
- print(BACKSPACE, num);
-// flush();
- }
-
- /**
- * Flush the console output stream. This is important for printout out single characters (like a backspace or
- * keyboard) that we want the console to handle immediately.
- */
- public void flush() throws IOException {
- out.flush();
- }
-
- private int backspaceAll() throws IOException {
- return backspace(Integer.MAX_VALUE);
- }
-
- /**
- * Issue <em>num</em> backspaces.
- *
- * @return the number of characters backed up
- */
- private int backspace(final int num) throws IOException {
- if (buf.cursor == 0) {
- return 0;
- }
-
- int count = 0;
-
- int termwidth = getTerminal().getWidth();
- int lines = getCursorPosition() / termwidth;
- count = moveCursor(-1 * num) * -1;
- buf.buffer.delete(buf.cursor, buf.cursor + count);
- if (getCursorPosition() / termwidth != lines) {
- if (getTerminal().isAnsiSupported()) {
- // debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
- printAnsiSequence("K");
- // if cursor+num wraps, then we need to clear the line(s) below too
- // last char printed is one pos less than cursor so we subtract
- // one
-/*
- // TODO: fixme (does not work - test with reverse search with wrapping line and CTRL-E)
- int endCol = (getCursorPosition() + num - 1) % termwidth;
- int curCol = getCursorPosition() % termwidth;
- if (endCol < curCol) lines++;
- for (int i = 1; i < lines; i++) {
- printAnsiSequence("B");
- printAnsiSequence("2K");
- }
- for (int i = 1; i < lines; i++) {
- printAnsiSequence("A");
- }
- return count;
-*/
- }
- }
- drawBuffer(count);
-
- return count;
- }
-
- /**
- * Issue a backspace.
- *
- * @return true if successful
- */
- public boolean backspace() throws IOException {
- return backspace(1) == 1;
- }
-
- protected boolean moveToEnd() throws IOException {
- return moveCursor(buf.length() - buf.cursor) > 0;
- }
-
- /**
- * Delete the character at the current position and redraw the remainder of the buffer.
- */
- private boolean deleteCurrentCharacter() throws IOException {
- if (buf.length() == 0 || buf.cursor == buf.length()) {
- return false;
- }
-
- buf.buffer.deleteCharAt(buf.cursor);
- drawBuffer(1);
- return true;
- }
-
- private boolean previousWord() throws IOException {
- while (isDelimiter(buf.charLeftOfCursor()) && (moveCursor(-1) != 0)) {
- // nothing
- }
-
- while (!isDelimiter(buf.charLeftOfCursor()) && (moveCursor(-1) != 0)) {
- // nothing
- }
-
- return true;
- }
-
- private boolean nextWord() throws IOException {
- while (isDelimiter(buf.charAtCursor()) && (moveCursor(1) != 0)) {
- // nothing
- }
-
- while (!isDelimiter(buf.charAtCursor()) && (moveCursor(1) != 0)) {
- // nothing
- }
-
- return true;
- }
-
- private boolean deletePreviousWord() throws IOException {
- while (isDelimiter(buf.charLeftOfCursor()) && backspace()) {
- // nothing
- }
-
- while (!isDelimiter(buf.charLeftOfCursor()) && backspace()) {
- // nothing
- }
-
- return true;
- }
-
- private boolean deleteNextWord() throws IOException {
- while (isDelimiter(buf.charAtCursor()) && deleteCurrentCharacter()) {
- // nothing
- }
-
- while (!isDelimiter(buf.charAtCursor()) && deleteCurrentCharacter()) {
- // nothing
- }
-
- return true;
- }
-
- /**
- * Move the cursor <i>where</i> characters.
- *
- * @param num If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
- * @return The number of spaces we moved
- */
- public int moveCursor(final int num) throws IOException {
- int where = num;
-
- if ((buf.cursor == 0) && (where <= 0)) {
- return 0;
- }
-
- if ((buf.cursor == buf.buffer.length()) && (where >= 0)) {
- return 0;
- }
-
- if ((buf.cursor + where) < 0) {
- where = -buf.cursor;
- }
- else if ((buf.cursor + where) > buf.buffer.length()) {
- where = buf.buffer.length() - buf.cursor;
- }
-
- moveInternal(where);
-
- return where;
- }
-
- /**
- * Move the cursor <i>where</i> characters, without checking the current buffer.
- *
- * @param where the number of characters to move to the right or left.
- */
- private void moveInternal(final int where) throws IOException {
- // debug ("move cursor " + where + " ("
- // + buf.cursor + " => " + (buf.cursor + where) + ")");
- buf.cursor += where;
-
- if (getTerminal().isAnsiSupported()) {
- if (where < 0) {
- back(Math.abs(where));
- } else {
- int width = getTerminal().getWidth();
- int cursor = getCursorPosition();
- int oldLine = (cursor - where) / width;
- int newLine = cursor / width;
- if (newLine > oldLine) {
- if (getTerminal().hasWeirdWrap()) {
- // scroll up if at bottom
- // note:
- // on rxvt cywgin getTerminal().getHeight() is incorrect
- // MacOs xterm does not seem to support scrolling
- if (getCurrentAnsiRow() == getTerminal().getHeight()) {
- printAnsiSequence((newLine - oldLine) + "S");
- }
- }
- printAnsiSequence((newLine - oldLine) + "B");
- }
- printAnsiSequence(1 +(cursor % width) + "G");
- }
-// flush();
- return;
- }
-
- char c;
-
- if (where < 0) {
- int len = 0;
- for (int i = buf.cursor; i < buf.cursor - where; i++) {
- if (buf.buffer.charAt(i) == '\t') {
- len += TAB_WIDTH;
- }
- else {
- len++;
- }
- }
-
- char chars[] = new char[len];
- Arrays.fill(chars, BACKSPACE);
- out.write(chars);
-
- return;
- }
- else if (buf.cursor == 0) {
- return;
- }
- else if (mask != null) {
- c = mask;
- }
- else {
- print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
- return;
- }
-
- // null character mask: don't output anything
- if (mask == NULL_MASK) {
- return;
- }
-
- print(c, Math.abs(where));
- }
-
- // FIXME: replace() is not used
-
- public final boolean replace(final int num, final String replacement) {
- buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
- try {
- moveCursor(-num);
- drawBuffer(Math.max(0, num - replacement.length()));
- moveCursor(replacement.length());
- }
- catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- //
- // Key reading
- //
-
- /**
- * Read a character from the console.
- *
- * @return the character, or -1 if an EOF is received.
- */
- public final int readVirtualKey() throws IOException {
- int c = getTerminal().readVirtualKey(in);
-
- Log.trace("Keystroke: ", c);
-
- // clear any echo characters
- clearEcho(c);
-
- return c;
- }
-
- /**
- * Clear the echoed characters for the specified character code.
- */
- private int clearEcho(final int c) throws IOException {
- // if the terminal is not echoing, then ignore
- if (!getTerminal().isEchoEnabled()) {
- return 0;
- }
-
- // otherwise, clear
- int num = countEchoCharacters((char) c);
- back(num);
- drawBuffer(num);
-
- return num;
- }
-
- private int countEchoCharacters(final char c) {
- // tabs as special: we need to determine the number of spaces
- // to cancel based on what out current cursor position is
- if (c == 9) {
- int tabStop = 8; // will this ever be different?
- int position = getCursorPosition();
-
- return tabStop - (position % tabStop);
- }
-
- return getPrintableCharacters(c).length();
- }
-
- /**
- * Return the number of characters that will be printed when the specified
- * character is echoed to the screen
- *
- * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
- */
- private StringBuilder getPrintableCharacters(final char ch) {
- StringBuilder sbuff = new StringBuilder();
-
- if (ch >= 32) {
- if (ch < 127) {
- sbuff.append(ch);
- }
- else if (ch == 127) {
- sbuff.append('^');
- sbuff.append('?');
- }
- else {
- sbuff.append('M');
- sbuff.append('-');
-
- if (ch >= (128 + 32)) {
- if (ch < (128 + 127)) {
- sbuff.append((char) (ch - 128));
- }
- else {
- sbuff.append('^');
- sbuff.append('?');
- }
- }
- else {
- sbuff.append('^');
- sbuff.append((char) (ch - 128 + 64));
- }
- }
- }
- else {
- sbuff.append('^');
- sbuff.append((char) (ch + 64));
- }
-
- return sbuff;
- }
-
- public final int readCharacter(final char... allowed) throws IOException {
- // if we restrict to a limited set and the current character is not in the set, then try again.
- char c;
-
- Arrays.sort(allowed); // always need to sort before binarySearch
-
- while (Arrays.binarySearch(allowed, c = (char) readVirtualKey()) < 0) {
- // nothing
- }
-
- return c;
- }
-
- //
- // Key Bindings
- //
-
- public static final String JLINE_COMPLETION_THRESHOLD = "jline.completion.threshold";
-
- public static final String JLINE_KEYBINDINGS = "jline.keybindings";
-
- public static final String JLINEBINDINGS_PROPERTIES = ".jlinebindings.properties";
-
- /**
- * The map for logical operations.
- */
- private final short[] keyBindings;
-
- private short[] loadKeyBindings(InputStream input) throws IOException {
- if (input == null) {
- try {
- File file = new File(Configuration.getUserHome(), JLINEBINDINGS_PROPERTIES);
-
- String path = Configuration.getString(JLINE_KEYBINDINGS);
- if (path != null) {
- file = new File(path);
- }
-
- if (file.isFile()) {
- Log.debug("Loading user bindings from: ", file);
- input = new FileInputStream(file);
- }
- }
- catch (Exception e) {
- Log.error("Failed to load user bindings", e);
- }
- }
-
- if (input == null) {
- Log.debug("Using default bindings");
- input = getTerminal().getDefaultBindings();
- }
-
- short[] keyBindings = new short[Character.MAX_VALUE * 2];
-
- Arrays.fill(keyBindings, Operation.UNKNOWN.code);
-
- // Loads the key bindings. Bindings file is in the format:
- //
- // keycode: operation name
-
- if (input != null) {
- input = new BufferedInputStream(input);
- Properties p = new Properties();
- p.load(input);
- input.close();
-
- for (Object key : p.keySet()) {
- String val = (String) key;
-
- try {
- short code = Short.parseShort(val);
- String name = p.getProperty(val);
- Operation op = Operation.valueOf(name);
- keyBindings[code] = op.code;
- }
- catch (NumberFormatException e) {
- Log.error("Failed to convert binding code: ", val, e);
- }
- }
-
- // hardwired arrow key bindings
- // keybindings[VK_UP] = PREV_HISTORY;
- // keybindings[VK_DOWN] = NEXT_HISTORY;
- // keybindings[VK_LEFT] = PREV_CHAR;
- // keybindings[VK_RIGHT] = NEXT_CHAR;
- }
-
- return keyBindings;
- }
-
- int getKeyForAction(final short logicalAction) {
- for (int i = 0; i < keyBindings.length; i++) {
- if (keyBindings[i] == logicalAction) {
- return i;
- }
- }
-
- return -1;
- }
-
- int getKeyForAction(final Operation op) {
- assert op != null;
- return getKeyForAction(op.code);
- }
-
- public void printBindings() {
- System.out.println("printBindings(): keyBindings.length = " + keyBindings.length);
- for (int i = 0; i < keyBindings.length; i++) {
- if (keyBindings[i] != Operation.UNKNOWN.code) {
- System.out.println("keyBindings[" + i + "] = " + keyBindings[i]);
- }
- }
- }
-
- /**
- * Reads the console input and returns an array of the form [raw, key binding].
- */
- private int[] readBinding() throws IOException {
- int c = readVirtualKey();
-
- if (c == -1) {
- return null;
- }
-
- // extract the appropriate key binding
- short code = keyBindings[c];
-
- Log.trace("Translated: ", c, " -> ", code);
-
- return new int[]{c, code};
- }
-
- //
- // Line Reading
- //
-
- /**
- * Read the next line and return the contents of the buffer.
- */
- public String readLine() throws IOException {
- return readLine((String) null);
- }
-
- /**
- * Read the next line with the specified character mask. If null, then
- * characters will be echoed. If 0, then no characters will be echoed.
- */
- public String readLine(final Character mask) throws IOException {
- return readLine(null, mask);
- }
-
- public String readLine(final String prompt) throws IOException {
- return readLine(prompt, null);
- }
-
- /**
- * Read a line from the <i>in</i> {@link InputStream}, and return the line
- * (without any trailing newlines).
- *
- * @param prompt The prompt to issue to the console, may be null.
- * @return A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
- * was pressed).
- */
- public String readLine(String prompt, final Character mask) throws IOException {
- // prompt may be null
- // mask may be null
-
- // FIXME: This blows, each call to readLine will reset the console's state which doesn't seem very nice.
- this.mask = mask;
- if (prompt != null) {
- setPrompt(prompt);
- }
- else {
- prompt = getPrompt();
- }
-
- try {
- if (!getTerminal().isSupported()) {
- beforeReadLine(prompt, mask);
- }
-
- if (prompt != null && prompt.length() > 0) {
- out.write(prompt);
- out.flush();
- }
-
- // if the terminal is unsupported, just use plain-java reading
- if (!getTerminal().isSupported()) {
- return readLine(in);
- }
-
- String originalPrompt = this.prompt;
-
- final int NORMAL = 1;
- final int SEARCH = 2;
- int state = NORMAL;
-
- boolean success = true;
-
- while (true) {
- int[] next = readBinding();
-
- if (next == null) {
- return null;
- }
-
- int c = next[0];
- // int code = next[1];
- Operation code = Operation.valueOf(next[1]);
-
- if (c == -1) {
- return null;
- }
-
- // Search mode.
- //
- // Note that we have to do this first, because if there is a command
- // not linked to a search command, we leave the search mode and fall
- // through to the normal state.
- if (state == SEARCH) {
- int cursorDest = -1;
-
- switch (code) {
- // This doesn't work right now, it seems CTRL-G is not passed
- // down correctly. :(
- case ABORT:
- state = NORMAL;
- break;
-
- case SEARCH_PREV:
- if (searchTerm.length() == 0) {
- searchTerm.append(previousSearchTerm);
- }
-
- if (searchIndex == -1) {
- searchIndex = searchBackwards(searchTerm.toString());
- } else {
- searchIndex = searchBackwards(searchTerm.toString(), searchIndex);
- }
- break;
-
- case DELETE_PREV_CHAR:
- if (searchTerm.length() > 0) {
- searchTerm.deleteCharAt(searchTerm.length() - 1);
- searchIndex = searchBackwards(searchTerm.toString());
- }
- break;
-
- case UNKNOWN:
- searchTerm.appendCodePoint(c);
- searchIndex = searchBackwards(searchTerm.toString());
- break;
-
- default:
- // Set buffer and cursor position to the found string.
- if (searchIndex != -1) {
- history.moveTo(searchIndex);
- // set cursor position to the found string
- cursorDest = history.current().toString().indexOf(searchTerm.toString());
- }
- state = NORMAL;
- break;
- }
-
- // if we're still in search mode, print the search status
- if (state == SEARCH) {
- if (searchTerm.length() == 0) {
- printSearchStatus("", "");
- searchIndex = -1;
- } else {
- if (searchIndex == -1) {
- beep();
- } else {
- printSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
- }
- }
- }
- // otherwise, restore the line
- else {
- restoreLine(originalPrompt, cursorDest);
- }
- }
-
- if (state == NORMAL) {
- switch (code) {
- case EXIT: // ctrl-d
- if (buf.buffer.length() == 0) {
- return null;
- } else {
- success = deleteCurrentCharacter();
- }
- break;
-
- case COMPLETE: // tab
- success = complete();
- break;
-
- case MOVE_TO_BEG:
- success = setCursorPosition(0);
- break;
-
- case KILL_LINE: // CTRL-K
- success = killLine();
- break;
-
- case CLEAR_SCREEN: // CTRL-L
- success = clearScreen();
- break;
-
- case KILL_LINE_PREV: // CTRL-U
- success = resetLine();
- break;
-
- case NEWLINE: // enter
- moveToEnd();
- println(); // output newline
- flush();
- return finishBuffer();
-
- case DELETE_PREV_CHAR: // backspace
- success = backspace();
- break;
-
- case DELETE_NEXT_CHAR: // delete
- success = deleteCurrentCharacter();
- break;
-
- case MOVE_TO_END:
- success = moveToEnd();
- break;
-
- case PREV_CHAR:
- success = moveCursor(-1) != 0;
- break;
-
- case NEXT_CHAR:
- success = moveCursor(1) != 0;
- break;
-
- case NEXT_HISTORY:
- success = moveHistory(true);
- break;
-
- case PREV_HISTORY:
- success = moveHistory(false);
- break;
-
- case ABORT:
- case REDISPLAY:
- break;
-
- case PASTE:
- success = paste();
- break;
-
- case DELETE_PREV_WORD:
- success = deletePreviousWord();
- break;
-
- case DELETE_NEXT_WORD:
- success = deleteNextWord();
- break;
-
- case PREV_WORD:
- success = previousWord();
- break;
-
- case NEXT_WORD:
- success = nextWord();
- break;
-
- case START_OF_HISTORY:
- success = history.moveToFirst();
- if (success) {
- setBuffer(history.current());
- }
- break;
-
- case END_OF_HISTORY:
- success = history.moveToLast();
- if (success) {
- setBuffer(history.current());
- }
- break;
-
- case CLEAR_LINE:
- moveInternal(-(buf.cursor));
- killLine();
- break;
-
- case INSERT:
- buf.setOverTyping(!buf.isOverTyping());
- break;
-
- case SEARCH_PREV: // CTRL-R
- if (searchTerm != null) {
- previousSearchTerm = searchTerm.toString();
- }
- searchTerm = new StringBuffer(buf.buffer);
- state = SEARCH;
- if (searchTerm.length() > 0) {
- searchIndex = searchBackwards(searchTerm.toString());
- if (searchIndex == -1) {
- beep();
- }
- printSearchStatus(searchTerm.toString(),
- searchIndex > -1 ? history.get(searchIndex).toString() : "");
- } else {
- searchIndex = -1;
- printSearchStatus("", "");
- }
- break;
-
- case UNKNOWN:
- default:
- if (c != 0) { // ignore null chars
- ActionListener action = triggeredActions.get((char) c);
- if (action != null) {
- action.actionPerformed(null);
- }
- else {
- putChar(c, true);
- }
- }
- else {
- success = false;
- }
- }
-
- if (!success) {
- beep();
- }
-
- flush();
- }
- }
- }
- finally {
- if (!getTerminal().isSupported()) {
- afterReadLine();
- }
- }
- }
-
- /**
- * Read a line for unsupported terminals.
- */
- private String readLine(final InputStream in) throws IOException {
- StringBuilder buff = new StringBuilder();
-
- while (true) {
- int i = in.read();
-
- if (i == -1 || i == '\n' || i == '\r') {
- return buff.toString();
- }
-
- buff.append((char) i);
- }
-
- // return new BufferedReader (new InputStreamReader (in)).readLine ();
- }
-
- //
- // Completion
- //
-
- private final List<Completer> completers = new LinkedList<Completer>();
-
- private CompletionHandler completionHandler = new CandidateListCompletionHandler();
-
- /**
- * Add the specified {@link jline.console.completer.Completer} to the list of handlers for tab-completion.
- *
- * @param completer the {@link jline.console.completer.Completer} to add
- * @return true if it was successfully added
- */
- public boolean addCompleter(final Completer completer) {
- return completers.add(completer);
- }
-
- /**
- * Remove the specified {@link jline.console.completer.Completer} from the list of handlers for tab-completion.
- *
- * @param completer The {@link Completer} to remove
- * @return True if it was successfully removed
- */
- public boolean removeCompleter(final Completer completer) {
- return completers.remove(completer);
- }
-
- /**
- * Returns an unmodifiable list of all the completers.
- */
- public Collection<Completer> getCompleters() {
- return Collections.unmodifiableList(completers);
- }
-
- public void setCompletionHandler(final CompletionHandler handler) {
- assert handler != null;
- this.completionHandler = handler;
- }
-
- public CompletionHandler getCompletionHandler() {
- return this.completionHandler;
- }
-
- /**
- * Use the completers to modify the buffer with the appropriate completions.
- *
- * @return true if successful
- */
- protected boolean complete() throws IOException {
- // debug ("tab for (" + buf + ")");
- if (completers.size() == 0) {
- return false;
- }
-
- List<CharSequence> candidates = new LinkedList<CharSequence>();
- String bufstr = buf.buffer.toString();
- int cursor = buf.cursor;
-
- int position = -1;
-
- for (Completer comp : completers) {
- if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
- break;
- }
- }
-
- return candidates.size() != 0 && getCompletionHandler().complete(this, candidates, position);
- }
-
- /**
- * The number of tab-completion candidates above which a warning will be
- * prompted before showing all the candidates.
- */
- private int autoprintThreshold = Integer.getInteger(JLINE_COMPLETION_THRESHOLD, 100); // same default as bash
-
- /**
- * @param threshold the number of candidates to print without issuing a warning.
- */
- public void setAutoprintThreshold(final int threshold) {
- this.autoprintThreshold = threshold;
- }
-
- /**
- * @return the number of candidates to print without issuing a warning.
- */
- public int getAutoprintThreshold() {
- return autoprintThreshold;
- }
-
- private boolean paginationEnabled;
-
- /**
- * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
- */
- public void setPaginationEnabled(final boolean enabled) {
- this.paginationEnabled = enabled;
- }
-
- /**
- * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
- */
- public boolean isPaginationEnabled() {
- return paginationEnabled;
- }
-
- //
- // History
- //
-
- private History history = new MemoryHistory();
-
- public void setHistory(final History history) {
- this.history = history;
- }
-
- public History getHistory() {
- return history;
- }
-
- private boolean historyEnabled = true;
-
- /**
- * Whether or not to add new commands to the history buffer.
- */
- public void setHistoryEnabled(final boolean enabled) {
- this.historyEnabled = enabled;
- }
-
- /**
- * Whether or not to add new commands to the history buffer.
- */
- public boolean isHistoryEnabled() {
- return historyEnabled;
- }
-
- /**
- * Move up or down the history tree.
- */
- private boolean moveHistory(final boolean next) throws IOException {
- if (next && !history.next()) {
- return false;
- }
- else if (!next && !history.previous()) {
- return false;
- }
-
- setBuffer(history.current());
-
- return true;
- }
-
- //
- // Printing
- //
-
- public static final String CR = System.getProperty("line.separator");
-
- /**
- * Output the specified character to the output stream without manipulating the current buffer.
- */
- private void print(final int c) throws IOException {
- if (c == '\t') {
- char chars[] = new char[TAB_WIDTH];
- Arrays.fill(chars, ' ');
- out.write(chars);
- return;
- }
-
- out.write(c);
- }
-
- /**
- * Output the specified characters to the output stream without manipulating the current buffer.
- */
- private void print(final char... buff) throws IOException {
- int len = 0;
- for (char c : buff) {
- if (c == '\t') {
- len += TAB_WIDTH;
- }
- else {
- len++;
- }
- }
-
- char chars[];
- if (len == buff.length) {
- chars = buff;
- }
- else {
- chars = new char[len];
- int pos = 0;
- for (char c : buff) {
- if (c == '\t') {
- Arrays.fill(chars, pos, pos + TAB_WIDTH, ' ');
- pos += TAB_WIDTH;
- }
- else {
- chars[pos] = c;
- pos++;
- }
- }
- }
-
- out.write(chars);
- }
-
- private void print(final char c, final int num) throws IOException {
- if (num == 1) {
- print(c);
- }
- else {
- char[] chars = new char[num];
- Arrays.fill(chars, c);
- print(chars);
- }
- }
-
- /**
- * Output the specified string to the output stream (but not the buffer).
- */
- public final void print(final CharSequence s) throws IOException {
- assert s != null;
- print(s.toString().toCharArray());
- }
-
- public final void println(final CharSequence s) throws IOException {
- assert s != null;
- print(s.toString().toCharArray());
- println();
- }
-
- /**
- * Output a platform-dependent newline.
- */
- public final void println() throws IOException {
- print(CR);
-// flush();
- }
-
- //
- // Actions
- //
-
- /**
- * Issue a delete.
- *
- * @return true if successful
- */
- public final boolean delete() throws IOException {
- return delete(1) == 1;
- }
-
- // FIXME: delete(int) only used by above + the return is always 1 and num is ignored
-
- /**
- * Issue <em>num</em> deletes.
- *
- * @return the number of characters backed up
- */
- private int delete(final int num) throws IOException {
- // TODO: Try to use jansi for this
-
- /* Commented out because of DWA-2949:
- if (buf.cursor == 0) {
- return 0;
- }
- */
-
- buf.buffer.delete(buf.cursor, buf.cursor + 1);
- drawBuffer(1);
-
- return 1;
- }
-
- /**
- * Kill the buffer ahead of the current cursor position.
- *
- * @return true if successful
- */
- public boolean killLine() throws IOException {
- int cp = buf.cursor;
- int len = buf.buffer.length();
-
- if (cp >= len) {
- return false;
- }
-
- int num = buf.buffer.length() - cp;
- clearAhead(num, 0);
-
- for (int i = 0; i < num; i++) {
- buf.buffer.deleteCharAt(len - i - 1);
- }
-
- return true;
- }
-
- /**
- * Clear the screen by issuing the ANSI "clear screen" code.
- */
- public boolean clearScreen() throws IOException {
- if (!getTerminal().isAnsiSupported()) {
- return false;
- }
-
- // send the ANSI code to clear the screen
- printAnsiSequence("2J");
-
- // then send the ANSI code to go to position 1,1
- printAnsiSequence("1;1H");
-
- redrawLine();
-
- return true;
- }
-
- /**
- * Issue an audible keyboard bell, if {@link #isBellEnabled} return true.
- */
- public void beep() throws IOException {
- if (isBellEnabled()) {
- print(KEYBOARD_BELL);
- // need to flush so the console actually beeps
- flush();
- }
- }
-
- /**
- * Paste the contents of the clipboard into the console buffer
- *
- * @return true if clipboard contents pasted
- */
- public boolean paste() throws IOException {
- Clipboard clipboard;
- try { // May throw ugly exception on system without X
- clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- }
- catch (Exception e) {
- return false;
- }
-
- if (clipboard == null) {
- return false;
- }
-
- Transferable transferable = clipboard.getContents(null);
-
- if (transferable == null) {
- return false;
- }
-
- try {
- Object content = transferable.getTransferData(DataFlavor.plainTextFlavor);
-
- // This fix was suggested in bug #1060649 at
- // http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
- // to get around the deprecated DataFlavor.plainTextFlavor, but it
- // raises a UnsupportedFlavorException on Mac OS X
-
- if (content == null) {
- try {
- content = new DataFlavor().getReaderForText(transferable);
- }
- catch (Exception e) {
- // ignore
- }
- }
-
- if (content == null) {
- return false;
- }
-
- String value;
-
- if (content instanceof Reader) {
- // TODO: we might want instead connect to the input stream
- // so we can interpret individual lines
- value = "";
- String line;
-
- BufferedReader read = new BufferedReader((Reader) content);
- while ((line = read.readLine()) != null) {
- if (value.length() > 0) {
- value += "\n";
- }
-
- value += line;
- }
- }
- else {
- value = content.toString();
- }
-
- if (value == null) {
- return true;
- }
-
- putString(value);
-
- return true;
- }
- catch (UnsupportedFlavorException e) {
- Log.error("Paste failed: ", e);
-
- return false;
- }
- }
-
- //
- // Triggered Actions
- //
-
- private final Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
-
- /**
- * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
- * <p/>
- * Say you want to close the application if the user enter q.
- * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
- */
- public void addTriggeredAction(final char c, final ActionListener listener) {
- triggeredActions.put(c, listener);
- }
-
- //
- // Formatted Output
- //
-
- /**
- * Output the specified {@link Collection} in proper columns.
- */
- public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
- if (items == null || items.isEmpty()) {
- return;
- }
-
- int width = getTerminal().getWidth();
- int height = getTerminal().getHeight();
-
- int maxWidth = 0;
- for (CharSequence item : items) {
- maxWidth = Math.max(maxWidth, item.length());
- }
- Log.debug("Max width: ", maxWidth);
-
- int showLines;
- if (isPaginationEnabled()) {
- showLines = height - 1; // page limit
- }
- else {
- showLines = Integer.MAX_VALUE;
- }
-
- StringBuilder buff = new StringBuilder();
- for (CharSequence item : items) {
- if ((buff.length() + maxWidth) > width) {
- println(buff);
- buff.setLength(0);
-
- if (--showLines == 0) {
- // Overflow
- print(resources.getString("display-more"));
- flush();
- int c = readVirtualKey();
- if (c == '\r' || c == '\n') {
- // one step forward
- showLines = 1;
- }
- else if (c != 'q') {
- // page forward
- showLines = height - 1;
- }
-
- back(resources.getString("display-more").length());
- if (c == 'q') {
- // cancel
- break;
- }
- }
- }
-
- // NOTE: toString() is important here due to AnsiString being retarded
- buff.append(item.toString());
- for (int i = 0; i < (maxWidth + 3 - item.length()); i++) {
- buff.append(' ');
- }
- }
-
- if (buff.length() > 0) {
- println(buff);
- }
- }
-
- //
- // Non-supported Terminal Support
- //
-
- private Thread maskThread;
-
- private void beforeReadLine(final String prompt, final Character mask) {
- if (mask != null && maskThread == null) {
- final String fullPrompt = "\r" + prompt
- + " "
- + " "
- + " "
- + "\r" + prompt;
-
- maskThread = new Thread()
- {
- public void run() {
- while (!interrupted()) {
- try {
- Writer out = getOutput();
- out.write(fullPrompt);
- out.flush();
- sleep(3);
- }
- catch (IOException e) {
- return;
- }
- catch (InterruptedException e) {
- return;
- }
- }
- }
- };
-
- maskThread.setPriority(Thread.MAX_PRIORITY);
- maskThread.setDaemon(true);
- maskThread.start();
- }
- }
-
- private void afterReadLine() {
- if (maskThread != null && maskThread.isAlive()) {
- maskThread.interrupt();
- }
-
- maskThread = null;
- }
-
- /**
- * Erases the current line with the existing prompt, then redraws the line
- * with the provided prompt and buffer
- * @param prompt
- * the new prompt
- * @param buffer
- * the buffer to be drawn
- * @param cursorDest
- * where you want the cursor set when the line has been drawn.
- * -1 for end of line.
- * */
- public void resetPromptLine(String prompt, String buffer, int cursorDest) throws IOException {
- // move cursor to end of line
- moveToEnd();
-
- // backspace all text, including prompt
- buf.buffer.append(this.prompt);
- buf.cursor += this.prompt.length();
- this.prompt = "";
- backspaceAll();
-
- this.prompt = prompt;
- redrawLine();
- setBuffer(buffer);
-
- // move cursor to destination (-1 will move to end of line)
- if (cursorDest < 0) cursorDest = buffer.length();
- setCursorPosition(cursorDest);
-
- flush();
- }
-
- public void printSearchStatus(String searchTerm, String match) throws IOException {
- String prompt = "(reverse-i-search)`" + searchTerm + "': ";
- String buffer = match;
- int cursorDest = match.indexOf(searchTerm);
- resetPromptLine(prompt, buffer, cursorDest);
- }
-
- public void restoreLine(String originalPrompt, int cursorDest) throws IOException {
- // TODO move cursor to matched string
- String prompt = lastLine(originalPrompt);
- String buffer = buf.buffer.toString();
- resetPromptLine(prompt, buffer, cursorDest);
- }
-
- //
- // History search
- //
- /**
- * Search backward in history from a given position.
- *
- * @param searchTerm substring to search for.
- * @param startIndex the index from which on to search
- * @return index where this substring has been found, or -1 else.
- */
- public int searchBackwards(String searchTerm, int startIndex) {
- return searchBackwards(searchTerm, startIndex, false);
- }
-
- /**
- * Search backwards in history from the current position.
- *
- * @param searchTerm substring to search for.
- * @return index where the substring has been found, or -1 else.
- */
- public int searchBackwards(String searchTerm) {
- return searchBackwards(searchTerm, history.index());
- }
-
-
- public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
- ListIterator<History.Entry> it = history.entries(startIndex);
- while (it.hasPrevious()) {
- History.Entry e = it.previous();
- if (startsWith) {
- if (e.value().toString().startsWith(searchTerm)) {
- return e.index();
- }
- } else {
- if (e.value().toString().contains(searchTerm)) {
- return e.index();
- }
- }
- }
- return -1;
- }
-
- //
- // Helpers
- //
-
- /**
- * Checks to see if the specified character is a delimiter. We consider a
- * character a delimiter if it is anything but a letter or digit.
- *
- * @param c The character to test
- * @return True if it is a delimiter
- */
- private boolean isDelimiter(final char c) {
- return !Character.isLetterOrDigit(c);
- }
-
- private void printAnsiSequence(String sequence) throws IOException {
- print(27);
- print('[');
- print(sequence);
- flush(); // helps with step debugging
- }
-
- // return column position, reported by the terminal
- private int getCurrentPosition() {
- // check for ByteArrayInputStream to disable for unit tests
- if (getTerminal().isAnsiSupported() && !(in instanceof ByteArrayInputStream)) {
- try {
- printAnsiSequence("6n");
- flush();
- StringBuffer b = new StringBuffer(8);
- // position is sent as <ESC>[{ROW};{COLUMN}R
- int r;
- while((r = in.read()) > -1 && r != 'R') {
- if (r != 27 && r != '[') {
- b.append((char) r);
- }
- }
- String[] pos = b.toString().split(";");
- return Integer.parseInt(pos[1]);
- } catch (Exception x) {
- // no luck
- }
- }
-
- return -1; // TODO: throw exception instead?
- }
-
- // return row position, reported by the terminal
- // needed to know whether to scroll up on cursor move in last col for weird
- // wrapping terminals - not tested for anything else
- private int getCurrentAnsiRow() {
- // check for ByteArrayInputStream to disable for unit tests
- if (getTerminal().isAnsiSupported() && !(in instanceof ByteArrayInputStream)) {
- try {
- printAnsiSequence("6n");
- flush();
- StringBuffer b = new StringBuffer(8);
- // position is sent as <ESC>[{ROW};{COLUMN}R
- int r;
- while((r = in.read()) > -1 && r != 'R') {
- if (r != 27 && r != '[') {
- b.append((char) r);
- }
- }
- String[] pos = b.toString().split(";");
- return Integer.parseInt(pos[0]);
- } catch (Exception x) {
- // no luck
- }
- }
-
- return -1; // TODO: throw exception instead?
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/CursorBuffer.java b/src/jline/src/main/java/scala/tools/jline/console/CursorBuffer.java
deleted file mode 100644
index 7993def002..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/CursorBuffer.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console;
-
-/**
- * A holder for a {@link StringBuilder} that also contains the current cursor position.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class CursorBuffer
-{
- private boolean overTyping = false;
-
- public int cursor = 0;
-
- public final StringBuilder buffer = new StringBuilder();
-
- public boolean isOverTyping() {
- return overTyping;
- }
-
- public void setOverTyping(final boolean b) {
- overTyping = b;
- }
-
- public int length() {
- return buffer.length();
- }
-
- /**
- * Gets the character to the left of the cursor.
- */
- public char charLeftOfCursor() {
- if (cursor <= 0) {
- return 0;
- }
-
- return buffer.charAt(cursor - 1);
- }
-
- /**
- * Gets the character at the cursor.
- */
- public char charAtCursor() {
- if (cursor < 0 || cursor >= buffer.length()) {
- return 0;
- }
- return buffer.charAt(cursor);
- }
-
- /**
- * Write the specific character into the buffer, setting the cursor position
- * ahead one. The text may overwrite or insert based on the current setting
- * of {@link #isOverTyping}.
- *
- * @param c the character to insert
- */
- public void write(final char c) {
- buffer.insert(cursor++, c);
- if (isOverTyping() && cursor < buffer.length()) {
- buffer.deleteCharAt(cursor);
- }
- }
-
- /**
- * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
- */
- public void write(final CharSequence str) {
- assert str != null;
-
- if (buffer.length() == 0) {
- buffer.append(str);
- }
- else {
- buffer.insert(cursor, str);
- }
-
- cursor += str.length();
-
- if (isOverTyping() && cursor < buffer.length()) {
- buffer.delete(cursor, (cursor + str.length()));
- }
- }
-
- public boolean clear() {
- if (buffer.length() == 0) {
- return false;
- }
-
- buffer.delete(0, buffer.length());
- cursor = 0;
- return true;
- }
-
- @Override
- public String toString() {
- return buffer.toString();
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/Key.java b/src/jline/src/main/java/scala/tools/jline/console/Key.java
deleted file mode 100644
index 2e713a7da2..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/Key.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Map from key name to key codes.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @see java.awt.event.KeyEvent
- * @since 2.0
- */
-public enum Key
-{
- CTRL_A(1),
-
- CTRL_B(2),
-
- CTRL_C(3),
-
- CTRL_D(4),
-
- CTRL_E(5),
-
- CTRL_F(6),
-
- CTRL_G(7),
-
- CTRL_K(11),
-
- CTRL_L(12),
-
- CTRL_N(14),
-
- CTRL_O(15),
-
- CTRL_P(16),
-
- CTRL_T(20),
-
- CTRL_W(23),
-
- CTRL_X(24),
-
- CTRL_OB(27),
-
- CTRL_QM(127),
-
- BACKSPACE('\b'),
-
- DELETE(127),;
-
- public final short code;
-
- Key(final int code) {
- this.code = (short) code;
- }
-
- private static final Map<Short, Key> codes;
-
- static {
- Map<Short, Key> map = new HashMap<Short, Key>();
-
- for (Key op : Key.values()) {
- map.put(op.code, op);
- }
-
- codes = map;
- }
-
- public static Key valueOf(final int code) {
- return codes.get((short) code);
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/Operation.java b/src/jline/src/main/java/scala/tools/jline/console/Operation.java
deleted file mode 100644
index 59ee878d45..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/Operation.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Map for console operation to virtual key bindings.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @see java.awt.event.KeyEvent
- * @since 2.0
- */
-public enum Operation
-{
- /**
- * Unknown operation.
- */
- UNKNOWN(-99),
-
- /**
- * Operation that moves to the beginning of the buffer.
- */
- MOVE_TO_BEG(-1),
-
- /**
- * Operation that moves to the end of the buffer.
- */
- MOVE_TO_END(-3),
-
- /**
- * Operation that moved to the previous character in the buffer.
- */
- PREV_CHAR(-4),
-
- /**
- * Operation that issues a newline.
- */
- NEWLINE(-6),
-
- /**
- * Operation that deletes the buffer from the current character to the end.
- */
- KILL_LINE(-7),
-
- /**
- * Operation that clears the screen.
- */
- CLEAR_SCREEN(-8),
-
- /**
- * Operation that sets the buffer to the next history item.
- */
- NEXT_HISTORY(-9),
-
- /**
- * Operation that sets the buffer to the previous history item.
- */
- PREV_HISTORY(-11),
-
- /**
- * Operation that redisplays the current buffer.
- */
- REDISPLAY(-13),
-
- /**
- * Operation that deletes the buffer from the cursor to the beginning.
- */
- KILL_LINE_PREV(-15),
-
- /**
- * Operation that deletes the previous word in the buffer.
- */
- DELETE_PREV_WORD(-16),
-
- /**
- * Operation that moves to the next character in the buffer.
- */
- NEXT_CHAR(-19),
-
- /**
- * Operation that moves to the previous character in the buffer.
- */
- REPEAT_PREV_CHAR(-20),
-
- /**
- * Operation that searches backwards in the command history.
- */
- SEARCH_PREV(-21),
-
- /**
- * Operation that repeats the character.
- */
- REPEAT_NEXT_CHAR(-24),
-
- /**
- * Operation that searches forward in the command history.
- */
- SEARCH_NEXT(-25),
-
- /**
- * Operation that moved to the previous whitespace.
- */
- PREV_SPACE_WORD(-27),
-
- /**
- * Operation that moved to the end of the current word.
- */
- TO_END_WORD(-29),
-
- /**
- * Operation that
- */
- REPEAT_SEARCH_PREV(-34),
-
- /**
- * Operation that
- */
- PASTE_PREV(-36),
-
- /**
- * Operation that
- */
- REPLACE_MODE(-37),
-
- /**
- * Operation that
- */
- SUBSTITUTE_LINE(-38),
-
- /**
- * Operation that
- */
- TO_PREV_CHAR(-39),
-
- /**
- * Operation that
- */
- NEXT_SPACE_WORD(-40),
-
- /**
- * Operation that
- */
- DELETE_PREV_CHAR(-41),
-
- /**
- * Operation that
- */
- ADD(-42),
-
- /**
- * Operation that
- */
- PREV_WORD(-43),
-
- /**
- * Operation that
- */
- CHANGE_META(-44),
-
- /**
- * Operation that
- */
- DELETE_META(-45),
-
- /**
- * Operation that
- */
- END_WORD(-46),
-
- /**
- * Operation that toggles insert/overtype
- */
- INSERT(-48),
-
- /**
- * Operation that
- */
- REPEAT_SEARCH_NEXT(-49),
-
- /**
- * Operation that
- */
- PASTE_NEXT(-50),
-
- /**
- * Operation that
- */
- REPLACE_CHAR(-51),
-
- /**
- * Operation that
- */
- SUBSTITUTE_CHAR(-52),
-
- /**
- * Operation that
- */
- TO_NEXT_CHAR(-53),
-
- /**
- * Operation that undoes the previous operation.
- */
- UNDO(-54),
-
- /**
- * Operation that moved to the next word.
- */
- NEXT_WORD(-55),
-
- /**
- * Operation that deletes the previous character.
- */
- DELETE_NEXT_CHAR(-56),
-
- /**
- * Operation that toggles between uppercase and lowercase.
- */
- CHANGE_CASE(-57),
-
- /**
- * Operation that performs completion operation on the current word.
- */
- COMPLETE(-58),
-
- /**
- * Operation that exits the command prompt.
- */
- EXIT(-59),
-
- /**
- * Operation that pastes the contents of the clipboard into the line
- */
- PASTE(-60),
-
- /**
- * Operation that moves the current History to the beginning.
- */
- START_OF_HISTORY(-61),
-
- /**
- * Operation that moves the current History to the end.
- */
- END_OF_HISTORY(-62),
-
- /**
- * Operation that clears whatever text is on the current line.
- */
- CLEAR_LINE(-63),
-
- /**
- * Cancel search
- */
- ABORT(-64),
-
- /**
- * Delete next word
- */
- DELETE_NEXT_WORD(-65),
-
- ;
-
- public final short code;
-
- Operation(final int code) {
- this.code = (short) code;
- }
-
- private static final Map<Short, Operation> codes;
-
- static {
- Map<Short, Operation> map = new HashMap<Short, Operation>();
-
- for (Operation op : Operation.values()) {
- map.put(op.code, op);
- }
-
- codes = map;
- }
-
- public static Operation valueOf(final int code) {
- return codes.get((short) code);
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/AggregateCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/AggregateCompleter.java
deleted file mode 100644
index 3170bd1c68..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/AggregateCompleter.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package scala.tools.jline.console.completer;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Completer which contains multiple completers and aggregates them together.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class AggregateCompleter
- implements Completer
-{
- private final List<Completer> completers = new ArrayList<Completer>();
-
- public AggregateCompleter() {
- // empty
- }
-
- public AggregateCompleter(final Collection<Completer> completers) {
- assert completers != null;
- this.completers.addAll(completers);
- }
-
- public AggregateCompleter(final Completer... completers) {
- this(Arrays.asList(completers));
- }
-
- public Collection<Completer> getCompleters() {
- return completers;
- }
-
- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
- // buffer could be null
- assert candidates != null;
-
- List<Completion> completions = new ArrayList<Completion>(completers.size());
-
- // Run each completer, saving its completion results
- int max = -1;
- for (Completer completer : completers) {
- Completion completion = new Completion(candidates);
- completion.complete(completer, buffer, cursor);
-
- // Compute the max cursor position
- max = Math.max(max, completion.cursor);
-
- completions.add(completion);
- }
-
- // Append candidates from completions which have the same cursor position as max
- for (Completion completion : completions) {
- if (completion.cursor == max) {
- candidates.addAll(completion.candidates);
- }
- }
-
- return max;
- }
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + "{" +
- "completers=" + completers +
- '}';
- }
-
- private class Completion
- {
- public final List<CharSequence> candidates;
-
- public int cursor;
-
- public Completion(final List<CharSequence> candidates) {
- assert candidates != null;
- this.candidates = new LinkedList<CharSequence>(candidates);
- }
-
- public void complete(final Completer completer, final String buffer, final int cursor) {
- assert completer != null;
-
- this.cursor = completer.complete(buffer, cursor, candidates);
- }
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/ArgumentCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/ArgumentCompleter.java
deleted file mode 100644
index 6f60029a1d..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/ArgumentCompleter.java
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.internal.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
- * This can be used instead of the individual completers having to know about argument parsing semantics.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class ArgumentCompleter
- implements Completer
-{
- private final ArgumentDelimiter delimiter;
-
- private final List<Completer> completers = new ArrayList<Completer>();
-
- private boolean strict = true;
-
- /**
- * Create a new completer with the specified argument delimiter.
- *
- * @param delimiter The delimiter for parsing arguments
- * @param completers The embedded completers
- */
- public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
- assert delimiter != null;
- this.delimiter = delimiter;
- assert completers != null;
- this.completers.addAll(completers);
- }
-
- /**
- * Create a new completer with the specified argument delimiter.
- *
- * @param delimiter The delimiter for parsing arguments
- * @param completers The embedded completers
- */
- public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
- this(delimiter, Arrays.asList(completers));
- }
-
- /**
- * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
- *
- * @param completers The embedded completers
- */
- public ArgumentCompleter(final Completer... completers) {
- this(new WhitespaceArgumentDelimiter(), completers);
- }
-
- /**
- * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
- *
- * @param completers The embedded completers
- */
- public ArgumentCompleter(final List<Completer> completers) {
- this(new WhitespaceArgumentDelimiter(), completers);
- }
-
- /**
- * If true, a completion at argument index N will only succeed
- * if all the completions from 0-(N-1) also succeed.
- */
- public void setStrict(final boolean strict) {
- this.strict = strict;
- }
-
- /**
- * Returns whether a completion at argument index N will success
- * if all the completions from arguments 0-(N-1) also succeed.
- *
- * @return True if strict.
- * @since 2.3
- */
- public boolean isStrict() {
- return this.strict;
- }
-
- /**
- * @since 2.3
- */
- public ArgumentDelimiter getDelimiter() {
- return delimiter;
- }
-
- /**
- * @since 2.3
- */
- public List<Completer> getCompleters() {
- return completers;
- }
-
- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
- // buffer can be null
- assert candidates != null;
-
- ArgumentDelimiter delim = getDelimiter();
- ArgumentList list = delim.delimit(buffer, cursor);
- int argpos = list.getArgumentPosition();
- int argIndex = list.getCursorArgumentIndex();
-
- if (argIndex < 0) {
- return -1;
- }
-
- List<Completer> completers = getCompleters();
- Completer completer;
-
- // if we are beyond the end of the completers, just use the last one
- if (argIndex >= completers.size()) {
- completer = completers.get(completers.size() - 1);
- }
- else {
- completer = completers.get(argIndex);
- }
-
- // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
- for (int i = 0; isStrict() && (i < argIndex); i++) {
- Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
- String[] args = list.getArguments();
- String arg = (args == null || i >= args.length) ? "" : args[i];
-
- List<CharSequence> subCandidates = new LinkedList<CharSequence>();
-
- if (sub.complete(arg, arg.length(), subCandidates) == -1) {
- return -1;
- }
-
- if (subCandidates.size() == 0) {
- return -1;
- }
- }
-
- int ret = completer.complete(list.getCursorArgument(), argpos, candidates);
-
- if (ret == -1) {
- return -1;
- }
-
- int pos = ret + list.getBufferPosition() - argpos;
-
- // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
- // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
- //
- // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
- // and hit TAB, we want "foo bar" instead of "foo bar".
-
- if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
- for (int i = 0; i < candidates.size(); i++) {
- CharSequence val = candidates.get(i);
-
- while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
- val = val.subSequence(0, val.length() - 1);
- }
-
- candidates.set(i, val);
- }
- }
-
- Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);
-
- return pos;
- }
-
- /**
- * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
- * arguments in order to dispatch the arguments to the nested {@link Completer}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static interface ArgumentDelimiter
- {
- /**
- * Break the specified buffer into individual tokens that can be completed on their own.
- *
- * @param buffer The buffer to split
- * @param pos The current position of the cursor in the buffer
- * @return The tokens
- */
- ArgumentList delimit(CharSequence buffer, int pos);
-
- /**
- * Returns true if the specified character is a whitespace parameter.
- *
- * @param buffer The complete command buffer
- * @param pos The index of the character in the buffer
- * @return True if the character should be a delimiter
- */
- boolean isDelimiter(CharSequence buffer, int pos);
- }
-
- /**
- * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
- * character should be used as a delimiter.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public abstract static class AbstractArgumentDelimiter
- implements ArgumentDelimiter
- {
- // TODO: handle argument quoting and escape characters
-
- private char[] quoteChars = {'\'', '"'};
-
- private char[] escapeChars = {'\\'};
-
- public void setQuoteChars(final char[] chars) {
- this.quoteChars = chars;
- }
-
- public char[] getQuoteChars() {
- return this.quoteChars;
- }
-
- public void setEscapeChars(final char[] chars) {
- this.escapeChars = chars;
- }
-
- public char[] getEscapeChars() {
- return this.escapeChars;
- }
-
- public ArgumentList delimit(final CharSequence buffer, final int cursor) {
- List<String> args = new LinkedList<String>();
- StringBuilder arg = new StringBuilder();
- int argpos = -1;
- int bindex = -1;
-
- for (int i = 0; (buffer != null) && (i <= buffer.length()); i++) {
- // once we reach the cursor, set the
- // position of the selected index
- if (i == cursor) {
- bindex = args.size();
- // the position in the current argument is just the
- // length of the current argument
- argpos = arg.length();
- }
-
- if ((i == buffer.length()) || isDelimiter(buffer, i)) {
- if (arg.length() > 0) {
- args.add(arg.toString());
- arg.setLength(0); // reset the arg
- }
- }
- else {
- arg.append(buffer.charAt(i));
- }
- }
-
- return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
- }
-
- /**
- * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
- * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
- * returns true from {@link #isDelimiterChar}.
- *
- * @param buffer The complete command buffer
- * @param pos The index of the character in the buffer
- * @return True if the character should be a delimiter
- */
- public boolean isDelimiter(final CharSequence buffer, final int pos) {
- return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
- }
-
- public boolean isQuoted(final CharSequence buffer, final int pos) {
- return false;
- }
-
- public boolean isEscaped(final CharSequence buffer, final int pos) {
- if (pos <= 0) {
- return false;
- }
-
- for (int i = 0; (escapeChars != null) && (i < escapeChars.length);
- i++) {
- if (buffer.charAt(pos) == escapeChars[i]) {
- return !isEscaped(buffer, pos - 1); // escape escape
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if the character at the specified position if a delimiter. This method will only be called if
- * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
- * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
- */
- public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
- }
-
- /**
- * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
- * {@link Character#isWhitespace}) as being a delimiter.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static class WhitespaceArgumentDelimiter
- extends AbstractArgumentDelimiter
- {
- /**
- * The character is a delimiter if it is whitespace, and the
- * preceding character is not an escape character.
- */
- @Override
- public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
- return Character.isWhitespace(buffer.charAt(pos));
- }
- }
-
- /**
- * The result of a delimited buffer.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static class ArgumentList
- {
- private String[] arguments;
-
- private int cursorArgumentIndex;
-
- private int argumentPosition;
-
- private int bufferPosition;
-
- /**
- * @param arguments The array of tokens
- * @param cursorArgumentIndex The token index of the cursor
- * @param argumentPosition The position of the cursor in the current token
- * @param bufferPosition The position of the cursor in the whole buffer
- */
- public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
- assert arguments != null;
-
- this.arguments = arguments;
- this.cursorArgumentIndex = cursorArgumentIndex;
- this.argumentPosition = argumentPosition;
- this.bufferPosition = bufferPosition;
- }
-
- public void setCursorArgumentIndex(final int i) {
- this.cursorArgumentIndex = i;
- }
-
- public int getCursorArgumentIndex() {
- return this.cursorArgumentIndex;
- }
-
- public String getCursorArgument() {
- if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
- return null;
- }
-
- return arguments[cursorArgumentIndex];
- }
-
- public void setArgumentPosition(final int pos) {
- this.argumentPosition = pos;
- }
-
- public int getArgumentPosition() {
- return this.argumentPosition;
- }
-
- public void setArguments(final String[] arguments) {
- this.arguments = arguments;
- }
-
- public String[] getArguments() {
- return this.arguments;
- }
-
- public void setBufferPosition(final int pos) {
- this.bufferPosition = pos;
- }
-
- public int getBufferPosition() {
- return this.bufferPosition;
- }
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java b/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java
deleted file mode 100644
index fa5bfd2777..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/CandidateListCompletionHandler.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.console.ConsoleReader;
-import scala.tools.jline.console.CursorBuffer;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.ResourceBundle;
-import java.util.Set;
-
-/**
- * A {@link CompletionHandler} that deals with multiple distinct completions
- * by outputting the complete list of possibilities to the console. This
- * mimics the behavior of the
- * <a href="http://www.gnu.org/directory/readline.html">readline</a> library.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class CandidateListCompletionHandler
- implements CompletionHandler
-{
- // TODO: handle quotes and escaped quotes && enable automatic escaping of whitespace
-
- public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
- IOException
- {
- CursorBuffer buf = reader.getCursorBuffer();
-
- // if there is only one completion, then fill in the buffer
- if (candidates.size() == 1) {
- CharSequence value = candidates.get(0);
-
- // fail if the only candidate is the same as the current buffer
- if (value.equals(buf.toString())) {
- return false;
- }
-
- setBuffer(reader, value, pos);
-
- return true;
- }
- else if (candidates.size() > 1) {
- String value = getUnambiguousCompletions(candidates);
- setBuffer(reader, value, pos);
- }
-
- printCandidates(reader, candidates);
-
- // redraw the current console buffer
- reader.drawLine();
-
- return true;
- }
-
- public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
- IOException
- {
- while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
- // empty
- }
-
- reader.putString(value);
- reader.setCursorPosition(offset + value.length());
- }
-
- /**
- * Print out the candidates. If the size of the candidates is greater than the
- * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
- *
- * @param candidates the list of candidates to print
- */
- public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws
- IOException
- {
- Set<CharSequence> distinct = new HashSet<CharSequence>(candidates);
-
- if (distinct.size() > reader.getAutoprintThreshold()) {
- //noinspection StringConcatenation
- reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size()));
- reader.flush();
-
- int c;
-
- String noOpt = Messages.DISPLAY_CANDIDATES_NO.format();
- String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format();
- char[] allowed = {yesOpt.charAt(0), noOpt.charAt(0)};
-
- while ((c = reader.readCharacter(allowed)) != -1) {
- String tmp = new String(new char[]{(char) c});
-
- if (noOpt.startsWith(tmp)) {
- reader.println();
- return;
- }
- else if (yesOpt.startsWith(tmp)) {
- break;
- }
- else {
- reader.beep();
- }
- }
- }
-
- // copy the values and make them distinct, without otherwise affecting the ordering. Only do it if the sizes differ.
- if (distinct.size() != candidates.size()) {
- Collection<CharSequence> copy = new ArrayList<CharSequence>();
-
- for (CharSequence next : candidates) {
- if (!copy.contains(next)) {
- copy.add(next);
- }
- }
-
- candidates = copy;
- }
-
- reader.println();
- reader.printColumns(candidates);
- }
-
- /**
- * Returns a root that matches all the {@link String} elements of the specified {@link List},
- * or null if there are no commonalities. For example, if the list contains
- * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
- */
- private String getUnambiguousCompletions(final List<CharSequence> candidates) {
- if (candidates == null || candidates.isEmpty()) {
- return null;
- }
-
- // convert to an array for speed
- String[] strings = candidates.toArray(new String[candidates.size()]);
-
- String first = strings[0];
- StringBuilder candidate = new StringBuilder();
-
- for (int i = 0; i < first.length(); i++) {
- if (startsWith(first.substring(0, i + 1), strings)) {
- candidate.append(first.charAt(i));
- }
- else {
- break;
- }
- }
-
- return candidate.toString();
- }
-
- /**
- * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
- */
- private boolean startsWith(final String starts, final String[] candidates) {
- for (String candidate : candidates) {
- if (!candidate.startsWith(starts)) {
- return false;
- }
- }
-
- return true;
- }
-
- private static enum Messages
- {
- DISPLAY_CANDIDATES,
- DISPLAY_CANDIDATES_YES,
- DISPLAY_CANDIDATES_NO,;
-
- private static final
- ResourceBundle
- bundle =
- ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault());
-
- public String format(final Object... args) {
- if (bundle == null)
- return "";
- else
- return String.format(bundle.getString(name()), args);
- }
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/Completer.java b/src/jline/src/main/java/scala/tools/jline/console/completer/Completer.java
deleted file mode 100644
index 52d33847f2..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/Completer.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.completer;
-
-import java.util.List;
-
-/**
- * A completer is the mechanism by which tab-completion candidates will be resolved.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface Completer
-{
- //
- // FIXME: Check if we can use CharSequece for buffer?
- //
-
- /**
- * Populates <i>candidates</i> with a list of possible completions for the <i>buffer</i>.
- *
- * The <i>candidates</i> list will not be sorted before being displayed to the user: thus, the
- * complete method should sort the {@link List} before returning.
- *
- * @param buffer The buffer
- * @param cursor The current position of the cursor in the <i>buffer</i>
- * @param candidates The {@link List} of candidates to populate
- * @return The index of the <i>buffer</i> for which the completion will be relative
- */
- int complete(String buffer, int cursor, List<CharSequence> candidates);
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/CompletionHandler.java b/src/jline/src/main/java/scala/tools/jline/console/completer/CompletionHandler.java
deleted file mode 100644
index 030dc84205..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/CompletionHandler.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.console.ConsoleReader;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Handler for dealing with candidates for tab-completion.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface CompletionHandler
-{
- boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/EnumCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/EnumCompleter.java
deleted file mode 100644
index 5ad049b857..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/EnumCompleter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package scala.tools.jline.console.completer;
-
-/**
- * {@link Completer} for {@link Enum} names.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class EnumCompleter
- extends StringsCompleter
-{
- public EnumCompleter(Class<? extends Enum> source) {
- assert source != null;
-
- for (Enum<?> n : source.getEnumConstants()) {
- this.getStrings().add(n.name().toLowerCase());
- }
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/FileNameCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/FileNameCompleter.java
deleted file mode 100644
index 6556138769..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/FileNameCompleter.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.internal.Configuration;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * A file name completer takes the buffer and issues a list of
- * potential completions.
- * <p/>
- * This completer tries to behave as similar as possible to
- * <i>bash</i>'s file name completion (using GNU readline)
- * with the following exceptions:
- * <p/>
- * <ul>
- * <li>Candidates that are directories will end with "/"</li>
- * <li>Wildcard regular expressions are not evaluated or replaced</li>
- * <li>The "~" character can be used to represent the user's home,
- * but it cannot complete to other users' homes, since java does
- * not provide any way of determining that easily</li>
- * </ul>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class FileNameCompleter
- implements Completer
-{
- // TODO: Handle files with spaces in them
-
- private static final boolean OS_IS_WINDOWS;
-
- static {
- String os = Configuration.getOsName();
- OS_IS_WINDOWS = os.contains("windows");
- }
-
- public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
- // buffer can be null
- assert candidates != null;
-
- if (buffer == null) {
- buffer = "";
- }
-
- if (OS_IS_WINDOWS) {
- buffer = buffer.replace('/', '\\');
- }
-
- String translated = buffer;
-
- File homeDir = getUserHome();
-
- // Special character: ~ maps to the user's home directory
- if (translated.startsWith("~" + separator())) {
- translated = homeDir.getPath() + translated.substring(1);
- }
- else if (translated.startsWith("~")) {
- translated = homeDir.getParentFile().getAbsolutePath();
- }
- else if (!(translated.startsWith(separator()))) {
- String cwd = getUserDir().getAbsolutePath();
- translated = cwd + separator() + translated;
- }
-
- File file = new File(translated);
- final File dir;
-
- if (translated.endsWith(separator())) {
- dir = file;
- }
- else {
- dir = file.getParentFile();
- }
-
- File[] entries = dir == null ? new File[0] : dir.listFiles();
-
- return matchFiles(buffer, translated, entries, candidates);
- }
-
- protected String separator() {
- return File.separator;
- }
-
- protected File getUserHome() {
- return Configuration.getUserHome();
- }
-
- protected File getUserDir() {
- return new File(".");
- }
-
- protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
- if (files == null) {
- return -1;
- }
-
- int matches = 0;
-
- // first pass: just count the matches
- for (File file : files) {
- if (file.getAbsolutePath().startsWith(translated)) {
- matches++;
- }
- }
- for (File file : files) {
- if (file.getAbsolutePath().startsWith(translated)) {
- CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
- candidates.add(render(file, name).toString());
- }
- }
-
- final int index = buffer.lastIndexOf(separator());
-
- return index + separator().length();
- }
-
- protected CharSequence render(final File file, final CharSequence name) {
- assert file != null;
- assert name != null;
-
- return name;
- }
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/NullCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/NullCompleter.java
deleted file mode 100644
index 93cf563bcd..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/NullCompleter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package scala.tools.jline.console.completer;
-
-import java.util.List;
-
-/**
- * Null completer.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public final class NullCompleter
- implements Completer
-{
- public static final NullCompleter INSTANCE = new NullCompleter();
-
- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
- return -1;
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/StringsCompleter.java b/src/jline/src/main/java/scala/tools/jline/console/completer/StringsCompleter.java
deleted file mode 100644
index 2abfdd0340..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/StringsCompleter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package scala.tools.jline.console.completer;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-/**
- * Completer for a set of strings.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class StringsCompleter
- implements Completer
-{
- private final SortedSet<String> strings = new TreeSet<String>();
-
- public StringsCompleter() {
- // empty
- }
-
- public StringsCompleter(final Collection<String> strings) {
- assert strings != null;
- getStrings().addAll(strings);
- }
-
- public StringsCompleter(final String... strings) {
- this(Arrays.asList(strings));
- }
-
- public Collection<String> getStrings() {
- return strings;
- }
-
- public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
- // buffer could be null
- assert candidates != null;
-
- if (buffer == null) {
- candidates.addAll(strings);
- }
- else {
- for (String match : strings.tailSet(buffer)) {
- if (!match.startsWith(buffer)) {
- break;
- }
-
- candidates.add(match);
- }
- }
-
- if (candidates.size() == 1) {
- candidates.set(0, candidates.get(0) + " ");
- }
-
- return candidates.isEmpty() ? -1 : 0;
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/completer/package-info.java b/src/jline/src/main/java/scala/tools/jline/console/completer/package-info.java
deleted file mode 100644
index 8150710cfc..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/completer/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Console completer support.
- *
- * @since 2.3
- */
-package scala.tools.jline.console.completer; \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/history/FileHistory.java b/src/jline/src/main/java/scala/tools/jline/console/history/FileHistory.java
deleted file mode 100644
index 5eccba3ce5..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/history/FileHistory.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.history;
-
-import scala.tools.jline.internal.Log;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.Flushable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.io.Reader;
-import java.util.ListIterator;
-
-/**
- * {@link History} using a file for persistent backing.
- * <p/>
- * Implementers should install shutdown hook to call {@link FileHistory#flush}
- * to save history to disk.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public class FileHistory
- extends MemoryHistory
- implements PersistentHistory, Flushable
-{
- private final File file;
-
- public FileHistory(final File file) throws IOException {
- assert file != null;
- this.file = file;
- load(file);
- }
-
- public File getFile() {
- return file;
- }
-
- public void load(final File file) throws IOException {
- assert file != null;
- if (file.exists()) {
- Log.trace("Loading history from: ", file);
- load(new FileReader(file));
- }
- }
-
- public void load(final InputStream input) throws IOException {
- assert input != null;
- load(new InputStreamReader(input));
- }
-
- public void load(final Reader reader) throws IOException {
- assert reader != null;
- BufferedReader input = new BufferedReader(reader);
-
- String item;
- while ((item = input.readLine()) != null) {
- add(item);
- }
- }
-
- public void flush() throws IOException {
- Log.trace("Flushing history");
-
- if (!file.exists()) {
- File dir = file.getParentFile();
- if (!dir.exists() && !dir.mkdirs()) {
- Log.warn("Failed to create directory: ", dir);
- }
- if (!file.createNewFile()) {
- Log.warn("Failed to create file: ", file);
- }
- }
-
- PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
- try {
- for (Entry entry : this) {
- out.println(entry.value());
- }
- }
- finally {
- out.close();
- }
- }
-
- public void purge() throws IOException {
- Log.trace("Purging history");
-
- clear();
-
- if (!file.delete()) {
- Log.warn("Failed to delete history file: ", file);
- }
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/history/History.java b/src/jline/src/main/java/scala/tools/jline/console/history/History.java
deleted file mode 100644
index d8602f2150..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/history/History.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.history;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-
-/**
- * Console history.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface History
- extends Iterable<History.Entry>
-{
- int size();
-
- boolean isEmpty();
-
- int index();
-
- void clear();
-
- CharSequence get(int index);
-
- void add(CharSequence line);
-
- void replace(CharSequence item);
-
- //
- // Entries
- //
-
- interface Entry
- {
- int index();
-
- CharSequence value();
- }
-
- ListIterator<Entry> entries(int index);
-
- ListIterator<Entry> entries();
-
- Iterator<Entry> iterator();
-
- //
- // Navigation
- //
-
- CharSequence current();
-
- boolean previous();
-
- boolean next();
-
- boolean moveToFirst();
-
- boolean moveToLast();
-
- boolean moveTo(int index);
-
- void moveToEnd();
-}
diff --git a/src/jline/src/main/java/scala/tools/jline/console/history/MemoryHistory.java b/src/jline/src/main/java/scala/tools/jline/console/history/MemoryHistory.java
deleted file mode 100644
index 3af936428a..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/history/MemoryHistory.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.history;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-
-/**
- * Non-persistent {@link History}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class MemoryHistory
- implements History
-{
- public static final int DEFAULT_MAX_SIZE = 500;
-
- private final LinkedList<CharSequence> items = new LinkedList<CharSequence>();
-
- private int maxSize = DEFAULT_MAX_SIZE;
-
- private boolean ignoreDuplicates = true;
-
- private boolean autoTrim = false;
-
- // NOTE: These are all ideas from looking at the Bash man page:
-
- // TODO: Add ignore space? (lines starting with a space are ignored)
-
- // TODO: Add ignore patterns?
-
- // TODO: Add history timestamp?
-
- // TODO: Add erase dups?
-
- private int offset = 0;
-
- private int index = 0;
-
- public void setMaxSize(final int maxSize) {
- this.maxSize = maxSize;
- maybeResize();
- }
-
- public int getMaxSize() {
- return maxSize;
- }
-
- public boolean isIgnoreDuplicates() {
- return ignoreDuplicates;
- }
-
- public void setIgnoreDuplicates(final boolean flag) {
- this.ignoreDuplicates = flag;
- }
-
- public boolean isAutoTrim() {
- return autoTrim;
- }
-
- public void setAutoTrim(final boolean flag) {
- this.autoTrim = flag;
- }
-
- public int size() {
- return items.size();
- }
-
- public boolean isEmpty() {
- return items.isEmpty();
- }
-
- public int index() {
- return offset + index;
- }
-
- public void clear() {
- items.clear();
- offset = 0;
- index = 0;
- }
-
- public CharSequence get(final int index) {
- return items.get(index - offset);
- }
-
- public void add(CharSequence item) {
- assert item != null;
-
- if (isAutoTrim()) {
- item = String.valueOf(item).trim();
- }
-
- if (isIgnoreDuplicates()) {
- if (!items.isEmpty() && item.equals(items.getLast())) {
- return;
- }
- }
-
- items.add(item);
-
- maybeResize();
- }
-
- public void replace(final CharSequence item) {
- items.removeLast();
- add(item);
- }
-
- private void maybeResize() {
- while (size() > getMaxSize()) {
- items.removeFirst();
- offset++;
- }
-
- index = size();
- }
-
- public ListIterator<Entry> entries(final int index) {
- return new EntriesIterator(index - offset);
- }
-
- public ListIterator<Entry> entries() {
- return entries(offset);
- }
-
- public Iterator<Entry> iterator() {
- return entries();
- }
-
- private static class EntryImpl
- implements Entry
- {
- private final int index;
-
- private final CharSequence value;
-
- public EntryImpl(int index, CharSequence value) {
- this.index = index;
- this.value = value;
- }
-
- public int index() {
- return index;
- }
-
- public CharSequence value() {
- return value;
- }
-
- @Override
- public String toString() {
- return String.format("%d: %s", index, value);
- }
- }
-
- private class EntriesIterator
- implements ListIterator<Entry>
- {
- private final ListIterator<CharSequence> source;
-
- private EntriesIterator(final int index) {
- source = items.listIterator(index);
- }
-
- public Entry next() {
- if (!source.hasNext()) {
- throw new NoSuchElementException();
- }
- return new EntryImpl(offset + source.nextIndex(), source.next());
- }
-
- public Entry previous() {
- if (!source.hasPrevious()) {
- throw new NoSuchElementException();
- }
- return new EntryImpl(offset + source.previousIndex(), source.previous());
- }
-
- public int nextIndex() {
- return offset + source.nextIndex();
- }
-
- public int previousIndex() {
- return offset + source.previousIndex();
- }
-
- public boolean hasNext() {
- return source.hasNext();
- }
-
- public boolean hasPrevious() {
- return source.hasPrevious();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public void set(final Entry entry) {
- throw new UnsupportedOperationException();
- }
-
- public void add(final Entry entry) {
- throw new UnsupportedOperationException();
- }
- }
-
- //
- // Navigation
- //
-
- /**
- * This moves the history to the last entry. This entry is one position
- * before the moveToEnd() position.
- *
- * @return Returns false if there were no history entries or the history
- * index was already at the last entry.
- */
- public boolean moveToLast() {
- int lastEntry = size() - 1;
- if (lastEntry >= 0 && lastEntry != index) {
- index = size() - 1;
- return true;
- }
-
- return false;
- }
-
- /**
- * Move to the specified index in the history
- * @param index
- * @return
- */
- public boolean moveTo(int index) {
- index -= offset;
- if (index >= 0 && index < size() ) {
- this.index = index;
- return true;
- }
- return false;
- }
-
- /**
- * Moves the history index to the first entry.
- *
- * @return Return false if there are no entries in the history or if the
- * history is already at the beginning.
- */
- public boolean moveToFirst() {
- if (size() > 0 && index != 0) {
- index = 0;
- return true;
- }
-
- return false;
- }
-
- /**
- * Move to the end of the history buffer. This will be a blank entry, after
- * all of the other entries.
- */
- public void moveToEnd() {
- index = size();
- }
-
- /**
- * Return the content of the current buffer.
- */
- public CharSequence current() {
- if (index >= size()) {
- return "";
- }
-
- return items.get(index);
- }
-
- /**
- * Move the pointer to the previous element in the buffer.
- *
- * @return true if we successfully went to the previous element
- */
- public boolean previous() {
- if (index <= 0) {
- return false;
- }
-
- index--;
-
- return true;
- }
-
- /**
- * Move the pointer to the next element in the buffer.
- *
- * @return true if we successfully went to the next element
- */
- public boolean next() {
- if (index >= size()) {
- return false;
- }
-
- index++;
-
- return true;
- }
-
-
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/history/PersistentHistory.java b/src/jline/src/main/java/scala/tools/jline/console/history/PersistentHistory.java
deleted file mode 100644
index 916532e7fc..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/history/PersistentHistory.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.console.history;
-
-import java.io.IOException;
-
-/**
- * Persistent {@link History}.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public interface PersistentHistory
- extends History
-{
- /**
- * Flush all items to persistent storage.
- *
- * @throws IOException Flush failed
- */
- void flush() throws IOException;
-
- /**
- * Purge persistent storage and {@link #clear}.
- *
- * @throws IOException Purge failed
- */
- void purge() throws IOException;
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/history/package-info.java b/src/jline/src/main/java/scala/tools/jline/console/history/package-info.java
deleted file mode 100644
index 4635752898..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/history/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Console history support.
- *
- * @since 2.0
- */
-package scala.tools.jline.console.history; \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/console/package-info.java b/src/jline/src/main/java/scala/tools/jline/console/package-info.java
deleted file mode 100644
index 9f284e9c05..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/console/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Console support.
- *
- * @since 2.0
- */
-package scala.tools.jline.console; \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/internal/Configuration.java b/src/jline/src/main/java/scala/tools/jline/internal/Configuration.java
deleted file mode 100644
index 5350d6c19e..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/internal/Configuration.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package scala.tools.jline.internal;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-/**
- * Provides access to configuration values.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.4
- */
-public final class Configuration
-{
- public static final String JLINE_RC = ".jline.rc";
-
- private static final Properties userprops;
-
- static {
- Properties props = new Properties();
-
- File file = new File(getUserHome(), JLINE_RC);
- if (file.exists() && file.canRead()) {
- try {
- InputStream input = new BufferedInputStream(new FileInputStream(file));
- try {
- props.load(input);
- Log.debug("Loaded user configuration: ", file);
- }
- finally {
- input.close();
- }
- }
- catch (IOException e) {
- Log.warn("Unable to read user configuration: ", file, e);
- }
- }
- else {
- Log.trace("User configuration file missing or unreadable: ", file);
- }
-
- userprops = props;
- }
-
- private static boolean isEmpty(final String value) {
- return value == null || value.trim().length() == 0;
- }
-
- public static String getString(final String name, final String defaultValue) {
- assert name != null;
-
- String value;
-
- // Check sysprops first, it always wins
- value = System.getProperty(name);
-
- if (isEmpty(value)) {
- // Next try userprops
- value = userprops.getProperty(name);
-
- if (isEmpty(value)) {
- // else use the default
- value = defaultValue;
- }
- }
-
- return value;
- }
-
- public static String getString(final String name) {
- return getString(name, null);
- }
-
- public static Boolean getBoolean(final String name, final Boolean defaultValue) {
- String value = getString(name);
- if (isEmpty(value)) {
- return defaultValue;
- }
- return Boolean.valueOf(value);
- }
-
- public static Boolean getBoolean(final String name) {
- return getBoolean(name, null);
- }
-
- //
- // System property helpers
- //
-
- public static File getUserHome() {
- return new File(System.getProperty("user.home"));
- }
-
- public static String getOsName() {
- return System.getProperty("os.name").toLowerCase();
- }
-
- public static String getFileEncoding() {
- return System.getProperty("file.encoding");
- }
-
- public static String getInputEncoding() {
- return System.getProperty("input.encoding", "UTF-8");
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/internal/Log.java b/src/jline/src/main/java/scala/tools/jline/internal/Log.java
deleted file mode 100644
index b226a10532..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/internal/Log.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package scala.tools.jline.internal;
-
-import java.io.PrintStream;
-
-/**
- * Internal logger.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public final class Log
-{
- ///CLOVER:OFF
-
- public static enum Level
- {
- TRACE,
- DEBUG,
- INFO,
- WARN,
- ERROR
- }
-
- @SuppressWarnings({"StringConcatenation"})
- public static final boolean DEBUG = Boolean.getBoolean(Log.class.getName() + ".debug");
-
- @SuppressWarnings({"StringConcatenation"})
- public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
-
- private static PrintStream output = System.err;
-
- public static PrintStream getOutput() {
- return output;
- }
-
- public static void setOutput(final PrintStream out) {
- assert out != null;
- output = out;
- }
-
- private static void print(final Object message) {
- if (message instanceof Throwable) {
- ((Throwable) message).printStackTrace();
- }
- else if (message.getClass().isArray()) {
- Object[] array = (Object[]) message;
-
- for (int i = 0; i < array.length; i++) {
- output.print(array[i]);
- if (i + 1 < array.length) {
- output.print(",");
- }
- }
- }
- else {
- output.print(message);
- }
- }
-
- private static void log(final Level level, final Object[] messages) {
- //noinspection SynchronizeOnNonFinalField
- synchronized (output) {
- output.format("[%s] ", level);
-
- for (Object message : messages) {
- print(message);
- }
-
- output.println();
- output.flush();
- }
- }
-
- public static void trace(final Object... messages) {
- if (TRACE) {
- log(Level.TRACE, messages);
- }
- }
-
- public static void debug(final Object... messages) {
- if (TRACE || DEBUG) {
- log(Level.DEBUG, messages);
- }
- }
-
- public static void warn(final Object... messages) {
- log(Level.WARN, messages);
- }
-
- public static void error(final Object... messages) {
- log(Level.ERROR, messages);
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/internal/ReplayPrefixOneCharInputStream.java b/src/jline/src/main/java/scala/tools/jline/internal/ReplayPrefixOneCharInputStream.java
deleted file mode 100644
index 2adabdd2ab..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/internal/ReplayPrefixOneCharInputStream.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package scala.tools.jline.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.MessageFormat;
-
-/**
- * This is awkward and inefficient, but probably the minimal way to add UTF-8 support to JLine
- *
- * @author <a href="mailto:Marc.Herbert@continuent.com">Marc Herbert</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.0
- */
-public final class ReplayPrefixOneCharInputStream
- extends InputStream
-{
- private byte firstByte;
-
- private int byteLength;
-
- private InputStream wrappedStream;
-
- private int byteRead;
-
- private final String encoding;
-
- public ReplayPrefixOneCharInputStream(final String encoding) {
- assert encoding != null;
- this.encoding = encoding;
- }
-
- public String getEncoding() {
- return encoding;
- }
-
- public void setInput(final int recorded, final InputStream wrapped) throws IOException {
- this.byteRead = 0;
- this.firstByte = (byte) recorded;
- this.wrappedStream = wrapped;
-
- byteLength = 1;
- if (encoding.equalsIgnoreCase("UTF-8")) {
- setInputUTF8(recorded, wrapped);
- }
- else if (encoding.equalsIgnoreCase("UTF-16")) {
- byteLength = 2;
- }
- else if (encoding.equalsIgnoreCase("UTF-32")) {
- byteLength = 4;
- }
- }
-
-
- public void setInputUTF8(final int recorded, final InputStream wrapped) throws IOException {
- // 110yyyyy 10zzzzzz
- if ((firstByte & (byte) 0xE0) == (byte) 0xC0) {
- this.byteLength = 2;
- }
- // 1110xxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF0) == (byte) 0xE0) {
- this.byteLength = 3;
- }
- // 11110www 10xxxxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF8) == (byte) 0xF0) {
- this.byteLength = 4;
- }
- else {
- throw new IOException(MessageFormat.format("Invalid UTF-8 first byte: {0}", firstByte));
- }
- }
-
- public int read() throws IOException {
- if (available() == 0) {
- return -1;
- }
-
- byteRead++;
-
- if (byteRead == 1) {
- return firstByte;
- }
-
- return wrappedStream.read();
- }
-
- /**
- * InputStreamReader is greedy and will try to read bytes in advance. We
- * do NOT want this to happen since we use a temporary/"losing bytes"
- * InputStreamReader above, that's why we hide the real
- * wrappedStream.available() here.
- */
- public int available() {
- return byteLength - byteRead;
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/internal/TerminalLineSettings.java b/src/jline/src/main/java/scala/tools/jline/internal/TerminalLineSettings.java
deleted file mode 100644
index 151862c14d..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/internal/TerminalLineSettings.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-
-package scala.tools.jline.internal;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.MessageFormat;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Provides access to terminal line settings via <tt>stty</tt>.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
- * @since 2.0
- */
-public final class TerminalLineSettings
-{
- public static final String JLINE_STTY = "jline.stty";
-
- public static final String DEFAULT_STTY = "stty";
-
- public static final String JLINE_SH = "jline.sh";
-
- public static final String DEFAULT_SH = "sh";
-
- private static String sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
-
- private static String shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
-
- private String config;
-
- private long configLastFetched;
-
- public TerminalLineSettings() throws IOException, InterruptedException {
- config = get("-a");
- configLastFetched = System.currentTimeMillis();
-
- Log.debug("Config: ", config);
-
- // sanity check
- if (config.length() == 0) {
- throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
- }
- }
-
- public String getConfig() {
- return config;
- }
-
- public void restore() throws IOException, InterruptedException {
- set("sane");
- }
-
- public String get(final String args) throws IOException, InterruptedException {
- return stty(args);
- }
-
- public void set(final String args) throws IOException, InterruptedException {
- stty(args);
- }
-
- /**
- * <p>
- * Get the value of a stty property, including the management of a cache.
- * </p>
- *
- * @param name the stty property.
- * @return the stty property value.
- */
- public int getProperty(String name) {
- assert name != null;
- try {
- // tty properties are cached so we don't have to worry too much about getting term widht/height
- if (config == null || System.currentTimeMillis() - configLastFetched > 1000 ) {
- config = get("-a");
- configLastFetched = System.currentTimeMillis();
- }
- return this.getProperty(name, config);
- } catch (Exception e) {
- Log.warn("Failed to query stty ", name, e);
- return -1;
- }
- }
-
- /**
- * <p>
- * Parses a stty output (provided by stty -a) and return the value of a given property.
- * </p>
- *
- * @param name property name.
- * @param stty string resulting of stty -a execution.
- * @return value of the given property.
- */
- protected int getProperty(String name, String stty) {
- // try the first kind of regex
- Pattern pattern = Pattern.compile(name + "\\s+=\\s+([^;]*)[;\\n\\r]");
- Matcher matcher = pattern.matcher(stty);
- if (!matcher.find()) {
- // try a second kind of regex
- pattern = Pattern.compile(name + "\\s+([^;]*)[;\\n\\r]");
- matcher = pattern.matcher(stty);
- if (!matcher.find()) {
- // try a second try of regex
- pattern = Pattern.compile("(\\S*)\\s+" + name);
- matcher = pattern.matcher(stty);
- if (!matcher.find()) {
- return -1;
- }
- }
- }
- return parseControlChar(matcher.group(1));
- }
-
- private int parseControlChar(String str) {
- // under
- if ("<undef>".equals(str)) {
- return -1;
- }
- // octal
- if (str.charAt(0) == '0') {
- return Integer.parseInt(str, 8);
- }
- // decimal
- if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
- return Integer.parseInt(str, 10);
- }
- // control char
- if (str.charAt(0) == '^') {
- if (str.charAt(1) == '?') {
- return 127;
- } else {
- return str.charAt(1) - 64;
- }
- } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
- if (str.charAt(2) == '^') {
- if (str.charAt(3) == '?') {
- return 127 + 128;
- } else {
- return str.charAt(3) - 64 + 128;
- }
- } else {
- return str.charAt(2) + 128;
- }
- } else {
- return str.charAt(0);
- }
- }
-
- private static String stty(final String args) throws IOException, InterruptedException {
- assert args != null;
- return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
- }
-
- private static String exec(final String cmd) throws IOException, InterruptedException {
- assert cmd != null;
- return exec(shCommand, "-c", cmd);
- }
-
- private static String exec(final String... cmd) throws IOException, InterruptedException {
- assert cmd != null;
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
- Log.trace("Running: ", cmd);
-
- Process p = Runtime.getRuntime().exec(cmd);
-
- InputStream in = null;
- InputStream err = null;
- OutputStream out = null;
- try {
- int c;
- in = p.getInputStream();
- while ((c = in.read()) != -1) {
- bout.write(c);
- }
- err = p.getErrorStream();
- while ((c = err.read()) != -1) {
- bout.write(c);
- }
- out = p.getOutputStream();
- p.waitFor();
- }
- finally {
- close(in, out, err);
- }
-
- String result = bout.toString();
-
- Log.trace("Result: ", result);
-
- return result;
- }
-
- private static void close(final Closeable... closeables) {
- for (Closeable c : closeables) {
- try {
- c.close();
- }
- catch (Exception e) {
- // Ignore
- }
- }
- }
-} \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/internal/package-info.java b/src/jline/src/main/java/scala/tools/jline/internal/package-info.java
deleted file mode 100644
index d27444cfdf..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/internal/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 the original author(s).
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Internal support.
- *
- * @since 2.0
- */
-package scala.tools.jline.internal; \ No newline at end of file
diff --git a/src/jline/src/main/java/scala/tools/jline/package-info.java b/src/jline/src/main/java/scala/tools/jline/package-info.java
deleted file mode 100644
index fde16f98de..0000000000
--- a/src/jline/src/main/java/scala/tools/jline/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2009 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * JLine 2.
- *
- * @since 2.0
- */
-package scala.tools.jline; \ No newline at end of file
diff --git a/src/jline/src/main/resources/scala/tools/jline/console/completer/CandidateListCompletionHandler.properties b/src/jline/src/main/resources/scala/tools/jline/console/completer/CandidateListCompletionHandler.properties
deleted file mode 100644
index fd097efb8a..0000000000
--- a/src/jline/src/main/resources/scala/tools/jline/console/completer/CandidateListCompletionHandler.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-DISPLAY_CANDIDATES=Display all %d possibilities? (y or n)
-DISPLAY_CANDIDATES_YES=y
-DISPLAY_CANDIDATES_NO=n
-DISPLAY_MORE=--More--
diff --git a/src/jline/src/main/resources/scala/tools/jline/keybindings.properties b/src/jline/src/main/resources/scala/tools/jline/keybindings.properties
deleted file mode 100644
index ad932d2a80..0000000000
--- a/src/jline/src/main/resources/scala/tools/jline/keybindings.properties
+++ /dev/null
@@ -1,71 +0,0 @@
-# Keybinding mapping for JLine. The format is:
-# [key code]=[logical operation]
-
-# CTRL-A: move to the beginning of the line
-1=MOVE_TO_BEG
-
-# CTRL-B: move to the previous character
-2=PREV_CHAR
-
-# CTRL-D: close out the input stream
-4=EXIT
-
-# CTRL-E: move the cursor to the end of the line
-5=MOVE_TO_END
-
-# CTRL-F: move to the next character
-6=NEXT_CHAR
-
-# CTRL-G: abort
-7=ABORT
-
-# BACKSPACE, CTRL-H: delete the previous character
-# 8 is the ASCII code for backspace and therefor
-# deleting the previous character
-8=DELETE_PREV_CHAR
-
-# TAB, CTRL-I: signal that console completion should be attempted
-9=COMPLETE
-
-# CTRL-J, CTRL-M: newline
-10=NEWLINE
-
-# CTRL-K: erase the current line
-11=KILL_LINE
-
-# CTRL-L: clear screen
-12=CLEAR_SCREEN
-
-# ENTER: newline
-13=NEWLINE
-
-# CTRL-N: scroll to the next element in the history buffer
-14=NEXT_HISTORY
-
-# CTRL-O: move to the previous word
-15=PREV_WORD
-
-# CTRL-P: scroll to the previous element in the history buffer
-16=PREV_HISTORY
-
-# CTRL-R: search history
-18=SEARCH_PREV
-
-# CTRL-T: move to next word
-20=NEXT_WORD
-
-# CTRL-U: delete all the characters before the cursor position
-21=KILL_LINE_PREV
-
-# CTRL-V: paste the contents of the clipboard (useful for Windows terminal)
-22=PASTE
-
-# CTRL-W: delete the word directly before the cursor
-23=DELETE_PREV_WORD
-
-# CTRL-X: delete the word directly after the cursor
-24=DELETE_NEXT_WORD
-
-# DELETE, CTRL-?: delete the next character
-# 127 is the ASCII code for delete
-127=DELETE_NEXT_CHAR
diff --git a/src/jline/src/main/resources/scala/tools/jline/windowsbindings.properties b/src/jline/src/main/resources/scala/tools/jline/windowsbindings.properties
deleted file mode 100644
index 340b5aa5b9..0000000000
--- a/src/jline/src/main/resources/scala/tools/jline/windowsbindings.properties
+++ /dev/null
@@ -1,71 +0,0 @@
-# Keybinding mapping for JLine. The format is:
-# [key code]=[logical operation]
-
-# CTRL-A: move to the beginning of the line
-1=MOVE_TO_BEG
-
-# CTRL-B: move to the previous character
-2=PREV_CHAR
-
-# CTRL-C: toggle overtype mode (frankly, I wasn't sure where to bind this)
-3=INSERT
-
-# CTRL-D: close out the input stream
-4=EXIT
-
-# CTRL-E: move the cursor to the end of the line
-5=MOVE_TO_END
-
-# CTRL-F: move to the next character
-6=NEXT_CHAR
-
-# CTRL-G: move to the previous word
-7=ABORT
-
-# CTRL-H: delete the previous character
-8=DELETE_PREV_CHAR
-
-# TAB, CTRL-I: signal that console completion should be attempted
-9=COMPLETE
-
-# CTRL-J, CTRL-M: newline
-10=NEWLINE
-
-# CTRL-K: erase the current line
-11=KILL_LINE
-
-# CTRL-L: clear screen
-12=CLEAR_SCREEN
-
-# ENTER: newline
-13=NEWLINE
-
-# CTRL-N: scroll to the next element in the history buffer
-14=NEXT_HISTORY
-
-# CTRL-O: move to the previous word
-15=PREV_WORD
-
-# CTRL-P: scroll to the previous element in the history buffer
-16=PREV_HISTORY
-
-# CTRL-R: search backwards in history
-18=SEARCH_PREV
-
-# CTRL-S: Move to the end of the history
-19=END_OF_HISTORY
-
-# CTRL-U: delete all the characters before the cursor position
-21=KILL_LINE_PREV
-
-# CTRL-V: paste the contents of the clipboard (useful for Windows terminal)
-22=PASTE
-
-# CTRL-W: delete the word directly before the cursor
-23=DELETE_PREV_WORD
-
-# CTRL-[: escape - clear the current line.
-27=CLEAR_LINE
-
-# CTRL-?: delete the previous character
-127=DELETE_NEXT_CHAR
diff --git a/src/jline/src/test/java/scala/tools/jline/TerminalFactoryTest.java b/src/jline/src/test/java/scala/tools/jline/TerminalFactoryTest.java
deleted file mode 100644
index c0c070bdfd..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/TerminalFactoryTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package scala.tools.jline;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Tests for the {@link TerminalFactory}.
- */
-public class TerminalFactoryTest
-{
- @Before
- public void setUp() throws Exception {
- TerminalFactory.reset();
- }
-
- @Test
- public void testConfigureNone() {
- TerminalFactory.configure(TerminalFactory.NONE);
- Terminal t = TerminalFactory.get();
- assertNotNull(t);
- assertEquals(UnsupportedTerminal.class.getName(), t.getClass().getName());
- }
-
- @Test
- public void testConfigureUnsupportedTerminal() {
- TerminalFactory.configure(UnsupportedTerminal.class.getName());
- Terminal t = TerminalFactory.get();
- assertNotNull(t);
- assertEquals(UnsupportedTerminal.class.getName(), t.getClass().getName());
- }
-} \ No newline at end of file
diff --git a/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTest.java b/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTest.java
deleted file mode 100644
index 0e6cba15a0..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTest.java
+++ /dev/null
@@ -1,261 +0,0 @@
-package scala.tools.jline.console;
-
-import scala.tools.jline.TerminalFactory;
-import scala.tools.jline.WindowsTerminal;
-import scala.tools.jline.console.history.History;
-import scala.tools.jline.console.history.MemoryHistory;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import static scala.tools.jline.WindowsTerminal.WindowsKey.DELETE_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.END_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.ESCAPE_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.HOME_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.INSERT_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.LEFT_ARROW_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.NUMPAD_KEY_INDICATOR;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.PAGE_DOWN_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.PAGE_UP_KEY;
-import static scala.tools.jline.WindowsTerminal.WindowsKey.SPECIAL_KEY_INDICATOR;
-import static scala.tools.jline.console.Operation.DELETE_NEXT_CHAR;
-import static scala.tools.jline.console.Operation.DELETE_PREV_CHAR;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Tests for the {@link ConsoleReader}.
- */
-public class ConsoleReaderTest
-{
- @Before
- public void setUp() throws Exception {
- System.setProperty(WindowsTerminal.JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE, "false");
- }
-
- private void assertWindowsKeyBehavior(String expected, char[] input) throws Exception {
- StringBuilder buffer = new StringBuilder();
- buffer.append(input);
- ConsoleReader reader = createConsole(buffer.toString().getBytes());
- assertNotNull(reader);
- String line = reader.readLine();
- assertEquals(expected, line);
- }
-
- private ConsoleReader createConsole(byte[] bytes) throws Exception {
- InputStream in = new ByteArrayInputStream(bytes);
- Writer writer = new StringWriter();
- ConsoleReader reader = new ConsoleReader(in, writer);
- reader.setHistory(createSeededHistory());
- return reader;
- }
-
- private History createSeededHistory() {
- History history = new MemoryHistory();
- history.add("dir");
- history.add("cd c:\\");
- history.add("mkdir monkey");
- return history;
- }
-
- @Test
- public void testDeleteAndBackspaceKeymappings() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- ConsoleReader consoleReader = new ConsoleReader();
- assertNotNull(consoleReader);
- assertEquals(127, consoleReader.getKeyForAction(DELETE_NEXT_CHAR));
- assertEquals(8, consoleReader.getKeyForAction(DELETE_PREV_CHAR));
- }
-
- @Test
- public void testReadline() throws Exception {
- ConsoleReader consoleReader = createConsole("Sample String\r\n".getBytes());
- assertNotNull(consoleReader);
- String line = consoleReader.readLine();
- assertEquals("Sample String", line);
- }
-
- @Test
- public void testDeleteOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 'S', 's',
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) LEFT_ARROW_KEY.code,
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) DELETE_KEY.code, '\r', 'n'
- };
- assertWindowsKeyBehavior("S", characters);
- }
-
- @Test
- public void testNumpadDeleteOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 'S', 's',
- (char) NUMPAD_KEY_INDICATOR.code,
- (char) LEFT_ARROW_KEY.code,
- (char) NUMPAD_KEY_INDICATOR.code,
- (char) DELETE_KEY.code, '\r', 'n'
- };
- assertWindowsKeyBehavior("S", characters);
- }
-
- @Test
- public void testHomeKeyOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 'S', 's',
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) HOME_KEY.code, 'x', '\r', '\n'
- };
- assertWindowsKeyBehavior("xSs", characters);
-
- }
-
- @Test
- public void testEndKeyOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 'S', 's',
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) HOME_KEY.code, 'x',
- (char) SPECIAL_KEY_INDICATOR.code, (char) END_KEY.code,
- 'j', '\r', '\n'
- };
- assertWindowsKeyBehavior("xSsj", characters);
- }
-
- @Test
- public void testPageUpOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) PAGE_UP_KEY.code, '\r', '\n'
- };
- assertWindowsKeyBehavior("dir", characters);
- }
-
- @Test
- public void testPageDownOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) PAGE_DOWN_KEY.code, '\r', '\n'
- };
- assertWindowsKeyBehavior("mkdir monkey", characters);
- }
-
- @Test
- public void testEscapeOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 's', 's', 's',
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) ESCAPE_KEY.code, '\r', '\n'
- };
- assertWindowsKeyBehavior("", characters);
- }
-
- @Test
- public void testInsertOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
- return;
- }
-
- char[] characters = new char[]{
- 'o', 'p', 's',
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) HOME_KEY.code,
- (char) SPECIAL_KEY_INDICATOR.code,
- (char) INSERT_KEY.code, 'o', 'o', 'p', 's', '\r', '\n'
- };
- assertWindowsKeyBehavior("oops", characters);
- }
-
- @Test
- public void testExpansion() throws Exception {
- ConsoleReader reader = new ConsoleReader();
- MemoryHistory history = new MemoryHistory();
- history.setMaxSize(3);
- history.add("foo");
- history.add("dir");
- history.add("cd c:\\");
- history.add("mkdir monkey");
- reader.setHistory(history);
-
- assertEquals("echo a!", reader.expandEvents("echo a!"));
- assertEquals("mkdir monkey ; echo a!", reader.expandEvents("!! ; echo a!"));
- assertEquals("echo ! a", reader.expandEvents("echo ! a"));
- assertEquals("echo !\ta", reader.expandEvents("echo !\ta"));
-
- assertEquals("mkdir barey", reader.expandEvents("^monk^bar^"));
- assertEquals("mkdir barey", reader.expandEvents("^monk^bar"));
- assertEquals("a^monk^bar", reader.expandEvents("a^monk^bar"));
-
- assertEquals("mkdir monkey", reader.expandEvents("!!"));
- assertEquals("echo echo a", reader.expandEvents("echo !#a"));
-
- assertEquals("mkdir monkey", reader.expandEvents("!mk"));
- try {
- reader.expandEvents("!mz");
- } catch (IllegalArgumentException e) {
- assertEquals("!mz: event not found", e.getMessage());
- }
-
- assertEquals("mkdir monkey", reader.expandEvents("!?mo"));
- assertEquals("mkdir monkey", reader.expandEvents("!?mo?"));
-
- assertEquals("mkdir monkey", reader.expandEvents("!-1"));
- assertEquals("cd c:\\", reader.expandEvents("!-2"));
- assertEquals("cd c:\\", reader.expandEvents("!2"));
- assertEquals("mkdir monkey", reader.expandEvents("!3"));
- try {
- reader.expandEvents("!20");
- } catch (IllegalArgumentException e) {
- assertEquals("!20: event not found", e.getMessage());
- }
- try {
- reader.expandEvents("!-20");
- } catch (IllegalArgumentException e) {
- assertEquals("!-20: event not found", e.getMessage());
- }
- }
-}
diff --git a/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTestSupport.java b/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTestSupport.java
deleted file mode 100644
index c19099f0b2..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/ConsoleReaderTestSupport.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-package scala.tools.jline.console;
-
-import scala.tools.jline.UnixTerminal;
-import org.junit.Before;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_DOWN;
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_LEFT;
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_PREFIX;
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_RIGHT;
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_START;
-import static scala.tools.jline.UnixTerminal.UnixKey.ARROW_UP;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-/**
- * Provides support for console reader tests.
- */
-public abstract class ConsoleReaderTestSupport
-{
- protected ConsoleReader console;
-
- @Before
- public void setUp() throws Exception {
- console = new ConsoleReader(null, new PrintWriter(new OutputStreamWriter(new ByteArrayOutputStream())), new UnixTerminal());
- }
-
- protected void assertBuffer(final String expected, final Buffer buffer) throws IOException {
- assertBuffer(expected, buffer, true);
- }
-
- protected void assertBuffer(final String expected, final Buffer buffer, final boolean clear) throws IOException {
- // clear current buffer, if any
- if (clear) {
- console.finishBuffer();
- console.getHistory().clear();
- }
-
- console.setInput(new ByteArrayInputStream(buffer.getBytes()));
-
- // run it through the reader
- while (console.readLine((String) null) != null) {
- // ignore
- }
-
- assertEquals(expected, console.getCursorBuffer().toString());
- }
-
- private int getKeyForAction(final Operation key) {
- return getKeyForAction(key.code);
- }
-
- private int getKeyForAction(final short logicalAction) {
- int action = console.getKeyForAction(logicalAction);
-
- if (action == -1) {
- console.printBindings();
- fail("Keystroke for logical action " + logicalAction + " was not bound in the console");
- }
-
- return action;
- }
-
- protected class Buffer
- {
- private final ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- public Buffer() {
- // nothing
- }
-
- public Buffer(final String str) {
- append(str);
- }
-
- public byte[] getBytes() {
- return out.toByteArray();
- }
-
- public Buffer op(final short operation) {
- return append(getKeyForAction(operation));
- }
-
- public Buffer op(final Operation op) {
- return op(op.code);
- }
-
- public Buffer ctrlA() {
- return append(getKeyForAction(Operation.MOVE_TO_BEG));
- }
-
- public Buffer ctrlU() {
- return append(getKeyForAction(Operation.KILL_LINE_PREV));
- }
-
- public Buffer tab() {
- return append(getKeyForAction(Operation.COMPLETE));
- }
-
- public Buffer back() {
- return append(getKeyForAction(Operation.DELETE_PREV_CHAR));
- }
-
- public Buffer left() {
- return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_LEFT.code);
- }
-
- public Buffer right() {
- return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_RIGHT.code);
- }
-
- public Buffer up() {
- return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_UP.code);
- }
-
- public Buffer down() {
- return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_DOWN.code);
- }
-
- public Buffer append(final String str) {
- for (byte b : str.getBytes()) {
- append(b);
- }
- return this;
- }
-
- public Buffer append(final int i) {
- out.write((byte) i);
- return this;
- }
- }
-}
diff --git a/src/jline/src/test/java/scala/tools/jline/console/EditLineTest.java b/src/jline/src/test/java/scala/tools/jline/console/EditLineTest.java
deleted file mode 100644
index 6f5d46121e..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/EditLineTest.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-package scala.tools.jline.console;
-
-import org.junit.Test;
-
-import static scala.tools.jline.console.Operation.*;
-
-/**
- * Tests various features of editing lines.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class EditLineTest
- extends ConsoleReaderTestSupport
-{
- @Test
- public void testDeletePreviousWord() throws Exception {
- Buffer b = new Buffer("This is a test");
-
- assertBuffer("This is a ", b = b.op(DELETE_PREV_WORD));
- assertBuffer("This is ", b = b.op(DELETE_PREV_WORD));
- assertBuffer("This ", b = b.op(DELETE_PREV_WORD));
- assertBuffer("", b = b.op(DELETE_PREV_WORD));
- assertBuffer("", b = b.op(DELETE_PREV_WORD));
- assertBuffer("", b.op(DELETE_PREV_WORD));
- }
-
- @Test
- public void testDeleteNextWord() throws Exception {
- Buffer b = new Buffer("This is a test ");
-
- assertBuffer(" is a test ", b = b.op(MOVE_TO_BEG).op(DELETE_NEXT_WORD));
- assertBuffer(" a test ", b = b.op(DELETE_NEXT_WORD));
- assertBuffer(" test ", b = b.op(DELETE_NEXT_WORD));
- assertBuffer(" ", b = b.op(DELETE_NEXT_WORD));
- assertBuffer("", b = b.op(DELETE_NEXT_WORD));
- assertBuffer("", b.op(DELETE_NEXT_WORD));
- }
-
- @Test
- public void testMoveToEnd() throws Exception {
- Buffer b = new Buffer("This is a test");
-
- assertBuffer("This is a XtestX",
- new Buffer("This is a test").op(PREV_WORD)
- .append('X')
- .op(MOVE_TO_END)
- .append('X'));
-
- assertBuffer("This is Xa testX",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .append('X')
- .op(MOVE_TO_END)
- .append('X'));
-
- assertBuffer("This Xis a testX",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .append('X')
- .op(MOVE_TO_END)
- .append('X'));
- }
-
- @Test
- public void testPreviousWord() throws Exception {
- assertBuffer("This is a Xtest",
- new Buffer("This is a test").op(PREV_WORD)
- .append('X'));
- assertBuffer("This is Xa test",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .append('X'));
- assertBuffer("This Xis a test",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .op(PREV_WORD)
- .append('X'));
- }
-
- @Test
- public void testNextWord() throws Exception {
- assertBuffer("ThisX is a test",
- new Buffer("This is a test").op(MOVE_TO_BEG)
- .op(NEXT_WORD)
- .append('X'));
- assertBuffer("This isX a test",
- new Buffer("This is a test").op(MOVE_TO_BEG)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .append('X'));
- assertBuffer("This is aX test",
- new Buffer("This is a test").op(MOVE_TO_BEG)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .append('X'));
- assertBuffer("This is a testX ",
- new Buffer("This is a test ").op(MOVE_TO_BEG)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .op(NEXT_WORD)
- .append('X'));
- }
-
- @Test
- public void testLineStart() throws Exception {
- assertBuffer("XThis is a test",
- new Buffer("This is a test").ctrlA().append('X'));
- assertBuffer("TXhis is a test",
- new Buffer("This is a test").ctrlA().right().append('X'));
- }
-
- @Test
- public void testClearLine() throws Exception {
- assertBuffer("", new Buffer("This is a test").ctrlU());
- assertBuffer("t", new Buffer("This is a test").left().ctrlU());
- assertBuffer("st", new Buffer("This is a test").left().left().ctrlU());
- }
-
- @Test
- public void testRight() throws Exception {
- Buffer b = new Buffer("This is a test");
- b = b.left().right().back();
- assertBuffer("This is a tes", b);
- b = b.left().left().left().right().left().back();
- assertBuffer("This is ates", b);
- b.append('X');
- assertBuffer("This is aXtes", b);
- }
-
- @Test
- public void testLeft() throws Exception {
- Buffer b = new Buffer("This is a test");
- b = b.left().left().left();
- assertBuffer("This is a est", b = b.back());
- assertBuffer("This is aest", b = b.back());
- assertBuffer("This is est", b = b.back());
- assertBuffer("This isest", b = b.back());
- assertBuffer("This iest", b = b.back());
- assertBuffer("This est", b = b.back());
- assertBuffer("Thisest", b = b.back());
- assertBuffer("Thiest", b = b.back());
- assertBuffer("Thest", b = b.back());
- assertBuffer("Test", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b.back());
- }
-
- @Test
- public void testBackspace() throws Exception {
- Buffer b = new Buffer("This is a test");
- assertBuffer("This is a tes", b = b.back());
- assertBuffer("This is a te", b = b.back());
- assertBuffer("This is a t", b = b.back());
- assertBuffer("This is a ", b = b.back());
- assertBuffer("This is a", b = b.back());
- assertBuffer("This is ", b = b.back());
- assertBuffer("This is", b = b.back());
- assertBuffer("This i", b = b.back());
- assertBuffer("This ", b = b.back());
- assertBuffer("This", b = b.back());
- assertBuffer("Thi", b = b.back());
- assertBuffer("Th", b = b.back());
- assertBuffer("T", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b.back());
- }
-
- @Test
- public void testBuffer() throws Exception {
- assertBuffer("This is a test", new Buffer("This is a test"));
- }
-}
diff --git a/src/jline/src/test/java/scala/tools/jline/console/completer/ArgumentCompleterTest.java b/src/jline/src/test/java/scala/tools/jline/console/completer/ArgumentCompleterTest.java
deleted file mode 100644
index 9e2a2ab031..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/completer/ArgumentCompleterTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.console.ConsoleReaderTestSupport;
-import scala.tools.jline.console.completer.ArgumentCompleter;
-import scala.tools.jline.console.completer.StringsCompleter;
-import org.junit.Test;
-
-/**
- * Tests for {@link jline.console.completer.ArgumentCompleter}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ArgumentCompleterTest
- extends ConsoleReaderTestSupport
-{
- @Test
- public void test1() throws Exception {
- console.addCompleter(new ArgumentCompleter(new StringsCompleter("foo", "bar", "baz")));
-
- assertBuffer("foo foo ", new Buffer("foo f").tab());
- assertBuffer("foo ba", new Buffer("foo b").tab());
- assertBuffer("foo ba", new Buffer("foo ba").tab());
- assertBuffer("foo baz ", new Buffer("foo baz").tab());
-
- // test completion in the mid range
- assertBuffer("foo baz", new Buffer("f baz").left().left().left().left().tab());
- assertBuffer("ba foo", new Buffer("b foo").left().left().left().left().tab());
- assertBuffer("foo ba baz", new Buffer("foo b baz").left().left().left().left().tab());
- assertBuffer("foo foo baz", new Buffer("foo f baz").left().left().left().left().tab());
- }
-} \ No newline at end of file
diff --git a/src/jline/src/test/java/scala/tools/jline/console/completer/NullCompleterTest.java b/src/jline/src/test/java/scala/tools/jline/console/completer/NullCompleterTest.java
deleted file mode 100644
index 70a4c3b554..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/completer/NullCompleterTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.console.ConsoleReaderTestSupport;
-import scala.tools.jline.console.completer.NullCompleter;
-import org.junit.Test;
-
-/**
- * Tests for {@link NullCompleter}.
- *
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- */
-public class NullCompleterTest
- extends ConsoleReaderTestSupport
-{
- @Test
- public void test1() throws Exception {
- console.addCompleter(NullCompleter.INSTANCE);
-
- assertBuffer("f", new Buffer("f").tab());
- assertBuffer("ba", new Buffer("ba").tab());
- assertBuffer("baz", new Buffer("baz").tab());
- }
-} \ No newline at end of file
diff --git a/src/jline/src/test/java/scala/tools/jline/console/completer/StringsCompleterTest.java b/src/jline/src/test/java/scala/tools/jline/console/completer/StringsCompleterTest.java
deleted file mode 100644
index 518b88d031..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/completer/StringsCompleterTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package scala.tools.jline.console.completer;
-
-import scala.tools.jline.console.ConsoleReaderTestSupport;
-import scala.tools.jline.console.completer.StringsCompleter;
-import org.junit.Test;
-
-/**
- * Tests for {@link jline.console.completer.StringsCompleter}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class StringsCompleterTest
- extends ConsoleReaderTestSupport
-{
- @Test
- public void test1() throws Exception {
- console.addCompleter(new StringsCompleter("foo", "bar", "baz"));
-
- assertBuffer("foo ", new Buffer("f").tab());
- // single tab completes to unambiguous "ba"
- assertBuffer("ba", new Buffer("b").tab());
- assertBuffer("ba", new Buffer("ba").tab());
- assertBuffer("baz ", new Buffer("baz").tab());
- }
-} \ No newline at end of file
diff --git a/src/jline/src/test/java/scala/tools/jline/console/history/HistoryTest.java b/src/jline/src/test/java/scala/tools/jline/console/history/HistoryTest.java
deleted file mode 100644
index 0a987b2b26..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/history/HistoryTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-package scala.tools.jline.console.history;
-
-import scala.tools.jline.console.ConsoleReaderTestSupport;
-import org.junit.Test;
-
-import static scala.tools.jline.console.Operation.MOVE_TO_BEG;
-import static scala.tools.jline.console.Operation.NEWLINE;
-import static scala.tools.jline.console.Operation.NEXT_HISTORY;
-import static scala.tools.jline.console.Operation.PREV_HISTORY;
-import static scala.tools.jline.console.Operation.PREV_CHAR;
-
-/**
- * Tests command history.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class HistoryTest
- extends ConsoleReaderTestSupport
-{
- @Test
- public void testSingleHistory() throws Exception {
- Buffer b = new Buffer().
- append("test line 1").op(NEWLINE).
- append("test line 2").op(NEWLINE).
- append("test line 3").op(NEWLINE).
- append("test line 4").op(NEWLINE).
- append("test line 5").op(NEWLINE).
- append("");
-
- assertBuffer("", b);
-
- assertBuffer("test line 5", b = b.op(PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(PREV_CHAR));
- assertBuffer("test line 4", b = b.op(PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
- assertBuffer("test line 4", b = b.op(PREV_HISTORY));
- assertBuffer("test line 3", b = b.op(PREV_HISTORY));
- assertBuffer("test line 2", b = b.op(PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(PREV_HISTORY));
-
- // beginning of history
- assertBuffer("test line 1", b = b.op(PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(PREV_HISTORY));
-
- assertBuffer("test line 2", b = b.op(NEXT_HISTORY));
- assertBuffer("test line 3", b = b.op(NEXT_HISTORY));
- assertBuffer("test line 4", b = b.op(NEXT_HISTORY));
- assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
-
- // end of history
- assertBuffer("", b = b.op(NEXT_HISTORY));
- assertBuffer("", b = b.op(NEXT_HISTORY));
- assertBuffer("", b = b.op(NEXT_HISTORY));
-
- assertBuffer("test line 5", b = b.op(PREV_HISTORY));
- assertBuffer("test line 4", b = b.op(PREV_HISTORY));
- b = b.op(MOVE_TO_BEG).append("XXX").op(NEWLINE);
- assertBuffer("XXXtest line 4", b = b.op(PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(PREV_HISTORY));
- assertBuffer("test line 4", b = b.op(PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(NEXT_HISTORY));
- assertBuffer("", b = b.op(NEXT_HISTORY));
-
- assertBuffer("XXXtest line 4", b = b.op(PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
- }
-}
diff --git a/src/jline/src/test/java/scala/tools/jline/console/history/MemoryHistoryTest.java b/src/jline/src/test/java/scala/tools/jline/console/history/MemoryHistoryTest.java
deleted file mode 100644
index 91b81548c8..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/console/history/MemoryHistoryTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2010 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package scala.tools.jline.console.history;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static junit.framework.Assert.*;
-
-/**
- * Tests for {@link MemoryHistory}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class MemoryHistoryTest
-{
- private MemoryHistory history;
-
- @Before
- public void setUp() {
- history = new MemoryHistory();
- }
-
- @After
- public void tearDown() {
- history = null;
- }
-
- @Test
- public void testAdd() {
- assertEquals(0, history.size());
-
- history.add("test");
-
- assertEquals(1, history.size());
- assertEquals("test", history.get(0));
- assertEquals(1, history.index());
- }
-
- private void assertHistoryContains(final int offset, final String... items) {
- assertEquals(items.length, history.size());
- int i=0;
- for (History.Entry entry : history) {
- assertEquals(offset + i, entry.index());
- assertEquals(items[i++], entry.value());
- }
- }
-
- @Test
- public void testOffset() {
- history.setMaxSize(5);
-
- assertEquals(0, history.size());
- assertEquals(0, history.index());
-
- history.add("a");
- history.add("b");
- history.add("c");
- history.add("d");
- history.add("e");
-
- assertEquals(5, history.size());
- assertEquals(5, history.index());
- assertHistoryContains(0, "a", "b", "c", "d", "e");
-
- history.add("f");
-
- assertEquals(5, history.size());
- assertEquals(6, history.index());
-
- assertHistoryContains(1, "b", "c", "d", "e", "f");
- assertEquals("f", history.get(5));
- }
-
- @Test
- public void testReplace() {
- assertEquals(0, history.size());
-
- history.add("a");
- history.add("b");
- history.replace("c");
-
- assertHistoryContains(0, "a", "c");
- }
-} \ No newline at end of file
diff --git a/src/jline/src/test/java/scala/tools/jline/example/Example.java b/src/jline/src/test/java/scala/tools/jline/example/Example.java
deleted file mode 100644
index a89a09c5c9..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/example/Example.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2002-2006, Marc Prud'hommeaux. All rights reserved.
- *
- * This software is distributable under the BSD license. See the terms of the
- * BSD license in the documentation provided with this software.
- */
-package scala.tools.jline.example;
-
-import scala.tools.jline.console.completer.*;
-import scala.tools.jline.console.ConsoleReader;
-
-import java.io.*;
-import java.util.*;
-
-public class Example
-{
- public static void usage() {
- System.out.println("Usage: java " + Example.class.getName()
- + " [none/simple/files/dictionary [trigger mask]]");
- System.out.println(" none - no completors");
- System.out.println(" simple - a simple completor that comples "
- + "\"foo\", \"bar\", and \"baz\"");
- System.out
- .println(" files - a completor that comples " + "file names");
- System.out.println(" classes - a completor that comples "
- + "java class names");
- System.out
- .println(" trigger - a special word which causes it to assume "
- + "the next line is a password");
- System.out.println(" mask - is the character to print in place of "
- + "the actual password character");
- System.out.println(" color - colored prompt and feedback");
- System.out.println("\n E.g - java Example simple su '*'\n"
- + "will use the simple compleator with 'su' triggering\n"
- + "the use of '*' as a password mask.");
- }
-
- public static void main(String[] args) throws IOException {
- Character mask = null;
- String trigger = null;
- boolean color = false;
-
- ConsoleReader reader = new ConsoleReader();
-
- reader.setBellEnabled(false);
- reader.setPrompt("prompt> ");
-
- if ((args == null) || (args.length == 0)) {
- usage();
-
- return;
- }
-
- List<Completer> completors = new LinkedList<Completer>();
-
- if (args.length > 0) {
- if (args[0].equals("none")) {
- }
- else if (args[0].equals("files")) {
- completors.add(new FileNameCompleter());
- }
- else if (args[0].equals("simple")) {
- completors.add(new StringsCompleter("foo", "bar", "baz"));
- }
- else if (args[0].equals("color")) {
- color = true;
- reader.setPrompt("\u001B[1mfoo\u001B[0m@bar\u001B[32m@baz\u001B[0m> ");
- }
- else {
- usage();
-
- return;
- }
- }
-
- if (args.length == 3) {
- mask = args[2].charAt(0);
- trigger = args[1];
- }
-
- for (Completer c : completors) {
- reader.addCompleter(c);
- }
-
- String line;
- PrintWriter out = new PrintWriter(
- reader.getTerminal().wrapOutIfNeeded(System.out));
-
- while ((line = reader.readLine()) != null) {
- if (color){
- out.println("\u001B[33m======>\u001B[0m\"" + line + "\"");
- } else {
- out.println("======>\"" + line + "\"");
- }
- out.flush();
-
- // If we input the special word then we will mask
- // the next line.
- if ((trigger != null) && (line.compareTo(trigger) == 0)) {
- line = reader.readLine("password> ", mask);
- }
- if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")) {
- break;
- }
- }
- }
-}
diff --git a/src/jline/src/test/java/scala/tools/jline/internal/TerminalLineSettingsTest.java b/src/jline/src/test/java/scala/tools/jline/internal/TerminalLineSettingsTest.java
deleted file mode 100644
index 3af10887f1..0000000000
--- a/src/jline/src/test/java/scala/tools/jline/internal/TerminalLineSettingsTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package scala.tools.jline.internal;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for the {@link TerminalLineSettings}.
- *
- * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
- */
-public class TerminalLineSettingsTest
-{
- private TerminalLineSettings settings;
-
- private final String linuxSttySample = "speed 38400 baud; rows 85; columns 244; line = 0;\n" +
- "intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;\n" +
- "-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts\n" +
- "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8\n" +
- "opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n" +
- "isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke";
-
- private final String solarisSttySample = "speed 38400 baud; \n" +
- "rows = 85; columns = 244; ypixels = 0; xpixels = 0;\n" +
- "csdata ?\n" +
- "eucw 1:0:0:0, scrw 1:0:0:0\n" +
- "intr = ^c; quit = ^\\; erase = ^?; kill = ^u;\n" +
- "eof = ^d; eol = -^?; eol2 = -^?; swtch = <undef>;\n" +
- "start = ^q; stop = ^s; susp = ^z; dsusp = ^y;\n" +
- "rprnt = ^r; flush = ^o; werase = ^w; lnext = ^v;\n" +
- "-parenb -parodd cs8 -cstopb -hupcl cread -clocal -loblk -crtscts -crtsxoff -parext \n" +
- "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc \n" +
- "ixon ixany -ixoff imaxbel \n" +
- "isig icanon -xcase echo echoe echok -echonl -noflsh \n" +
- "-tostop echoctl -echoprt echoke -defecho -flusho -pendin iexten \n" +
- "opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3";
-
- private final String aixSttySample = "speed 38400 baud; 85 rows; 244 columns;\n" +
- "eucw 1:1:0:0, scrw 1:1:0:0:\n" +
- "intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>\n" +
- "eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; dsusp = ^Y; reprint = ^R\n" +
- "discard = ^O; werase = ^W; lnext = ^V\n" +
- "-parenb -parodd cs8 -cstopb -hupcl cread -clocal -parext \n" +
- "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc \n" +
- "ixon ixany -ixoff imaxbel \n" +
- "isig icanon -xcase echo echoe echok -echonl -noflsh \n" +
- "-tostop echoctl -echoprt echoke -flusho -pending iexten \n" +
- "opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3";
-
- private final String macOsSttySample = "speed 9600 baud; 47 rows; 155 columns;\n" +
- "lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl\n" +
- "-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
- "-extproc\n" +
- "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8\n" +
- "-ignbrk brkint -inpck -ignpar -parmrk\n" +
- "oflags: opost onlcr -oxtabs -onocr -onlret\n" +
- "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
- "-dtrflow -mdmbuf\n" +
- "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
- "eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
- "min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
- "stop = ^S; susp = ^Z; time = 0; werase = ^W;";
-
- private final String netBsdSttySample = "speed 38400 baud; 85 rows; 244 columns;\n" +
- "lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl\n" +
- " -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
- " -extproc\n" +
- "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk\n" +
- " brkint -inpck -ignpar -parmrk\n" +
- "oflags: opost onlcr -ocrnl oxtabs onocr onlret\n" +
- "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -mdmbuf\n" +
- " -cdtrcts\n" +
- "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
- " eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
- " min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
- " stop = ^S; susp = ^Z; time = 0; werase = ^W;";
-
- private final String freeBsdSttySample = "speed 9600 baud; 32 rows; 199 columns;\n" +
- "lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl\n" +
- " -echoprt -altwerase -noflsh -tostop -flusho -pendin -nokerninfo\n" +
- " -extproc\n" +
- "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk\n" +
- " brkint -inpck -ignpar -parmrk\n" +
- "oflags: opost onlcr -ocrnl tab0 -onocr -onlret\n" +
- "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
- " -dtrflow -mdmbuf\n" +
- "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
- " eol2 = <undef>; erase = ^?; erase2 = ^H; intr = ^C; kill = ^U;\n" +
- " lnext = ^V; min = 1; quit = ^\\; reprint = ^R; start = ^Q;\n" +
- " status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;";
-
- @Before
- public void setUp() throws Exception {
- settings = new TerminalLineSettings();
- }
-
- @Test
- public void testGetConfig() {
- String config = settings.getConfig();
- System.out.println(config);
- }
-
- @Test
- public void testLinuxSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", linuxSttySample));
- assertEquals(244, settings.getProperty("columns", linuxSttySample));
- assertEquals(85, settings.getProperty("rows", linuxSttySample));
- }
-
- @Test
- public void testSolarisSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", solarisSttySample));
- assertEquals(244, settings.getProperty("columns", solarisSttySample));
- assertEquals(85, settings.getProperty("rows", solarisSttySample));
- }
-
- @Test
- public void testAixSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", aixSttySample));
- assertEquals(244, settings.getProperty("columns", aixSttySample));
- assertEquals(85, settings.getProperty("rows", aixSttySample));
- }
-
- @Test
- public void testMacOsSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", macOsSttySample));
- assertEquals(155, settings.getProperty("columns", macOsSttySample));
- assertEquals(47, settings.getProperty("rows", macOsSttySample));
- }
-
- @Test
- public void testNetBsdSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", netBsdSttySample));
- assertEquals(244, settings.getProperty("columns", netBsdSttySample));
- assertEquals(85, settings.getProperty("rows", netBsdSttySample));
- }
-
- @Test
- public void testFreeBsdSttyParsing() {
- assertEquals(0x7f, settings.getProperty("erase", freeBsdSttySample));
- assertEquals(199, settings.getProperty("columns", freeBsdSttySample));
- assertEquals(32, settings.getProperty("rows", freeBsdSttySample));
- }
-
-} \ No newline at end of file
diff --git a/src/library/scala/StringContext.scala b/src/library/scala/StringContext.scala
index c9e632c70e..2632994a34 100644
--- a/src/library/scala/StringContext.scala
+++ b/src/library/scala/StringContext.scala
@@ -104,7 +104,7 @@ case class StringContext(parts: String*) {
* ''Note:'' Even when using the raw interpolator, Scala will preprocess unicode escapes.
* For example:
* {{{
- * scala> raw"\u005cu0025"
+ * scala> raw"\u005cu0023"
* res0: String = #
* }}}
*
@@ -112,8 +112,6 @@ case class StringContext(parts: String*) {
* @throws An `IllegalArgumentException`
* if the number of `parts` in the enclosing `StringContext` does not exceed
* the number of arguments `arg` by exactly 1.
- * @throws A `StringContext.InvalidEscapeException` if a `parts` string contains a backslash (`\`) character
- * that does not start a valid escape sequence.
*/
def raw(args: Any*): String = standardInterpolator(identity, args)
@@ -165,7 +163,7 @@ case class StringContext(parts: String*) {
*/
// The implementation is hardwired to `scala.tools.reflect.MacroImplementations.macro_StringInterpolation_f`
// Using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def f(args: Any*): String = macro ???
+ def f[A >: Any](args: A*): String = macro ???
}
object StringContext {
@@ -175,8 +173,13 @@ object StringContext {
* @param str The offending string
* @param idx The index of the offending backslash character in `str`.
*/
- class InvalidEscapeException(str: String, @deprecatedName('idx) val index: Int)
- extends IllegalArgumentException("invalid escape character at index "+index+" in \""+str+"\"")
+ class InvalidEscapeException(str: String, @deprecatedName('idx) val index: Int) extends IllegalArgumentException(
+ s"""invalid escape ${
+ require(index >= 0 && index < str.length)
+ val ok = """[\b, \t, \n, \f, \r, \\, \", \']"""
+ if (index == str.length - 1) "at terminal" else s"'\\${str(index + 1)}' not one of $ok at"
+ } index $index in "$str". Use \\\\ for literal \\."""
+ )
/** Expands standard Scala escape sequences in a string.
* Escape sequences are:
diff --git a/src/library/scala/collection/IterableProxy.scala b/src/library/scala/collection/IterableProxy.scala
index 3a0e2ab115..97aa830c5a 100644
--- a/src/library/scala/collection/IterableProxy.scala
+++ b/src/library/scala/collection/IterableProxy.scala
@@ -16,4 +16,5 @@ package collection
* @version 2.8
* @since 2.8
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait IterableProxy[+A] extends Iterable[A] with IterableProxyLike[A, Iterable[A]]
diff --git a/src/library/scala/collection/MapProxy.scala b/src/library/scala/collection/MapProxy.scala
index 941c1f5a4a..26a7c710ee 100644
--- a/src/library/scala/collection/MapProxy.scala
+++ b/src/library/scala/collection/MapProxy.scala
@@ -17,4 +17,5 @@ package collection
* @version 1.0, 21/07/2003
* @since 1
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]]
diff --git a/src/library/scala/collection/SetProxy.scala b/src/library/scala/collection/SetProxy.scala
index f9f38f148a..e17fb215b9 100644
--- a/src/library/scala/collection/SetProxy.scala
+++ b/src/library/scala/collection/SetProxy.scala
@@ -17,4 +17,5 @@ package collection
* @author Martin Odersky
* @version 2.0, 01/01/2007
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]]
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index d3a7db6968..a8731a51b1 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -253,7 +253,7 @@ trait TraversableLike[+A, +Repr] extends Any
b.result
}
- private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = {
+ private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = {
val b = newBuilder
for (x <- this)
if (p(x) != isFlipped) b += x
diff --git a/src/library/scala/collection/TraversableProxy.scala b/src/library/scala/collection/TraversableProxy.scala
index 65936da0e4..9eec685d10 100644
--- a/src/library/scala/collection/TraversableProxy.scala
+++ b/src/library/scala/collection/TraversableProxy.scala
@@ -21,4 +21,5 @@ package collection
* @version 2.8
* @since 2.8
*/
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3")
trait TraversableProxy[+A] extends Traversable[A] with TraversableProxyLike[A, Traversable[A]]
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index 26ccd09803..720dfeed59 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -364,15 +364,16 @@ extends scala.collection.AbstractSeq[Int]
override def equals(other: Any) = other match {
case x: Range =>
// Note: this must succeed for overfull ranges (length > Int.MaxValue)
- (x canEqual this) && (
- isEmpty || // all empty sequences are equal
- (start == x.start && { // Otherwise, must have same start
- val l0 = last
- (l0 == x.last && ( // And same end
- start == l0 || step == x.step // And either the same step, or not take any steps
- ))
- })
- )
+ (x canEqual this) && {
+ if (isEmpty) x.isEmpty // empty sequences are equal
+ else // this is non-empty...
+ x.nonEmpty && start == x.start && { // ...so other must contain something and have same start
+ val l0 = last
+ (l0 == x.last && ( // And same end
+ start == l0 || step == x.step // And either the same step, or not take any steps
+ ))
+ }
+ }
case _ =>
super.equals(other)
}
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 37a0b373da..1f97c4c769 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -468,6 +468,16 @@ self =>
)
else super.flatMap(f)(bf)
+ override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = {
+ // optimization: drop leading prefix of elems for which f returns false
+ // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise
+ var rest = this
+ while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail
+ // private utility func to avoid `this` on stack (would be needed for the lazy arg)
+ if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped)
+ else Stream.Empty
+ }
+
/** Returns all the elements of this `Stream` that satisfy the predicate `p`
* in a new `Stream` - i.e., it is still a lazy data structure. The order of
* the elements is preserved
@@ -481,15 +491,7 @@ self =>
* // produces
* }}}
*/
- override def filter(p: A => Boolean): Stream[A] = {
- // optimization: drop leading prefix of elems for which f returns false
- // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise
- var rest = this
- while (!rest.isEmpty && !p(rest.head)) rest = rest.tail
- // private utility func to avoid `this` on stack (would be needed for the lazy arg)
- if (rest.nonEmpty) Stream.filteredTail(rest, p)
- else Stream.Empty
- }
+ override def filter(p: A => Boolean): Stream[A] = filterImpl(p, isFlipped = false) // This override is only left in 2.11 because of binary compatibility, see PR #3925
override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p)
@@ -1187,8 +1189,8 @@ object Stream extends SeqFactory[Stream] {
else cons(start, range(start + step, end, step))
}
- private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = {
- cons(stream.head, stream.tail filter p)
+ private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = {
+ cons(stream.head, stream.tail.filterImpl(p, isFlipped))
}
private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = {
diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala
index 4674c9174b..11d3bb8b02 100644
--- a/src/library/scala/concurrent/ExecutionContext.scala
+++ b/src/library/scala/concurrent/ExecutionContext.scala
@@ -61,28 +61,44 @@ or import scala.concurrent.ExecutionContext.Implicits.global.""")
trait ExecutionContext {
/** Runs a block of code on this execution context.
+ *
+ * @param runnable the task to execute
*/
def execute(runnable: Runnable): Unit
/** Reports that an asynchronous computation failed.
+ *
+ * @param cause the cause of the failure
*/
def reportFailure(@deprecatedName('t) cause: Throwable): Unit
- /** Prepares for the execution of a task. Returns the prepared
- * execution context. A valid implementation of `prepare` is one
- * that simply returns `this`.
+ /** Prepares for the execution of a task. Returns the prepared execution context.
+ *
+ * `prepare` should be called at the site where an `ExecutionContext` is received (for
+ * example, through an implicit method parameter). The returned execution context may
+ * then be used to execute tasks. The role of `prepare` is to save any context relevant
+ * to an execution's ''call site'', so that this context may be restored at the
+ * ''execution site''. (These are often different: for example, execution may be
+ * suspended through a `Promise`'s future until the `Promise` is completed, which may
+ * be done in another thread, on another stack.)
+ *
+ * Note: a valid implementation of `prepare` is one that simply returns `this`.
+ *
+ * @return the prepared execution context
*/
def prepare(): ExecutionContext = this
}
/**
- * An [[ExecutionContext]] that is also a Java [[Executor]].
+ * An [[ExecutionContext]] that is also a
+ * Java [[http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html Executor]].
*/
trait ExecutionContextExecutor extends ExecutionContext with Executor
/**
- * An [[ExecutionContext]] that is also a Java [[ExecutorService]].
+ * An [[ExecutionContext]] that is also a
+ * Java [[http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html ExecutorService]].
*/
trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService
@@ -91,38 +107,70 @@ trait ExecutionContextExecutorService extends ExecutionContextExecutor with Exec
*/
object ExecutionContext {
/**
- * This is the explicit global ExecutionContext,
- * call this when you want to provide the global ExecutionContext explicitly
+ * The explicit global `ExecutionContext`. Invoke `global` when you want to provide the global
+ * `ExecutionContext` explicitly.
+ *
+ * The default `ExecutionContext` implementation is backed by a port of
+ * [[http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166-4jdk7docs/java/util/concurrent/ForkJoinPool.html java.util.concurrent.ForkJoinPool]].
+ *
+ * @return the global `ExecutionContext`
*/
def global: ExecutionContextExecutor = Implicits.global
object Implicits {
/**
- * This is the implicit global ExecutionContext,
- * import this when you want to provide the global ExecutionContext implicitly
+ * The implicit global `ExecutionContext`. Import `global` when you want to provide the global
+ * `ExecutionContext` implicitly.
+ *
+ * The default `ExecutionContext` implementation is backed by a port of
+ * [[http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166-4jdk7docs/java/util/concurrent/ForkJoinPool.html java.util.concurrent.ForkJoinPool]].
*/
implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor)
}
/** Creates an `ExecutionContext` from the given `ExecutorService`.
+ *
+ * @param e the `ExecutorService` to use
+ * @param reporter a function for error reporting
+ * @return the `ExecutionContext` using the given `ExecutorService`
*/
def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit): ExecutionContextExecutorService =
impl.ExecutionContextImpl.fromExecutorService(e, reporter)
- /** Creates an `ExecutionContext` from the given `ExecutorService` with the default Reporter.
+ /** Creates an `ExecutionContext` from the given `ExecutorService` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]].
+ *
+ * If it is guaranteed that none of the executed tasks are blocking, a single-threaded `ExecutorService`
+ * can be used to create an `ExecutionContext` as follows:
+ *
+ * {{{
+ * import java.util.concurrent.Executors
+ * val ec = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor())
+ * }}}
+ *
+ * @param e the `ExecutorService` to use
+ * @return the `ExecutionContext` using the given `ExecutorService`
*/
def fromExecutorService(e: ExecutorService): ExecutionContextExecutorService = fromExecutorService(e, defaultReporter)
/** Creates an `ExecutionContext` from the given `Executor`.
+ *
+ * @param e the `Executor` to use
+ * @param reporter a function for error reporting
+ * @return the `ExecutionContext` using the given `Executor`
*/
def fromExecutor(e: Executor, reporter: Throwable => Unit): ExecutionContextExecutor =
impl.ExecutionContextImpl.fromExecutor(e, reporter)
- /** Creates an `ExecutionContext` from the given `Executor` with the default Reporter.
+ /** Creates an `ExecutionContext` from the given `Executor` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]].
+ *
+ * @param e the `Executor` to use
+ * @return the `ExecutionContext` using the given `Executor`
*/
def fromExecutor(e: Executor): ExecutionContextExecutor = fromExecutor(e, defaultReporter)
- /** The default reporter simply prints the stack trace of the `Throwable` to System.err.
+ /** The default reporter simply prints the stack trace of the `Throwable` to [[http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#err System.err]].
+ *
+ * @return the function for error reporting
*/
def defaultReporter: Throwable => Unit = _.printStackTrace()
}
diff --git a/src/library/scala/runtime/SeqCharSequence.scala b/src/library/scala/runtime/SeqCharSequence.scala
index ce7d7afc9e..74e67bb9e7 100644
--- a/src/library/scala/runtime/SeqCharSequence.scala
+++ b/src/library/scala/runtime/SeqCharSequence.scala
@@ -44,5 +44,10 @@ final class ArrayCharSequence(val xs: Array[Char], start: Int, end: Int) extends
new ArrayCharSequence(xs, start1, start1 + newlen)
}
}
- override def toString = xs drop start take length mkString ""
+ override def toString = {
+ val start = math.max(this.start, 0)
+ val end = math.min(xs.length, start + length)
+
+ if (start >= end) "" else new String(xs, start, end - start)
+ }
}
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index 2e1bfb02e4..5c4e706dc1 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -6,7 +6,6 @@
** |/ **
\* */
-
/**
* This package is concerned with regular expression (regex) matching against strings,
* with the main goal of pulling out information from those matches, or replacing
@@ -28,117 +27,127 @@
* into a [[java.lang.String]].
*
*/
-package scala
-package util.matching
+package scala.util.matching
import scala.collection.AbstractIterator
import java.util.regex.{ Pattern, Matcher }
-/** This class provides methods for creating and using regular expressions.
- * It is based on the regular expressions of the JDK since 1.4.
+/** A regular expression is used to determine whether a string matches a pattern
+ * and, if it does, to extract or transform the parts that match.
*
- * Its main goal is to extract strings that match a pattern, or the subgroups
- * that make it up. For that reason, it is usually used with for comprehensions
- * and matching (see methods for examples).
+ * This class delegates to the [[java.util.regex]] package of the Java Platform.
+ * See the documentation for [[java.util.regex.Pattern]] for details about
+ * the regular expression syntax for pattern strings.
*
- * A Regex is created from a [[java.lang.String]] representation of the
- * regular expression pattern^1^. That pattern is compiled
- * during construction, so frequently used patterns should be declared outside
- * loops if performance is of concern. Possibly, they might be declared on a
- * companion object, so that they need only to be initialized once.
+ * An instance of `Regex` represents a compiled regular expression pattern.
+ * Since compilation is expensive, frequently used `Regex`es should be constructed
+ * once, outside of loops and perhaps in a companion object.
*
- * The canonical way of creating regex patterns is by using the method `r`, provided
- * on [[java.lang.String]] through an implicit conversion into
- * [[scala.collection.immutable.WrappedString]]. Using triple quotes to write these
- * strings avoids having to quote the backslash character (`\`).
+ * The canonical way to create a `Regex` is by using the method `r`, provided
+ * implicitly for strings:
*
- * Using the constructor directly, on the other hand, makes
- * it possible to declare names for subgroups in the pattern.
+ * {{{
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
+ * }}}
*
- * For example, both declarations below generate the same regex, but the second
- * one associate names with the subgroups.
+ * Since escapes are not processed in multi-line string literals, using triple quotes
+ * avoids having to escape the backslash character, so that `"\\d"` can be written `"""\d"""`.
+ *
+ * To extract the capturing groups when a `Regex` is matched, use it as
+ * an extractor in a pattern match:
*
* {{{
- * val dateP1 = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
- * val dateP2 = new scala.util.matching.Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day")
+ * "2004-01-20" match {
+ * case date(year, month, day) => s"$year was a good year for PLs."
+ * }
* }}}
*
- * There are two ways of using a `Regex` to find a pattern: calling methods on
- * Regex, such as `findFirstIn` or `findAllIn`, or using it as an extractor in a
- * pattern match.
+ * To check only whether the `Regex` matches, ignoring any groups,
+ * use a sequence wildcard:
+ *
+ * {{{
+ * "2004-01-20" match {
+ * case date(_*) => "It's a date!"
+ * }
+ * }}}
*
- * Note that, when calling `findAllIn`, the resulting [[scala.util.matching.Regex.MatchIterator]]
- * needs to be initialized (by calling `hasNext` or `next()`, or causing these to be
- * called) before information about a match can be retrieved:
+ * That works because a `Regex` extractor produces a sequence of strings.
+ * Extracting only the year from a date could also be expressed with
+ * a sequence wildcard:
*
* {{{
- * val msg = "I love Scala"
+ * "2004-01-20" match {
+ * case date(year, _*) => s"$year was a good year for PLs."
+ * }
+ * }}}
*
- * // val start = " ".r.findAllIn(msg).start // throws an IllegalStateException
+ * In a pattern match, `Regex` normally matches the entire input.
+ * However, an unanchored `Regex` finds the pattern anywhere
+ * in the input.
*
- * val matches = " ".r.findAllIn(msg)
- * matches.hasNext // initializes the matcher
- * val start = matches.start
+ * {{{
+ * val embeddedDate = date.unanchored
+ * "Date: 2004-01-20 17:25:18 GMT (10 years, 28 weeks, 5 days, 17 hours and 51 minutes ago)" match {
+ * case embeddedDate("2004", "01", "20") => "A Scala is born."
+ * }
* }}}
*
- * When Regex is used as an extractor in a pattern match, note that it
- * only succeeds if the whole text can be matched. For this reason, one usually
- * calls a method to find the matching substrings, and then use it as an extractor
- * to break match into subgroups.
+ * To find or replace matches of the pattern, use the various find and replace methods.
+ * There is a flavor of each method that produces matched strings and
+ * another that produces `Match` objects.
*
- * As an example, the above patterns can be used like this:
+ * For example, pattern matching with an unanchored `Regex`, as in the previous example,
+ * is the same as using `findFirstMatchIn`, except that the findFirst methods return an `Option`,
+ * or `None` for no match:
*
* {{{
- * val dateP1(year, month, day) = "2011-07-15"
+ * val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15"
+ * val firstDate = date findFirstIn dates getOrElse "No date found."
+ * val firstYear = for (m <- date findFirstMatchIn dates) yield m group 1
+ * }}}
*
- * // val dateP1(year, month, day) = "Date 2011-07-15" // throws an exception at runtime
+ * To find all matches:
*
- * val copyright: String = dateP1 findFirstIn "Date of this document: 2011-07-15" match {
- * case Some(dateP1(year, month, day)) => "Copyright "+year
- * case None => "No copyright"
- * }
+ * {{{
+ * val allYears = for (m <- date findAllMatchIn dates) yield m group 1
+ * }}}
*
- * val copyright: Option[String] = for {
- * dateP1(year, month, day) <- dateP1 findFirstIn "Last modified 2011-07-15"
- * } yield year
-
- * def getYears(text: String): Iterator[String] = for (dateP1(year, _, _) <- dateP1 findAllIn text) yield year
- * def getFirstDay(text: String): Option[String] = for (m <- dateP2 findFirstMatchIn text) yield m group "day"
+ * But `findAllIn` returns a special iterator of strings that can be queried for the `MatchData`
+ * of the last match:
+ *
+ * {{{
+ * val mi = date findAllIn dates
+ * val oldies = mi filter (_ => (mi group 1).toInt < 1960) map (s => s"$s: An oldie but goodie.")
* }}}
*
- * Regex does not provide a method that returns a [[scala.Boolean]]. One can
- * use [[java.lang.String]] `matches` method, or, if `Regex` is preferred,
- * either ignore the return value or test the `Option` for emptyness. For example:
+ * Note that `findAllIn` finds matches that don't overlap. (See [[findAllIn]] for more examples.)
*
* {{{
- * def hasDate(text: String): Boolean = (dateP1 findFirstIn text).nonEmpty
- * def printLinesWithDates(lines: Traversable[String]) {
- * lines foreach { line =>
- * dateP1 findFirstIn line foreach { _ => println(line) }
- * }
- * }
+ * val num = """(\d+)""".r
+ * val all = (num findAllIn "123").toList // List("123"), not List("123", "23", "3")
* }}}
*
- * There are also methods that can be used to replace the patterns
- * on a text. The substitutions can be simple replacements, or more
- * complex functions. For example:
+ * Text replacement can be performed unconditionally or as a function of the current match:
*
* {{{
- * val months = Map( 1 -> "Jan", 2 -> "Feb", 3 -> "Mar",
- * 4 -> "Apr", 5 -> "May", 6 -> "Jun",
- * 7 -> "Jul", 8 -> "Aug", 9 -> "Sep",
- * 10 -> "Oct", 11 -> "Nov", 12 -> "Dec")
- *
- * import scala.util.matching.Regex.Match
- * def reformatDate(text: String) = dateP2 replaceAllIn ( text, (m: Match) =>
- * "%s %s, %s" format (months(m group "month" toInt), m group "day", m group "year")
- * )
+ * val redacted = date replaceAllIn (dates, "XXXX-XX-XX")
+ * val yearsOnly = date replaceAllIn (dates, m => m group 1)
+ * val months = (0 to 11) map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" }
+ * val reformatted = date replaceAllIn (dates, _ match { case date(y,m,d) => f"${months(m.toInt - 1)} $d, $y" })
* }}}
*
- * You can use special pattern syntax constructs like `(?idmsux-idmsux)`¹ to switch
- * various regex compilation options like `CASE_INSENSITIVE` or `UNICODE_CASE`.
+ * Pattern matching the `Match` against the `Regex` that created it does not reapply the `Regex`.
+ * In the expression for `reformatted`, each `date` match is computed once. But it is possible to apply a
+ * `Regex` to a `Match` resulting from a different pattern:
+ *
+ * {{{
+ * val docSpree = """2011(?:-\d{2}){2}""".r
+ * val docView = date replaceAllIn (dates, _ match {
+ * case docSpree() => "Historic doc spree!"
+ * case _ => "Something else happened"
+ * })
+ * }}}
*
- * @note ¹ A detailed description is available in [[java.util.regex.Pattern]].
* @see [[java.util.regex.Pattern]]
*
* @author Thibaud Hottelier
@@ -154,9 +163,8 @@ import java.util.regex.{ Pattern, Matcher }
* interpreted as a reference to a group in the matched pattern, with numbers
* 1 through 9 corresponding to the first nine groups, and 0 standing for the
* whole match. Any other character is an error. The backslash (`\`) character
- * will be interpreted as an escape character, and can be used to escape the
- * dollar sign. One can use [[scala.util.matching.Regex]]'s `quoteReplacement`
- * to automatically escape these characters.
+ * will be interpreted as an escape character and can be used to escape the
+ * dollar sign. Use `Regex.quoteReplacement` to escape these characters.
*/
@SerialVersionUID(-2094783597747625537L)
class Regex private[matching](val pattern: Pattern, groupNames: String*) extends Serializable {
@@ -164,51 +172,84 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
import Regex._
- /**
- * @param regex A string representing a regular expression
- * @param groupNames A mapping from names to indices in capture groups
- */
+ /** Compile a regular expression, supplied as a string, into a pattern that
+ * can be matched against inputs.
+ *
+ * If group names are supplied, they can be used this way:
+ *
+ * {{{
+ * val namedDate = new Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day")
+ * val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year"
+ * }}}
+ *
+ * This constructor does not support options as flags, which must be
+ * supplied as inline flags in the pattern string: `(?idmsux-idmsux)`.
+ *
+ * @param regex The regular expression to compile.
+ * @param groupNames Names of capturing groups.
+ */
def this(regex: String, groupNames: String*) = this(Pattern.compile(regex), groupNames: _*)
/** Tries to match a [[java.lang.CharSequence]].
+ *
* If the match succeeds, the result is a list of the matching
* groups (or a `null` element if a group did not match any input).
* If the pattern specifies no groups, then the result will be an empty list
* on a successful match.
*
* This method attempts to match the entire input by default; to find the next
- * matching subsequence, use an unanchored Regex.
-
+ * matching subsequence, use an unanchored `Regex`.
+ *
* For example:
*
* {{{
* val p1 = "ab*c".r
* val p1Matches = "abbbc" match {
- * case p1() => true
+ * case p1() => true // no groups
* case _ => false
* }
* val p2 = "a(b*)c".r
+ * val p2Matches = "abbbc" match {
+ * case p2(_*) => true // any groups
+ * case _ => false
+ * }
* val numberOfB = "abbbc" match {
- * case p2(b) => Some(b.length)
+ * case p2(b) => Some(b.length) // one group
* case _ => None
* }
* val p3 = "b*".r.unanchored
* val p3Matches = "abbbc" match {
- * case p3() => true
+ * case p3() => true // find the b's
* case _ => false
* }
+ * val p4 = "a(b*)(c+)".r
+ * val p4Matches = "abbbcc" match {
+ * case p4(_*) => true // multiple groups
+ * case _ => false
+ * }
+ * val allGroups = "abbbcc" match {
+ * case p4(all @ _*) => all mkString "/" // "bbb/cc"
+ * case _ => ""
+ * }
+ * val cGroup = "abbbcc" match {
+ * case p4(_, c) => c
+ * case _ => ""
+ * }
* }}}
*
* @param s The string to match
* @return The matches
*/
- def unapplySeq(s: CharSequence): Option[List[String]] = {
- val m = pattern matcher s
- if (runMatcher(m)) Some((1 to m.groupCount).toList map m.group)
- else None
+ def unapplySeq(s: CharSequence): Option[List[String]] = s match {
+ case null => None
+ case _ =>
+ val m = pattern matcher s
+ if (runMatcher(m)) Some((1 to m.groupCount).toList map m.group)
+ else None
}
/** Tries to match the String representation of a [[scala.Char]].
+ *
* If the match succeeds, the result is the first matching
* group if any groups are defined, or an empty Sequence otherwise.
*
@@ -247,13 +288,16 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
}
/** Tries to match on a [[scala.util.matching.Regex.Match]].
+ *
* A previously failed match results in None.
+ *
* If a successful match was made against the current pattern, then that result is used.
+ *
* Otherwise, this Regex is applied to the previously matched input,
* and the result of that match is used.
*/
def unapplySeq(m: Match): Option[List[String]] =
- if (m.matched == null) None
+ if (m == null || m.matched == null) None
else if (m.matcher.pattern == this.pattern) Some((1 to m.groupCount).toList map m.group)
else unapplySeq(m.matched)
@@ -274,30 +318,47 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
// @see UnanchoredRegex
protected def runMatcher(m: Matcher) = m.matches()
- /** Return all non-overlapping matches of this regexp in given character
+ /** Return all non-overlapping matches of this `Regex` in the given character
* sequence as a [[scala.util.matching.Regex.MatchIterator]],
* which is a special [[scala.collection.Iterator]] that returns the
- * matched strings, but can also be converted into a normal iterator
- * that returns objects of type [[scala.util.matching.Regex.Match]]
- * that can be queried for data such as the text that precedes the
- * match, subgroups, etc.
+ * matched strings but can also be queried for more data about the last match,
+ * such as capturing groups and start position.
+ *
+ * A `MatchIterator` can also be converted into an iterator
+ * that returns objects of type [[scala.util.matching.Regex.Match]],
+ * such as is normally returned by `findAllMatchIn`.
*
* Where potential matches overlap, the first possible match is returned,
- * followed by the next match that is completely after the first. For
- * instance, `"hat[^a]+".r` will match `hath` and `hattth` in the string
- * `"hathatthattthatttt"`.
+ * followed by the next match that follows the input consumed by the
+ * first match:
+ *
+ * {{{
+ * val hat = "hat[^a]+".r
+ * val hathaway = "hathatthattthatttt"
+ * val hats = (hat findAllIn hathaway).toList // List(hath, hattth)
+ * val pos = (hat findAllMatchIn hathaway map (_.start)).toList // List(0, 7)
+ * }}}
+ *
+ * To return overlapping matches, it is possible to formulate a regular expression
+ * with lookahead (`?=`) that does not consume the overlapping region.
+ *
+ * {{{
+ * val madhatter = "(h)(?=(at[^a]+))".r
+ * val madhats = (madhatter findAllMatchIn hathaway map {
+ * case madhatter(x,y) => s"$x$y"
+ * }).toList // List(hath, hatth, hattth, hatttt)
+ * }}}
*
- * Attempting to retrieve information about a match before initializing
- * the iterator can result in [[java.lang.IllegalStateException]]s. See
- * [[scala.util.matching.Regex.MatchIterator]] for details.
+ * Attempting to retrieve match information before performing the first match
+ * or after exhausting the iterator results in [[java.lang.IllegalStateException]].
+ * See [[scala.util.matching.Regex.MatchIterator]] for details.
*
* @param source The text to match against.
- * @return A [[scala.util.matching.Regex.MatchIterator]] of all matches.
+ * @return A [[scala.util.matching.Regex.MatchIterator]] of matched substrings.
* @example {{{for (words <- """\w+""".r findAllIn "A simple example.") yield words}}}
*/
def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames)
-
/** Return all non-overlapping matches of this regexp in given character sequence as a
* [[scala.collection.Iterator]] of [[scala.util.matching.Regex.Match]].
*
@@ -316,8 +377,8 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
}
}
- /** Return optionally first matching string of this regexp in given character sequence,
- * or None if it does not exist.
+ /** Return an optional first matching string of this `Regex` in the given character sequence,
+ * or None if there is no match.
*
* @param source The text to match against.
* @return An [[scala.Option]] of the first matching string in the text.
@@ -328,13 +389,11 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
if (m.find) Some(m.group) else None
}
- /** Return optionally first match of this regexp in given character sequence,
+ /** Return an optional first match of this `Regex` in the given character sequence,
* or None if it does not exist.
*
- * The main difference between this method and `findFirstIn` is that the (optional) return
- * type for this is [[scala.util.matching.Regex.Match]], through which more
- * data can be obtained about the match, such as the strings that precede and follow it,
- * or subgroups.
+ * If the match is successful, the [[scala.util.matching.Regex.Match]] can be queried for
+ * more data.
*
* @param source The text to match against.
* @return A [[scala.Option]] of [[scala.util.matching.Regex.Match]] of the first matching string in the text.
@@ -345,30 +404,28 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
if (m.find) Some(new Match(source, m, groupNames)) else None
}
- /** Return optionally match of this regexp at the beginning of the
- * given character sequence, or None if regexp matches no prefix
+ /** Return an optional match of this `Regex` at the beginning of the
+ * given character sequence, or None if it matches no prefix
* of the character sequence.
*
- * The main difference from this method to `findFirstIn` is that this
- * method will not return any matches that do not begin at the start
- * of the text being matched against.
+ * Unlike `findFirstIn`, this method will only return a match at
+ * the beginning of the input.
*
* @param source The text to match against.
* @return A [[scala.Option]] of the matched prefix.
- * @example {{{"""[a-z]""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}}
+ * @example {{{"""\p{Lower}""".r findPrefixOf "A simple example." // returns None, since the text does not begin with a lowercase letter}}}
*/
def findPrefixOf(source: CharSequence): Option[String] = {
val m = pattern.matcher(source)
if (m.lookingAt) Some(m.group) else None
}
- /** Return optionally match of this regexp at the beginning of the
- * given character sequence, or None if regexp matches no prefix
+ /** Return an optional match of this `Regex` at the beginning of the
+ * given character sequence, or None if it matches no prefix
* of the character sequence.
*
- * The main difference from this method to `findFirstMatchIn` is that
- * this method will not return any matches that do not begin at the
- * start of the text being matched against.
+ * Unlike `findFirstMatchIn`, this method will only return a match at
+ * the beginning of the input.
*
* @param source The text to match against.
* @return A [[scala.Option]] of the [[scala.util.matching.Regex.Match]] of the matched string.
@@ -402,7 +459,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
* import scala.util.matching.Regex
* val datePattern = new Regex("""(\d\d\d\d)-(\d\d)-(\d\d)""", "year", "month", "day")
* val text = "From 2011-07-15 to 2011-07-17"
- * val repl = datePattern replaceAllIn (text, m => m.group("month")+"/"+m.group("day"))
+ * val repl = datePattern replaceAllIn (text, m => s"${m group "month"}/${m group "day"}")
* }}}
*
* $replacementString
@@ -425,10 +482,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
* {{{
* import scala.util.matching.Regex._
*
- * val map = Map("x" -> "a var", "y" -> """some $ and \ signs""")
+ * val vars = Map("x" -> "a var", "y" -> """some $ and \ signs""")
* val text = "A text with variables %x, %y and %z."
* val varPattern = """%(\w+)""".r
- * val mapper = (m: Match) => map get (m group 1) map (quoteReplacement(_))
+ * val mapper = (m: Match) => vars get (m group 1) map (quoteReplacement(_))
* val repl = varPattern replaceSomeIn (text, mapper)
* }}}
*
@@ -469,17 +526,25 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
pattern.split(toSplit)
/** Create a new Regex with the same pattern, but no requirement that
- * the entire String matches in extractor patterns. For instance, the strings
- * shown below lead to successful matches, where they would not otherwise.
+ * the entire String matches in extractor patterns.
+ *
+ * Normally, matching on `date` behaves as though the pattern were
+ * enclosed in anchors, `"^pattern$"`.
+ *
+ * The unanchored `Regex` behaves as though those anchors were removed.
+ *
+ * Note that this method does not actually strip any matchers from the pattern.
+ *
+ * Calling `anchored` returns the original `Regex`.
*
* {{{
- * val dateP1 = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r.unanchored
*
- * val dateP1(year, month, day) = "Date 2011-07-15"
+ * val date(year, month, day) = "Date 2011-07-15" // OK
*
* val copyright: String = "Date of this document: 2011-07-15" match {
- * case dateP1(year, month, day) => "Copyright "+year
- * case _ => "No copyright"
+ * case date(year, month, day) => s"Copyright $year" // OK
+ * case _ => "No copyright"
* }
* }}}
*
@@ -494,6 +559,10 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends
override def toString = regex
}
+/** A [[Regex]] that finds the first match when used in a pattern match.
+ *
+ * @see [[Regex#unanchored]]
+ */
trait UnanchoredRegex extends Regex {
override protected def runMatcher(m: Matcher) = m.find()
override def unanchored = this
@@ -509,70 +578,79 @@ object Regex {
*/
trait MatchData {
- /** The source from where the match originated */
+ /** The source from which the match originated */
val source: CharSequence
- /** The names of the groups, or some empty sequence if one defined */
+ /** The names of the groups, or an empty sequence if none defined */
val groupNames: Seq[String]
- /** The number of subgroups in the pattern (not all of these need to match!) */
+ /** The number of capturing groups in the pattern.
+ * (For a given successful match, some of those groups may not have matched any input.)
+ */
def groupCount: Int
/** The index of the first matched character, or -1 if nothing was matched */
def start: Int
/** The index of the first matched character in group `i`,
- * or -1 if nothing was matched for that group */
+ * or -1 if nothing was matched for that group.
+ */
def start(i: Int): Int
- /** The index of the last matched character, or -1 if nothing was matched */
+ /** The index following the last matched character, or -1 if nothing was matched. */
def end: Int
/** The index following the last matched character in group `i`,
- * or -1 if nothing was matched for that group */
+ * or -1 if nothing was matched for that group.
+ */
def end(i: Int): Int
- /** The matched string, or `null` if nothing was matched */
+ /** The matched string, or `null` if nothing was matched. */
def matched: String =
if (start >= 0) source.subSequence(start, end).toString
else null
/** The matched string in group `i`,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def group(i: Int): String =
if (start(i) >= 0) source.subSequence(start(i), end(i)).toString
else null
- /** All matched subgroups, i.e., not including group(0) */
+ /** All capturing groups, i.e., not including group(0). */
def subgroups: List[String] = (1 to groupCount).toList map group
/** The char sequence before first character of match,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def before: CharSequence =
if (start >= 0) source.subSequence(0, start)
else null
/** The char sequence before first character of match in group `i`,
- * or `null` if nothing was matched for that group */
+ * or `null` if nothing was matched for that group.
+ */
def before(i: Int): CharSequence =
if (start(i) >= 0) source.subSequence(0, start(i))
else null
/** Returns char sequence after last character of match,
- * or `null` if nothing was matched */
+ * or `null` if nothing was matched.
+ */
def after: CharSequence =
if (end >= 0) source.subSequence(end, source.length)
else null
/** The char sequence after last character of match in group `i`,
- * or `null` if nothing was matched for that group */
+ * or `null` if nothing was matched for that group.
+ */
def after(i: Int): CharSequence =
if (end(i) >= 0) source.subSequence(end(i), source.length)
else null
private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex
- /** Returns the group with given name
+ /** Returns the group with given name.
*
* @param id The group name
* @return The requested group
@@ -583,24 +661,22 @@ object Regex {
case Some(index) => group(index)
}
- /** The matched string; equivalent to `matched.toString` */
+ /** The matched string; equivalent to `matched.toString`. */
override def toString = matched
-
}
- /** Provides information about a succesful match.
- */
+ /** Provides information about a successful match. */
class Match(val source: CharSequence,
private[matching] val matcher: Matcher,
val groupNames: Seq[String]) extends MatchData {
- /** The index of the first matched character */
+ /** The index of the first matched character. */
val start = matcher.start
- /** The index following the last matched character */
+ /** The index following the last matched character. */
val end = matcher.end
- /** The number of subgroups */
+ /** The number of subgroups. */
def groupCount = matcher.groupCount
private lazy val starts: Array[Int] =
@@ -608,19 +684,19 @@ object Regex {
private lazy val ends: Array[Int] =
((0 to groupCount) map matcher.end).toArray
- /** The index of the first matched character in group `i` */
+ /** The index of the first matched character in group `i`. */
def start(i: Int) = starts(i)
- /** The index following the last matched character in group `i` */
+ /** The index following the last matched character in group `i`. */
def end(i: Int) = ends(i)
/** The match itself with matcher-dependent lazy vals forced,
- * so that match is valid even once matcher is advanced
+ * so that match is valid even once matcher is advanced.
*/
def force: this.type = { starts; ends; this }
}
- /** An extractor object for Matches, yielding the matched string
+ /** An extractor object for Matches, yielding the matched string.
*
* This can be used to help writing replacer functions when you
* are not interested in match data. For example:
@@ -635,15 +711,15 @@ object Regex {
def unapply(m: Match): Some[String] = Some(m.matched)
}
- /** An extractor object that yields the groups in the match. Using an extractor
- * rather than the original regex avoids recomputing the match.
+ /** An extractor object that yields the groups in the match. Using this extractor
+ * rather than the original `Regex` ensures that the match is not recomputed.
*
* {{{
* import scala.util.matching.Regex.Groups
*
- * val datePattern = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
+ * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
* val text = "The doc spree happened on 2011-07-15."
- * val day = datePattern replaceAllIn(text, _ match { case Groups(year, month, day) => month+"/"+day })
+ * val day = date replaceAllIn(text, _ match { case Groups(_, month, day) => s"$month/$day" })
* }}}
*/
object Groups {
@@ -672,7 +748,7 @@ object Regex {
nextSeen
}
- /** The next matched substring of `source` */
+ /** The next matched substring of `source`. */
def next(): String = {
if (!hasNext) throw new NoSuchElementException
nextSeen = false
@@ -681,28 +757,28 @@ object Regex {
override def toString = super[AbstractIterator].toString
- /** The index of the first matched character */
+ /** The index of the first matched character. */
def start: Int = matcher.start
- /** The index of the first matched character in group `i` */
+ /** The index of the first matched character in group `i`. */
def start(i: Int): Int = matcher.start(i)
- /** The index of the last matched character */
+ /** The index of the last matched character. */
def end: Int = matcher.end
- /** The index following the last matched character in group `i` */
+ /** The index following the last matched character in group `i`. */
def end(i: Int): Int = matcher.end(i)
- /** The number of subgroups */
+ /** The number of subgroups. */
def groupCount = matcher.groupCount
- /** Convert to an iterator that yields MatchData elements instead of Strings */
+ /** Convert to an iterator that yields MatchData elements instead of Strings. */
def matchData: Iterator[Match] = new AbstractIterator[Match] {
def hasNext = self.hasNext
def next = { self.next(); new Match(source, matcher, groupNames).force }
}
- /** Convert to an iterator that yields MatchData elements instead of Strings and has replacement support */
+ /** Convert to an iterator that yields MatchData elements instead of Strings and has replacement support. */
private[matching] def replacementData = new AbstractIterator[Match] with Replacement {
def matcher = self.matcher
def hasNext = self.hasNext
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index 5b6ff2325c..3230fdbc67 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -9,6 +9,7 @@ package api
import scala.reflect.runtime.{universe => ru}
import scala.annotation.compileTimeOnly
+import java.io.ObjectStreamException
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
@@ -157,23 +158,23 @@ trait Exprs { self: Universe =>
|if you want to get a value of the underlying expression, add scala-compiler.jar to the classpath,
|import `scala.tools.reflect.Eval` and call `<your expr>.eval` instead.""".trim.stripMargin)
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedExpr(treec, implicitly[WeakTypeTag[T]].in(ru.rootMirror))
}
}
+@SerialVersionUID(1L)
private[scala] class SerializedExpr(var treec: TreeCreator, var tag: ru.WeakTypeTag[_]) extends Serializable {
- private def writeObject(out: java.io.ObjectOutputStream): Unit = {
- out.writeObject(treec)
- out.writeObject(tag)
- }
-
- private def readObject(in: java.io.ObjectInputStream): Unit = {
- treec = in.readObject().asInstanceOf[TreeCreator]
- tag = in.readObject().asInstanceOf[ru.WeakTypeTag[_]]
- }
+ import scala.reflect.runtime.universe.{Expr, runtimeMirror}
+ @throws(classOf[ObjectStreamException])
private def readResolve(): AnyRef = {
- import ru._
- Expr(rootMirror, treec)(tag)
+ val loader: ClassLoader = try {
+ Thread.currentThread().getContextClassLoader()
+ } catch {
+ case se: SecurityException => null
+ }
+ val m = runtimeMirror(loader)
+ Expr(m, treec)(tag.in(m))
}
}
diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala
index e905aa4153..eaae05bed5 100644
--- a/src/reflect/scala/reflect/api/Quasiquotes.scala
+++ b/src/reflect/scala/reflect/api/Quasiquotes.scala
@@ -13,7 +13,7 @@ trait Quasiquotes { self: Universe =>
protected trait api {
// implementation is hardwired to `dispatch` method of `scala.tools.reflect.quasiquotes.Quasiquotes`
// using the mechanism implemented in `scala.tools.reflect.FastTrack`
- def apply[T](args: T*): Tree = macro ???
+ def apply[A >: Any](args: A*): Tree = macro ???
def unapply(scrutinee: Any): Any = macro ???
}
object q extends api
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index dddd3c0e61..42cf600c85 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -260,6 +260,9 @@ trait Symbols { self: Universe =>
* with an object definition (module class in scala compiler parlance).
* If yes, `isType` is also guaranteed to be true.
*
+ * Note to compiler developers: During the "mixin" phase, trait implementation class symbols
+ * receive the `lateMODULE` flag, hence `isImplClass && isModuleClass` becomes true.
+ *
* @group Tests
*/
def isModuleClass: Boolean = false
diff --git a/src/reflect/scala/reflect/api/TreeCreator.scala b/src/reflect/scala/reflect/api/TreeCreator.scala
index 027c840955..000eaa1aa6 100644
--- a/src/reflect/scala/reflect/api/TreeCreator.scala
+++ b/src/reflect/scala/reflect/api/TreeCreator.scala
@@ -2,12 +2,12 @@ package scala
package reflect
package api
-/** This is an internal implementation class.
+/** A mirror-aware factory for trees.
*
* This class is used internally by Scala Reflection, and is not recommended for use in client code.
*
- * @group ReflectionAPI
+ * @group ReflectionAPI
*/
-abstract class TreeCreator {
+abstract class TreeCreator extends Serializable {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Tree
}
diff --git a/src/reflect/scala/reflect/api/TypeCreator.scala b/src/reflect/scala/reflect/api/TypeCreator.scala
index 37fff90b43..cbd55b9428 100644
--- a/src/reflect/scala/reflect/api/TypeCreator.scala
+++ b/src/reflect/scala/reflect/api/TypeCreator.scala
@@ -8,6 +8,6 @@ package api
*
* @group ReflectionAPI
*/
-abstract class TypeCreator {
+abstract class TypeCreator extends Serializable {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type
}
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
index 1dfc84be69..7db375ca61 100644
--- a/src/reflect/scala/reflect/api/TypeTags.scala
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -9,6 +9,7 @@ package api
import java.lang.{ Class => jClass }
import scala.language.implicitConversions
+import java.io.ObjectStreamException
/**
* A `TypeTag[T]` encapsulates the runtime type representation of some type `T`.
@@ -233,6 +234,7 @@ trait TypeTags { self: Universe =>
val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]]
otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec)
}
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false)
}
@@ -293,10 +295,13 @@ trait TypeTags { self: Universe =>
val otherMirror1 = otherMirror.asInstanceOf[scala.reflect.api.Mirror[otherMirror.universe.type]]
otherMirror.universe.TypeTag[T](otherMirror1, tpec)
}
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
}
/* @group TypeTags */
+ // This class only exists to silence MIMA complaining about a binary incompatibility.
+ // Only the top-level class (api.PredefTypeCreator) should be used.
private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator {
def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = {
copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
@@ -304,8 +309,9 @@ trait TypeTags { self: Universe =>
}
/* @group TypeTags */
- private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new PredefTypeCreator(copyIn)) {
+ private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new api.PredefTypeCreator(copyIn)) {
override lazy val tpe: Type = _tpe
+ @throws(classOf[ObjectStreamException])
private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
}
@@ -341,20 +347,27 @@ trait TypeTags { self: Universe =>
def symbolOf[T: WeakTypeTag]: TypeSymbol
}
+// This class should be final, but we can't do that in Scala 2.11.x without breaking
+// binary incompatibility.
+@SerialVersionUID(1L)
private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
- private def writeObject(out: java.io.ObjectOutputStream): Unit = {
- out.writeObject(tpec)
- out.writeBoolean(concrete)
- }
-
- private def readObject(in: java.io.ObjectInputStream): Unit = {
- tpec = in.readObject().asInstanceOf[TypeCreator]
- concrete = in.readBoolean()
+ import scala.reflect.runtime.universe.{TypeTag, WeakTypeTag, runtimeMirror}
+ @throws(classOf[ObjectStreamException])
+ private def readResolve(): AnyRef = {
+ val loader: ClassLoader = try {
+ Thread.currentThread().getContextClassLoader()
+ } catch {
+ case se: SecurityException => null
+ }
+ val m = runtimeMirror(loader)
+ if (concrete) TypeTag(m, tpec)
+ else WeakTypeTag(m, tpec)
}
+}
- private def readResolve(): AnyRef = {
- import scala.reflect.runtime.universe._
- if (concrete) TypeTag(rootMirror, tpec)
- else WeakTypeTag(rootMirror, tpec)
+/* @group TypeTags */
+private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator {
+ def apply[U <: Universe with Singleton](m: scala.reflect.api.Mirror[U]): U # Type = {
+ copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
}
}
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index f814a746f5..fcef4dd6be 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -388,11 +388,11 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
case Literal(const) => LiteralAnnotArg(const)
case Apply(ArrayModule, args) => ArrayAnnotArg(args map encodeJavaArg toArray)
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => NestedAnnotArg(treeToAnnotation(arg))
- case _ => throw new Exception("unexpected java argument shape $arg: literals, arrays and nested annotations are supported")
+ case _ => throw new Exception(s"unexpected java argument shape $arg: literals, arrays and nested annotations are supported")
}
def encodeJavaArgs(args: List[Tree]): List[(Name, ClassfileAnnotArg)] = args match {
case AssignOrNamedArg(Ident(name), arg) :: rest => (name, encodeJavaArg(arg)) :: encodeJavaArgs(rest)
- case arg :: rest => throw new Exception("unexpected java argument shape $arg: only AssignOrNamedArg trees are supported")
+ case arg :: rest => throw new Exception(s"unexpected java argument shape $arg: only AssignOrNamedArg trees are supported")
case Nil => Nil
}
val atp = tpt.tpe
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index bf560a21e5..02578e2038 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -836,12 +836,18 @@ trait Definitions extends api.StandardDefinitions {
def typeOfMemberNamedHead(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.head)())
def typeOfMemberNamedApply(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.apply)(IntTpe))
def typeOfMemberNamedDrop(tp: Type) = typeArgOfBaseTypeOr(tp, SeqClass)(resultOfMatchingMethod(tp, nme.drop)(IntTpe))
- def typesOfSelectors(tp: Type) = getterMemberTypes(tp, productSelectors(tp))
+ def typesOfSelectors(tp: Type) =
+ if (isTupleType(tp)) tp.typeArgs
+ else getterMemberTypes(tp, productSelectors(tp))
+
// SI-8128 Still using the type argument of the base type at Seq/Option if this is an old-style (2.10 compatible)
// extractor to limit exposure to regressions like the reported problem with existentials.
// TODO fix the existential problem in the general case, see test/pending/pos/t8128.scala
private def typeArgOfBaseTypeOr(tp: Type, baseClass: Symbol)(or: => Type): Type = (tp baseType baseClass).typeArgs match {
- case x :: Nil => x
+ case x :: Nil =>
+ val x1 = x
+ val x2 = repackExistential(x1)
+ x2
case _ => or
}
diff --git a/src/reflect/scala/reflect/internal/Internals.scala b/src/reflect/scala/reflect/internal/Internals.scala
index e9916cf7d1..26f3bfd9d0 100644
--- a/src/reflect/scala/reflect/internal/Internals.scala
+++ b/src/reflect/scala/reflect/internal/Internals.scala
@@ -129,7 +129,7 @@ trait Internals extends api.Internals {
def typeBounds(lo: Type, hi: Type): TypeBounds = self.TypeBounds(lo, hi)
def boundedWildcardType(bounds: TypeBounds): BoundedWildcardType = self.BoundedWildcardType(bounds)
- def subpatterns(tree: Tree): Option[List[Tree]] = tree.attachments.get[SubpatternsAttachment].map(_.patterns.map(_.duplicate))
+ def subpatterns(tree: Tree): Option[List[Tree]] = tree.attachments.get[SubpatternsAttachment].map(_.patterns.map(duplicateAndKeepPositions))
type Decorators = MacroDecoratorApi
lazy val decorators: Decorators = new MacroDecoratorApi {
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index 2caa30d27e..759bd2e791 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -866,7 +866,7 @@ trait ReificationSupport { self: SymbolTable =>
protected def mkCases(cases: List[Tree]): List[CaseDef] = cases.map {
case c: CaseDef => c
- case tree => throw new IllegalArgumentException("$tree is not valid representation of pattern match case")
+ case tree => throw new IllegalArgumentException(s"$tree is not valid representation of pattern match case")
}
object SyntacticPartialFunction extends SyntacticPartialFunctionExtractor {
diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala
index 423127803e..f2de83bc5d 100644
--- a/src/reflect/scala/reflect/internal/Reporting.scala
+++ b/src/reflect/scala/reflect/internal/Reporting.scala
@@ -89,6 +89,9 @@ abstract class Reporter {
def count(severity: Severity): Int
def resetCount(severity: Severity): Unit
+ def errorCount: Int = count(ERROR)
+ def warningCount: Int = count(WARNING)
+
def hasErrors: Boolean = count(ERROR) > 0
def hasWarnings: Boolean = count(WARNING) > 0
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 2ce54d2259..2670faa22d 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -55,25 +55,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def newFreeTypeSymbol(name: TypeName, flags: Long = 0L, origin: String): FreeTypeSymbol =
new FreeTypeSymbol(name, origin) initFlags flags
- /** The original owner of a class. Used by the backend to generate
- * EnclosingMethod attributes.
+ /**
+ * This map stores the original owner the the first time the owner of a symbol is re-assigned.
+ * The original owner of a symbol is needed in some places in the backend. Ideally, owners should
+ * be versioned like the type history.
*/
- val originalOwner = perRunCaches.newMap[Symbol, Symbol]()
+ private val originalOwnerMap = perRunCaches.newMap[Symbol, Symbol]()
// TODO - don't allow the owner to be changed without checking invariants, at least
// when under some flag. Define per-phase invariants for owner/owned relationships,
// e.g. after flatten all classes are owned by package classes, there are lots and
// lots of these to be declared (or more realistically, discovered.)
- protected def saveOriginalOwner(sym: Symbol) {
- if (originalOwner contains sym) ()
- else originalOwner(sym) = sym.rawowner
- }
- protected def originalEnclosingMethod(sym: Symbol): Symbol = {
- if (sym.isMethod || sym == NoSymbol) sym
- else {
- val owner = originalOwner.getOrElse(sym, sym.rawowner)
- if (sym.isLocalDummy) owner.enclClass.primaryConstructor
- else originalEnclosingMethod(owner)
+ protected def saveOriginalOwner(sym: Symbol): Unit = {
+ // some synthetic symbols have NoSymbol as owner initially
+ if (sym.owner != NoSymbol) {
+ if (originalOwnerMap contains sym) ()
+ else originalOwnerMap(sym) = sym.rawowner
}
}
@@ -757,8 +754,22 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* So "isModuleNotMethod" exists not for its achievement in
* brevity, but to encapsulate the relevant condition.
*/
- def isModuleNotMethod = isModule && !isMethod
- def isStaticModule = isModuleNotMethod && isStatic
+ def isModuleNotMethod = {
+ if (isModule) {
+ if (phase.refChecked) this.info // force completion to make sure lateMETHOD is there.
+ !isMethod
+ } else false
+ }
+
+ // After RefChecks, the `isStatic` check is mostly redundant: all non-static modules should
+ // be methods (and vice versa). There's a corner case on the vice-versa with mixed-in module
+ // symbols:
+ // trait T { object A }
+ // object O extends T
+ // The module symbol A is cloned into T$impl (addInterfaces), and then cloned into O (mixin).
+ // Since the original A is not static, it's turned into a method. The clone in O however is
+ // static (owned by a module), but it's also a method.
+ def isStaticModule = isModuleNotMethod && isStatic
final def isInitializedToDefault = !isType && hasAllFlags(DEFAULTINIT | ACCESSOR)
final def isThisSym = isTerm && owner.thisSym == this
@@ -775,7 +786,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
info.firstParent.typeSymbol == AnyValClass && !isPrimitiveValueClass
final def isMethodWithExtension =
- isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isMacro
+ isMethod && owner.isDerivedValueClass && !isParamAccessor && !isConstructor && !hasFlag(SUPERACCESSOR) && !isMacro && !isSpecialized
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
final def isDefinedInPackage = effectiveOwner.isPackageClass
@@ -909,10 +920,31 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
)
final def isModuleVar = hasFlag(MODULEVAR)
- /** Is this symbol static (i.e. with no outer instance)?
- * Q: When exactly is a sym marked as STATIC?
- * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or any number of levels deep.
- * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
+ /**
+ * Is this symbol static (i.e. with no outer instance)?
+ * Q: When exactly is a sym marked as STATIC?
+ * A: If it's a member of a toplevel object, or of an object contained in a toplevel object, or
+ * any number of levels deep.
+ * http://groups.google.com/group/scala-internals/browse_thread/thread/d385bcd60b08faf6
+ *
+ * TODO: should this only be invoked on class / module symbols? because there's also `isStaticMember`.
+ *
+ * Note: the result of `isStatic` changes over time.
+ * - Lambdalift local definitions to the class level, the `owner` field is modified.
+ * object T { def foo { object O } }
+ * After lambdalift, the OModule.isStatic is true.
+ *
+ * - After flatten, nested classes are moved to the package level. Invoking `owner` on a
+ * class returns a package class, for which `isStaticOwner` is true. For example,
+ * class C { object O }
+ * OModuleClass.isStatic is true after flatten. Using phase travel to get before flatten,
+ * method `owner` returns the class C.
+ *
+ * Why not make a stable version of `isStatic`? Maybe some parts of the compiler depend on the
+ * current implementation. For example
+ * trait T { def foo = 1 }
+ * The method `foo` in the implementation class T$impl will be `isStatic`, because trait
+ * impl classes get the `lateMODULE` flag (T$impl.isStaticOwner is true).
*/
def isStatic = (this hasFlag STATIC) || owner.isStaticOwner
@@ -1099,13 +1131,28 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// ------ owner attribute --------------------------------------------------------------
- /** In general when seeking the owner of a symbol, one should call `owner`.
- * The other possibilities include:
- * - call `safeOwner` if it is expected that the target may be NoSymbol
- * - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol
+ /**
+ * The owner of a symbol. Changes over time to adapt to the structure of the trees:
+ * - Up to lambdalift, the owner is the lexically enclosing definition. For definitions
+ * in a local block, the owner is also the next enclosing definition.
+ * - After lambdalift, all local method and class definitions (those not owned by a class
+ * or package class) change their owner to the enclosing class. This is done through
+ * a destructive "sym.owner = sym.owner.enclClass". The old owner is saved by
+ * saveOriginalOwner.
+ * - After flatten, all classes are owned by a PackageClass. This is done through a
+ * phase check (if after flatten) in the (overridden) method "def owner" in
+ * ModuleSymbol / ClassSymbol. The `rawowner` field is not modified.
+ * - Owners are also changed in other situations, for example when moving trees into a new
+ * lexical context, e.g. in the named/default arguments tranformation, or when translating
+ * extension method definitions.
+ *
+ * In general when seeking the owner of a symbol, one should call `owner`.
+ * The other possibilities include:
+ * - call `safeOwner` if it is expected that the target may be NoSymbol
+ * - call `assertOwner` if it is an unrecoverable error if the target is NoSymbol
*
- * `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev.
- * `assertOwner` aborts compilation immediately if called on NoSymbol.
+ * `owner` behaves like `safeOwner`, but logs NoSymbol.owner calls under -Xdev.
+ * `assertOwner` aborts compilation immediately if called on NoSymbol.
*/
def owner: Symbol = {
if (Statistics.hotEnabled) Statistics.incCounter(ownerCount)
@@ -1114,6 +1161,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
final def safeOwner: Symbol = if (this eq NoSymbol) NoSymbol else owner
final def assertOwner: Symbol = if (this eq NoSymbol) abort("no-symbol does not have an owner") else owner
+ /**
+ * The initial owner of this symbol.
+ */
+ def originalOwner: Symbol = originalOwnerMap.getOrElse(this, rawowner)
+
// TODO - don't allow the owner to be changed without checking invariants, at least
// when under some flag. Define per-phase invariants for owner/owned relationships,
// e.g. after flatten all classes are owned by package classes, there are lots and
@@ -1127,7 +1179,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
def ownerChain: List[Symbol] = this :: owner.ownerChain
- def originalOwnerChain: List[Symbol] = this :: originalOwner.getOrElse(this, rawowner).originalOwnerChain
// Non-classes skip self and return rest of owner chain; overridden in ClassSymbol.
def enclClassChain: List[Symbol] = owner.enclClassChain
@@ -2062,16 +2113,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* is not one. */
def enclosingPackage: Symbol = enclosingPackageClass.companionModule
- /** Return the original enclosing method of this symbol. It should return
- * the same thing as enclMethod when called before lambda lift,
- * but it preserves the original nesting when called afterwards.
- *
- * @note This method is NOT available in the presentation compiler run. The
- * originalOwner map is not populated for memory considerations (the symbol
- * may hang on to lazy types and in turn to whole (outdated) compilation units.
- */
- def originalEnclosingMethod: Symbol = Symbols.this.originalEnclosingMethod(this)
-
/** The method or class which logically encloses the current symbol.
* If the symbol is defined in the initialization part of a template
* this is the template's primary constructor, otherwise it is
@@ -2811,6 +2852,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def owner = {
if (Statistics.hotEnabled) Statistics.incCounter(ownerCount)
+ // a module symbol may have the lateMETHOD flag after refchecks, see isModuleNotMethod
if (!isMethod && needsFlatClasses) rawowner.owner
else rawowner
}
@@ -3471,7 +3513,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def rawInfo: Type = NoType
override def accessBoundary(base: Symbol): Symbol = enclosingRootClass
def cloneSymbolImpl(owner: Symbol, newFlags: Long) = abort("NoSymbol.clone()")
- override def originalEnclosingMethod = this
}
protected def makeNoSymbol: NoSymbol = new NoSymbol
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index 9066c73393..6e8e992d16 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -451,10 +451,10 @@ abstract class TreeGen {
def mkSyntheticUnit() = Literal(Constant(())).updateAttachment(SyntheticUnitAttachment)
/** Create block of statements `stats` */
- def mkBlock(stats: List[Tree]): Tree =
+ def mkBlock(stats: List[Tree], doFlatten: Boolean = true): Tree =
if (stats.isEmpty) mkSyntheticUnit()
else if (!stats.last.isTerm) Block(stats, mkSyntheticUnit())
- else if (stats.length == 1) stats.head
+ else if (stats.length == 1 && doFlatten) stats.head
else Block(stats.init, stats.last)
/** Create a block that wraps multiple statements but don't
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index b7d7d4df88..c521277f69 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -509,13 +509,6 @@ abstract class TreeInfo {
case _ => false
}
- /** The parameter ValDefs of a method definition that have vararg types of the form T*
- */
- def repeatedParams(tree: Tree): List[ValDef] = tree match {
- case DefDef(_, _, _, vparamss, _, _) => vparamss.flatten filter (vd => isRepeatedParamType(vd.tpt))
- case _ => Nil
- }
-
/** Is tpt a by-name parameter type of the form => T? */
def isByNameParamType(tpt: Tree) = tpt match {
case TypeTree() => definitions.isByNameParamType(tpt.tpe)
diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
index b808666360..8d4c3f752f 100644
--- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
+++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala
@@ -254,12 +254,13 @@ abstract class UnPickler {
// (4) Call the mirror's "missing" hook.
adjust(mirrorThatLoaded(owner).missingHook(owner, name)) orElse {
// (5) Create a stub symbol to defer hard failure a little longer.
- val fullName = s"${owner.fullName}.$name"
+ val advice = moduleAdvice(s"${owner.fullName}.$name")
val missingMessage =
- s"""|bad symbolic reference to $fullName encountered in class file '$filename'.
- |Cannot access ${name.longString} in ${owner.kindString} ${owner.fullName}. The current classpath may be
- |missing a definition for $fullName, or $filename may have been compiled against a version that's
- |incompatible with the one found on the current classpath.${moduleAdvice(fullName)}""".stripMargin
+ s"""|missing or invalid dependency detected while loading class file '$filename'.
+ |Could not access ${name.longString} in ${owner.kindString} ${owner.fullName},
+ |because it (or its dependencies) are missing. Check your build definition for
+ |missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
+ |A full rebuild may help if '$filename' was compiled against an incompatible version of ${owner.fullName}.$advice""".stripMargin
owner.newStubSymbol(name, missingMessage)
}
}
diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala
index 5ccdc15a03..b5c340645a 100644
--- a/src/reflect/scala/reflect/macros/Attachments.scala
+++ b/src/reflect/scala/reflect/macros/Attachments.scala
@@ -35,7 +35,7 @@ abstract class Attachments { self =>
def all: Set[Any] = Set.empty
private def matchesTag[T: ClassTag](datum: Any) =
- classTag[T].runtimeClass == datum.getClass
+ classTag[T].runtimeClass.isInstance(datum)
/** An underlying payload of the given class type `T`. */
def get[T: ClassTag]: Option[T] =
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 6584d80de3..b7f229b6e5 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -807,31 +807,26 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
// field containing the cache for structural calls.
if (mods.isStatic) module.moduleClass.orElse(clazz) else clazz
- /** Methods which need to be treated with care
- * because they either are getSimpleName or call getSimpleName:
+ /**
+ * Certain method of the Java reflection api cannot be used on classfiles created by Scala.
+ * See the comment in test/files/jvm/javaReflection/Test.scala. The methods are
*
* public String getSimpleName()
* public boolean isAnonymousClass()
* public boolean isLocalClass()
* public String getCanonicalName()
- *
- * A typical manifestation:
- *
- * // java.lang.Error: sOwner(class Test$A$1) has failed
- * // Caused by: java.lang.InternalError: Malformed class name
- * // at java.lang.Class.getSimpleName(Class.java:1133)
- * // at java.lang.Class.isAnonymousClass(Class.java:1188)
- * // at java.lang.Class.isLocalClass(Class.java:1199)
- * // (see t5256c.scala for more details)
+ * public boolean isSynthetic()
*
* TODO - find all such calls and wrap them.
* TODO - create mechanism to avoid the recurrence of unwrapped calls.
*/
implicit class RichClass(jclazz: jClass[_]) {
- // `jclazz.isLocalClass` doesn't work because of problems with `getSimpleName`
- // hence we have to approximate by removing the `isAnonymousClass` check
-// def isLocalClass0: Boolean = jclazz.isLocalClass
- def isLocalClass0: Boolean = jclazz.getEnclosingMethod != null || jclazz.getEnclosingConstructor != null
+ // As explained in the javaReflection test, Class.isLocalClass is true for all non-member
+ // nested classes in Scala. This is fine per se, however the implementation may throw an
+ // InternalError. We therefore re-implement it here.
+ // TODO: this method should be renamed to `isLocalOrAnonymousClass`.
+ // due to bin compat that's only possible in 2.12, we cannot introduce a new alias in 2.11.
+ def isLocalClass0: Boolean = jclazz.getEnclosingClass != null && !jclazz.isMemberClass
}
/**
diff --git a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
index 7ba68b8733..50ea8d9868 100644
--- a/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
+++ b/src/reflect/scala/reflect/runtime/SymbolLoaders.scala
@@ -65,10 +65,15 @@ private[reflect] trait SymbolLoaders { self: SymbolTable =>
class LazyPackageType extends LazyType with FlagAgnosticCompleter {
override def complete(sym: Symbol) {
assert(sym.isPackageClass)
- sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
+ // Time travel to a phase before refchecks avoids an initialization issue. `openPackageModule`
+ // creates a module symbol and invokes invokes `companionModule` while the `infos` field is
+ // still null. This calls `isModuleNotMethod`, which forces the `info` if run after refchecks.
+ slowButSafeEnteringPhaseNotLaterThan(picklerPhase) {
+ sym setInfo new ClassInfoType(List(), new PackageScope(sym), sym)
// override def safeToString = pkgClass.toString
- openPackageModule(sym)
- markAllCompleted(sym)
+ openPackageModule(sym)
+ markAllCompleted(sym)
+ }
}
}
diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
index ce0eadc04f..50c89f7442 100644
--- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala
+++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala
@@ -430,7 +430,14 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter)
import scala.concurrent.duration._
Await.ready(globalFuture, 60.seconds)
- (line ne null) && (command(line) match {
+ if (line eq null) {
+ // SI-4563: this means the console was properly interrupted (Ctrl+D usually)
+ // so we display the output message (which by default ends with
+ // a newline so as not to break the user's terminal)
+ if (in.interactive) out.print(Properties.shellInterruptedString)
+
+ false
+ } else (command(line) match {
case Result(false, _) => false
case Result(_, Some(line)) => addReplay(line) ; true
case _ => true
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index 8ea8759ee5..6e30b73e0e 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -1121,7 +1121,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
def apply(line: String): Result = debugging(s"""parse("$line")""") {
var isIncomplete = false
- currentRun.reporting.withIncompleteHandler((_, _) => isIncomplete = true) {
+ currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true) {
reporter.reset()
val trees = newUnitParser(line).parseStats()
if (reporter.hasErrors) Error
diff --git a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
index f4cbcb50fe..a37cdc2ec8 100644
--- a/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
+++ b/src/repl/scala/tools/nsc/interpreter/MemberHandlers.scala
@@ -116,7 +116,7 @@ trait MemberHandlers {
else any2stringOf(path, maxStringElements)
val vidString =
- if (replProps.vids) s"""" + " @ " + "%%8x".format(System.identityHashCode($path)) + " """.trim
+ if (replProps.vids) s"""" + f"@$${System.identityHashCode($path)}%8x" + """"
else ""
""" + "%s%s: %s = " + %s""".format(string2code(prettyName), vidString, string2code(req typeOf name), resultString)
diff --git a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
index 10c382e169..cbf8ff22ba 100644
--- a/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/ScaladocAnalyzer.scala
@@ -190,7 +190,7 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
typeParams.nonEmpty || version.nonEmpty || since.nonEmpty
}
def isDirty = unclean(unmooredParser parseComment doc)
- if ((doc ne null) && (settings.lint || isDirty))
+ if ((doc ne null) && (settings.warnDocDetached || isDirty))
reporter.warning(doc.pos, "discarding unmoored doc comment")
}
@@ -208,7 +208,7 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
super.skipDocComment()
}
override def skipBlockComment(): Unit = {
- inDocComment = false
+ inDocComment = false // ??? this means docBuffer won't receive contents of this comment???
docBuffer = new StringBuilder("/*")
super.skipBlockComment()
}
@@ -217,9 +217,10 @@ abstract class ScaladocSyntaxAnalyzer[G <: Global](val global: G) extends Syntax
def foundStarComment(start: Int, end: Int) = try {
val str = docBuffer.toString
val pos = Position.range(unit.source, start, start, end)
- unit.comment(pos, str)
- if (inDocComment)
+ if (inDocComment) {
+ signalParsedDocComment(str, pos)
lastDoc = DocComment(str, pos)
+ }
true
} finally {
docBuffer = null
diff --git a/src/scaladoc/scala/tools/nsc/doc/Settings.scala b/src/scaladoc/scala/tools/nsc/doc/Settings.scala
index 02929c5ecb..44683f1755 100644
--- a/src/scaladoc/scala/tools/nsc/doc/Settings.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/Settings.scala
@@ -249,7 +249,7 @@ class Settings(error: String => Unit, val printMsg: String => Unit = println(_))
val idx = s.indexOf("#")
if (idx > 0) {
val (first, last) = s.splitAt(idx)
- Some(new File(first).getAbsolutePath -> appendIndex(last.substring(1)))
+ Some(new File(first).getCanonicalPath -> appendIndex(last.substring(1)))
} else {
error(s"Illegal -doc-external-doc option; expected a pair with '#' separator, found: '$s'")
None
diff --git a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
index 339129bdbc..64eb1adbea 100644
--- a/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/model/MemberLookup.scala
@@ -45,7 +45,7 @@ trait MemberLookup extends base.MemberLookupBase {
sym.info.member(newTermName("package"))
else sym
Option(sym1.associatedFile) flatMap (_.underlyingSource) flatMap { src =>
- val path = src.path
+ val path = src.canonicalPath
settings.extUrlMapping get path map { url =>
LinkToExternal(name, url + "#" + name)
}
diff --git a/test/files/jvm/innerClassAttribute.check b/test/files/jvm/innerClassAttribute.check
new file mode 100644
index 0000000000..20518aa49e
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute.check
@@ -0,0 +1,54 @@
+#partest !-Ydelambdafy:method
+-- A4 --
+A4$$anonfun$f$1 / null / null / 17
+A4$$anonfun$f$1 / null / null / 17
+A4 / f / (Lscala/collection/immutable/List;)Lscala/collection/immutable/List;
+-- A19 --
+A19$$anonfun$1 / null / null / 17
+A19$$anonfun$2 / null / null / 17
+A19$$anonfun$3 / null / null / 17
+A19$$anonfun$1 / null / null / 17
+A19$$anonfun$2 / null / null / 17
+A19$$anonfun$3 / null / null / 17
+A19 / null / null
+A19 / null / null
+A19 / null / null
+-- A20 --
+A20$$anonfun$4 / null / null / 17
+fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`
+A20$$anonfun$4 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$1 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
+fun2 () => (): itself and the outer closure
+A20$$anonfun$4 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$1 / null / null / 17
+fun3 () => () => (): itself, the outer closure and its child closure
+A20$$anonfun$4 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
+fun4: () => 1: itself and the two outer closures
+A20$$anonfun$4 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$3 / null / null / 17
+A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2 / null / null / 17
+enclosing: nested closures have the apply method of the outer closure
+A20 / null / null
+A20$$anonfun$4 / apply / ()Lscala/Function0;
+A20$$anonfun$4 / apply / ()Lscala/Function0;
+A20$$anonfun$4$$anonfun$apply$3 / apply / ()Lscala/Function0;
+#partest -Ydelambdafy:method
+-- A4 --
+null / null / null
+-- A19 --
+null / null / null
+null / null / null
+null / null / null
+-- A20 --
+fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`
+fun2 () => (): itself and the outer closure
+fun3 () => () => (): itself, the outer closure and its child closure
+fun4: () => 1: itself and the two outer closures
+enclosing: nested closures have the apply method of the outer closure
+null / null / null
+null / null / null
+null / null / null
+null / null / null
diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala
new file mode 100644
index 0000000000..9c3ea7f013
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/Classes_1.scala
@@ -0,0 +1,187 @@
+class A1 {
+ class B
+}
+
+class A2 {
+ object B
+}
+
+object A3 {
+ class B1
+ object B2
+}
+
+class A4 {
+ def f(l: List[Int]): List[Int] = {
+ l map (_ + 1)
+ }
+}
+
+class A5 {
+ def f(): Object = {
+ object B
+ B
+ }
+}
+
+trait A6 {
+ def hui = -6
+ trait TT
+}
+
+class A7 extends A6
+
+abstract class A8 extends A6 {
+ def fish: TT
+}
+
+class A9 {
+ class brick extends annotation.StaticAnnotation
+}
+
+class A10 {
+ val a9 = new A9()
+ // there's no reference to brick in the bytecode (only in the pickle), so there's no InnerClass attribute for it.
+ @a9.brick def f = -7
+}
+
+class A11 {
+ @JavaAnnot_1.Ann def f = -8
+}
+
+object A12 {
+ object B {
+ class C
+ }
+}
+
+class A13 {
+ def oak: A12.B.C = new A12.B.C
+}
+
+class A14 {
+ def f = {
+ val x: Object = {
+ class K
+ new K
+ }
+ x
+ }
+ def g = {
+ val x: Object = new A6 { }
+ }
+}
+
+object A15 {
+ def f = {
+ class B { // non-static, even though it doesn't have an outer pointer
+ class C // non-static
+ }
+ }
+}
+
+class A16 {
+ val x: A6 = {
+ class U extends A6
+ new A6 { }
+ }
+
+ {
+ class V extends A6
+ new A6 { }
+ }
+
+ new A6 { }
+}
+
+class A17 {
+ object B {
+ class C // not static, also has an outer pointer.
+ }
+}
+
+class A18 {
+ def f = {
+ def g = {
+ class A
+ new A6 { }
+ val y = {
+ if ((new Object).hashCode() == 1) {class B {} ; new B} else 2
+ if ((new Object).hashCode() == 1) new A6 { } else "haifish"
+ }
+ }
+ }
+}
+
+class A19 {
+ ((x: Int) => x + 3)
+
+ val x = {
+ ((x: Int) => x + 1)
+ }
+
+ {
+ ((x: Int) => x + 2)
+ }
+}
+
+class A20 {
+ () => {
+ {() => ()}
+ {() => () => 1}
+ }
+}
+
+class A21 {
+ class I1
+ def f = { class J1 }
+}
+object A21 {
+ class I2
+ object I3 {
+ class J2 // static
+ }
+ def g = { class J3 } // non-static
+ val x = { class J4 } // non-static
+ {
+ class J5 // non-static (!)
+ new J5
+ }
+}
+
+class A22 {
+ class C
+ object C {
+ class D // inner class of C$, not of C. Not added to the inner class table of C, only to C$
+ }
+}
+
+class A23 {
+ def f = {
+ val a = new Java_A_1()
+ val c = new Java_A_1.C()
+ val d = new Java_A_1.C.D()
+ val e = new c.E()
+ val f = new a.F()
+ val g = new f.G()
+ }
+}
+
+trait A24Sym
+
+trait A24Base {
+ // trait with concrete members: interface plus (absract) impl class
+ trait DefinitionsApi {
+ def Abs: A24Sym
+ def Conc: A24Sym = new A24Sym { }
+ }
+}
+
+trait A24 extends A24Base {
+ class DefinitionsClass extends DefinitionsApi {
+ // bridge methods are generated for Abs and Conc. there used to be a bug: the bridge symbol was a ModuleSymbol,
+ // calling companionClass would return NoSymbol. i changed erasure to make the bridge symbol is a MethodSymbol.
+ object Abs extends A24Sym
+ override object Conc extends A24Sym
+ }
+}
diff --git a/test/files/jvm/innerClassAttribute/JavaAnnot_1.java b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java
new file mode 100644
index 0000000000..27c4d4e5d3
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java
@@ -0,0 +1,3 @@
+public class JavaAnnot_1 {
+ public static @interface Ann {}
+}
diff --git a/test/files/jvm/innerClassAttribute/Java_A_1.java b/test/files/jvm/innerClassAttribute/Java_A_1.java
new file mode 100644
index 0000000000..3357d05e2b
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/Java_A_1.java
@@ -0,0 +1,10 @@
+public class Java_A_1 {
+ public static class C {
+ public static class D { }
+ public class E { }
+ }
+
+ public class F {
+ public class G { }
+ }
+}
diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala
new file mode 100644
index 0000000000..882edbcdd7
--- /dev/null
+++ b/test/files/jvm/innerClassAttribute/Test.scala
@@ -0,0 +1,352 @@
+import scala.tools.partest.BytecodeTest
+import scala.tools.asm
+import asm.tree.{ClassNode, InnerClassNode}
+import asm.{Opcodes => Flags}
+import scala.collection.JavaConverters._
+
+object Test extends BytecodeTest {
+ def assertSame(a: Any, b: Any) = {
+ assert(a == b, s"\na: $a\nb: $b")
+ }
+
+ val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC
+ val publicAbstractInterface = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT | Flags.ACC_INTERFACE
+
+ def innerClassNodes(className: String): List[InnerClassNode] = {
+ loadClassNode(className).innerClasses.asScala.toList.sortBy(_.name)
+ }
+
+ final case class EnclosingMethod(name: String, descriptor: String, outerClass: String)
+ def enclosingMethod(className: String) = {
+ val n = loadClassNode(className)
+ EnclosingMethod(n.outerMethod, n.outerMethodDesc, n.outerClass)
+ }
+
+ def assertMember(node: InnerClassNode, outer: String, inner: String, name: Option[String] = None, flags: Int = Flags.ACC_PUBLIC) = {
+ assertSame(node.name, name.getOrElse(s"$outer$$$inner"))
+ assertSame(node.outerName, outer)
+ assertSame(node.innerName, inner)
+ assertSame(node.access, flags)
+ }
+
+ def assertAnonymous(node: InnerClassNode, name: String, flags: Int = Flags.ACC_PUBLIC | Flags.ACC_FINAL) = {
+ assertSame(node.name, name)
+ assertSame(node.outerName, null)
+ assertSame(node.innerName, null)
+ assertSame(node.access, flags)
+ }
+
+ def assertLocal(node: InnerClassNode, name: String, inner: String, flags: Int = Flags.ACC_PUBLIC) = {
+ assertSame(node.name, name)
+ assertSame(node.outerName, null)
+ assertSame(node.innerName, inner)
+ assertSame(node.access, flags)
+ }
+
+ def assertEnclosingMethod(className: String, outerClass: String, name: String, descriptor: String) = {
+ val encl = enclosingMethod(className)
+ assertSame(encl.outerClass, outerClass)
+ assertSame(encl.name, name)
+ assertSame(encl.descriptor, descriptor)
+ }
+
+ def assertNoEnclosingMethod(className: String) = {
+ assertSame(enclosingMethod(className).outerClass, null)
+ }
+
+ def printInnerClassNodes(className: String) = {
+ for (n <- innerClassNodes(className)) {
+ println(s"${n.name} / ${n.outerName} / ${n.innerName} / ${n.access}")
+ }
+ }
+
+ def printEnclosingMethod(className: String) = {
+ val e = enclosingMethod(className)
+ println(s"${e.outerClass} / ${e.name} / ${e.descriptor}")
+ }
+
+ def lambdaClass(anonfunName: String, lambdaName: String): String = {
+ if (classpath.findClass(anonfunName).isDefined) anonfunName else lambdaName
+ }
+
+ def testA1() = {
+ val List(b1) = innerClassNodes("A1")
+ assertMember(b1, "A1", "B")
+ val List(b2) = innerClassNodes("A1$B")
+ assertMember(b2, "A1", "B")
+ }
+
+ def testA2() = {
+ val List(b1) = innerClassNodes("A2")
+ assertMember(b1, "A2", "B$")
+ val List(b2) = innerClassNodes("A2$B$")
+ assertMember(b2, "A2", "B$")
+ }
+
+ def testA3() = {
+ def t(c: String) = {
+ val List(b1, b2) = innerClassNodes(c)
+ // the outer class for classes nested inside top-level modules is not the module class, but the mirror class.
+ // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility".
+ assertMember(b1, "A3", "B1", flags = publicStatic)
+ assertMember(b2, "A3", "B2$", flags = publicStatic)
+ }
+ t("A3$")
+ // the mirror class has the same inner class attributes as the module
+ // class (added when the mirror is created in the backend)
+ t("A3")
+ }
+
+ def testA4() = {
+ println("-- A4 --")
+ printInnerClassNodes("A4")
+ val fun = lambdaClass("A4$$anonfun$f$1", "A4$lambda$$f$1")
+ printInnerClassNodes(fun)
+ printEnclosingMethod(fun)
+ }
+
+ def testA5() = {
+ val List(b1) = innerClassNodes("A5")
+ assertLocal(b1, "A5$B$2$", "B$2$")
+ val List(b2) = innerClassNodes("A5$B$2$")
+ assertLocal(b2, "A5$B$2$", "B$2$")
+ assertEnclosingMethod(
+ "A5$B$2$",
+ "A5", "f", "()Ljava/lang/Object;")
+ }
+
+ def testA6() = {
+ val List(tt1) = innerClassNodes("A6")
+ assertMember(tt1, "A6", "TT", flags = publicAbstractInterface)
+ val List() = innerClassNodes("A6$class")
+ val List(tt2) = innerClassNodes("A6$TT")
+ assertMember(tt2, "A6", "TT", flags = publicAbstractInterface)
+ }
+
+ def testA7() = {
+ val List() = innerClassNodes("A7")
+ }
+
+ def testA8() = {
+ val List(tt) = innerClassNodes("A8")
+ assertMember(tt, "A6", "TT", flags = publicAbstractInterface)
+ }
+
+ def testA10() = {
+ val List() = innerClassNodes("A10")
+ }
+
+ def testA11() = {
+ val List(ann) = innerClassNodes("A11")
+ // in the java class file, the INNERCLASS attribute has more flags (public | static | abstract | interface | annotation)
+ // the scala compiler has its own interpretation of java annotations ant their flags.. it only emits publicStatic.
+ assertMember(ann, "JavaAnnot_1", "Ann", flags = publicStatic)
+ }
+
+ def testA13() = {
+ val List(b, c) = innerClassNodes("A13")
+ assertMember(b, "A12", "B$", flags = publicStatic)
+ assertMember(c, "A12$B$", "C", name = Some("A12$B$C"), flags = publicStatic)
+ }
+
+ def testA14() = {
+ val List(anon, k) = innerClassNodes("A14")
+
+ assertLocal(k, "A14$K$1", "K$1")
+ assertEnclosingMethod(
+ "A14$K$1",
+ "A14", "f", "()Ljava/lang/Object;")
+
+ assertAnonymous(anon, "A14$$anon$1")
+ assertEnclosingMethod(
+ "A14$$anon$1",
+ "A14", "g", "()V")
+ }
+
+ def testA15() = {
+ val List(b) = innerClassNodes("A15")
+ assertLocal(b, "A15$B$3", "B$3")
+
+ val List(_, c) = innerClassNodes("A15$B$3")
+ assertMember(c, "A15$B$3", "C")
+
+ assertEnclosingMethod(
+ "A15$B$3",
+ "A15$", "f", "()V")
+ assertNoEnclosingMethod("A15$B$3$C")
+ }
+
+ def testA16() = {
+ val List(anon1, anon2, anon3, u, v) = innerClassNodes("A16")
+ assertAnonymous(anon1, "A16$$anon$2")
+ assertAnonymous(anon2, "A16$$anon$3")
+ assertAnonymous(anon3, "A16$$anon$4")
+
+ assertLocal(u, "A16$U$1", "U$1")
+ assertLocal(v, "A16$V$1", "V$1")
+
+ assertEnclosingMethod(
+ "A16$$anon$2",
+ "A16", null, null)
+ assertEnclosingMethod(
+ "A16$$anon$3",
+ "A16", null, null)
+ assertEnclosingMethod(
+ "A16$$anon$4",
+ "A16", null, null)
+
+ assertEnclosingMethod(
+ "A16$U$1",
+ "A16", null, null)
+ assertEnclosingMethod(
+ "A16$V$1",
+ "A16", null, null)
+ }
+
+ def testA17() = {
+ val List(b, c) = innerClassNodes("A17$B$")
+ assertMember(b, "A17", "B$")
+ assertMember(c, "A17$B$", "C", name = Some("A17$B$C")) // not static, has an outer pointer.
+ }
+
+ def testA18() = {
+ val List(anon1, anon2, a, b) = innerClassNodes("A18")
+ assertAnonymous(anon1, "A18$$anon$5")
+ assertAnonymous(anon2, "A18$$anon$6")
+
+ assertLocal(a, "A18$A$1", "A$1")
+ assertLocal(b, "A18$B$4", "B$4")
+
+ assertEnclosingMethod(
+ "A18$$anon$5",
+ "A18", "g$1", "()V")
+ assertEnclosingMethod(
+ "A18$$anon$6",
+ "A18", "g$1", "()V")
+
+ assertEnclosingMethod(
+ "A18$A$1",
+ "A18", "g$1", "()V")
+ assertEnclosingMethod(
+ "A18$B$4",
+ "A18", "g$1", "()V")
+ }
+
+ def testA19() = {
+ println("-- A19 --")
+
+ printInnerClassNodes("A19")
+
+ val fun1 = lambdaClass("A19$$anonfun$1", "A19$lambda$1")
+ val fun2 = lambdaClass("A19$$anonfun$2", "A19$lambda$2")
+ val fun3 = lambdaClass("A19$$anonfun$3", "A19$lambda$3")
+
+ printInnerClassNodes(fun1)
+ printInnerClassNodes(fun2)
+ printInnerClassNodes(fun3)
+
+ printEnclosingMethod(fun1)
+ printEnclosingMethod(fun2)
+ printEnclosingMethod(fun3)
+ }
+
+ def testA20() = {
+ println("-- A20 --")
+
+ printInnerClassNodes("A20")
+
+ val fun1 = lambdaClass("A20$$anonfun$4", "A20$lambda$1")
+ val fun2 = lambdaClass("A20$$anonfun$4$$anonfun$apply$1", "A20$lambda$$$anonfun$5$1")
+ val fun3 = lambdaClass("A20$$anonfun$4$$anonfun$apply$3", "A20$lambda$$$anonfun$5$2")
+ val fun4 = lambdaClass("A20$$anonfun$4$$anonfun$apply$3$$anonfun$apply$2", "A20$lambda$$$anonfun$7$1")
+
+ println("fun1: attribute for itself and the two child closures `() => ()` and `() => () => 1`")
+ printInnerClassNodes(fun1)
+ println("fun2 () => (): itself and the outer closure")
+ printInnerClassNodes(fun2)
+ println("fun3 () => () => (): itself, the outer closure and its child closure")
+ printInnerClassNodes(fun3)
+ println("fun4: () => 1: itself and the two outer closures")
+ printInnerClassNodes(fun4)
+
+ println("enclosing: nested closures have the apply method of the outer closure")
+ printEnclosingMethod(fun1)
+ printEnclosingMethod(fun2)
+ printEnclosingMethod(fun3)
+ printEnclosingMethod(fun4)
+ }
+
+ def testA21() = {
+ val List(i1c, i2c, i3c, j1) = innerClassNodes("A21")
+ assertMember(i1c, "A21", "I1")
+ assertMember(i2c, "A21", "I2", flags = publicStatic)
+ assertMember(i3c, "A21", "I3$", flags = publicStatic)
+ assertLocal(j1, "A21$J1$1", "J1$1")
+
+ val List(i2m, i3m, j3, j4, j5) = innerClassNodes("A21$")
+ assertMember(i2m, "A21", "I2", flags = publicStatic)
+ assertMember(i3m, "A21", "I3$", flags = publicStatic)
+ assertLocal(j3, "A21$J3$1", "J3$1")
+ assertLocal(j4, "A21$J4$1", "J4$1")
+ assertLocal(j5, "A21$J5$1", "J5$1") // non-static!
+
+ val List(i3x, j2x) = innerClassNodes("A21$I3$J2")
+ assertMember(j2x, "A21$I3$", "J2", name = Some("A21$I3$J2"), flags = publicStatic)
+
+ assertNoEnclosingMethod("A21$I3$J2")
+ assertEnclosingMethod("A21$J3$1", "A21$", "g", "()V")
+ assertEnclosingMethod("A21$J4$1", "A21$", null, null)
+ assertEnclosingMethod("A21$J5$1", "A21$", null, null)
+ }
+
+ def testA22() = {
+ val List(cc) = innerClassNodes("A22$C")
+ assertMember(cc, "A22", "C")
+ val List(cm, d) = innerClassNodes("A22$C$")
+ assertMember(cm, "A22", "C$")
+ assertMember(d, "A22$C$", "D", name = Some("A22$C$D"))
+ }
+
+ def testA23() {
+ val List(c, d, e, f, g) = innerClassNodes("A23")
+ assertMember(c, "Java_A_1", "C", flags = publicStatic)
+ assertMember(d, "Java_A_1$C", "D", flags = publicStatic)
+ assertMember(e, "Java_A_1$C", "E")
+ assertMember(f, "Java_A_1", "F")
+ assertMember(g, "Java_A_1$F", "G")
+ }
+
+ def testA24() {
+ val List(defsCls, abs, conc, defsApi, defsApiImpl) = innerClassNodes("A24$DefinitionsClass")
+ assertMember(defsCls, "A24", "DefinitionsClass")
+ assertMember(abs, "A24$DefinitionsClass", "Abs$")
+ assertMember(conc, "A24$DefinitionsClass", "Conc$")
+ assertMember(defsApi, "A24Base", "DefinitionsApi", flags = publicAbstractInterface)
+ assertMember(defsApiImpl, "A24Base", "DefinitionsApi$class", flags = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT)
+ }
+
+ def show(): Unit = {
+ testA1()
+ testA2()
+ testA3()
+ testA4()
+ testA5()
+ testA6()
+ testA7()
+ testA8()
+ testA10()
+ testA11()
+ testA13()
+ testA14()
+ testA15()
+ testA16()
+ testA17()
+ testA18()
+ testA19()
+ testA20()
+ testA21()
+ testA22()
+ testA23()
+ testA24()
+ }
+}
diff --git a/test/files/jvm/interpreter.check b/test/files/jvm/interpreter.check
index d124794e72..d03edb638c 100644
--- a/test/files/jvm/interpreter.check
+++ b/test/files/jvm/interpreter.check
@@ -361,7 +361,7 @@ It would fail on the following inputs: Exp(), Term()
^
f: (e: Exp)Int
-scala>
+scala> :quit
plusOne: (x: Int)Int
res0: Int = 6
res0: String = after reset
diff --git a/test/files/jvm/javaReflection.check b/test/files/jvm/javaReflection.check
new file mode 100644
index 0000000000..aeb894f741
--- /dev/null
+++ b/test/files/jvm/javaReflection.check
@@ -0,0 +1,259 @@
+#partest !-Ydelambdafy:method
+A$$anonfun$$lessinit$greater$1 / null (canon) / $anonfun$$lessinit$greater$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / public A(int) (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anonfun$$lessinit$greater$1$$anonfun$apply$1 / null (canon) / $anonfun$apply$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A$$anonfun$$lessinit$greater$1 (cls) / null (constr) / public final scala.Function0 A$$anonfun$$lessinit$greater$1.apply() (meth)
+- properties : true (local) / false (member)
+A$$anonfun$2 / null (canon) / $anonfun$2 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anonfun$3 / null (canon) / $anonfun$3 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anonfun$4 / null (canon) / $anonfun$4 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anonfun$f$1 / null (canon) / $anonfun$f$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$$anonfun$f$2 / null (canon) / $anonfun$f$2 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$D$$anonfun$1 / null (canon) / anonfun$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+AO$$anonfun$5 / null (canon) / anonfun$5 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class AO$ (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+AT$$anonfun$6 / null (canon) / $anonfun$6 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / interface AT (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+#partest -Ydelambdafy:method
+A$D$lambda$1 / A$D$lambda$1 (canon) / A$D$lambda$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$$$anonfun$7$1 / A$lambda$$$anonfun$7$1 (canon) / A$lambda$$$anonfun$7$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$$$lessinit$greater$1 / A$lambda$$$lessinit$greater$1 (canon) / A$lambda$$$lessinit$greater$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$$f$1 / A$lambda$$f$1 (canon) / A$lambda$$f$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$$f$2 / A$lambda$$f$2 (canon) / A$lambda$$f$2 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$1 / A$lambda$1 (canon) / A$lambda$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$2 / A$lambda$2 (canon) / A$lambda$2 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$lambda$3 / A$lambda$3 (canon) / A$lambda$3 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+AO$lambda$1 / AO$lambda$1 (canon) / AO$lambda$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+AT$class$lambda$1 / AT$class$lambda$1 (canon) / AT$class$lambda$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+#partest
+A / A (canon) / A (simple)
+- declared cls: List(class A$B, interface A$C, class A$D$)
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+A$$anon$1 / null (canon) / $anon$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anon$3 / null (canon) / $anon$3 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anon$4 / null (canon) / $anon$4 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$$anon$5 / null (canon) / $anon$5 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$$anon$6 / null (canon) / $anon$6 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$$anon$7 / null (canon) / $anon$7 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / public A(int) (constr) / null (meth)
+- properties : true (local) / false (member)
+A$B / A.B (canon) / B (simple)
+- declared cls: List()
+- enclosing : class A (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$C / A.C (canon) / C (simple)
+- declared cls: List()
+- enclosing : class A (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$D$ / A.D$ (canon) / D$ (simple)
+- declared cls: List(class A$D$B, interface A$D$C, class A$D$D$)
+- enclosing : class A (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$D$$anon$2 / null (canon) / anon$2 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$D$B / Malformed class name (canon) / Malformed class name (simple)
+- declared cls: List()
+- enclosing : class A$D$ (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$D$C / Malformed class name (canon) / Malformed class name (simple)
+- declared cls: List()
+- enclosing : class A$D$ (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$D$D$ / Malformed class name (canon) / Malformed class name (simple)
+- declared cls: List()
+- enclosing : class A$D$ (declaring cls) / class A$D$ (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+A$D$KB$1 / null (canon) / Malformed class name (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A$D$ (cls) / null (constr) / public void A$D$.f() (meth)
+- properties : Malformed class name (local) / false (member)
+A$E$1 / null (canon) / E$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$F$1 / null (canon) / F$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$G$2$ / null (canon) / G$2$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$H$1 / null (canon) / H$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$I$1 / null (canon) / I$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$J$2$ / null (canon) / J$2$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / public java.lang.Object A.f() (meth)
+- properties : true (local) / false (member)
+A$K$1 / null (canon) / K$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$L$1 / null (canon) / L$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$M$2$ / null (canon) / M$2$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$N$1 / null (canon) / N$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$O$1 / null (canon) / O$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$P$2$ / null (canon) / P$2$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+A$Q$1 / null (canon) / Q$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / public A(int) (constr) / null (meth)
+- properties : true (local) / false (member)
+A$R$1 / null (canon) / R$1 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / public A(int) (constr) / null (meth)
+- properties : true (local) / false (member)
+A$S$2$ / null (canon) / S$2$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class A (cls) / public A(int) (constr) / null (meth)
+- properties : true (local) / false (member)
+AO / AO (canon) / AO (simple)
+- declared cls: List(class AO$B, interface AO$C, class AO$D$)
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+AO$ / AO$ (canon) / AO$ (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+AO$$anon$8 / null (canon) / anon$8 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / class AO$ (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+AO$B / AO.B (canon) / B (simple)
+- declared cls: List()
+- enclosing : class AO (declaring cls) / class AO (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AO$C / AO.C (canon) / C (simple)
+- declared cls: List()
+- enclosing : class AO (declaring cls) / class AO (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AO$D$ / AO.D$ (canon) / D$ (simple)
+- declared cls: List()
+- enclosing : class AO (declaring cls) / class AO (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AT / AT (canon) / AT (simple)
+- declared cls: List(class AT$B, interface AT$C, class AT$D$)
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+AT$$anon$9 / null (canon) / $anon$9 (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / interface AT (cls) / null (constr) / null (meth)
+- properties : true (local) / false (member)
+AT$B / AT.B (canon) / B (simple)
+- declared cls: List()
+- enclosing : interface AT (declaring cls) / interface AT (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AT$C / AT.C (canon) / C (simple)
+- declared cls: List()
+- enclosing : interface AT (declaring cls) / interface AT (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AT$D$ / AT.D$ (canon) / D$ (simple)
+- declared cls: List()
+- enclosing : interface AT (declaring cls) / interface AT (cls) / null (constr) / null (meth)
+- properties : false (local) / true (member)
+AT$class / AT$class (canon) / AT$class (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+T / T (canon) / T (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
+T$class / T$class (canon) / T$class (simple)
+- declared cls: List()
+- enclosing : null (declaring cls) / null (cls) / null (constr) / null (meth)
+- properties : false (local) / false (member)
diff --git a/test/files/jvm/javaReflection/Classes_1.scala b/test/files/jvm/javaReflection/Classes_1.scala
new file mode 100644
index 0000000000..11963e2770
--- /dev/null
+++ b/test/files/jvm/javaReflection/Classes_1.scala
@@ -0,0 +1,84 @@
+// See Test.scala for comments
+
+trait T { def f = 1 }
+
+class A {
+ // member class
+ class B
+ // member trait
+ trait C
+ // member object
+ object D {
+ class B
+ trait C
+ object D
+ new T { }
+ (() => -1)
+ def f = { class KB }
+ }
+
+ // anonymous class, not a member
+ new T { }
+
+ // anonymous function, not a member
+ (() => 1)
+
+ def f = {
+ class E
+ trait F
+ object G
+ new T { }
+ (() => 2)
+
+ if (new Object().hashCode == 1) {
+ class H
+ trait I
+ object J
+ new T { }
+ (() => 3)
+ } else {
+ ()
+ }
+ }
+
+ {
+ class K
+ trait L
+ object M
+ new T { }
+ (() => 4)
+ }
+
+ val x = {
+ class N
+ trait O
+ object P
+ new T { }
+ (() => 5)
+ }
+
+ def this(x: Int) {
+ this()
+ class Q
+ trait R
+ object S
+ new T { }
+ (() => () => 5)
+ }
+}
+
+object AO {
+ class B
+ trait C
+ object D
+ new T { }
+ (() => 1)
+}
+
+trait AT {
+ class B
+ trait C
+ object D
+ new T { }
+ (() => 1)
+}
diff --git a/test/files/jvm/javaReflection/Test.scala b/test/files/jvm/javaReflection/Test.scala
new file mode 100644
index 0000000000..5b6ef1b573
--- /dev/null
+++ b/test/files/jvm/javaReflection/Test.scala
@@ -0,0 +1,137 @@
+/**
+Interesting aspects of Java reflection applied to scala classes. TL;DR: you should not use
+getSimpleName / getCanonicalName / isAnonymousClass / isLocalClass / isSynthetic.
+
+ - Some methods in Java reflection assume a certain structure in the class names. Scalac
+ can produce class files that don't respect this structure. Certain methods in reflection
+ therefore give surprising answers or may even throw an exception.
+
+ In particular, the method "getSimpleName" assumes that classes are named after the Java spec
+ http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.1
+
+ Consider the following Scala example:
+ class A { object B { class C } }
+
+ The classfile for C has the name "A$B$C", while the classfile for the module B has the
+ name "A$B$".
+
+ For "cClass.getSimpleName, the implementation first strips the name of the enclosing class,
+ which produces "C". The implementation then expects a "$" character, which is missing, and
+ throws an InternalError.
+
+ Consider another example:
+ trait T
+ class A { val x = new T {} }
+ object B { val x = new T {} }
+
+ The anonymous classes are named "A$$anon$1" and "B$$anon$2". If you call "getSimpleName",
+ you get "$anon$1" (leading $) and "anon$2" (no leading $).
+
+ - There are certain other methods in the Java reflection API that depend on getSimpleName.
+ These should be avoided, they yield unexpected results:
+
+ - isAnonymousClass is always false. Scala-defined classes are never anonymous for Java
+ reflection. Java reflection insepects the class name to decide whether a class is
+ anonymous, based on the name spec referenced above.
+ Also, the implementation of "isAnonymousClass" calls "getSimpleName", which may throw.
+
+ - isLocalClass: should be true true for local classes (nested classes that are not
+ members), but not for anonymous classes. Since "isAnonymousClass" is always false,
+ Java reflection thinks that all Scala-defined anonymous classes are local.
+ The implementation may also throw, since it uses "isAnonymousClass":
+ class A { object B { def f = { class KB; new KB } } }
+ (new A).B.f.getClass.isLocalClass // boom
+
+ - getCanonicalName: uses "getSimpleName" in the implementation. In the first example,
+ cClass.getCanonicalName also fails with an InternalError.
+
+ - Scala-defined classes are never synthetic for Java reflection. The implementation
+ checks for the SYNTHETEIC flag, which does not seem to be added by scalac (maybe this
+ will change some day).
+*/
+
+object Test {
+
+ def tr[T](m: => T): String = try {
+ val r = m
+ if (r == null) "null"
+ else r.toString
+ } catch { case e: InternalError => e.getMessage }
+
+ def assertNotAnonymous(c: Class[_]) = {
+ val an = try {
+ c.isAnonymousClass
+ } catch {
+ // isAnonymousClass is implemented using getSimpleName, which may throw.
+ case e: InternalError => false
+ }
+ assert(!an, c)
+ }
+
+ def ruleMemberOrLocal(c: Class[_]) = {
+ // if it throws, then it's because of the call from isLocalClass to isAnonymousClass.
+ // we know that isAnonymousClass is always false, so it has to be a local class.
+ val loc = try { c.isLocalClass } catch { case e: InternalError => true }
+ if (loc)
+ assert(!c.isMemberClass, c)
+ if (c.isMemberClass)
+ assert(!loc, c)
+ }
+
+ def ruleMemberDeclaring(c: Class[_]) = {
+ if (c.isMemberClass)
+ assert(c.getDeclaringClass.getDeclaredClasses.toList.map(_.getName) contains c.getName)
+ }
+
+ def ruleScalaAnonClassIsLocal(c: Class[_]) = {
+ if (c.getName contains "$anon$")
+ assert(c.isLocalClass, c)
+ }
+
+ def ruleScalaAnonFunInlineIsLocal(c: Class[_]) = {
+ // exclude lambda classes generated by delambdafy:method. nested closures have both "anonfun" and "lambda".
+ if (c.getName.contains("$anonfun$") && !c.getName.contains("$lambda$"))
+ assert(c.isLocalClass, c)
+ }
+
+ def ruleScalaAnonFunMethodIsToplevel(c: Class[_]) = {
+ if (c.getName.contains("$lambda$"))
+ assert(c.getEnclosingClass == null, c)
+ }
+
+ def showClass(name: String) = {
+ val c = Class.forName(name)
+
+ println(s"${c.getName} / ${tr(c.getCanonicalName)} (canon) / ${tr(c.getSimpleName)} (simple)")
+ println( "- declared cls: "+ c.getDeclaredClasses.toList.sortBy(_.getName))
+ println(s"- enclosing : ${c.getDeclaringClass} (declaring cls) / ${c.getEnclosingClass} (cls) / ${c.getEnclosingConstructor} (constr) / ${c.getEnclosingMethod} (meth)")
+ println(s"- properties : ${tr(c.isLocalClass)} (local) / ${c.isMemberClass} (member)")
+
+ assertNotAnonymous(c)
+ assert(!c.isSynthetic, c)
+
+ ruleMemberOrLocal(c)
+ ruleMemberDeclaring(c)
+ ruleScalaAnonClassIsLocal(c)
+ ruleScalaAnonFunInlineIsLocal(c)
+ ruleScalaAnonFunMethodIsToplevel(c)
+ }
+
+ def main(args: Array[String]): Unit = {
+ def isAnonFunClassName(s: String) = s.contains("$anonfun$") || s.contains("$lambda$")
+
+ val classfiles = new java.io.File(sys.props("partest.output")).listFiles().toList.map(_.getName).collect({
+ // exclude files from Test.scala, just take those from Classes_1.scala
+ case s if !s.startsWith("Test") && s.endsWith(".class") => s.substring(0, s.length - 6)
+ }).sortWith((a, b) => {
+ // sort such that first there are all anonymous funcitions, then all other classes.
+ // within those cathegories, sort lexically.
+ // this makes the check file smaller: it differs for anonymous functions between -Ydelambdafy:inline/method.
+ // the other classes are the same.
+ if (isAnonFunClassName(a)) !isAnonFunClassName(b) || a < b
+ else !isAnonFunClassName(b) && a < b
+ })
+
+ classfiles foreach showClass
+ }
+} \ No newline at end of file
diff --git a/test/files/jvm/throws-annot-from-java.check b/test/files/jvm/throws-annot-from-java.check
index be3ba412f8..c541b26fcc 100644
--- a/test/files/jvm/throws-annot-from-java.check
+++ b/test/files/jvm/throws-annot-from-java.check
@@ -44,4 +44,4 @@ bar
tp.typeParams.isEmpty: true
throws[test.PolymorphicException[_]](classOf[test.PolymorphicException])
-scala>
+scala> :quit
diff --git a/test/files/jvm/varargs.check b/test/files/jvm/varargs.check
index 8379befe93..986f98896a 100644
--- a/test/files/jvm/varargs.check
+++ b/test/files/jvm/varargs.check
@@ -1,3 +1,4 @@
7
10
-19 \ No newline at end of file
+19
+a
diff --git a/test/files/jvm/varargs/JavaClass.java b/test/files/jvm/varargs/JavaClass.java
index 9851e1b78b..6928ee5adc 100644
--- a/test/files/jvm/varargs/JavaClass.java
+++ b/test/files/jvm/varargs/JavaClass.java
@@ -11,5 +11,6 @@ public class JavaClass {
va.vi(1, 2, 3, 4);
varargz(5, 1.0, 2.0, 3.0);
va.vt(16, "", "", "");
+ System.out.println(va.vt1(16, "a", "b", "c"));
}
} \ No newline at end of file
diff --git a/test/files/jvm/varargs/VaClass.scala b/test/files/jvm/varargs/VaClass.scala
index 6343f9c6f6..e94e8a625a 100644
--- a/test/files/jvm/varargs/VaClass.scala
+++ b/test/files/jvm/varargs/VaClass.scala
@@ -9,5 +9,5 @@ class VaClass {
@varargs def vs(a: Int, b: String*) = println(a + b.length)
@varargs def vi(a: Int, b: Int*) = println(a + b.sum)
@varargs def vt[T](a: Int, b: T*) = println(a + b.length)
-
+ @varargs def vt1[T](a: Int, b: T*): T = b.head
}
diff --git a/test/files/jvm/xml05.check b/test/files/jvm/xml05.check
index 92ea995350..cad907525d 100644
--- a/test/files/jvm/xml05.check
+++ b/test/files/jvm/xml05.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> <city name="San Jos&eacute;"/>
res0: scala.xml.Elem = <city name="San Jos&eacute;"/>
-scala>
+scala> :quit
diff --git a/test/files/neg/forgot-interpolator.check b/test/files/neg/forgot-interpolator.check
index 8988458982..8e75350518 100644
--- a/test/files/neg/forgot-interpolator.check
+++ b/test/files/neg/forgot-interpolator.check
@@ -1,25 +1,25 @@
-forgot-interpolator.scala:4: warning: `$bippy` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:4: warning: possible missing interpolator: detected interpolated identifier `$bippy`
def f = "Put the $bippy in the $bippy!" // warn 1
^
-forgot-interpolator.scala:14: warning: That looks like an interpolated expression! Did you forget the interpolator?
+forgot-interpolator.scala:14: warning: possible missing interpolator: detected an interpolated expression
def f = """Put the ${println("bippy")} in the bippy!""" // warn 2
^
-forgot-interpolator.scala:30: warning: `$beppo` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:30: warning: possible missing interpolator: detected interpolated identifier `$beppo`
def f = "$beppo was a marx bros who saw dollars." // warn 3
^
-forgot-interpolator.scala:34: warning: `$aleppo` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:34: warning: possible missing interpolator: detected interpolated identifier `$aleppo`
def f = "$aleppo is a pepper and a city." // warn 4
^
-forgot-interpolator.scala:47: warning: `$hippo` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:47: warning: possible missing interpolator: detected interpolated identifier `$hippo`
def h = "$hippo takes an implicit" // warn 6
^
-forgot-interpolator.scala:88: warning: `$groucho` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:88: warning: possible missing interpolator: detected interpolated identifier `$groucho`
def f2 = "I salute $groucho" // warn 7
^
-forgot-interpolator.scala:89: warning: `$dingo` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:89: warning: possible missing interpolator: detected interpolated identifier `$dingo`
def f3 = "I even salute $dingo" // warn 8
^
-forgot-interpolator.scala:90: warning: `$calico` looks like an interpolated identifier! Did you forget the interpolator?
+forgot-interpolator.scala:90: warning: possible missing interpolator: detected interpolated identifier `$calico`
def f4 = "I also salute $calico" // warn 9
^
error: No warnings can be incurred under -Xfatal-warnings.
diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala
index a53054d890..ca1ac30821 100644
--- a/test/files/neg/forgot-interpolator.scala
+++ b/test/files/neg/forgot-interpolator.scala
@@ -54,8 +54,8 @@ package test {
}
}
import annotation._
- @implicitNotFound("No Z in ${A}") // no warn
- class Z[A]
+ @implicitNotFound("No Z in ${T}") // no warn
+ class Z[T]
}
diff --git a/test/files/neg/macro-basic-mamdmi.check b/test/files/neg/macro-basic-mamdmi.check
index 61df5131cc..54743d4936 100644
--- a/test/files/neg/macro-basic-mamdmi.check
+++ b/test/files/neg/macro-basic-mamdmi.check
@@ -1,5 +1,13 @@
+Impls_Macros_Test_1.scala:33: error: macro implementation not found: foo
+(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
+ println(foo(2) + Macros.bar(2) * new Macros().quux(4))
+ ^
+Impls_Macros_Test_1.scala:33: error: macro implementation not found: bar
+(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
+ println(foo(2) + Macros.bar(2) * new Macros().quux(4))
+ ^
Impls_Macros_Test_1.scala:33: error: macro implementation not found: quux
(the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
println(foo(2) + Macros.bar(2) * new Macros().quux(4))
^
-one error found
+three errors found
diff --git a/test/files/neg/t3909.check b/test/files/neg/t3909.check
index 7da0195607..052b49f855 100644
--- a/test/files/neg/t3909.check
+++ b/test/files/neg/t3909.check
@@ -1,4 +1,5 @@
t3909.scala:1: error: in object DO, multiple overloaded alternatives of m1 define default arguments
+Error occurred in an application involving default arguments.
object DO {
^
one error found
diff --git a/test/files/neg/t4851.check b/test/files/neg/t4851.check
index 132dd91b50..d5711a889b 100644
--- a/test/files/neg/t4851.check
+++ b/test/files/neg/t4851.check
@@ -29,13 +29,13 @@ S.scala:7: warning: Adapting argument list by creating a 3-tuple: this may not b
val y2 = new Some(1, 2, 3)
^
S.scala:9: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want.
- signature: J2[T](x: T): J2[T]
+ signature: J2(x: T): J2[T]
given arguments: <none>
after adaptation: new J2((): Unit)
val z1 = new J2
^
S.scala:10: warning: Adaptation of argument list by inserting () has been deprecated: this is unlikely to be what you want.
- signature: J2[T](x: T): J2[T]
+ signature: J2(x: T): J2[T]
given arguments: <none>
after adaptation: new J2((): Unit)
val z2 = new J2()
diff --git a/test/files/neg/t4851.flags b/test/files/neg/t4851.flags
index ca0d0a0ba3..044ce22c84 100644
--- a/test/files/neg/t4851.flags
+++ b/test/files/neg/t4851.flags
@@ -1 +1 @@
--Ywarn-adapted-args -Xfatal-warnings -deprecation
+-Xlint:adapted-args -Xfatal-warnings -deprecation
diff --git a/test/files/neg/t4851/J2.java b/test/files/neg/t4851/J2.java
index 82954d9489..a90f48e269 100644
--- a/test/files/neg/t4851/J2.java
+++ b/test/files/neg/t4851/J2.java
@@ -1,11 +1,11 @@
public class J2<T> {
T x;
- public <T> J(T x) {
+ public J2(T x) {
this.x = x;
}
public String toString() {
return "J2:" + x.getClass();
}
-} \ No newline at end of file
+}
diff --git a/test/files/neg/t5148.check b/test/files/neg/t5148.check
index 8a667f4b88..0de4fe2d4c 100644
--- a/test/files/neg/t5148.check
+++ b/test/files/neg/t5148.check
@@ -1,5 +1,6 @@
-error: bad symbolic reference to scala.tools.nsc.interpreter.IMain.Request encountered in class file 'Imports.class'.
-Cannot access type Request in class scala.tools.nsc.interpreter.IMain. The current classpath may be
-missing a definition for scala.tools.nsc.interpreter.IMain.Request, or Imports.class may have been compiled against a version that's
-incompatible with the one found on the current classpath.
+error: missing or invalid dependency detected while loading class file 'Imports.class'.
+Could not access type Request in class scala.tools.nsc.interpreter.IMain,
+because it (or its dependencies) are missing. Check your build definition for
+missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
+A full rebuild may help if 'Imports.class' was compiled against an incompatible version of scala.tools.nsc.interpreter.IMain.
one error found
diff --git a/test/files/neg/t5691.check b/test/files/neg/t5691.check
new file mode 100644
index 0000000000..a51ca98a10
--- /dev/null
+++ b/test/files/neg/t5691.check
@@ -0,0 +1,24 @@
+t5691.scala:7: warning: type parameter D defined in method foobar shadows trait D defined in class B. You may want to rename your type parameter, or possibly remove it.
+ def foobar[D](in: D) = in.toString
+ ^
+t5691.scala:10: warning: type parameter D defined in type MySeq shadows trait D defined in class B. You may want to rename your type parameter, or possibly remove it.
+ type MySeq[D] = Seq[D]
+ ^
+t5691.scala:15: warning: type parameter T defined in method bar shadows type T defined in class Foo. You may want to rename your type parameter, or possibly remove it.
+ def bar[T](w: T) = w.toString
+ ^
+t5691.scala:13: warning: type parameter T defined in class Foo shadows type T defined in class B. You may want to rename your type parameter, or possibly remove it.
+ class Foo[T](t: T) {
+ ^
+t5691.scala:19: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it.
+ class C[M[List[_]]]
+ ^
+t5691.scala:20: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it.
+ type E[M[List[_]]] = Int
+ ^
+t5691.scala:21: warning: type parameter List defined in type M shadows type List defined in package object scala. You may want to rename your type parameter, or possibly remove it.
+ def foo[N[M[List[_]]]] = ???
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+7 warnings found
+one error found
diff --git a/test/files/neg/t5691.flags b/test/files/neg/t5691.flags
new file mode 100644
index 0000000000..0e09b8575b
--- /dev/null
+++ b/test/files/neg/t5691.flags
@@ -0,0 +1 @@
+-Xlint:type-parameter-shadow -language:higherKinds -Xfatal-warnings
diff --git a/test/files/neg/t5691.scala b/test/files/neg/t5691.scala
new file mode 100644
index 0000000000..e6a9bdc16a
--- /dev/null
+++ b/test/files/neg/t5691.scala
@@ -0,0 +1,27 @@
+class B {
+
+ type T = Int
+ trait D
+
+ // method parameter shadows some other type
+ def foobar[D](in: D) = in.toString
+
+ // type member's parameter shadows some other type
+ type MySeq[D] = Seq[D]
+
+ // class parameter shadows some other type
+ class Foo[T](t: T) {
+ // a type parameter shadows another type parameter
+ def bar[T](w: T) = w.toString
+ }
+
+ // even deeply nested...
+ class C[M[List[_]]]
+ type E[M[List[_]]] = Int
+ def foo[N[M[List[_]]]] = ???
+
+ // ...but not between type parameters in the same list
+ class F[A, M[L[A]]] // no warning!
+ type G[A, M[L[A]]] = Int // no warning!
+ def bar[A, N[M[L[A]]]] = ??? // no warning!
+}
diff --git a/test/files/neg/t6675b.scala b/test/files/neg/t6675b.scala
index c86c9c3955..da27e1b91f 100644
--- a/test/files/neg/t6675b.scala
+++ b/test/files/neg/t6675b.scala
@@ -13,7 +13,7 @@ object NativelyTwo {
}
-class A {
+class E {
def f1 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight(a) => a } // warn
def f2 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b)) => a } // no warn
def f3 = (Left((0, 0)): Either[(Int, Int), (Int, Int)]) match { case LeftOrRight((a, b, c)) => a } // fail
diff --git a/test/files/neg/t7848-interp-warn.check b/test/files/neg/t7848-interp-warn.check
index b7df6d8ce2..4cf9d55ffd 100644
--- a/test/files/neg/t7848-interp-warn.check
+++ b/test/files/neg/t7848-interp-warn.check
@@ -1,10 +1,10 @@
-t7848-interp-warn.scala:8: warning: `$foo` looks like an interpolated identifier! Did you forget the interpolator?
+t7848-interp-warn.scala:8: warning: possible missing interpolator: detected interpolated identifier `$foo`
"An important $foo message!"
^
-t7848-interp-warn.scala:12: warning: That looks like an interpolated expression! Did you forget the interpolator?
+t7848-interp-warn.scala:12: warning: possible missing interpolator: detected an interpolated expression
"A doubly important ${foo * 2} message!"
^
-t7848-interp-warn.scala:16: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator?
+t7848-interp-warn.scala:16: warning: possible missing interpolator: detected interpolated identifier `$bar`
def j = s"Try using '${ "something like $bar" }' instead." // warn
^
error: No warnings can be incurred under -Xfatal-warnings.
diff --git a/test/files/neg/t7848-interp-warn.flags b/test/files/neg/t7848-interp-warn.flags
index 7949c2afa2..b0d7bc25cb 100644
--- a/test/files/neg/t7848-interp-warn.flags
+++ b/test/files/neg/t7848-interp-warn.flags
@@ -1 +1 @@
--Xlint -Xfatal-warnings
+-Xlint:missing-interpolator -Xfatal-warnings
diff --git a/test/files/neg/t8035-no-adapted-args.check b/test/files/neg/t8035-no-adapted-args.check
new file mode 100644
index 0000000000..43637b2c1f
--- /dev/null
+++ b/test/files/neg/t8035-no-adapted-args.check
@@ -0,0 +1,21 @@
+t8035-no-adapted-args.scala:4: warning: No automatic adaptation here: use explicit parentheses.
+ signature: Test.f[T](x: T): Int
+ given arguments: 1, 2, 3
+ after adaptation: Test.f((1, 2, 3): (Int, Int, Int))
+ f(1, 2, 3)
+ ^
+t8035-no-adapted-args.scala:4: error: too many arguments for method f: (x: (Int, Int, Int))Int
+ f(1, 2, 3)
+ ^
+t8035-no-adapted-args.scala:5: warning: No automatic adaptation here: use explicit parentheses.
+ signature: Test.f[T](x: T): Int
+ given arguments: <none>
+ after adaptation: Test.f((): Unit)
+ f()
+ ^
+t8035-no-adapted-args.scala:5: error: not enough arguments for method f: (x: Unit)Int.
+Unspecified value parameter x.
+ f()
+ ^
+two warnings found
+two errors found
diff --git a/test/files/neg/t8035-no-adapted-args.flags b/test/files/neg/t8035-no-adapted-args.flags
new file mode 100644
index 0000000000..b3e8c505e2
--- /dev/null
+++ b/test/files/neg/t8035-no-adapted-args.flags
@@ -0,0 +1 @@
+-Yno-adapted-args \ No newline at end of file
diff --git a/test/files/neg/t8035-no-adapted-args.scala b/test/files/neg/t8035-no-adapted-args.scala
new file mode 100644
index 0000000000..82690ebe94
--- /dev/null
+++ b/test/files/neg/t8035-no-adapted-args.scala
@@ -0,0 +1,6 @@
+object Test {
+ def f[T](x: T) = 0
+
+ f(1, 2, 3)
+ f()
+}
diff --git a/test/files/neg/t8266-invalid-interp.check b/test/files/neg/t8266-invalid-interp.check
index 70dd4081b0..bb2d44a80c 100644
--- a/test/files/neg/t8266-invalid-interp.check
+++ b/test/files/neg/t8266-invalid-interp.check
@@ -1,10 +1,10 @@
t8266-invalid-interp.scala:4: error: Trailing '\' escapes nothing.
f"a\",
^
-t8266-invalid-interp.scala:5: error: invalid escape character at index 1 in "a\xc"
+t8266-invalid-interp.scala:5: error: invalid escape '\x' not one of [\b, \t, \n, \f, \r, \\, \", \'] at index 1 in "a\xc". Use \\ for literal \.
f"a\xc",
^
-t8266-invalid-interp.scala:7: error: invalid escape character at index 1 in "a\vc"
+t8266-invalid-interp.scala:7: error: invalid escape '\v' not one of [\b, \t, \n, \f, \r, \\, \", \'] at index 1 in "a\vc". Use \\ for literal \.
f"a\vc"
^
three errors found
diff --git a/test/files/neg/t8525.check b/test/files/neg/t8525.check
new file mode 100644
index 0000000000..5287e43b7a
--- /dev/null
+++ b/test/files/neg/t8525.check
@@ -0,0 +1,15 @@
+t8525.scala:7: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
+ signature: X.f(p: (Int, Int)): Int
+ given arguments: 3, 4
+ after adaptation: X.f((3, 4): (Int, Int))
+ def g = f(3, 4) // adapted
+ ^
+t8525.scala:9: warning: private[this] value name in class X shadows mutable name inherited from class Named. Changes to name will not be visible within class X - you may want to give them distinct names.
+ override def toString = name // shadowing mutable var name
+ ^
+t8525.scala:8: warning: side-effecting nullary methods are discouraged: suggest defining as `def u()` instead
+ def u: Unit = () // unitarian universalist
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+three warnings found
+one error found
diff --git a/test/files/neg/t8525.flags b/test/files/neg/t8525.flags
new file mode 100644
index 0000000000..53b2dfe7ec
--- /dev/null
+++ b/test/files/neg/t8525.flags
@@ -0,0 +1 @@
+-Xfatal-warnings -Xlint:-missing-interpolator -Xlint
diff --git a/test/files/neg/t8525.scala b/test/files/neg/t8525.scala
new file mode 100644
index 0000000000..7bed04904f
--- /dev/null
+++ b/test/files/neg/t8525.scala
@@ -0,0 +1,10 @@
+
+class Named(var name: String)
+
+class X(name: String) extends Named(name) {
+ def x = "Hi, $name" // missing interp
+ def f(p: (Int, Int)): Int = p._1 * p._2
+ def g = f(3, 4) // adapted
+ def u: Unit = () // unitarian universalist
+ override def toString = name // shadowing mutable var name
+}
diff --git a/test/files/neg/t8610-arg.check b/test/files/neg/t8610-arg.check
new file mode 100644
index 0000000000..d6fe207119
--- /dev/null
+++ b/test/files/neg/t8610-arg.check
@@ -0,0 +1,6 @@
+t8610-arg.scala:8: warning: side-effecting nullary methods are discouraged: suggest defining as `def u()` instead
+ def u: Unit = () // unitarian universalist
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/t8610-arg.flags b/test/files/neg/t8610-arg.flags
new file mode 100644
index 0000000000..f331ba9383
--- /dev/null
+++ b/test/files/neg/t8610-arg.flags
@@ -0,0 +1 @@
+-Xfatal-warnings -Xlint nullary-unit
diff --git a/test/files/neg/t8610-arg.scala b/test/files/neg/t8610-arg.scala
new file mode 100644
index 0000000000..7bed04904f
--- /dev/null
+++ b/test/files/neg/t8610-arg.scala
@@ -0,0 +1,10 @@
+
+class Named(var name: String)
+
+class X(name: String) extends Named(name) {
+ def x = "Hi, $name" // missing interp
+ def f(p: (Int, Int)): Int = p._1 * p._2
+ def g = f(3, 4) // adapted
+ def u: Unit = () // unitarian universalist
+ override def toString = name // shadowing mutable var name
+}
diff --git a/test/files/neg/t8610.check b/test/files/neg/t8610.check
new file mode 100644
index 0000000000..334a947549
--- /dev/null
+++ b/test/files/neg/t8610.check
@@ -0,0 +1,18 @@
+t8610.scala:5: warning: possible missing interpolator: detected interpolated identifier `$name`
+ def x = "Hi, $name" // missing interp
+ ^
+t8610.scala:7: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
+ signature: X.f(p: (Int, Int)): Int
+ given arguments: 3, 4
+ after adaptation: X.f((3, 4): (Int, Int))
+ def g = f(3, 4) // adapted
+ ^
+t8610.scala:9: warning: private[this] value name in class X shadows mutable name inherited from class Named. Changes to name will not be visible within class X - you may want to give them distinct names.
+ override def toString = name // shadowing mutable var name
+ ^
+t8610.scala:8: warning: side-effecting nullary methods are discouraged: suggest defining as `def u()` instead
+ def u: Unit = () // unitarian universalist
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+four warnings found
+one error found
diff --git a/test/files/neg/t8610.flags b/test/files/neg/t8610.flags
new file mode 100644
index 0000000000..954eaba352
--- /dev/null
+++ b/test/files/neg/t8610.flags
@@ -0,0 +1 @@
+-Xfatal-warnings -Xlint
diff --git a/test/files/neg/t8610.scala b/test/files/neg/t8610.scala
new file mode 100644
index 0000000000..7bed04904f
--- /dev/null
+++ b/test/files/neg/t8610.scala
@@ -0,0 +1,10 @@
+
+class Named(var name: String)
+
+class X(name: String) extends Named(name) {
+ def x = "Hi, $name" // missing interp
+ def f(p: (Int, Int)): Int = p._1 * p._2
+ def g = f(3, 4) // adapted
+ def u: Unit = () // unitarian universalist
+ override def toString = name // shadowing mutable var name
+}
diff --git a/test/files/neg/t8736-c.check b/test/files/neg/t8736-c.check
new file mode 100644
index 0000000000..06b2228543
--- /dev/null
+++ b/test/files/neg/t8736-c.check
@@ -0,0 +1,11 @@
+t8736-c.scala:4: warning: higher-kinded type should be enabled
+by making the implicit value scala.language.higherKinds visible.
+This can be achieved by adding the import clause 'import scala.language.higherKinds'
+or by setting the compiler option -language:higherKinds.
+See the Scala docs for value scala.language.higherKinds for a discussion
+why the feature should be explicitly enabled.
+ def hk[M[_]] = ???
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/t8736-c.flags b/test/files/neg/t8736-c.flags
new file mode 100644
index 0000000000..fde5313c96
--- /dev/null
+++ b/test/files/neg/t8736-c.flags
@@ -0,0 +1 @@
+-feature -language:-higherKinds,_ -Xfatal-warnings
diff --git a/test/files/neg/t8736-c.scala b/test/files/neg/t8736-c.scala
new file mode 100644
index 0000000000..8432775ae1
--- /dev/null
+++ b/test/files/neg/t8736-c.scala
@@ -0,0 +1,7 @@
+// scalac: -feature -language:-higherKinds,_ -Xfatal-warnings
+// showing that wildcard doesn't supersede explicit disablement
+class X {
+ def hk[M[_]] = ???
+
+ implicit def imp(x: X): Int = x.hashCode
+}
diff --git a/test/files/neg/warn-inferred-any.flags b/test/files/neg/warn-inferred-any.flags
index a3127d392a..b580dfbbe3 100644
--- a/test/files/neg/warn-inferred-any.flags
+++ b/test/files/neg/warn-inferred-any.flags
@@ -1 +1 @@
--Xfatal-warnings -Ywarn-infer-any
+-Xfatal-warnings -Xlint:infer-any
diff --git a/test/files/pos/macro-attachments/Macros_1.scala b/test/files/pos/macro-attachments/Macros_1.scala
new file mode 100644
index 0000000000..38d05d5b85
--- /dev/null
+++ b/test/files/pos/macro-attachments/Macros_1.scala
@@ -0,0 +1,19 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.whitebox.Context
+
+trait Base
+class Att extends Base
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ import c.internal._
+ import decorators._
+ val dummy = q"x"
+ dummy.updateAttachment(new Att)
+ if (dummy.attachments.get[Base].isEmpty) c.abort(c.enclosingPosition, "that's not good")
+ q"()"
+ }
+
+ def foo: Any = macro impl
+} \ No newline at end of file
diff --git a/test/files/pos/macro-attachments/Test_2.scala b/test/files/pos/macro-attachments/Test_2.scala
new file mode 100644
index 0000000000..acfddae942
--- /dev/null
+++ b/test/files/pos/macro-attachments/Test_2.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ Macros.foo
+} \ No newline at end of file
diff --git a/test/files/pos/t8013.flags b/test/files/pos/t8013.flags
index 954eaba352..3955bb6710 100644
--- a/test/files/pos/t8013.flags
+++ b/test/files/pos/t8013.flags
@@ -1 +1 @@
--Xfatal-warnings -Xlint
+-Xfatal-warnings -Xlint:-infer-any,_
diff --git a/test/files/pos/t8736-b.flags b/test/files/pos/t8736-b.flags
new file mode 100644
index 0000000000..1ad4eabe0f
--- /dev/null
+++ b/test/files/pos/t8736-b.flags
@@ -0,0 +1 @@
+-feature -language:_ -Xfatal-warnings
diff --git a/test/files/pos/t8736-b.scala b/test/files/pos/t8736-b.scala
new file mode 100644
index 0000000000..903292d232
--- /dev/null
+++ b/test/files/pos/t8736-b.scala
@@ -0,0 +1,7 @@
+// scalac: -feature -language:_ -Xfatal-warnings
+// showing that all are set
+class X {
+ def hk[M[_]] = ???
+
+ implicit def imp(x: X): Int = x.hashCode
+}
diff --git a/test/files/pos/t8736.flags b/test/files/pos/t8736.flags
new file mode 100644
index 0000000000..7fe42f7340
--- /dev/null
+++ b/test/files/pos/t8736.flags
@@ -0,0 +1 @@
+-feature -language:implicitConversions -language:higherKinds -language:-implicitConversions -Xfatal-warnings
diff --git a/test/files/pos/t8736.scala b/test/files/pos/t8736.scala
new file mode 100644
index 0000000000..46c0cdfd00
--- /dev/null
+++ b/test/files/pos/t8736.scala
@@ -0,0 +1,7 @@
+// scalac: -feature -language:implicitConversions -language:higherKinds -language:-implicitConversions -Xfatal-warnings
+// showing that multiple settings are respected, and explicit enablement has precedence
+class X {
+ def hk[M[_]] = ???
+
+ implicit def imp(x: X): Int = x.hashCode
+}
diff --git a/test/files/pos/t8743.scala b/test/files/pos/t8743.scala
new file mode 100644
index 0000000000..03b0cd7044
--- /dev/null
+++ b/test/files/pos/t8743.scala
@@ -0,0 +1,15 @@
+import annotation.varargs
+
+object VarArgs {
+ @varargs
+ def foo[A](x: A, xs: String*): A = ???
+
+ @varargs
+ def bar[A](x: List[A], xs: String*): A = ???
+
+ @varargs
+ def baz[A](x: List[A], xs: String*): A = ???
+
+ @varargs
+ def boz[A](x: A, xs: String*): Nothing = ???
+}
diff --git a/test/files/pos/t8781/Macro_1.scala b/test/files/pos/t8781/Macro_1.scala
new file mode 100644
index 0000000000..ecd9c5e8d5
--- /dev/null
+++ b/test/files/pos/t8781/Macro_1.scala
@@ -0,0 +1,13 @@
+import scala.reflect.macros.whitebox.Context
+import language.experimental.macros
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ val name = TypeName(c.freshName())
+ q"class $name extends T; new $name"
+ }
+ def fresh: Any = macro impl
+}
+
+trait T
diff --git a/test/files/pos/t8781/Test_2.flags b/test/files/pos/t8781/Test_2.flags
new file mode 100644
index 0000000000..24e2109690
--- /dev/null
+++ b/test/files/pos/t8781/Test_2.flags
@@ -0,0 +1 @@
+-Ymacro-expand:discard -Ystop-after:typer
diff --git a/test/files/pos/t8781/Test_2.scala b/test/files/pos/t8781/Test_2.scala
new file mode 100644
index 0000000000..3ca6406599
--- /dev/null
+++ b/test/files/pos/t8781/Test_2.scala
@@ -0,0 +1,5 @@
+object Test {
+ implicit class RichT(t: T) { def augmented = "" }
+
+ Macros.fresh.augmented
+}
diff --git a/test/files/pos/t8793.scala b/test/files/pos/t8793.scala
new file mode 100644
index 0000000000..1276155675
--- /dev/null
+++ b/test/files/pos/t8793.scala
@@ -0,0 +1,15 @@
+package regr
+
+trait F[A]
+
+class G(val a: F[_], val b: F[_])
+
+object G {
+ def unapply(g: G) = Option((g.a, g.b))
+}
+
+object H {
+ def unapply(g: G) = g match {
+ case G(a, _) => Option(a)
+ }
+}
diff --git a/test/files/pos/t8828.flags b/test/files/pos/t8828.flags
new file mode 100644
index 0000000000..e68991f643
--- /dev/null
+++ b/test/files/pos/t8828.flags
@@ -0,0 +1 @@
+-Xlint:inaccessible -Xfatal-warnings
diff --git a/test/files/pos/t8828.scala b/test/files/pos/t8828.scala
new file mode 100644
index 0000000000..92092b4dd4
--- /dev/null
+++ b/test/files/pos/t8828.scala
@@ -0,0 +1,20 @@
+
+package outer
+
+package inner {
+
+ private[inner] class A
+
+ // the class is final: no warning
+ private[outer] final class B {
+ def doWork(a: A): A = a
+ }
+
+ // the trait is sealed and doWork is not
+ // and cannot be overriden: no warning
+ private[outer] sealed trait C {
+ def doWork(a: A): A = a
+ }
+
+ private[outer] final class D extends C
+}
diff --git a/test/files/run/abstypetags_serialize.check b/test/files/run/abstypetags_serialize.check
index bddc4523e6..1b5e2ebddf 100644
--- a/test/files/run/abstypetags_serialize.check
+++ b/test/files/run/abstypetags_serialize.check
@@ -1,2 +1,2 @@
-java.io.NotSerializableException: Test$$typecreator1$1
-java.io.NotSerializableException: Test$$typecreator2$1
+WeakTypeTag[T]
+WeakTypeTag[U[String]]
diff --git a/test/files/run/class-symbol-contravariant.check b/test/files/run/class-symbol-contravariant.check
index 987f215bca..cbb90b52c2 100644
--- a/test/files/run/class-symbol-contravariant.check
+++ b/test/files/run/class-symbol-contravariant.check
@@ -33,4 +33,4 @@ res2: Boolean = true
scala> sym.isContravariant // was true
res3: Boolean = false
-scala>
+scala> :quit
diff --git a/test/files/run/constant-type.check b/test/files/run/constant-type.check
index 77bdf618e6..a7ba5a46c2 100644
--- a/test/files/run/constant-type.check
+++ b/test/files/run/constant-type.check
@@ -23,4 +23,4 @@ Class[String](classOf[java.lang.String])
scala> { ConstantType(Constant(s)); exitingPhase(currentRun.erasurePhase)(println(ConstantType(Constant(s)))); }
Class(classOf[java.lang.String])
-scala>
+scala> :quit
diff --git a/test/files/run/constrained-types.check b/test/files/run/constrained-types.check
index a3cd59b9fb..89a08d5ccb 100644
--- a/test/files/run/constrained-types.check
+++ b/test/files/run/constrained-types.check
@@ -148,4 +148,4 @@ scala> val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message
val x = 3 : Int @Annot(e+f+g+h) // should have a graceful error message
^
-scala>
+scala> :quit
diff --git a/test/files/run/exprs_serialize.check b/test/files/run/exprs_serialize.check
index 20ad6c110c..551823ccdc 100644
--- a/test/files/run/exprs_serialize.check
+++ b/test/files/run/exprs_serialize.check
@@ -1,2 +1,19 @@
-java.io.NotSerializableException: Test$$treecreator1$1
-java.io.NotSerializableException: Test$$treecreator2$1
+Expr[Int(2)](2)
+Expr[java.lang.String]({
+ def foo = "hello";
+ foo.$plus("world!")
+})
+Expr[Boolean]({
+ def foo(x: Int) = {
+ class Local extends AnyRef {
+ def <init>() = {
+ super.<init>();
+ ()
+ };
+ val f = 2
+ };
+ val obj = new Local();
+ x.$percent(obj.f).$eq$eq(0)
+ };
+ foo(5)
+})
diff --git a/test/files/run/exprs_serialize.scala b/test/files/run/exprs_serialize.scala
index c4310b0fe1..91027803b4 100644
--- a/test/files/run/exprs_serialize.scala
+++ b/test/files/run/exprs_serialize.scala
@@ -26,4 +26,14 @@ object Test extends App {
test(reify(2))
test(reify{def foo = "hello"; foo + "world!"})
-} \ No newline at end of file
+ test(reify {
+ def foo(x: Int) = {
+ class Local {
+ val f = 2
+ }
+ val obj = new Local
+ x % obj.f == 0
+ }
+ foo(5)
+ })
+}
diff --git a/test/files/run/kind-repl-command.check b/test/files/run/kind-repl-command.check
index 1c292572e6..586b2710e1 100644
--- a/test/files/run/kind-repl-command.check
+++ b/test/files/run/kind-repl-command.check
@@ -25,4 +25,4 @@ scala> :k Nonexisting
Nonexisting
^
-scala>
+scala> :quit
diff --git a/test/files/run/lub-visibility.check b/test/files/run/lub-visibility.check
index f76579412e..70734966f0 100644
--- a/test/files/run/lub-visibility.check
+++ b/test/files/run/lub-visibility.check
@@ -8,4 +8,4 @@ scala> // but reverted that for SI-5534.
scala> val x = List(List(), Vector())
x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing] with java.io.Serializable] = List(List(), Vector())
-scala>
+scala> :quit
diff --git a/test/files/run/macro-bundle-repl.check b/test/files/run/macro-bundle-repl.check
index 4a0b421606..75c5c2adda 100644
--- a/test/files/run/macro-bundle-repl.check
+++ b/test/files/run/macro-bundle-repl.check
@@ -21,4 +21,4 @@ defined term macro foo: Unit
scala> foo
-scala>
+scala> :quit
diff --git a/test/files/run/macro-rangepos-subpatterns.check b/test/files/run/macro-rangepos-subpatterns.check
new file mode 100644
index 0000000000..760e15d019
--- /dev/null
+++ b/test/files/run/macro-rangepos-subpatterns.check
@@ -0,0 +1 @@
+The width of the subpattern is: 2
diff --git a/test/files/run/macro-rangepos-subpatterns.flags b/test/files/run/macro-rangepos-subpatterns.flags
new file mode 100644
index 0000000000..fcf951d907
--- /dev/null
+++ b/test/files/run/macro-rangepos-subpatterns.flags
@@ -0,0 +1 @@
+-Yrangepos \ No newline at end of file
diff --git a/test/files/run/macro-rangepos-subpatterns/Macros_1.scala b/test/files/run/macro-rangepos-subpatterns/Macros_1.scala
new file mode 100644
index 0000000000..0f30862347
--- /dev/null
+++ b/test/files/run/macro-rangepos-subpatterns/Macros_1.scala
@@ -0,0 +1,18 @@
+import scala.reflect.macros.whitebox.Context
+import language.experimental.macros
+
+object Extractor {
+ def unapply(x: Any): Any = macro unapplyImpl
+ def unapplyImpl(c: Context)(x: c.Tree) = {
+ import c.universe._
+ import internal._
+ val pos = subpatterns(x).get.head.pos
+ q"""
+ new {
+ def isEmpty = false
+ def get = ${"The width of the subpattern is: " + (pos.end - pos.start + 1)}
+ def unapply(x: Any) = this
+ }.unapply($x)
+ """
+ }
+}
diff --git a/test/files/run/macro-rangepos-subpatterns/Test_2.scala b/test/files/run/macro-rangepos-subpatterns/Test_2.scala
new file mode 100644
index 0000000000..7b076e6632
--- /dev/null
+++ b/test/files/run/macro-rangepos-subpatterns/Test_2.scala
@@ -0,0 +1,5 @@
+object Test extends App {
+ 42 match {
+ case Extractor(a) => println(a)
+ }
+}
diff --git a/test/files/run/macro-repl-basic.check b/test/files/run/macro-repl-basic.check
index 86b4d472ed..fab03d1558 100644
--- a/test/files/run/macro-repl-basic.check
+++ b/test/files/run/macro-repl-basic.check
@@ -49,4 +49,4 @@ import Macros.Shmacros._
scala> println(foo(2) + Macros.bar(2) * new Macros().quux(4))
31
-scala>
+scala> :quit
diff --git a/test/files/run/macro-repl-dontexpand.check b/test/files/run/macro-repl-dontexpand.check
index 20d3b2d702..6ecc9245fa 100644
--- a/test/files/run/macro-repl-dontexpand.check
+++ b/test/files/run/macro-repl-dontexpand.check
@@ -13,4 +13,4 @@ bar2: (c: scala.reflect.macros.whitebox.Context)Nothing
scala> def foo2 = macro bar2
defined term macro foo2: Nothing
-scala>
+scala> :quit
diff --git a/test/files/run/macro-system-properties.check b/test/files/run/macro-system-properties.check
index ffbd5a8aa8..e2e2bd32b9 100644
--- a/test/files/run/macro-system-properties.check
+++ b/test/files/run/macro-system-properties.check
@@ -19,4 +19,4 @@ defined object Test
scala> object Test { class C(implicit a: Any) { GrabContext.grab } }
defined object Test
-scala>
+scala> :quit
diff --git a/test/files/run/names-defaults.check b/test/files/run/names-defaults.check
index 25999c488a..c358dc5849 100644
--- a/test/files/run/names-defaults.check
+++ b/test/files/run/names-defaults.check
@@ -124,3 +124,4 @@ List(1, 2)
3
3
(1,0), (1,2)
+1 1 0
diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala
index 05cd4a540c..b7ed490cbc 100644
--- a/test/files/run/names-defaults.scala
+++ b/test/files/run/names-defaults.scala
@@ -401,6 +401,10 @@ object Test extends App {
C4441a().copy()
C4441b()().copy()()
+ // SI-8117
+ def f8177(a: Int = 0, b: Int = 0, c: Int = 0) = s"$a $b $c"
+ println(f8177(a = 1, 1))
+
// DEFINITIONS
def test1(a: Int, b: String) = println(a +": "+ b)
def test2(u: Int, v: Int)(k: String, l: Int) = println(l +": "+ k +", "+ (u + v))
diff --git a/test/files/run/private-override.check b/test/files/run/private-override.check
deleted file mode 100644
index 00750edc07..0000000000
--- a/test/files/run/private-override.check
+++ /dev/null
@@ -1 +0,0 @@
-3
diff --git a/test/files/run/reflection-attachments.check b/test/files/run/reflection-attachments.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/reflection-attachments.check
diff --git a/test/files/run/reflection-equality.check b/test/files/run/reflection-equality.check
index 682326bc18..d60d861a90 100644
--- a/test/files/run/reflection-equality.check
+++ b/test/files/run/reflection-equality.check
@@ -48,4 +48,4 @@ res2: Boolean = true
scala> t2 <:< t1
res3: Boolean = true
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-magicsymbols-repl.check b/test/files/run/reflection-magicsymbols-repl.check
index 72aef1d3be..ca8857ada4 100644
--- a/test/files/run/reflection-magicsymbols-repl.check
+++ b/test/files/run/reflection-magicsymbols-repl.check
@@ -34,4 +34,4 @@ scala.Null
scala.Nothing
scala.Singleton
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-repl-classes.check b/test/files/run/reflection-repl-classes.check
index 03a6aef2b5..5ebf993a87 100644
--- a/test/files/run/reflection-repl-classes.check
+++ b/test/files/run/reflection-repl-classes.check
@@ -30,4 +30,4 @@ scala>
scala> mm(new A)
res0: Any = 1
-scala>
+scala> :quit
diff --git a/test/files/run/reflection-repl-elementary.check b/test/files/run/reflection-repl-elementary.check
index 4a223e8a24..e948c9fd61 100644
--- a/test/files/run/reflection-repl-elementary.check
+++ b/test/files/run/reflection-repl-elementary.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> scala.reflect.runtime.universe.typeOf[List[Nothing]]
res0: reflect.runtime.universe.Type = scala.List[Nothing]
-scala>
+scala> :quit
diff --git a/test/files/run/reify-repl-fail-gracefully.check b/test/files/run/reify-repl-fail-gracefully.check
index 29ccee3cc6..c9e69744d6 100644
--- a/test/files/run/reify-repl-fail-gracefully.check
+++ b/test/files/run/reify-repl-fail-gracefully.check
@@ -14,4 +14,4 @@ scala> reify
reify
^
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_22.check b/test/files/run/reify_newimpl_22.check
index 1432d10127..952f384a1c 100644
--- a/test/files/run/reify_newimpl_22.check
+++ b/test/files/run/reify_newimpl_22.check
@@ -22,4 +22,4 @@ scala> {
^
2
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_23.check b/test/files/run/reify_newimpl_23.check
index 217f0a98c7..b7e9bfdfbc 100644
--- a/test/files/run/reify_newimpl_23.check
+++ b/test/files/run/reify_newimpl_23.check
@@ -21,4 +21,4 @@ scala> def foo[T]{
^
foo: [T]=> Unit
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_25.check b/test/files/run/reify_newimpl_25.check
index 93ad69defa..4f36ba10ee 100644
--- a/test/files/run/reify_newimpl_25.check
+++ b/test/files/run/reify_newimpl_25.check
@@ -12,4 +12,4 @@ scala> {
^
TypeTag[x.type]
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_26.check b/test/files/run/reify_newimpl_26.check
index 8e0ad87bf2..681b862795 100644
--- a/test/files/run/reify_newimpl_26.check
+++ b/test/files/run/reify_newimpl_26.check
@@ -14,4 +14,4 @@ foo: [T]=> Unit
scala> foo[Int]
WeakTypeTag[scala.List[T]]
-scala>
+scala> :quit
diff --git a/test/files/run/reify_newimpl_35.check b/test/files/run/reify_newimpl_35.check
index f884d2c0d0..bd9b3a2fb1 100644
--- a/test/files/run/reify_newimpl_35.check
+++ b/test/files/run/reify_newimpl_35.check
@@ -10,4 +10,4 @@ foo: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtim
scala> println(foo)
Expr[List[Nothing]](Nil)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-assign.check b/test/files/run/repl-assign.check
index bdc7793c37..faa8a93244 100644
--- a/test/files/run/repl-assign.check
+++ b/test/files/run/repl-assign.check
@@ -13,4 +13,4 @@ x: Int = 12
scala> y = 13
y: Int = 13
-scala>
+scala> :quit
diff --git a/test/files/run/repl-bare-expr.check b/test/files/run/repl-bare-expr.check
index 97ae208ff4..07cf23412f 100644
--- a/test/files/run/repl-bare-expr.check
+++ b/test/files/run/repl-bare-expr.check
@@ -47,4 +47,4 @@ Bovine.x: List[Any] = List(Ruminant(5), Cow, Moooooo)
scala> Bovine.x
res4: List[Any] = List(Ruminant(5), Cow, Moooooo)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-colon-type.check b/test/files/run/repl-colon-type.check
index 1f6d3e2b39..9898027c1d 100644
--- a/test/files/run/repl-colon-type.check
+++ b/test/files/run/repl-colon-type.check
@@ -218,4 +218,4 @@ Unit
scala> :type println("side effect!")
Unit
-scala>
+scala> :quit
diff --git a/test/files/run/repl-empty-package.check b/test/files/run/repl-empty-package.check
index ecf79c2c6d..d3b75f685e 100644
--- a/test/files/run/repl-empty-package.check
+++ b/test/files/run/repl-empty-package.check
@@ -4,4 +4,4 @@ Type :help for more information.
scala> println(Bippy.bippy)
bippy!
-scala>
+scala> :quit
diff --git a/test/files/run/repl-javap-app.check b/test/files/run/repl-javap-app.check
index 1136b415d7..eb3718f44b 100644
--- a/test/files/run/repl-javap-app.check
+++ b/test/files/run/repl-javap-app.check
@@ -15,7 +15,7 @@ public final void delayedEndpoint$MyApp$1();
Start Length Slot Name Signature
0 9 0 this LMyApp$;
-scala>
+scala> :quit
#partest java7
Welcome to Scala
Type in expressions to have them evaluated.
@@ -37,7 +37,7 @@ scala> :javap -app MyApp$
line 5: 0
}
-scala>
+scala> :quit
#partest java8
Welcome to Scala
Type in expressions to have them evaluated.
@@ -60,4 +60,4 @@ scala> :javap -app MyApp$
line 5: 0
}
-scala>
+scala> :quit
diff --git a/test/files/run/repl-out-dir.check b/test/files/run/repl-out-dir.check
index 3e51c63155..c354492898 100644
--- a/test/files/run/repl-out-dir.check
+++ b/test/files/run/repl-out-dir.check
@@ -46,4 +46,4 @@ repl-out-dir-run.obj
Test$.class
Test.class
-scala>
+scala> :quit
diff --git a/test/files/run/repl-parens.check b/test/files/run/repl-parens.check
index 15f4b4524a..74d15ff93c 100644
--- a/test/files/run/repl-parens.check
+++ b/test/files/run/repl-parens.check
@@ -81,4 +81,4 @@ scala>
scala> List(1) ++ List('a')
res16: List[AnyVal] = List(1, a)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-2.check b/test/files/run/repl-paste-2.check
index ab3809a2e0..6ea8e2f419 100644
--- a/test/files/run/repl-paste-2.check
+++ b/test/files/run/repl-paste-2.check
@@ -58,4 +58,4 @@ scala> x.length + res5
res3: Int = 129
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-3.check b/test/files/run/repl-paste-3.check
index 8fae61792e..23e402852f 100644
--- a/test/files/run/repl-paste-3.check
+++ b/test/files/run/repl-paste-3.check
@@ -7,4 +7,4 @@ scala> println(3)
scala> List(1,2)
res1: List[Int] = List(1, 2)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-paste-4.scala b/test/files/run/repl-paste-4.scala
index 0060dc1ff6..cb0a6aa768 100644
--- a/test/files/run/repl-paste-4.scala
+++ b/test/files/run/repl-paste-4.scala
@@ -14,7 +14,7 @@ s"""|Type in expressions to have them evaluated.
|scala> Foo(new Foo)
|res0: Int = 7
|
- |scala> """
+ |scala> :quit"""
def pastie = testPath changeExtension "pastie"
}
diff --git a/test/files/run/repl-paste-raw.scala b/test/files/run/repl-paste-raw.scala
index 2953796f99..3b41254e96 100644
--- a/test/files/run/repl-paste-raw.scala
+++ b/test/files/run/repl-paste-raw.scala
@@ -15,6 +15,6 @@ s"""|Type in expressions to have them evaluated.
|scala> favoriteThing.hasString
|res0: Boolean = true
|
- |scala> """
+ |scala> :quit"""
def pastie = testPath changeExtension "pastie"
}
diff --git a/test/files/run/repl-paste.check b/test/files/run/repl-paste.check
index 97f177ddc4..171447214f 100644
--- a/test/files/run/repl-paste.check
+++ b/test/files/run/repl-paste.check
@@ -23,4 +23,4 @@ defined class Dingus
defined object Dingus
x: Int = 110
-scala>
+scala> :quit
diff --git a/test/files/run/repl-power.check b/test/files/run/repl-power.check
index 8a8ca46012..e2318c93f2 100644
--- a/test/files/run/repl-power.check
+++ b/test/files/run/repl-power.check
@@ -27,4 +27,4 @@ m: $r.treedsl.global.Literal = 10
scala> typed(m).tpe // typed is in scope
res2: $r.treedsl.global.Type = Int(10)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-reset.check b/test/files/run/repl-reset.check
index ed95c7b8ff..cd7893bbc3 100644
--- a/test/files/run/repl-reset.check
+++ b/test/files/run/repl-reset.check
@@ -54,4 +54,4 @@ defined class BippyBungus
scala> { new BippyBungus ; x1 }
res2: Int = 4
-scala>
+scala> :quit
diff --git a/test/files/run/repl-save.scala b/test/files/run/repl-save.scala
index 4539790b1a..c98e6aebc3 100644
--- a/test/files/run/repl-save.scala
+++ b/test/files/run/repl-save.scala
@@ -16,7 +16,7 @@ s"""|Type in expressions to have them evaluated.
|
|scala> :save $saveto
|
- |scala> """
+ |scala> :quit"""
def saveto = testOutput / "session.repl"
override def show() = {
super.show()
diff --git a/test/files/run/repl-term-macros.check b/test/files/run/repl-term-macros.check
index 3580bfe1f1..2cd0b93cd0 100644
--- a/test/files/run/repl-term-macros.check
+++ b/test/files/run/repl-term-macros.check
@@ -37,4 +37,4 @@ defined term macro foo3: (x: Int)(y: Int)Unit
scala> foo3(2)(3)
-scala>
+scala> :quit
diff --git a/test/files/run/repl-transcript.check b/test/files/run/repl-transcript.check
index 49891af900..b0f106387b 100644
--- a/test/files/run/repl-transcript.check
+++ b/test/files/run/repl-transcript.check
@@ -35,4 +35,4 @@ scala> res6.sum + res5
res0: Int = 5273
-scala>
+scala> :quit
diff --git a/test/files/run/repl-trim-stack-trace.scala b/test/files/run/repl-trim-stack-trace.scala
index 483659146a..a53ce3b3e4 100644
--- a/test/files/run/repl-trim-stack-trace.scala
+++ b/test/files/run/repl-trim-stack-trace.scala
@@ -32,7 +32,7 @@ java.lang.Exception
at .f(<console>:7)
... 69 elided
-scala> """
+scala> :quit"""
// normalize the "elided" lines because the frame count depends on test context
lazy val elided = """(\s+\.{3} )\d+( elided)""".r
diff --git a/test/files/run/repl-type-verbose.check b/test/files/run/repl-type-verbose.check
index e37754a060..6f6b47b86d 100644
--- a/test/files/run/repl-type-verbose.check
+++ b/test/files/run/repl-type-verbose.check
@@ -187,4 +187,4 @@ PolyType(
)
)
-scala>
+scala> :quit
diff --git a/test/files/run/stringinterpolation_macro-run.check b/test/files/run/stringinterpolation_macro-run.check
index ead61e76ac..c7f46bac87 100644
--- a/test/files/run/stringinterpolation_macro-run.check
+++ b/test/files/run/stringinterpolation_macro-run.check
@@ -63,5 +63,9 @@ She is 4 feet tall.
05/26/12
05/26/12
%
+ mind
+------
+matter
+
7 7 9
7 9 9
diff --git a/test/files/run/stringinterpolation_macro-run.scala b/test/files/run/stringinterpolation_macro-run.scala
index a6def98540..e18375d521 100644
--- a/test/files/run/stringinterpolation_macro-run.scala
+++ b/test/files/run/stringinterpolation_macro-run.scala
@@ -115,6 +115,7 @@ println(f"""${"1234"}%TD""")
// literals and arg indexes
println(f"%%")
+println(f" mind%n------%nmatter%n")
println(f"${7}%d %<d ${9}%d")
println(f"${7}%d %2$$d ${9}%d")
diff --git a/test/files/run/t3376.check b/test/files/run/t3376.check
index cc6949d326..b8fd2843f6 100644
--- a/test/files/run/t3376.check
+++ b/test/files/run/t3376.check
@@ -13,4 +13,4 @@ m2: M[Float] = mmm
scala> val m3 = new M[String]()
m3: M[String] = mmm
-scala>
+scala> :quit
diff --git a/test/files/run/t4025.check b/test/files/run/t4025.check
index 2d4f644c5a..e8c6851236 100644
--- a/test/files/run/t4025.check
+++ b/test/files/run/t4025.check
@@ -14,4 +14,4 @@ scala>
scala> def f(c: Any) = c match { case Red(_) => () }
f: (c: Any)Unit
-scala>
+scala> :quit
diff --git a/test/files/run/t4172.check b/test/files/run/t4172.check
index a748430e2e..315c1c9dbd 100644
--- a/test/files/run/t4172.check
+++ b/test/files/run/t4172.check
@@ -5,4 +5,4 @@ scala> val c = { class C { override def toString = "C" }; ((new C, new C { def f
warning: there was one feature warning; re-run with -feature for details
c: (C, C{def f: Int}) forSome { type C <: AnyRef } = (C,C)
-scala>
+scala> :quit
diff --git a/test/files/run/t4216.check b/test/files/run/t4216.check
index 091e55a0c7..e4610e87d3 100644
--- a/test/files/run/t4216.check
+++ b/test/files/run/t4216.check
@@ -34,4 +34,4 @@ res4: java.util.List[V] = [V@0]
scala> o(new V(0))
res5: java.util.List[Any] = [V@0]
-scala>
+scala> :quit
diff --git a/test/files/run/t4285.check b/test/files/run/t4285.check
index 314c8e5a35..b952cb8e1b 100644
--- a/test/files/run/t4285.check
+++ b/test/files/run/t4285.check
@@ -10,4 +10,4 @@ y: scala.collection.mutable.WrappedArray[Int] = WrappedArray(2, 4, 6, 8, 10, 12,
scala> println(y.sum)
56
-scala>
+scala> :quit
diff --git a/test/files/run/t4332.scala b/test/files/run/t4332.scala
index 5a67922911..1c7e7d73de 100644
--- a/test/files/run/t4332.scala
+++ b/test/files/run/t4332.scala
@@ -12,7 +12,7 @@ object Test extends DirectTest {
}
def isExempt(sym: Symbol) = {
- val exempt = Set("view", "repr", "sliceWithKnownDelta", "sliceWithKnownBound", "transform")
+ val exempt = Set("view", "repr", "sliceWithKnownDelta", "sliceWithKnownBound", "transform", "filterImpl")
(exempt contains sym.name.decoded)
}
diff --git a/test/files/run/t4542.check b/test/files/run/t4542.check
index a53f31a3c7..f7716dc2f0 100644
--- a/test/files/run/t4542.check
+++ b/test/files/run/t4542.check
@@ -12,4 +12,4 @@ scala> val f = new Foo
^
f: Foo = Bippy
-scala>
+scala> :quit
diff --git a/test/files/run/t4594-repl-settings.scala b/test/files/run/t4594-repl-settings.scala
index 8b8b2e3746..4202991607 100644
--- a/test/files/run/t4594-repl-settings.scala
+++ b/test/files/run/t4594-repl-settings.scala
@@ -22,5 +22,5 @@ object Test extends SessionTest {
| ^
|b: String
|
- |scala> """
+ |scala> :quit"""
}
diff --git a/test/files/run/t4671.check b/test/files/run/t4671.check
index 0c36083759..1640dac8e4 100644
--- a/test/files/run/t4671.check
+++ b/test/files/run/t4671.check
@@ -43,4 +43,4 @@ println(s.mkString(""))
}
-scala>
+scala> :quit
diff --git a/test/files/run/t4710.check b/test/files/run/t4710.check
index 6ee7198b4b..0dd49dfbd3 100644
--- a/test/files/run/t4710.check
+++ b/test/files/run/t4710.check
@@ -5,4 +5,4 @@ scala> def method : String = { implicit def f(s: Symbol) = "" ; 'symbol }
warning: there was one feature warning; re-run with -feature for details
method: String
-scala>
+scala> :quit
diff --git a/test/files/run/t5072.check b/test/files/run/t5072.check
index ddd49c71cb..ab34e49869 100644
--- a/test/files/run/t5072.check
+++ b/test/files/run/t5072.check
@@ -7,4 +7,4 @@ defined class C
scala> Thread.currentThread.getContextClassLoader.loadClass(classOf[C].getName)
res0: Class[_] = class C
-scala>
+scala> :quit
diff --git a/test/files/run/t5256c.check b/test/files/run/t5256c.check
index 7fcd0eb722..3eb7b13a97 100644
--- a/test/files/run/t5256c.check
+++ b/test/files/run/t5256c.check
@@ -2,5 +2,5 @@ class A$1
Test.A$1
java.lang.Object {
def foo(): Nothing
- def <init>(): A$1
+ def <init>(): Test.A$1
}
diff --git a/test/files/run/t5256d.check b/test/files/run/t5256d.check
index d42d234386..c2b49989ab 100644
--- a/test/files/run/t5256d.check
+++ b/test/files/run/t5256d.check
@@ -25,4 +25,4 @@ scala.AnyRef {
def foo: scala.Nothing
}
-scala>
+scala> :quit
diff --git a/test/files/run/t5535.check b/test/files/run/t5535.check
index a0c87a47f4..84097ccea9 100644
--- a/test/files/run/t5535.check
+++ b/test/files/run/t5535.check
@@ -13,4 +13,4 @@ f: Int => Int = <function1>
scala> println(f(10))
11
-scala>
+scala> :quit
diff --git a/test/files/run/t5537.check b/test/files/run/t5537.check
index b9d521f301..98265ccc92 100644
--- a/test/files/run/t5537.check
+++ b/test/files/run/t5537.check
@@ -13,4 +13,4 @@ res2: List[scala.collection.immutable.List.type] = List()
scala> List[Set.type]()
res3: List[Set.type] = List()
-scala>
+scala> :quit
diff --git a/test/files/run/t5583.check b/test/files/run/t5583.check
index af96405bdd..32d285cbb3 100644
--- a/test/files/run/t5583.check
+++ b/test/files/run/t5583.check
@@ -13,4 +13,4 @@ scala> for (i <- 1 to 10) {s += i}
scala> println(s)
165
-scala>
+scala> :quit
diff --git a/test/files/run/t5655.check b/test/files/run/t5655.check
index 06c6b32599..4bbc54b641 100644
--- a/test/files/run/t5655.check
+++ b/test/files/run/t5655.check
@@ -23,4 +23,4 @@ and import x
x
^
-scala>
+scala> :quit
diff --git a/test/files/run/t5789.check b/test/files/run/t5789.check
index bcb2382559..193abfaff0 100644
--- a/test/files/run/t5789.check
+++ b/test/files/run/t5789.check
@@ -7,4 +7,4 @@ n: Int = 2
scala> () => n
res0: () => Int = <function0>
-scala>
+scala> :quit
diff --git a/test/files/run/t6086-repl.check b/test/files/run/t6086-repl.check
index 115eff5f85..b904f118e8 100644
--- a/test/files/run/t6086-repl.check
+++ b/test/files/run/t6086-repl.check
@@ -7,4 +7,4 @@ defined class X
scala> scala.reflect.runtime.universe.typeOf[X]
res0: reflect.runtime.universe.Type = X
-scala>
+scala> :quit
diff --git a/test/files/run/t6146b.check b/test/files/run/t6146b.check
index a3b09efcd9..6998873fb7 100644
--- a/test/files/run/t6146b.check
+++ b/test/files/run/t6146b.check
@@ -60,4 +60,4 @@ res2: u.Type = O.S3
scala> memType(S4, fTpe)
res3: u.Type = S4
-scala>
+scala> :quit
diff --git a/test/files/run/t6187.check b/test/files/run/t6187.check
index 0180125809..9a9e266ec6 100644
--- a/test/files/run/t6187.check
+++ b/test/files/run/t6187.check
@@ -29,4 +29,4 @@ res1: List[Int] = List(1)
scala> List("") collect { case x => x }
res2: List[String] = List("")
-scala>
+scala> :quit
diff --git a/test/files/run/t6273.check b/test/files/run/t6273.check
index bef0b227d2..3b682800df 100644
--- a/test/files/run/t6273.check
+++ b/test/files/run/t6273.check
@@ -12,4 +12,4 @@ x: String =
y = 55
"
-scala>
+scala> :quit
diff --git a/test/files/run/t6320.check b/test/files/run/t6320.check
index 013acc1c54..af7c865690 100644
--- a/test/files/run/t6320.check
+++ b/test/files/run/t6320.check
@@ -10,4 +10,4 @@ defined class Dyn
scala> new Dyn(Map("foo" -> 10)).foo[Int]
res0: Int = 10
-scala>
+scala> :quit
diff --git a/test/files/run/t6329_repl.check b/test/files/run/t6329_repl.check
index ad0bb46e5b..ebb1aace7c 100644
--- a/test/files/run/t6329_repl.check
+++ b/test/files/run/t6329_repl.check
@@ -32,4 +32,4 @@ res6: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collecti
scala> classTag[scala.collection.immutable.Set[_]]
res7: scala.reflect.ClassTag[scala.collection.immutable.Set[_]] = scala.collection.immutable.Set
-scala>
+scala> :quit
diff --git a/test/files/run/t6329_repl_bug.check b/test/files/run/t6329_repl_bug.check
index 38a8de5606..84297a629f 100644
--- a/test/files/run/t6329_repl_bug.check
+++ b/test/files/run/t6329_repl_bug.check
@@ -14,4 +14,4 @@ res0: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List[<?>]
scala> scala.reflect.classTag[List[_]]
res1: scala.reflect.ClassTag[List[_]] = scala.collection.immutable.List
-scala>
+scala> :quit
diff --git a/test/files/run/t6381.check b/test/files/run/t6381.check
index 4ed11d59ff..49c6a784ad 100644
--- a/test/files/run/t6381.check
+++ b/test/files/run/t6381.check
@@ -16,4 +16,4 @@ defined term macro pos: String
scala> pos
res0: String = class scala.reflect.internal.util.RangePosition
-scala>
+scala> :quit
diff --git a/test/files/run/t6434.check b/test/files/run/t6434.check
index f898b6b781..0a75ae2bd5 100644
--- a/test/files/run/t6434.check
+++ b/test/files/run/t6434.check
@@ -7,4 +7,4 @@ f: (x: => Int)Int
scala> f _
res0: (=> Int) => Int = <function1>
-scala>
+scala> :quit
diff --git a/test/files/run/t6439.check b/test/files/run/t6439.check
index f8d5b3a8cd..c4b7591069 100644
--- a/test/files/run/t6439.check
+++ b/test/files/run/t6439.check
@@ -70,4 +70,4 @@ defined object lookup
scala> lookup("F") // this now works as a result of changing .typeSymbol to .typeSymbolDirect in IMain#Request#definedSymbols
res0: $r.intp.global.Symbol = type F
-scala>
+scala> :quit
diff --git a/test/files/run/t6440.check b/test/files/run/t6440.check
index 27d5d1380e..2358f08fcc 100644
--- a/test/files/run/t6440.check
+++ b/test/files/run/t6440.check
@@ -1,4 +1,5 @@
-pos: source-newSource1.scala,line-9,offset=109 bad symbolic reference to <root>.pack1 encountered in class file 'U.class'.
-Cannot access term pack1 in package <root>. The current classpath may be
-missing a definition for <root>.pack1, or U.class may have been compiled against a version that's
-incompatible with the one found on the current classpath. ERROR
+pos: source-newSource1.scala,line-9,offset=109 missing or invalid dependency detected while loading class file 'U.class'.
+Could not access term pack1 in package <root>,
+because it (or its dependencies) are missing. Check your build definition for
+missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
+A full rebuild may help if 'U.class' was compiled against an incompatible version of <root>. ERROR
diff --git a/test/files/run/t6440b.check b/test/files/run/t6440b.check
index 0b642c2c35..a6100d6d1e 100644
--- a/test/files/run/t6440b.check
+++ b/test/files/run/t6440b.check
@@ -1,4 +1,5 @@
-pos: NoPosition bad symbolic reference to pack1.T encountered in class file 'U.class'.
-Cannot access type T in package pack1. The current classpath may be
-missing a definition for pack1.T, or U.class may have been compiled against a version that's
-incompatible with the one found on the current classpath. ERROR
+pos: NoPosition missing or invalid dependency detected while loading class file 'U.class'.
+Could not access type T in package pack1,
+because it (or its dependencies) are missing. Check your build definition for
+missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.)
+A full rebuild may help if 'U.class' was compiled against an incompatible version of pack1. ERROR
diff --git a/test/files/run/t6507.check b/test/files/run/t6507.check
index 3536c42381..5da4aa3a24 100644
--- a/test/files/run/t6507.check
+++ b/test/files/run/t6507.check
@@ -21,4 +21,4 @@ scala> res0
!
res1: A = A
-scala>
+scala> :quit
diff --git a/test/files/run/t6549.check b/test/files/run/t6549.check
index d5dfc5ebe8..be3445927e 100644
--- a/test/files/run/t6549.check
+++ b/test/files/run/t6549.check
@@ -25,4 +25,4 @@ m(scala.Symbol("s")).xxx: Any = 's
scala> val `"` = 0
": Int = 0
-scala>
+scala> :quit
diff --git a/test/files/run/t6631.scala b/test/files/run/t6631.scala
deleted file mode 100644
index e472b83d50..0000000000
--- a/test/files/run/t6631.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-import reflect.ClassTag
-
-object Test extends App {
- def intercept[T <: Throwable : ClassTag](act: => Any) = try {
- act
- } catch {
- case x: Throwable =>
- val cls = implicitly[ClassTag[T]].runtimeClass
- assert(cls.isInstance(x), (x.getClass, x, cls).toString)
- }
- assert(s"""\f\r\n\t""" == "\f\r\n\t")
-
- import StringContext.InvalidEscapeException
- intercept[InvalidEscapeException](s"""\""")
- intercept[InvalidEscapeException](s"""\x""")
- intercept[InvalidEscapeException](s"\")
-
-}
diff --git a/test/files/run/t6937.check b/test/files/run/t6937.check
index 4729dc7006..5c5d4485b6 100644
--- a/test/files/run/t6937.check
+++ b/test/files/run/t6937.check
@@ -19,4 +19,4 @@ apiru: scala.reflect.api.Universe = <lazy>
scala> apiru.typeTag[A].in(cm)
res0: reflect.runtime.universe.TypeTag[A] = TypeTag[A]
-scala>
+scala> :quit
diff --git a/test/files/run/t7185.check b/test/files/run/t7185.check
index ebf85b731f..e4f80a8ff9 100644
--- a/test/files/run/t7185.check
+++ b/test/files/run/t7185.check
@@ -29,4 +29,4 @@ res0: Any =
}
}
-scala>
+scala> :quit
diff --git a/test/files/run/t7319.check b/test/files/run/t7319.check
index 2ac4142098..e35cfc90c0 100644
--- a/test/files/run/t7319.check
+++ b/test/files/run/t7319.check
@@ -40,4 +40,4 @@ scala> Range(1,2).toArray: Seq[_]
scala> 0
res2: Int = 0
-scala>
+scala> :quit
diff --git a/test/files/run/t7482a.check b/test/files/run/t7482a.check
index 943538f352..a21ef7b68f 100644
--- a/test/files/run/t7482a.check
+++ b/test/files/run/t7482a.check
@@ -7,4 +7,4 @@ v: java.util.ArrayList[String] = []
scala> val v: java.util.ArrayList[String] = new java.util.ArrayList[String](5)
v: java.util.ArrayList[String] = []
-scala>
+scala> :quit
diff --git a/test/files/run/t7634.check b/test/files/run/t7634.check
index aea3b94da5..9c6b8b47dd 100644
--- a/test/files/run/t7634.check
+++ b/test/files/run/t7634.check
@@ -5,4 +5,4 @@ Type :help for more information.
scala> .lines
res1: List[String] = List(shello, world.)
-scala>
+scala> :quit
diff --git a/test/files/run/t7747-repl.check b/test/files/run/t7747-repl.check
index ad924f482c..105b238d01 100644
--- a/test/files/run/t7747-repl.check
+++ b/test/files/run/t7747-repl.check
@@ -283,4 +283,4 @@ object $read extends $read {
}
res3: List[Product with Serializable] = List(BippyBups(), PuppyPups(), Bingo())
-scala>
+scala> :quit
diff --git a/test/files/run/t7801.check b/test/files/run/t7801.check
index d72060c684..e0b656b784 100644
--- a/test/files/run/t7801.check
+++ b/test/files/run/t7801.check
@@ -8,4 +8,4 @@ import g.abort
scala> class C(val a: Any) extends AnyVal
defined class C
-scala>
+scala> :quit
diff --git a/test/files/run/t7805-repl-i.check b/test/files/run/t7805-repl-i.check
index eecfff079a..7f66c06a11 100644
--- a/test/files/run/t7805-repl-i.check
+++ b/test/files/run/t7805-repl-i.check
@@ -8,4 +8,4 @@ Type :help for more information.
scala> Console println Try(8)
Success(8)
-scala>
+scala> :quit
diff --git a/test/files/run/t8608-no-format.scala b/test/files/run/t8608-no-format.scala
new file mode 100644
index 0000000000..71c369a7ea
--- /dev/null
+++ b/test/files/run/t8608-no-format.scala
@@ -0,0 +1,15 @@
+
+import scala.tools.partest.JavapTest
+
+object Test extends JavapTest {
+ def code = """
+ |f"hello, world"
+ |:javap -prv -
+ """.stripMargin
+
+ // no format
+ override def yah(res: Seq[String]) = {
+ // note: avoid the word "information"
+ res forall (!_.contains("StringOps.format"))
+ }
+}
diff --git a/test/files/run/t8610.check b/test/files/run/t8610.check
new file mode 100644
index 0000000000..b3ab7a9cef
--- /dev/null
+++ b/test/files/run/t8610.check
@@ -0,0 +1,7 @@
+t8610.scala:6: warning: Adapting argument list by creating a 2-tuple: this may not be what you want.
+ signature: X.f(p: (Int, Int)): Int
+ given arguments: 3, 4
+ after adaptation: X.f((3, 4): (Int, Int))
+ def g = f(3, 4) // adapted
+ ^
+Hi, $name
diff --git a/test/files/run/t8610.flags b/test/files/run/t8610.flags
new file mode 100644
index 0000000000..4195dec383
--- /dev/null
+++ b/test/files/run/t8610.flags
@@ -0,0 +1 @@
+-Xlint:adapted-args
diff --git a/test/files/run/t8610.scala b/test/files/run/t8610.scala
new file mode 100644
index 0000000000..dd9e8e861e
--- /dev/null
+++ b/test/files/run/t8610.scala
@@ -0,0 +1,13 @@
+
+// flags don't warn on u
+case class X(name: String) {
+ def x = "Hi, $name" // missing interp
+ def f(p: (Int, Int)): Int = p._1 * p._2
+ def g = f(3, 4) // adapted
+ def u: Unit = () // unitarian universalist
+}
+
+object Test extends App {
+ // poignant demonstration
+ Console println X("Bob").x
+}
diff --git a/test/files/run/t8738.scala b/test/files/run/t8738.scala
new file mode 100644
index 0000000000..6898301db7
--- /dev/null
+++ b/test/files/run/t8738.scala
@@ -0,0 +1,16 @@
+object Test {
+ def check(a: Range, b: Range) = (a == b) == (a.toList == b.toList)
+ def main(args: Array[String]) {
+ val lo = -2 to 2
+ val hi = lo
+ val step = List(-6,-2,-1,1,2,6)
+ for (i <- lo; j <- hi; n <- step; k <- lo; l <- hi; m <- step) {
+ assert(
+ check(i until j by n, k until l by m) &&
+ check(i until j by n, k to l by m) &&
+ check(i to j by n, k until l by m) &&
+ check(i to j by n, k to l by m)
+ )
+ }
+ }
+}
diff --git a/test/files/run/t8823.scala b/test/files/run/t8823.scala
new file mode 100644
index 0000000000..0ac653566a
--- /dev/null
+++ b/test/files/run/t8823.scala
@@ -0,0 +1,10 @@
+class Tuple2Int(val encoding: Long) extends AnyVal with Product2[Int, Int] {
+ def canEqual(that: Any) = false
+ def _1: Int = 1
+ def _2: Int = 2
+}
+
+object Test extends App {
+ assert(new Tuple2Int(0)._1 == 1)
+ assert(new Tuple2Int(0)._2 == 2)
+}
diff --git a/test/files/run/tpeCache-tyconCache.check b/test/files/run/tpeCache-tyconCache.check
index a892f5477a..ff604819e0 100644
--- a/test/files/run/tpeCache-tyconCache.check
+++ b/test/files/run/tpeCache-tyconCache.check
@@ -16,4 +16,4 @@ res0: Boolean = true
scala> AnyRefClass.tpe eq AnyRefClass.typeConstructor
res1: Boolean = true
-scala>
+scala> :quit
diff --git a/test/files/run/typetags_serialize.check b/test/files/run/typetags_serialize.check
index f79436ea5d..22928a2e94 100644
--- a/test/files/run/typetags_serialize.check
+++ b/test/files/run/typetags_serialize.check
@@ -1,2 +1,3 @@
-java.io.NotSerializableException: scala.reflect.api.TypeTags$PredefTypeCreator
-java.io.NotSerializableException: Test$$typecreator1$1
+TypeTag[Int]
+TypeTag[String]
+TypeTag[Test.C[Double]]
diff --git a/test/files/run/typetags_serialize.scala b/test/files/run/typetags_serialize.scala
index 3c842e6cc9..a7a7845232 100644
--- a/test/files/run/typetags_serialize.scala
+++ b/test/files/run/typetags_serialize.scala
@@ -4,6 +4,10 @@ import scala.reflect.runtime.{universe => ru}
import scala.reflect.runtime.{currentMirror => cm}
object Test extends App {
+ class C[A] {
+ def m(a: A): Int = 5
+ }
+
def test(tag: TypeTag[_]) =
try {
val fout = new ByteArrayOutputStream()
@@ -26,4 +30,5 @@ object Test extends App {
test(implicitly[TypeTag[Int]])
test(implicitly[TypeTag[String]])
+ test(implicitly[TypeTag[C[Double]]])
} \ No newline at end of file
diff --git a/test/files/run/typetags_without_scala_reflect_typetag_lookup.scala b/test/files/run/typetags_without_scala_reflect_typetag_lookup.scala
index 1fbdc62a1e..3d2b9f77be 100644
--- a/test/files/run/typetags_without_scala_reflect_typetag_lookup.scala
+++ b/test/files/run/typetags_without_scala_reflect_typetag_lookup.scala
@@ -36,8 +36,8 @@ object Test extends StoreReporterDirectTest {
println(filteredInfos.mkString("\n"))
storeReporter.infos.clear()
compileApp();
- // we should get bad symbolic reference errors, because we're trying to use an implicit that can't be unpickled
+ // we should get "missing or invalid dependency detected" errors, because we're trying to use an implicit that can't be unpickled
// but we don't know the number of these errors and their order, so I just ignore them all
- println(filteredInfos.filterNot(_.msg.contains("bad symbolic reference")).mkString("\n"))
+ println(filteredInfos.filterNot(_.msg.contains("missing or invalid dependency detected")).mkString("\n"))
}
}
diff --git a/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.scala b/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.scala
index 6804baa0c3..a865f4d137 100644
--- a/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.scala
+++ b/test/files/run/typetags_without_scala_reflect_typetag_manifest_interop.scala
@@ -40,8 +40,8 @@ object Test extends StoreReporterDirectTest {
println(filteredInfos.mkString("\n"))
storeReporter.infos.clear()
compileApp();
- // we should get bad symbolic reference errors, because we're trying to use an implicit that can't be unpickled
+ // we should get "missing or invalid dependency detected" errors, because we're trying to use an implicit that can't be unpickled
// but we don't know the number of these errors and their order, so I just ignore them all
- println(filteredInfos.filterNot (_.msg.contains("bad symbolic reference")).mkString("\n"))
+ println(filteredInfos.filterNot (_.msg.contains("missing or invalid dependency detected")).mkString("\n"))
}
}
diff --git a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
index 49ffaff630..07e8f3faac 100644
--- a/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermDeconstructionProps.scala
@@ -246,4 +246,11 @@ object TermDeconstructionProps extends QuasiquoteProperties("term deconstruction
assert(f ≈ `new`)
assert(argss.isEmpty)
}
+
+ property("SI-8703 extract block with single expression") = test {
+ val q"{ $a }" = Block(Nil, q"1")
+ val Literal(Constant(1)) = a
+ val q"{ $b }" = q"2"
+ val Literal(Constant(2)) = b
+ }
}
diff --git a/test/junit/scala/StringContextTest.scala b/test/junit/scala/StringContextTest.scala
index 5abfe90cd1..608b82bd96 100644
--- a/test/junit/scala/StringContextTest.scala
+++ b/test/junit/scala/StringContextTest.scala
@@ -48,4 +48,31 @@ class StringContextTest {
val res = processEscapes(s)
assertEquals("Scala", res)
}
+
+ @Test def t6631_baseline() = assertEquals("\f\r\n\t", s"""\f\r\n\t""")
+
+ @Test def t6631_badEscape() = assertThrows[InvalidEscapeException] {
+ s"""\x"""
+ }
+
+ // verifying that the standard interpolators can be supplanted
+ @Test def antiHijack_?() = {
+ object AllYourStringsAreBelongToMe { case class StringContext(args: Any*) { def s(args: Any) = "!!!!" } }
+ import AllYourStringsAreBelongToMe._
+ //assertEquals("????", s"????")
+ assertEquals("!!!!", s"????") // OK to hijack core interpolator ids
+ }
+
+ @Test def fIf() = {
+ val res = f"${if (true) 2.5 else 2.5}%.2f"
+ assertEquals("2.50", res)
+ }
+ @Test def fIfNot() = {
+ val res = f"${if (false) 2.5 else 3.5}%.2f"
+ assertEquals("3.50", res)
+ }
+ @Test def fHeteroArgs() = {
+ val res = f"${3.14}%.2f rounds to ${3}%d"
+ assertEquals("3.14 rounds to 3", res)
+ }
}
diff --git a/test/junit/scala/collection/StreamTest.scala b/test/junit/scala/collection/StreamTest.scala
new file mode 100644
index 0000000000..6dc1c79a48
--- /dev/null
+++ b/test/junit/scala/collection/StreamTest.scala
@@ -0,0 +1,18 @@
+package scala.collection.immutable
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Test
+import org.junit.Assert._
+
+@RunWith(classOf[JUnit4])
+class StreamTest {
+
+ @Test
+ def t6727_and_t6440(): Unit = {
+ assertTrue(Stream.continually(()).filter(_ => true).take(2) == Seq((), ()))
+ assertTrue(Stream.continually(()).filterNot(_ => false).take(2) == Seq((), ()))
+ assertTrue(Stream(1,2,3,4,5).filter(_ < 4) == Seq(1,2,3))
+ assertTrue(Stream(1,2,3,4,5).filterNot(_ > 4) == Seq(1,2,3,4))
+ }
+}
diff --git a/test/junit/scala/reflect/QTest.scala b/test/junit/scala/reflect/QTest.scala
new file mode 100644
index 0000000000..24c35dc401
--- /dev/null
+++ b/test/junit/scala/reflect/QTest.scala
@@ -0,0 +1,23 @@
+
+package scala.reflect
+
+import org.junit.Test
+import org.junit.Assert._
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import scala.tools.testing.AssertUtil._
+
+@RunWith(classOf[JUnit4])
+class QTest {
+
+ import reflect.runtime._
+ import universe._
+ @Test def qConstantsNotHomogenized() = {
+ //Apply(Select(Literal(Constant(1.0)), TermName("$plus")), List(Literal(Constant(1.0))))
+ val t = q"${1} + ${1.0}"
+ val Apply(Select(Literal(Constant(i)), TermName("$plus")), List(Literal(Constant(j)))) = t
+ assertEquals(1, i)
+ assertEquals(1.0, j)
+ }
+}
diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
index b592d06501..cb7e7050b0 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala
@@ -10,29 +10,33 @@ import org.junit.Assert._
@RunWith(classOf[JUnit4])
class BTypesTest {
- val g: Global = new Global(new Settings())
+ val settings = new Settings()
+ settings.processArgumentString("-usejavacp")
+ val g: Global = new Global(settings)
+ val run = new g.Run() // initializes some compiler internals
+ import g.{definitions => d, Symbol}
- val btypes = new BTypes[g.type](g) {
- def chrs = g.chrs
- override type BTypeName = g.TypeName
- override def createNewName(s: String) = g.newTypeName(s)
- }
+ def duringBackend[T](f: => T) = g.exitingDelambdafy(f)
+ val btypes = new BTypesFromSymbols[g.type](g)
import btypes._
+ duringBackend(btypes.intializeCoreBTypes())
+
+ def classBTypeFromSymbol(sym: Symbol) = duringBackend(btypes.classBTypeFromSymbol(sym))
- val jls = "java/lang/String"
- val jlo = "java/lang/Object"
+ val jlo = d.ObjectClass
+ val jls = d.StringClass
- val o = ClassBType(jlo)
- val s = ClassBType(jls)
+ val o = classBTypeFromSymbol(jlo)
+ val s = classBTypeFromSymbol(jls)
val oArr = ArrayBType(o)
val method = MethodBType(List(oArr, INT, DOUBLE, s), UNIT)
@Test
def classBTypesEquality() {
- val s1 = ClassBType(jls)
- val s2 = ClassBType(jls)
- val o = ClassBType(jlo)
+ val s1 = classBTypeFromSymbol(jls)
+ val s2 = classBTypeFromSymbol(jls)
+ val o = classBTypeFromSymbol(jlo)
assertEquals(s1, s2)
assertEquals(s1.hashCode, s2.hashCode)
assert(s1 != o)
@@ -40,11 +44,6 @@ class BTypesTest {
}
@Test
- def classBTypeRequiresInternalName() {
- assertThrows[AssertionError](ClassBType(s"L$jls;"), _ contains "Descriptor instead of internal name")
- }
-
- @Test
def typedOpcodes() {
assert(UNIT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD)
assert(INT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD)
@@ -55,7 +54,7 @@ class BTypesTest {
assert(FLOAT.typedOpcode(Opcodes.IALOAD) == Opcodes.FALOAD)
assert(LONG.typedOpcode(Opcodes.IALOAD) == Opcodes.LALOAD)
assert(DOUBLE.typedOpcode(Opcodes.IALOAD) == Opcodes.DALOAD)
- assert(ClassBType(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD)
+ assert(classBTypeFromSymbol(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD)
assert(UNIT.typedOpcode(Opcodes.IRETURN) == Opcodes.RETURN)
assert(BOOL.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN)
@@ -66,7 +65,7 @@ class BTypesTest {
assert(FLOAT.typedOpcode(Opcodes.IRETURN) == Opcodes.FRETURN)
assert(LONG.typedOpcode(Opcodes.IRETURN) == Opcodes.LRETURN)
assert(DOUBLE.typedOpcode(Opcodes.IRETURN) == Opcodes.DRETURN)
- assert(ClassBType(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN)
+ assert(classBTypeFromSymbol(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN)
}
@Test
@@ -84,21 +83,9 @@ class BTypesTest {
}
}
+ // TODO @lry do more tests
@Test
- def parseMethodDescriptorTest() {
- val descriptors = List(
- "()V",
- "(ID)I",
- "([[I[D)[D",
- s"(L$jls;[L$jlo;)[[L$jls;",
- s"(IL$jlo;)L$jls;"
- )
- for (d <- descriptors) {
- assertEquals(d, MethodBType(d).descriptor)
- }
+ def maxTypeTest() {
- // class types in method descriptor need surrounding 'L' and ';'
- assertThrows[MatchError](MethodBType("(java/lang/String)V"), _ == "j (of class java.lang.Character)")
- assertThrows[AssertionError](MethodBType("I"), _ contains "Not a valid method descriptor")
}
}
diff --git a/test/junit/scala/tools/nsc/settings/SettingsTest.scala b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
index e4b5ecc7c3..960d7f8ac1 100644
--- a/test/junit/scala/tools/nsc/settings/SettingsTest.scala
+++ b/test/junit/scala/tools/nsc/settings/SettingsTest.scala
@@ -26,7 +26,7 @@ class SettingsTest {
assertThrows[IllegalArgumentException](check("-Ytest-setting:rubbish"))
}
- @Test def userSettingsHavePredecenceOverOptimize() {
+ @Test def userSettingsHavePrecedenceOverOptimize() {
def check(args: String*): MutableSettings#BooleanSetting = {
val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
val (ok, residual) = s.processArguments(args.toList, processAll = true)
@@ -38,15 +38,23 @@ class SettingsTest {
assertFalse(check("-Yinline:false", "-optimise").value)
}
- @Test def userSettingsHavePredecenceOverLint() {
- def check(args: String*): MutableSettings#BooleanSetting = {
- val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
- val (ok, residual) = s.processArguments(args.toList, processAll = true)
- assert(residual.isEmpty)
- s.warnAdaptedArgs // among Xlint
- }
- assertTrue(check("-Xlint").value)
- assertFalse(check("-Xlint", "-Ywarn-adapted-args:false").value)
- assertFalse(check("-Ywarn-adapted-args:false", "-Xlint").value)
+ // for the given args, select the desired setting
+ private def check(args: String*)(b: MutableSettings => MutableSettings#BooleanSetting): MutableSettings#BooleanSetting = {
+ val s = new MutableSettings(msg => throw new IllegalArgumentException(msg))
+ val (ok, residual) = s.processArguments(args.toList, processAll = true)
+ assert(residual.isEmpty)
+ b(s)
+ }
+ @Test def userSettingsHavePrecedenceOverLint() {
+ assertTrue(check("-Xlint")(_.warnAdaptedArgs))
+ assertFalse(check("-Xlint", "-Ywarn-adapted-args:false")(_.warnAdaptedArgs))
+ assertFalse(check("-Ywarn-adapted-args:false", "-Xlint")(_.warnAdaptedArgs))
+ }
+
+ @Test def anonymousLintersCanBeNamed() {
+ assertTrue(check("-Xlint")(_.warnMissingInterpolator)) // among Xlint
+ assertFalse(check("-Xlint:-missing-interpolator")(_.warnMissingInterpolator))
+ assertFalse(check("-Xlint:-missing-interpolator", "-Xlint")(_.warnMissingInterpolator))
+ assertFalse(check("-Xlint", "-Xlint:-missing-interpolator")(_.warnMissingInterpolator))
}
}
diff --git a/test/junit/scala/util/matching/RegexTest.scala b/test/junit/scala/util/matching/RegexTest.scala
index d25842cc57..5b13397d6a 100644
--- a/test/junit/scala/util/matching/RegexTest.scala
+++ b/test/junit/scala/util/matching/RegexTest.scala
@@ -27,4 +27,21 @@ class RegexTest {
assertEquals("1", x)
assertEquals("1", y)
}
+
+ @Test def t8787nullMatch() = {
+ val r = """\d+""".r
+ val s: String = null
+ val x = s match { case r() => 1 ; case _ => 2 }
+ assertEquals(2, x)
+ }
+
+ @Test def t8787nullMatcher() = {
+ val r = """(\d+):(\d+)""".r
+ val s = "1:2 3:4 5:6"
+ val z = ((r findAllMatchIn s).toList :+ null) flatMap {
+ case r(x, y) => Some((x.toInt, y.toInt))
+ case _ => None
+ }
+ assertEquals(List((1,2),(3,4),(5,6)), z)
+ }
}
diff --git a/test/scaladoc/run/t8314.check b/test/scaladoc/run/t8314.check
new file mode 100644
index 0000000000..aa04c12c8f
--- /dev/null
+++ b/test/scaladoc/run/t8314.check
@@ -0,0 +1,3 @@
+Body(List(Paragraph(Chain(List(Summary(Chain(List(Text(This should be ), Monospace(Text(monospaced))))))))))
+
+Done.
diff --git a/test/scaladoc/run/t8314.scala b/test/scaladoc/run/t8314.scala
new file mode 100644
index 0000000000..7f6d6fdb00
--- /dev/null
+++ b/test/scaladoc/run/t8314.scala
@@ -0,0 +1,16 @@
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+ override def code = """
+ /** This should be `monospaced` */
+ class A
+ """
+
+ def scaladocSettings = ""
+
+ def testModel(root: Package) = {
+ import access._
+ root._class("A").comment foreach println
+ }
+}
diff --git a/test/scaladoc/run/t8557.check b/test/scaladoc/run/t8557.check
new file mode 100644
index 0000000000..619c56180b
--- /dev/null
+++ b/test/scaladoc/run/t8557.check
@@ -0,0 +1 @@
+Done.
diff --git a/test/scaladoc/run/t8557.scala b/test/scaladoc/run/t8557.scala
new file mode 100644
index 0000000000..451f004d7d
--- /dev/null
+++ b/test/scaladoc/run/t8557.scala
@@ -0,0 +1,32 @@
+import scala.tools.nsc.doc.base._
+import scala.tools.nsc.doc.model._
+import scala.tools.partest.ScaladocModelTest
+
+object Test extends ScaladocModelTest {
+
+ override def code = """
+ package scala.test.scaladoc.T8857
+
+ /**
+ * A link:
+ *
+ * [[scala.Option$ object Option]].
+ */
+ class A
+ """
+
+ // a non-canonical path to scala-library.jar should still work
+ // this is a bit fragile (depends on the current directory being the root of the repo ;
+ // ant & partest seem to do that properly)
+ def scaladocSettings = "-doc-external-doc build/pack/bin/../lib/scala-library.jar#http://www.scala-lang.org/api/current/"
+
+ def testModel(rootPackage: Package) = {
+ // get the quick access implicit defs in scope (_package(s), _class(es), _trait(s), object(s) _method(s), _value(s))
+ import access._
+
+ val a = rootPackage._package("scala")._package("test")._package("scaladoc")._package("T8857")._class("A")
+
+ val links = countLinks(a.comment.get, _.link.isInstanceOf[LinkToExternal])
+ assert(links == 1, links + " == 1 (the links to external in class A)")
+ }
+}
diff --git a/versions.properties b/versions.properties
index 1212734d22..c334629d20 100644
--- a/versions.properties
+++ b/versions.properties
@@ -24,6 +24,7 @@ scala-continuations-library.version.number=1.0.2
scala-swing.version.number=1.0.1
akka-actor.version.number=2.3.3
actors-migration.version.number=1.1.0
+jline.version=2.12
# external modules, used internally (not shipped)
partest.version.number=1.0.0